Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/prusa3d/PrusaSlicer.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/xs/src/igl
diff options
context:
space:
mode:
Diffstat (limited to 'xs/src/igl')
-rw-r--r--xs/src/igl/AABB.cpp1075
-rw-r--r--xs/src/igl/AABB.h413
-rw-r--r--xs/src/igl/ARAPEnergyType.h36
-rw-r--r--xs/src/igl/AtA_cached.cpp130
-rw-r--r--xs/src/igl/AtA_cached.h70
-rw-r--r--xs/src/igl/C_STR.h18
-rw-r--r--xs/src/igl/Camera.h359
-rw-r--r--xs/src/igl/EPS.cpp30
-rw-r--r--xs/src/igl/EPS.h32
-rw-r--r--xs/src/igl/HalfEdgeIterator.cpp158
-rw-r--r--xs/src/igl/HalfEdgeIterator.h114
-rw-r--r--xs/src/igl/Hit.h25
-rw-r--r--xs/src/igl/IO28
-rw-r--r--xs/src/igl/IndexComparison.h117
-rw-r--r--xs/src/igl/LinSpaced.h61
-rw-r--r--xs/src/igl/MeshBooleanType.h23
-rw-r--r--xs/src/igl/NormalType.h27
-rw-r--r--xs/src/igl/ONE.h22
-rw-r--r--xs/src/igl/PI.h19
-rw-r--r--xs/src/igl/REDRUM.h55
-rw-r--r--xs/src/igl/STR.h18
-rw-r--r--xs/src/igl/Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp128
-rw-r--r--xs/src/igl/Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp118
-rw-r--r--xs/src/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp137
-rw-r--r--xs/src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp1277
-rw-r--r--xs/src/igl/Singular_Value_Decomposition_Preamble.hpp78
-rw-r--r--xs/src/igl/SolverStatus.h23
-rw-r--r--xs/src/igl/SortableRow.h70
-rw-r--r--xs/src/igl/Timer.h179
-rw-r--r--xs/src/igl/Viewport.h69
-rw-r--r--xs/src/igl/WindingNumberAABB.h377
-rw-r--r--xs/src/igl/WindingNumberMethod.h23
-rw-r--r--xs/src/igl/WindingNumberTree.h503
-rw-r--r--xs/src/igl/ZERO.h21
-rwxr-xr-xxs/src/igl/active_set.cpp370
-rw-r--r--xs/src/igl/active_set.h111
-rw-r--r--xs/src/igl/adjacency_list.cpp168
-rw-r--r--xs/src/igl/adjacency_list.h51
-rw-r--r--xs/src/igl/adjacency_matrix.cpp74
-rw-r--r--xs/src/igl/adjacency_matrix.h51
-rw-r--r--xs/src/igl/all.cpp26
-rw-r--r--xs/src/igl/all.h36
-rw-r--r--xs/src/igl/all_edges.cpp26
-rw-r--r--xs/src/igl/all_edges.h38
-rw-r--r--xs/src/igl/all_pairs_distances.cpp39
-rw-r--r--xs/src/igl/all_pairs_distances.h41
-rw-r--r--xs/src/igl/ambient_occlusion.cpp137
-rw-r--r--xs/src/igl/ambient_occlusion.h80
-rw-r--r--xs/src/igl/angular_distance.cpp20
-rw-r--r--xs/src/igl/angular_distance.h30
-rw-r--r--xs/src/igl/anttweakbar/ReAntTweakBar.cpp934
-rw-r--r--xs/src/igl/anttweakbar/ReAntTweakBar.h286
-rw-r--r--xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.cpp81
-rw-r--r--xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.h31
-rw-r--r--xs/src/igl/any.cpp26
-rw-r--r--xs/src/igl/any.h35
-rw-r--r--xs/src/igl/any_of.cpp20
-rw-r--r--xs/src/igl/any_of.h26
-rw-r--r--xs/src/igl/arap.cpp312
-rw-r--r--xs/src/igl/arap.h104
-rw-r--r--xs/src/igl/arap_dof.cpp884
-rw-r--r--xs/src/igl/arap_dof.h244
-rw-r--r--xs/src/igl/arap_linear_block.cpp253
-rw-r--r--xs/src/igl/arap_linear_block.h78
-rw-r--r--xs/src/igl/arap_rhs.cpp89
-rw-r--r--xs/src/igl/arap_rhs.h42
-rw-r--r--xs/src/igl/average_onto_faces.cpp29
-rw-r--r--xs/src/igl/average_onto_faces.h36
-rw-r--r--xs/src/igl/average_onto_vertices.cpp33
-rw-r--r--xs/src/igl/average_onto_vertices.h35
-rw-r--r--xs/src/igl/avg_edge_length.cpp39
-rw-r--r--xs/src/igl/avg_edge_length.h41
-rw-r--r--xs/src/igl/axis_angle_to_quat.cpp42
-rw-r--r--xs/src/igl/axis_angle_to_quat.h33
-rw-r--r--xs/src/igl/barycenter.cpp57
-rw-r--r--xs/src/igl/barycenter.h36
-rw-r--r--xs/src/igl/barycentric_coordinates.cpp113
-rw-r--r--xs/src/igl/barycentric_coordinates.h68
-rwxr-xr-xxs/src/igl/barycentric_to_global.cpp44
-rwxr-xr-xxs/src/igl/barycentric_to_global.h42
-rw-r--r--xs/src/igl/basename.cpp38
-rw-r--r--xs/src/igl/basename.h29
-rw-r--r--xs/src/igl/bbw.cpp143
-rw-r--r--xs/src/igl/bbw.h77
-rw-r--r--xs/src/igl/bfs.cpp93
-rw-r--r--xs/src/igl/bfs.h54
-rw-r--r--xs/src/igl/bfs_orient.cpp100
-rw-r--r--xs/src/igl/bfs_orient.h36
-rw-r--r--xs/src/igl/biharmonic_coordinates.cpp203
-rw-r--r--xs/src/igl/biharmonic_coordinates.h90
-rw-r--r--xs/src/igl/bijective_composite_harmonic_mapping.cpp115
-rw-r--r--xs/src/igl/bijective_composite_harmonic_mapping.h79
-rw-r--r--xs/src/igl/bone_parents.cpp32
-rw-r--r--xs/src/igl/bone_parents.h32
-rw-r--r--xs/src/igl/boundary_conditions.cpp192
-rw-r--r--xs/src/igl/boundary_conditions.h55
-rw-r--r--xs/src/igl/boundary_facets.cpp141
-rw-r--r--xs/src/igl/boundary_facets.h52
-rwxr-xr-xxs/src/igl/boundary_loop.cpp153
-rwxr-xr-xxs/src/igl/boundary_loop.h66
-rw-r--r--xs/src/igl/bounding_box.cpp103
-rw-r--r--xs/src/igl/bounding_box.h39
-rw-r--r--xs/src/igl/bounding_box_diagonal.cpp26
-rw-r--r--xs/src/igl/bounding_box_diagonal.h28
-rw-r--r--xs/src/igl/canonical_quaternions.cpp21
-rw-r--r--xs/src/igl/canonical_quaternions.h129
-rw-r--r--xs/src/igl/cat.cpp267
-rw-r--r--xs/src/igl/cat.h71
-rw-r--r--xs/src/igl/ceil.cpp33
-rw-r--r--xs/src/igl/ceil.h30
-rw-r--r--xs/src/igl/centroid.cpp67
-rw-r--r--xs/src/igl/centroid.h49
-rw-r--r--xs/src/igl/circulation.cpp71
-rw-r--r--xs/src/igl/circulation.h56
-rw-r--r--xs/src/igl/circumradius.cpp26
-rw-r--r--xs/src/igl/circumradius.h34
-rw-r--r--xs/src/igl/collapse_edge.cpp394
-rw-r--r--xs/src/igl/collapse_edge.h216
-rw-r--r--xs/src/igl/collapse_small_triangles.cpp139
-rw-r--r--xs/src/igl/collapse_small_triangles.h40
-rw-r--r--xs/src/igl/colon.cpp66
-rw-r--r--xs/src/igl/colon.h65
-rw-r--r--xs/src/igl/colormap.cpp1434
-rw-r--r--xs/src/igl/colormap.h76
-rw-r--r--xs/src/igl/column_to_quats.cpp27
-rw-r--r--xs/src/igl/column_to_quats.h34
-rw-r--r--xs/src/igl/columnize.cpp63
-rw-r--r--xs/src/igl/columnize.h41
-rw-r--r--xs/src/igl/comb_cross_field.cpp148
-rw-r--r--xs/src/igl/comb_cross_field.h41
-rw-r--r--xs/src/igl/comb_frame_field.cpp82
-rw-r--r--xs/src/igl/comb_frame_field.h47
-rw-r--r--xs/src/igl/comb_line_field.cpp132
-rw-r--r--xs/src/igl/comb_line_field.h39
-rw-r--r--xs/src/igl/combine.cpp97
-rw-r--r--xs/src/igl/combine.h65
-rw-r--r--xs/src/igl/components.cpp98
-rw-r--r--xs/src/igl/components.h52
-rw-r--r--xs/src/igl/compute_frame_field_bisectors.cpp85
-rw-r--r--xs/src/igl/compute_frame_field_bisectors.h53
-rw-r--r--xs/src/igl/connect_boundary_to_infinity.cpp55
-rw-r--r--xs/src/igl/connect_boundary_to_infinity.h56
-rw-r--r--xs/src/igl/copyleft/README.md14
-rw-r--r--xs/src/igl/copyleft/cgal/BinaryWindingNumberOperations.h167
-rw-r--r--xs/src/igl/copyleft/cgal/CGAL_includes.hpp50
-rw-r--r--xs/src/igl/copyleft/cgal/CSGTree.h189
-rw-r--r--xs/src/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h36
-rw-r--r--xs/src/igl/copyleft/cgal/SelfIntersectMesh.h939
-rw-r--r--xs/src/igl/copyleft/cgal/assign.cpp80
-rw-r--r--xs/src/igl/copyleft/cgal/assign.h42
-rw-r--r--xs/src/igl/copyleft/cgal/assign_scalar.cpp136
-rw-r--r--xs/src/igl/copyleft/cgal/assign_scalar.h74
-rw-r--r--xs/src/igl/copyleft/cgal/barycenter.cpp15
-rw-r--r--xs/src/igl/copyleft/cgal/cell_adjacency.cpp34
-rw-r--r--xs/src/igl/copyleft/cgal/cell_adjacency.h50
-rw-r--r--xs/src/igl/copyleft/cgal/closest_facet.cpp504
-rw-r--r--xs/src/igl/copyleft/cgal/closest_facet.h110
-rw-r--r--xs/src/igl/copyleft/cgal/complex_to_mesh.cpp152
-rw-r--r--xs/src/igl/copyleft/cgal/complex_to_mesh.h47
-rw-r--r--xs/src/igl/copyleft/cgal/component_inside_component.cpp83
-rw-r--r--xs/src/igl/copyleft/cgal/component_inside_component.h75
-rw-r--r--xs/src/igl/copyleft/cgal/convex_hull.cpp72
-rw-r--r--xs/src/igl/copyleft/cgal/convex_hull.h56
-rw-r--r--xs/src/igl/copyleft/cgal/delaunay_triangulation.cpp62
-rw-r--r--xs/src/igl/copyleft/cgal/delaunay_triangulation.h47
-rw-r--r--xs/src/igl/copyleft/cgal/extract_cells.cpp547
-rw-r--r--xs/src/igl/copyleft/cgal/extract_cells.h116
-rw-r--r--xs/src/igl/copyleft/cgal/extract_feature.cpp123
-rw-r--r--xs/src/igl/copyleft/cgal/extract_feature.h90
-rw-r--r--xs/src/igl/copyleft/cgal/fast_winding_number.cpp82
-rw-r--r--xs/src/igl/copyleft/cgal/fast_winding_number.h66
-rw-r--r--xs/src/igl/copyleft/cgal/half_space_box.cpp123
-rw-r--r--xs/src/igl/copyleft/cgal/half_space_box.h63
-rw-r--r--xs/src/igl/copyleft/cgal/hausdorff.cpp39
-rw-r--r--xs/src/igl/copyleft/cgal/hausdorff.h62
-rw-r--r--xs/src/igl/copyleft/cgal/incircle.cpp39
-rw-r--r--xs/src/igl/copyleft/cgal/incircle.h39
-rw-r--r--xs/src/igl/copyleft/cgal/insert_into_cdt.cpp68
-rw-r--r--xs/src/igl/copyleft/cgal/insert_into_cdt.h60
-rw-r--r--xs/src/igl/copyleft/cgal/insphere.cpp41
-rw-r--r--xs/src/igl/copyleft/cgal/insphere.h40
-rw-r--r--xs/src/igl/copyleft/cgal/intersect_other.cpp289
-rw-r--r--xs/src/igl/copyleft/cgal/intersect_other.h91
-rw-r--r--xs/src/igl/copyleft/cgal/intersect_with_half_space.cpp88
-rw-r--r--xs/src/igl/copyleft/cgal/intersect_with_half_space.h96
-rw-r--r--xs/src/igl/copyleft/cgal/lexicographic_triangulation.cpp24
-rw-r--r--xs/src/igl/copyleft/cgal/lexicographic_triangulation.h47
-rw-r--r--xs/src/igl/copyleft/cgal/list_to_matrix.cpp15
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_boolean.cpp466
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_boolean.h229
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp39
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h37
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp76
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h44
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_to_polyhedron.cpp54
-rw-r--r--xs/src/igl/copyleft/cgal/mesh_to_polyhedron.h42
-rw-r--r--xs/src/igl/copyleft/cgal/minkowski_sum.cpp395
-rw-r--r--xs/src/igl/copyleft/cgal/minkowski_sum.h110
-rw-r--r--xs/src/igl/copyleft/cgal/order_facets_around_edge.cpp428
-rw-r--r--xs/src/igl/copyleft/cgal/order_facets_around_edge.h77
-rw-r--r--xs/src/igl/copyleft/cgal/order_facets_around_edges.cpp332
-rw-r--r--xs/src/igl/copyleft/cgal/order_facets_around_edges.h107
-rw-r--r--xs/src/igl/copyleft/cgal/orient2D.cpp37
-rw-r--r--xs/src/igl/copyleft/cgal/orient2D.h38
-rw-r--r--xs/src/igl/copyleft/cgal/orient3D.cpp39
-rw-r--r--xs/src/igl/copyleft/cgal/orient3D.h39
-rw-r--r--xs/src/igl/copyleft/cgal/outer_element.cpp232
-rw-r--r--xs/src/igl/copyleft/cgal/outer_element.h83
-rw-r--r--xs/src/igl/copyleft/cgal/outer_facet.cpp180
-rw-r--r--xs/src/igl/copyleft/cgal/outer_facet.h91
-rw-r--r--xs/src/igl/copyleft/cgal/outer_hull.cpp535
-rw-r--r--xs/src/igl/copyleft/cgal/outer_hull.h84
-rw-r--r--xs/src/igl/copyleft/cgal/peel_outer_hull_layers.cpp124
-rw-r--r--xs/src/igl/copyleft/cgal/peel_outer_hull_layers.h47
-rw-r--r--xs/src/igl/copyleft/cgal/peel_winding_number_layers.cpp33
-rw-r--r--xs/src/igl/copyleft/cgal/peel_winding_number_layers.h24
-rw-r--r--xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.cpp27
-rw-r--r--xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.h41
-rw-r--r--xs/src/igl/copyleft/cgal/point_areas.cpp181
-rw-r--r--xs/src/igl/copyleft/cgal/point_areas.h78
-rw-r--r--xs/src/igl/copyleft/cgal/point_mesh_squared_distance.cpp138
-rw-r--r--xs/src/igl/copyleft/cgal/point_mesh_squared_distance.h104
-rw-r--r--xs/src/igl/copyleft/cgal/point_segment_squared_distance.cpp41
-rw-r--r--xs/src/igl/copyleft/cgal/point_segment_squared_distance.h44
-rw-r--r--xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.cpp56
-rw-r--r--xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.h48
-rw-r--r--xs/src/igl/copyleft/cgal/point_triangle_squared_distance.cpp47
-rw-r--r--xs/src/igl/copyleft/cgal/point_triangle_squared_distance.h45
-rw-r--r--xs/src/igl/copyleft/cgal/points_inside_component.cpp350
-rw-r--r--xs/src/igl/copyleft/cgal/points_inside_component.h71
-rw-r--r--xs/src/igl/copyleft/cgal/polyhedron_to_mesh.cpp69
-rw-r--r--xs/src/igl/copyleft/cgal/polyhedron_to_mesh.h43
-rw-r--r--xs/src/igl/copyleft/cgal/projected_cdt.cpp82
-rw-r--r--xs/src/igl/copyleft/cgal/projected_cdt.h61
-rw-r--r--xs/src/igl/copyleft/cgal/projected_delaunay.cpp106
-rw-r--r--xs/src/igl/copyleft/cgal/projected_delaunay.h46
-rw-r--r--xs/src/igl/copyleft/cgal/propagate_winding_numbers.cpp324
-rw-r--r--xs/src/igl/copyleft/cgal/propagate_winding_numbers.h103
-rw-r--r--xs/src/igl/copyleft/cgal/read_triangle_mesh.cpp26
-rw-r--r--xs/src/igl/copyleft/cgal/read_triangle_mesh.h42
-rw-r--r--xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.cpp117
-rw-r--r--xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.h59
-rw-r--r--xs/src/igl/copyleft/cgal/remesh_intersections.cpp533
-rw-r--r--xs/src/igl/copyleft/cgal/remesh_intersections.h94
-rw-r--r--xs/src/igl/copyleft/cgal/remesh_self_intersections.cpp108
-rw-r--r--xs/src/igl/copyleft/cgal/remesh_self_intersections.h81
-rw-r--r--xs/src/igl/copyleft/cgal/remove_unreferenced.cpp20
-rw-r--r--xs/src/igl/copyleft/cgal/resolve_intersections.cpp90
-rw-r--r--xs/src/igl/copyleft/cgal/resolve_intersections.h51
-rw-r--r--xs/src/igl/copyleft/cgal/row_to_point.cpp18
-rw-r--r--xs/src/igl/copyleft/cgal/row_to_point.h38
-rw-r--r--xs/src/igl/copyleft/cgal/segment_segment_squared_distance.cpp129
-rw-r--r--xs/src/igl/copyleft/cgal/segment_segment_squared_distance.h46
-rw-r--r--xs/src/igl/copyleft/cgal/signed_distance_isosurface.cpp138
-rw-r--r--xs/src/igl/copyleft/cgal/signed_distance_isosurface.h54
-rw-r--r--xs/src/igl/copyleft/cgal/slice.cpp12
-rw-r--r--xs/src/igl/copyleft/cgal/slice_mask.cpp15
-rw-r--r--xs/src/igl/copyleft/cgal/snap_rounding.cpp206
-rw-r--r--xs/src/igl/copyleft/cgal/snap_rounding.h51
-rw-r--r--xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.cpp53
-rw-r--r--xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.h44
-rw-r--r--xs/src/igl/copyleft/cgal/subdivide_segments.cpp134
-rw-r--r--xs/src/igl/copyleft/cgal/subdivide_segments.h56
-rw-r--r--xs/src/igl/copyleft/cgal/submesh_aabb_tree.cpp58
-rw-r--r--xs/src/igl/copyleft/cgal/submesh_aabb_tree.h64
-rw-r--r--xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.cpp114
-rw-r--r--xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.h45
-rw-r--r--xs/src/igl/copyleft/cgal/trim_with_solid.cpp105
-rw-r--r--xs/src/igl/copyleft/cgal/trim_with_solid.h63
-rw-r--r--xs/src/igl/copyleft/cgal/unique.cpp14
-rw-r--r--xs/src/igl/copyleft/cgal/unique_rows.cpp18
-rw-r--r--xs/src/igl/copyleft/cgal/wire_mesh.cpp215
-rw-r--r--xs/src/igl/copyleft/cgal/wire_mesh.h67
-rw-r--r--xs/src/igl/copyleft/comiso/frame_field.cpp688
-rw-r--r--xs/src/igl/copyleft/comiso/frame_field.h57
-rw-r--r--xs/src/igl/copyleft/comiso/miq.cpp1534
-rw-r--r--xs/src/igl/copyleft/comiso/miq.h99
-rw-r--r--xs/src/igl/copyleft/comiso/nrosy.cpp941
-rw-r--r--xs/src/igl/copyleft/comiso/nrosy.h73
-rw-r--r--xs/src/igl/copyleft/cork/from_cork_mesh.cpp41
-rw-r--r--xs/src/igl/copyleft/cork/from_cork_mesh.h39
-rw-r--r--xs/src/igl/copyleft/cork/mesh_boolean.cpp99
-rw-r--r--xs/src/igl/copyleft/cork/mesh_boolean.h55
-rw-r--r--xs/src/igl/copyleft/cork/to_cork_mesh.cpp43
-rw-r--r--xs/src/igl/copyleft/cork/to_cork_mesh.h39
-rw-r--r--xs/src/igl/copyleft/marching_cubes.cpp258
-rw-r--r--xs/src/igl/copyleft/marching_cubes.h61
-rw-r--r--xs/src/igl/copyleft/marching_cubes_tables.h917
-rw-r--r--xs/src/igl/copyleft/offset_surface.cpp64
-rw-r--r--xs/src/igl/copyleft/offset_surface.h54
-rw-r--r--xs/src/igl/copyleft/opengl2/render_to_tga.cpp87
-rw-r--r--xs/src/igl/copyleft/opengl2/render_to_tga.h38
-rw-r--r--xs/src/igl/copyleft/opengl2/texture_from_tga.cpp68
-rw-r--r--xs/src/igl/copyleft/opengl2/texture_from_tga.h33
-rw-r--r--xs/src/igl/copyleft/opengl2/tga.cpp549
-rw-r--r--xs/src/igl/copyleft/opengl2/tga.h106
-rw-r--r--xs/src/igl/copyleft/progressive_hulls.cpp31
-rw-r--r--xs/src/igl/copyleft/progressive_hulls.h43
-rw-r--r--xs/src/igl/copyleft/progressive_hulls_cost_and_placement.cpp107
-rw-r--r--xs/src/igl/copyleft/progressive_hulls_cost_and_placement.h54
-rw-r--r--xs/src/igl/copyleft/quadprog.cpp599
-rw-r--r--xs/src/igl/copyleft/quadprog.h48
-rw-r--r--xs/src/igl/copyleft/swept_volume.cpp49
-rw-r--r--xs/src/igl/copyleft/swept_volume.h41
-rw-r--r--xs/src/igl/copyleft/tetgen/README7
-rw-r--r--xs/src/igl/copyleft/tetgen/cdt.cpp64
-rw-r--r--xs/src/igl/copyleft/tetgen/cdt.h72
-rw-r--r--xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.cpp78
-rw-r--r--xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.h55
-rw-r--r--xs/src/igl/copyleft/tetgen/mesh_with_skeleton.cpp102
-rw-r--r--xs/src/igl/copyleft/tetgen/mesh_with_skeleton.h72
-rw-r--r--xs/src/igl/copyleft/tetgen/read_into_tetgenio.cpp74
-rw-r--r--xs/src/igl/copyleft/tetgen/read_into_tetgenio.h62
-rw-r--r--xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp146
-rw-r--r--xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.h66
-rw-r--r--xs/src/igl/copyleft/tetgen/tetrahedralize.cpp220
-rw-r--r--xs/src/igl/copyleft/tetgen/tetrahedralize.h136
-rw-r--r--xs/src/igl/cotmatrix.cpp88
-rw-r--r--xs/src/igl/cotmatrix.h57
-rw-r--r--xs/src/igl/cotmatrix_entries.cpp110
-rw-r--r--xs/src/igl/cotmatrix_entries.h37
-rw-r--r--xs/src/igl/count.cpp65
-rw-r--r--xs/src/igl/count.h46
-rw-r--r--xs/src/igl/covariance_scatter_matrix.cpp76
-rw-r--r--xs/src/igl/covariance_scatter_matrix.h38
-rw-r--r--xs/src/igl/cross.cpp45
-rw-r--r--xs/src/igl/cross.h42
-rw-r--r--xs/src/igl/cross_field_missmatch.cpp142
-rw-r--r--xs/src/igl/cross_field_missmatch.h43
-rw-r--r--xs/src/igl/crouzeix_raviart_cotmatrix.cpp100
-rw-r--r--xs/src/igl/crouzeix_raviart_cotmatrix.h49
-rw-r--r--xs/src/igl/crouzeix_raviart_massmatrix.cpp85
-rw-r--r--xs/src/igl/crouzeix_raviart_massmatrix.h51
-rw-r--r--xs/src/igl/cumsum.cpp72
-rw-r--r--xs/src/igl/cumsum.h43
-rw-r--r--xs/src/igl/cut_mesh.cpp330
-rw-r--r--xs/src/igl/cut_mesh.h83
-rw-r--r--xs/src/igl/cut_mesh_from_singularities.cpp205
-rw-r--r--xs/src/igl/cut_mesh_from_singularities.h42
-rw-r--r--xs/src/igl/cylinder.cpp52
-rw-r--r--xs/src/igl/cylinder.h33
-rw-r--r--xs/src/igl/dated_copy.cpp91
-rw-r--r--xs/src/igl/dated_copy.h34
-rw-r--r--xs/src/igl/decimate.cpp366
-rw-r--r--xs/src/igl/decimate.h255
-rw-r--r--xs/src/igl/deform_skeleton.cpp58
-rw-r--r--xs/src/igl/deform_skeleton.h47
-rw-r--r--xs/src/igl/delaunay_triangulation.cpp86
-rw-r--r--xs/src/igl/delaunay_triangulation.h52
-rw-r--r--xs/src/igl/deprecated.h28
-rw-r--r--xs/src/igl/dfs.cpp60
-rw-r--r--xs/src/igl/dfs.h49
-rw-r--r--xs/src/igl/diag.cpp108
-rw-r--r--xs/src/igl/diag.h62
-rw-r--r--xs/src/igl/dihedral_angles.cpp94
-rw-r--r--xs/src/igl/dihedral_angles.h55
-rw-r--r--xs/src/igl/dijkstra.cpp71
-rw-r--r--xs/src/igl/dijkstra.h60
-rw-r--r--xs/src/igl/directed_edge_orientations.cpp29
-rw-r--r--xs/src/igl/directed_edge_orientations.h39
-rw-r--r--xs/src/igl/directed_edge_parents.cpp34
-rw-r--r--xs/src/igl/directed_edge_parents.h32
-rw-r--r--xs/src/igl/dirname.cpp46
-rw-r--r--xs/src/igl/dirname.h29
-rw-r--r--xs/src/igl/dot.cpp16
-rw-r--r--xs/src/igl/dot.h27
-rw-r--r--xs/src/igl/dot_row.cpp26
-rw-r--r--xs/src/igl/dot_row.h36
-rw-r--r--xs/src/igl/doublearea.cpp263
-rw-r--r--xs/src/igl/doublearea.h104
-rw-r--r--xs/src/igl/dqs.cpp74
-rw-r--r--xs/src/igl/dqs.h42
-rw-r--r--xs/src/igl/ears.cpp34
-rw-r--r--xs/src/igl/ears.h30
-rw-r--r--xs/src/igl/edge_collapse_is_valid.cpp86
-rw-r--r--xs/src/igl/edge_collapse_is_valid.h44
-rw-r--r--xs/src/igl/edge_flaps.cpp60
-rw-r--r--xs/src/igl/edge_flaps.h53
-rw-r--r--xs/src/igl/edge_lengths.cpp56
-rw-r--r--xs/src/igl/edge_lengths.h49
-rw-r--r--xs/src/igl/edge_topology.cpp110
-rw-r--r--xs/src/igl/edge_topology.h50
-rw-r--r--xs/src/igl/edges.cpp47
-rw-r--r--xs/src/igl/edges.h37
-rw-r--r--xs/src/igl/edges_to_path.cpp103
-rw-r--r--xs/src/igl/edges_to_path.h36
-rwxr-xr-xxs/src/igl/eigs.cpp176
-rw-r--r--xs/src/igl/eigs.h61
-rw-r--r--xs/src/igl/embree/EmbreeIntersector.h584
-rw-r--r--xs/src/igl/embree/Embree_convenience.h37
-rw-r--r--xs/src/igl/embree/ambient_occlusion.cpp62
-rw-r--r--xs/src/igl/embree/ambient_occlusion.h59
-rw-r--r--xs/src/igl/embree/bone_heat.cpp116
-rw-r--r--xs/src/igl/embree/bone_heat.h47
-rw-r--r--xs/src/igl/embree/bone_visible.cpp145
-rw-r--r--xs/src/igl/embree/bone_visible.h68
-rw-r--r--xs/src/igl/embree/embree2/rtcore.h257
-rw-r--r--xs/src/igl/embree/embree2/rtcore.isph220
-rw-r--r--xs/src/igl/embree/embree2/rtcore_geometry.h483
-rw-r--r--xs/src/igl/embree/embree2/rtcore_geometry.isph405
-rw-r--r--xs/src/igl/embree/embree2/rtcore_geometry_user.h154
-rw-r--r--xs/src/igl/embree/embree2/rtcore_geometry_user.isph128
-rw-r--r--xs/src/igl/embree/embree2/rtcore_ray.h195
-rw-r--r--xs/src/igl/embree/embree2/rtcore_ray.isph117
-rw-r--r--xs/src/igl/embree/embree2/rtcore_scene.h187
-rw-r--r--xs/src/igl/embree/embree2/rtcore_scene.isph152
-rw-r--r--xs/src/igl/embree/line_mesh_intersection.cpp85
-rw-r--r--xs/src/igl/embree/line_mesh_intersection.h51
-rw-r--r--xs/src/igl/embree/reorient_facets_raycast.cpp259
-rw-r--r--xs/src/igl/embree/reorient_facets_raycast.h73
-rw-r--r--xs/src/igl/embree/shape_diameter_function.cpp69
-rw-r--r--xs/src/igl/embree/shape_diameter_function.h60
-rw-r--r--xs/src/igl/embree/unproject_in_mesh.cpp55
-rw-r--r--xs/src/igl/embree/unproject_in_mesh.h72
-rw-r--r--xs/src/igl/embree/unproject_onto_mesh.cpp59
-rw-r--r--xs/src/igl/embree/unproject_onto_mesh.h73
-rw-r--r--xs/src/igl/euler_characteristic.cpp46
-rw-r--r--xs/src/igl/euler_characteristic.h46
-rw-r--r--xs/src/igl/exact_geodesic.cpp3225
-rw-r--r--xs/src/igl/exact_geodesic.h55
-rw-r--r--xs/src/igl/example_fun.cpp23
-rw-r--r--xs/src/igl/example_fun.h31
-rw-r--r--xs/src/igl/exterior_edges.cpp106
-rw-r--r--xs/src/igl/exterior_edges.h33
-rw-r--r--xs/src/igl/extract_manifold_patches.cpp103
-rw-r--r--xs/src/igl/extract_manifold_patches.h51
-rw-r--r--xs/src/igl/extract_non_manifold_edge_curves.cpp123
-rw-r--r--xs/src/igl/extract_non_manifold_edge_curves.h47
-rw-r--r--xs/src/igl/face_areas.cpp65
-rw-r--r--xs/src/igl/face_areas.h58
-rw-r--r--xs/src/igl/face_occurrences.cpp58
-rw-r--r--xs/src/igl/face_occurrences.h34
-rw-r--r--xs/src/igl/faces_first.cpp103
-rw-r--r--xs/src/igl/faces_first.h60
-rw-r--r--xs/src/igl/facet_components.cpp92
-rw-r--r--xs/src/igl/facet_components.h43
-rw-r--r--xs/src/igl/false_barycentric_subdivision.cpp59
-rw-r--r--xs/src/igl/false_barycentric_subdivision.h39
-rw-r--r--xs/src/igl/fast_winding_number.cpp324
-rw-r--r--xs/src/igl/fast_winding_number.h122
-rw-r--r--xs/src/igl/file_contents_as_string.cpp45
-rw-r--r--xs/src/igl/file_contents_as_string.h32
-rw-r--r--xs/src/igl/file_dialog_open.cpp87
-rw-r--r--xs/src/igl/file_dialog_open.h30
-rw-r--r--xs/src/igl/file_dialog_save.cpp86
-rw-r--r--xs/src/igl/file_dialog_save.h31
-rw-r--r--xs/src/igl/file_exists.cpp16
-rw-r--r--xs/src/igl/file_exists.h27
-rw-r--r--xs/src/igl/find.cpp138
-rw-r--r--xs/src/igl/find.h77
-rw-r--r--xs/src/igl/find_cross_field_singularities.cpp86
-rw-r--r--xs/src/igl/find_cross_field_singularities.h58
-rw-r--r--xs/src/igl/find_zero.cpp48
-rw-r--r--xs/src/igl/find_zero.h28
-rw-r--r--xs/src/igl/fit_plane.cpp56
-rw-r--r--xs/src/igl/fit_plane.h35
-rw-r--r--xs/src/igl/fit_rotations.cpp225
-rw-r--r--xs/src/igl/fit_rotations.h60
-rw-r--r--xs/src/igl/flip_avoiding_line_search.cpp320
-rw-r--r--xs/src/igl/flip_avoiding_line_search.h49
-rw-r--r--xs/src/igl/flip_edge.cpp153
-rw-r--r--xs/src/igl/flip_edge.h52
-rw-r--r--xs/src/igl/flipped_triangles.cpp55
-rw-r--r--xs/src/igl/flipped_triangles.h39
-rw-r--r--xs/src/igl/flood_fill.cpp103
-rw-r--r--xs/src/igl/flood_fill.h33
-rw-r--r--xs/src/igl/floor.cpp36
-rw-r--r--xs/src/igl/floor.h30
-rw-r--r--xs/src/igl/for_each.h78
-rw-r--r--xs/src/igl/forward_kinematics.cpp115
-rw-r--r--xs/src/igl/forward_kinematics.h74
-rw-r--r--xs/src/igl/frame_field_deformer.cpp411
-rw-r--r--xs/src/igl/frame_field_deformer.h49
-rw-r--r--xs/src/igl/frame_to_cross_field.cpp58
-rw-r--r--xs/src/igl/frame_to_cross_field.h39
-rw-r--r--xs/src/igl/frustum.cpp33
-rw-r--r--xs/src/igl/frustum.h44
-rw-r--r--xs/src/igl/gaussian_curvature.cpp56
-rw-r--r--xs/src/igl/gaussian_curvature.h35
-rw-r--r--xs/src/igl/get_seconds.cpp15
-rw-r--r--xs/src/igl/get_seconds.h38
-rw-r--r--xs/src/igl/get_seconds_hires.cpp29
-rw-r--r--xs/src/igl/get_seconds_hires.h22
-rw-r--r--xs/src/igl/grad.cpp243
-rw-r--r--xs/src/igl/grad.h46
-rw-r--r--xs/src/igl/grid.cpp51
-rw-r--r--xs/src/igl/grid.h32
-rw-r--r--xs/src/igl/grid_search.cpp64
-rw-r--r--xs/src/igl/grid_search.h42
-rw-r--r--xs/src/igl/group_sum_matrix.cpp46
-rw-r--r--xs/src/igl/group_sum_matrix.h45
-rw-r--r--xs/src/igl/guess_extension.cpp106
-rw-r--r--xs/src/igl/guess_extension.h25
-rw-r--r--xs/src/igl/harmonic.cpp175
-rw-r--r--xs/src/igl/harmonic.h122
-rw-r--r--xs/src/igl/harwell_boeing.cpp52
-rw-r--r--xs/src/igl/harwell_boeing.h48
-rw-r--r--xs/src/igl/hausdorff.cpp89
-rw-r--r--xs/src/igl/hausdorff.h83
-rw-r--r--xs/src/igl/hessian.cpp60
-rw-r--r--xs/src/igl/hessian.h47
-rw-r--r--xs/src/igl/hessian_energy.cpp64
-rw-r--r--xs/src/igl/hessian_energy.h45
-rw-r--r--xs/src/igl/histc.cpp113
-rw-r--r--xs/src/igl/histc.h56
-rw-r--r--xs/src/igl/hsv_to_rgb.cpp72
-rw-r--r--xs/src/igl/hsv_to_rgb.h41
-rw-r--r--xs/src/igl/igl_inline.h18
-rw-r--r--xs/src/igl/in_element.cpp65
-rw-r--r--xs/src/igl/in_element.h54
-rw-r--r--xs/src/igl/infinite_cost_stopping_condition.cpp108
-rw-r--r--xs/src/igl/infinite_cost_stopping_condition.h85
-rw-r--r--xs/src/igl/inradius.cpp33
-rw-r--r--xs/src/igl/inradius.h35
-rw-r--r--xs/src/igl/internal_angles.cpp130
-rw-r--r--xs/src/igl/internal_angles.h62
-rw-r--r--xs/src/igl/intersect.cpp50
-rw-r--r--xs/src/igl/intersect.h32
-rw-r--r--xs/src/igl/invert_diag.cpp46
-rw-r--r--xs/src/igl/invert_diag.h36
-rw-r--r--xs/src/igl/is_border_vertex.cpp39
-rw-r--r--xs/src/igl/is_border_vertex.h38
-rw-r--r--xs/src/igl/is_boundary_edge.cpp122
-rw-r--r--xs/src/igl/is_boundary_edge.h51
-rw-r--r--xs/src/igl/is_dir.cpp30
-rw-r--r--xs/src/igl/is_dir.h29
-rw-r--r--xs/src/igl/is_edge_manifold.cpp104
-rw-r--r--xs/src/igl/is_edge_manifold.h48
-rw-r--r--xs/src/igl/is_file.cpp26
-rw-r--r--xs/src/igl/is_file.h29
-rw-r--r--xs/src/igl/is_irregular_vertex.cpp44
-rw-r--r--xs/src/igl/is_irregular_vertex.h33
-rw-r--r--xs/src/igl/is_planar.cpp18
-rw-r--r--xs/src/igl/is_planar.h30
-rw-r--r--xs/src/igl/is_readable.cpp55
-rw-r--r--xs/src/igl/is_readable.h28
-rw-r--r--xs/src/igl/is_sparse.cpp28
-rw-r--r--xs/src/igl/is_sparse.h36
-rw-r--r--xs/src/igl/is_stl.cpp64
-rw-r--r--xs/src/igl/is_stl.h21
-rw-r--r--xs/src/igl/is_symmetric.cpp73
-rw-r--r--xs/src/igl/is_symmetric.h34
-rw-r--r--xs/src/igl/is_vertex_manifold.cpp101
-rw-r--r--xs/src/igl/is_vertex_manifold.h39
-rw-r--r--xs/src/igl/is_writable.cpp58
-rw-r--r--xs/src/igl/is_writable.h28
-rw-r--r--xs/src/igl/isdiag.cpp32
-rw-r--r--xs/src/igl/isdiag.h26
-rw-r--r--xs/src/igl/ismember.cpp185
-rw-r--r--xs/src/igl/ismember.h52
-rw-r--r--xs/src/igl/isolines.cpp116
-rw-r--r--xs/src/igl/isolines.h52
-rw-r--r--xs/src/igl/jet.cpp93
-rw-r--r--xs/src/igl/jet.h64
-rw-r--r--xs/src/igl/knn.cpp105
-rw-r--r--xs/src/igl/knn.h52
-rw-r--r--xs/src/igl/launch_medit.cpp69
-rw-r--r--xs/src/igl/launch_medit.h44
-rw-r--r--xs/src/igl/lbs_matrix.cpp184
-rw-r--r--xs/src/igl/lbs_matrix.h94
-rw-r--r--xs/src/igl/lexicographic_triangulation.cpp132
-rw-r--r--xs/src/igl/lexicographic_triangulation.h47
-rw-r--r--xs/src/igl/lim/lim.cpp137
-rw-r--r--xs/src/igl/lim/lim.h133
-rw-r--r--xs/src/igl/limit_faces.cpp63
-rw-r--r--xs/src/igl/limit_faces.h43
-rw-r--r--xs/src/igl/line_field_missmatch.cpp144
-rw-r--r--xs/src/igl/line_field_missmatch.h42
-rw-r--r--xs/src/igl/line_search.cpp50
-rw-r--r--xs/src/igl/line_search.h42
-rw-r--r--xs/src/igl/line_segment_in_rectangle.cpp103
-rw-r--r--xs/src/igl/line_segment_in_rectangle.h33
-rw-r--r--xs/src/igl/linprog.cpp302
-rw-r--r--xs/src/igl/linprog.h65
-rw-r--r--xs/src/igl/list_to_matrix.cpp175
-rw-r--r--xs/src/igl/list_to_matrix.h55
-rw-r--r--xs/src/igl/local_basis.cpp51
-rw-r--r--xs/src/igl/local_basis.h46
-rw-r--r--xs/src/igl/look_at.cpp44
-rw-r--r--xs/src/igl/look_at.h42
-rw-r--r--xs/src/igl/loop.cpp173
-rw-r--r--xs/src/igl/loop.h63
-rw-r--r--xs/src/igl/lscm.cpp72
-rw-r--r--xs/src/igl/lscm.h49
-rwxr-xr-xxs/src/igl/map_vertices_to_circle.cpp54
-rwxr-xr-xxs/src/igl/map_vertices_to_circle.h38
-rw-r--r--xs/src/igl/massmatrix.cpp166
-rw-r--r--xs/src/igl/massmatrix.h61
-rw-r--r--xs/src/igl/mat_max.cpp46
-rw-r--r--xs/src/igl/mat_max.h44
-rw-r--r--xs/src/igl/mat_min.cpp59
-rw-r--r--xs/src/igl/mat_min.h52
-rw-r--r--xs/src/igl/mat_to_quat.cpp141
-rw-r--r--xs/src/igl/mat_to_quat.h32
-rw-r--r--xs/src/igl/material_colors.h57
-rw-r--r--xs/src/igl/matlab/MatlabWorkspace.h579
-rw-r--r--xs/src/igl/matlab/MexStream.h56
-rw-r--r--xs/src/igl/matlab/matlabinterface.cpp330
-rw-r--r--xs/src/igl/matlab/matlabinterface.h90
-rw-r--r--xs/src/igl/matlab/mexErrMsgTxt.cpp17
-rw-r--r--xs/src/igl/matlab/mexErrMsgTxt.h25
-rw-r--r--xs/src/igl/matlab/parse_rhs.cpp83
-rw-r--r--xs/src/igl/matlab/parse_rhs.h42
-rw-r--r--xs/src/igl/matlab/prepare_lhs.cpp99
-rw-r--r--xs/src/igl/matlab/prepare_lhs.h49
-rw-r--r--xs/src/igl/matlab/requires_arg.cpp16
-rw-r--r--xs/src/igl/matlab/requires_arg.h29
-rw-r--r--xs/src/igl/matlab/validate_arg.cpp50
-rw-r--r--xs/src/igl/matlab/validate_arg.h38
-rw-r--r--xs/src/igl/matlab_format.cpp155
-rw-r--r--xs/src/igl/matlab_format.h89
-rw-r--r--xs/src/igl/matrix_to_list.cpp79
-rw-r--r--xs/src/igl/matrix_to_list.h55
-rw-r--r--xs/src/igl/max.cpp46
-rw-r--r--xs/src/igl/max.h27
-rw-r--r--xs/src/igl/max_faces_stopping_condition.cpp93
-rw-r--r--xs/src/igl/max_faces_stopping_condition.h75
-rw-r--r--xs/src/igl/max_size.cpp39
-rw-r--r--xs/src/igl/max_size.h29
-rw-r--r--xs/src/igl/median.cpp45
-rw-r--r--xs/src/igl/median.h30
-rw-r--r--xs/src/igl/min.cpp41
-rw-r--r--xs/src/igl/min.h28
-rw-r--r--xs/src/igl/min_quad_dense.cpp97
-rw-r--r--xs/src/igl/min_quad_dense.h47
-rw-r--r--xs/src/igl/min_quad_with_fixed.cpp597
-rw-r--r--xs/src/igl/min_quad_with_fixed.h179
-rw-r--r--xs/src/igl/min_size.cpp45
-rw-r--r--xs/src/igl/min_size.h30
-rw-r--r--xs/src/igl/mod.cpp34
-rw-r--r--xs/src/igl/mod.h33
-rw-r--r--xs/src/igl/mode.cpp62
-rw-r--r--xs/src/igl/mode.h35
-rw-r--r--xs/src/igl/mosek/bbw.cpp88
-rw-r--r--xs/src/igl/mosek/bbw.h60
-rw-r--r--xs/src/igl/mosek/mosek_guarded.cpp24
-rw-r--r--xs/src/igl/mosek/mosek_guarded.h31
-rw-r--r--xs/src/igl/mosek/mosek_linprog.cpp164
-rw-r--r--xs/src/igl/mosek/mosek_linprog.h59
-rw-r--r--xs/src/igl/mosek/mosek_quadprog.cpp343
-rw-r--r--xs/src/igl/mosek/mosek_quadprog.h145
-rw-r--r--xs/src/igl/mvc.cpp196
-rw-r--r--xs/src/igl/mvc.h40
-rw-r--r--xs/src/igl/nchoosek.cpp77
-rw-r--r--xs/src/igl/nchoosek.h46
-rw-r--r--xs/src/igl/next_filename.cpp38
-rw-r--r--xs/src/igl/next_filename.h36
-rw-r--r--xs/src/igl/normal_derivative.cpp118
-rw-r--r--xs/src/igl/normal_derivative.h44
-rw-r--r--xs/src/igl/normalize_quat.cpp41
-rw-r--r--xs/src/igl/normalize_quat.h32
-rw-r--r--xs/src/igl/normalize_row_lengths.cpp33
-rw-r--r--xs/src/igl/normalize_row_lengths.h37
-rw-r--r--xs/src/igl/normalize_row_sums.cpp29
-rw-r--r--xs/src/igl/normalize_row_sums.h33
-rw-r--r--xs/src/igl/null.cpp21
-rw-r--r--xs/src/igl/null.h36
-rw-r--r--xs/src/igl/octree.cpp176
-rw-r--r--xs/src/igl/octree.h62
-rw-r--r--xs/src/igl/on_boundary.cpp141
-rw-r--r--xs/src/igl/on_boundary.h51
-rw-r--r--xs/src/igl/opengl/MeshGL.cpp313
-rw-r--r--xs/src/igl/opengl/MeshGL.h133
-rw-r--r--xs/src/igl/opengl/ViewerCore.cpp391
-rw-r--r--xs/src/igl/opengl/ViewerCore.h199
-rw-r--r--xs/src/igl/opengl/ViewerData.cpp691
-rw-r--r--xs/src/igl/opengl/ViewerData.h276
-rw-r--r--xs/src/igl/opengl/bind_vertex_attrib_array.cpp24
-rw-r--r--xs/src/igl/opengl/bind_vertex_attrib_array.h32
-rw-r--r--xs/src/igl/opengl/create_index_vbo.cpp46
-rw-r--r--xs/src/igl/opengl/create_index_vbo.h35
-rw-r--r--xs/src/igl/opengl/create_mesh_vbo.cpp43
-rw-r--r--xs/src/igl/opengl/create_mesh_vbo.h61
-rw-r--r--xs/src/igl/opengl/create_shader_program.cpp141
-rw-r--r--xs/src/igl/opengl/create_shader_program.h64
-rw-r--r--xs/src/igl/opengl/create_vector_vbo.cpp57
-rw-r--r--xs/src/igl/opengl/create_vector_vbo.h38
-rw-r--r--xs/src/igl/opengl/destroy_shader_program.cpp50
-rw-r--r--xs/src/igl/opengl/destroy_shader_program.h35
-rw-r--r--xs/src/igl/opengl/gl.h25
-rw-r--r--xs/src/igl/opengl/gl_type_size.cpp30
-rw-r--r--xs/src/igl/opengl/gl_type_size.h28
-rw-r--r--xs/src/igl/opengl/glfw/Viewer.cpp950
-rw-r--r--xs/src/igl/opengl/glfw/Viewer.h178
-rw-r--r--xs/src/igl/opengl/glfw/ViewerPlugin.h182
-rw-r--r--xs/src/igl/opengl/glfw/background_window.cpp30
-rw-r--r--xs/src/igl/opengl/glfw/background_window.h34
-rw-r--r--xs/src/igl/opengl/glfw/imgui/ImGuiHelpers.h74
-rw-r--r--xs/src/igl/opengl/glfw/imgui/ImGuiMenu.cpp385
-rw-r--r--xs/src/igl/opengl/glfw/imgui/ImGuiMenu.h110
-rw-r--r--xs/src/igl/opengl/glfw/map_texture.cpp211
-rw-r--r--xs/src/igl/opengl/glfw/map_texture.h63
-rw-r--r--xs/src/igl/opengl/init_render_to_texture.cpp86
-rw-r--r--xs/src/igl/opengl/init_render_to_texture.h77
-rw-r--r--xs/src/igl/opengl/load_shader.cpp34
-rw-r--r--xs/src/igl/opengl/load_shader.h38
-rw-r--r--xs/src/igl/opengl/print_program_info_log.cpp28
-rw-r--r--xs/src/igl/opengl/print_program_info_log.h27
-rw-r--r--xs/src/igl/opengl/print_shader_info_log.cpp29
-rw-r--r--xs/src/igl/opengl/print_shader_info_log.h27
-rw-r--r--xs/src/igl/opengl/report_gl_error.cpp61
-rw-r--r--xs/src/igl/opengl/report_gl_error.h36
-rw-r--r--xs/src/igl/opengl/uniform_type_to_string.cpp71
-rw-r--r--xs/src/igl/opengl/uniform_type_to_string.h31
-rw-r--r--xs/src/igl/opengl/vertex_array.cpp61
-rw-r--r--xs/src/igl/opengl/vertex_array.h38
-rw-r--r--xs/src/igl/opengl2/MouseController.h691
-rw-r--r--xs/src/igl/opengl2/RotateWidget.h547
-rw-r--r--xs/src/igl/opengl2/TranslateWidget.h211
-rw-r--r--xs/src/igl/opengl2/draw_beach_ball.cpp283
-rw-r--r--xs/src/igl/opengl2/draw_beach_ball.h27
-rw-r--r--xs/src/igl/opengl2/draw_floor.cpp161
-rw-r--r--xs/src/igl/opengl2/draw_floor.h60
-rw-r--r--xs/src/igl/opengl2/draw_mesh.cpp278
-rw-r--r--xs/src/igl/opengl2/draw_mesh.h122
-rw-r--r--xs/src/igl/opengl2/draw_point.cpp100
-rw-r--r--xs/src/igl/opengl2/draw_point.h47
-rw-r--r--xs/src/igl/opengl2/draw_rectangular_marquee.cpp62
-rw-r--r--xs/src/igl/opengl2/draw_rectangular_marquee.h35
-rw-r--r--xs/src/igl/opengl2/draw_skeleton_3d.cpp166
-rw-r--r--xs/src/igl/opengl2/draw_skeleton_3d.h53
-rw-r--r--xs/src/igl/opengl2/draw_skeleton_vector_graphics.cpp122
-rw-r--r--xs/src/igl/opengl2/draw_skeleton_vector_graphics.h52
-rw-r--r--xs/src/igl/opengl2/flare_textures.h48
-rw-r--r--xs/src/igl/opengl2/gl.h44
-rw-r--r--xs/src/igl/opengl2/glext.h32
-rw-r--r--xs/src/igl/opengl2/glu.h30
-rw-r--r--xs/src/igl/opengl2/lens_flare.cpp195
-rw-r--r--xs/src/igl/opengl2/lens_flare.h93
-rw-r--r--xs/src/igl/opengl2/model_proj_viewport.cpp31
-rw-r--r--xs/src/igl/opengl2/model_proj_viewport.h33
-rw-r--r--xs/src/igl/opengl2/print_gl_get.cpp38
-rw-r--r--xs/src/igl/opengl2/print_gl_get.h28
-rw-r--r--xs/src/igl/opengl2/project.cpp73
-rw-r--r--xs/src/igl/opengl2/project.h47
-rw-r--r--xs/src/igl/opengl2/right_axis.cpp28
-rw-r--r--xs/src/igl/opengl2/right_axis.h34
-rw-r--r--xs/src/igl/opengl2/shine_textures.h66
-rw-r--r--xs/src/igl/opengl2/sort_triangles.cpp80
-rw-r--r--xs/src/igl/opengl2/sort_triangles.h70
-rw-r--r--xs/src/igl/opengl2/unproject.cpp63
-rw-r--r--xs/src/igl/opengl2/unproject.h46
-rw-r--r--xs/src/igl/opengl2/unproject_to_zero_plane.cpp45
-rw-r--r--xs/src/igl/opengl2/unproject_to_zero_plane.h42
-rw-r--r--xs/src/igl/opengl2/up_axis.cpp28
-rw-r--r--xs/src/igl/opengl2/up_axis.h36
-rw-r--r--xs/src/igl/opengl2/view_axis.cpp40
-rw-r--r--xs/src/igl/opengl2/view_axis.h43
-rw-r--r--xs/src/igl/orient_outward.cpp95
-rw-r--r--xs/src/igl/orient_outward.h43
-rw-r--r--xs/src/igl/orientable_patches.cpp105
-rw-r--r--xs/src/igl/orientable_patches.h41
-rw-r--r--xs/src/igl/oriented_facets.cpp56
-rw-r--r--xs/src/igl/oriented_facets.h41
-rw-r--r--xs/src/igl/orth.cpp32
-rw-r--r--xs/src/igl/orth.h43
-rw-r--r--xs/src/igl/ortho.cpp33
-rw-r--r--xs/src/igl/ortho.h42
-rw-r--r--xs/src/igl/outer_element.cpp280
-rw-r--r--xs/src/igl/outer_element.h110
-rw-r--r--xs/src/igl/parallel_for.h188
-rw-r--r--xs/src/igl/parallel_transport_angles.cpp128
-rw-r--r--xs/src/igl/parallel_transport_angles.h51
-rw-r--r--xs/src/igl/partition.cpp59
-rw-r--r--xs/src/igl/partition.h39
-rw-r--r--xs/src/igl/parula.cpp53
-rw-r--r--xs/src/igl/parula.h62
-rw-r--r--xs/src/igl/path_to_executable.cpp49
-rw-r--r--xs/src/igl/path_to_executable.h21
-rw-r--r--xs/src/igl/pathinfo.cpp47
-rw-r--r--xs/src/igl/pathinfo.h64
-rw-r--r--xs/src/igl/per_corner_normals.cpp111
-rw-r--r--xs/src/igl/per_corner_normals.h64
-rw-r--r--xs/src/igl/per_edge_normals.cpp130
-rw-r--r--xs/src/igl/per_edge_normals.h81
-rw-r--r--xs/src/igl/per_face_normals.cpp128
-rw-r--r--xs/src/igl/per_face_normals.h51
-rw-r--r--xs/src/igl/per_vertex_attribute_smoothing.cpp33
-rw-r--r--xs/src/igl/per_vertex_attribute_smoothing.h32
-rw-r--r--xs/src/igl/per_vertex_normals.cpp133
-rw-r--r--xs/src/igl/per_vertex_normals.h80
-rw-r--r--xs/src/igl/per_vertex_point_to_plane_quadrics.cpp157
-rw-r--r--xs/src/igl/per_vertex_point_to_plane_quadrics.h53
-rw-r--r--xs/src/igl/piecewise_constant_winding_number.cpp82
-rw-r--r--xs/src/igl/piecewise_constant_winding_number.h49
-rw-r--r--xs/src/igl/pinv.cpp35
-rw-r--r--xs/src/igl/pinv.h29
-rw-r--r--xs/src/igl/planarize_quad_mesh.cpp245
-rw-r--r--xs/src/igl/planarize_quad_mesh.h46
-rw-r--r--xs/src/igl/ply.h3168
-rw-r--r--xs/src/igl/png/readPNG.cpp47
-rw-r--r--xs/src/igl/png/readPNG.h39
-rw-r--r--xs/src/igl/png/render_to_png.cpp45
-rw-r--r--xs/src/igl/png/render_to_png.h41
-rw-r--r--xs/src/igl/png/render_to_png_async.cpp54
-rw-r--r--xs/src/igl/png/render_to_png_async.h45
-rw-r--r--xs/src/igl/png/texture_from_file.cpp61
-rw-r--r--xs/src/igl/png/texture_from_file.h39
-rw-r--r--xs/src/igl/png/texture_from_png.cpp83
-rw-r--r--xs/src/igl/png/texture_from_png.h54
-rw-r--r--xs/src/igl/png/writePNG.cpp46
-rw-r--r--xs/src/igl/png/writePNG.h41
-rw-r--r--xs/src/igl/point_in_circle.cpp18
-rw-r--r--xs/src/igl/point_in_circle.h34
-rw-r--r--xs/src/igl/point_in_poly.cpp51
-rw-r--r--xs/src/igl/point_in_poly.h36
-rw-r--r--xs/src/igl/point_mesh_squared_distance.cpp54
-rw-r--r--xs/src/igl/point_mesh_squared_distance.h52
-rw-r--r--xs/src/igl/point_simplex_squared_distance.cpp181
-rw-r--r--xs/src/igl/point_simplex_squared_distance.h72
-rw-r--r--xs/src/igl/polar_dec.cpp97
-rw-r--r--xs/src/igl/polar_dec.h53
-rw-r--r--xs/src/igl/polar_svd.cpp80
-rw-r--r--xs/src/igl/polar_svd.h54
-rw-r--r--xs/src/igl/polar_svd3x3.cpp113
-rw-r--r--xs/src/igl/polar_svd3x3.h43
-rw-r--r--xs/src/igl/polygon_mesh_to_triangle_mesh.cpp76
-rw-r--r--xs/src/igl/polygon_mesh_to_triangle_mesh.h48
-rw-r--r--xs/src/igl/principal_curvature.cpp854
-rw-r--r--xs/src/igl/principal_curvature.h68
-rw-r--r--xs/src/igl/print_ijv.cpp40
-rw-r--r--xs/src/igl/print_ijv.h35
-rw-r--r--xs/src/igl/print_vector.cpp59
-rw-r--r--xs/src/igl/print_vector.h29
-rw-r--r--xs/src/igl/procrustes.cpp140
-rw-r--r--xs/src/igl/procrustes.h137
-rw-r--r--xs/src/igl/project.cpp59
-rw-r--r--xs/src/igl/project.h48
-rw-r--r--xs/src/igl/project_isometrically_to_plane.cpp63
-rw-r--r--xs/src/igl/project_isometrically_to_plane.h48
-rw-r--r--xs/src/igl/project_to_line.cpp139
-rw-r--r--xs/src/igl/project_to_line.h83
-rw-r--r--xs/src/igl/project_to_line_segment.cpp55
-rw-r--r--xs/src/igl/project_to_line_segment.h50
-rw-r--r--xs/src/igl/pseudonormal_test.cpp224
-rw-r--r--xs/src/igl/pseudonormal_test.h78
-rw-r--r--xs/src/igl/pso.cpp174
-rw-r--r--xs/src/igl/pso.h59
-rw-r--r--xs/src/igl/qslim.cpp120
-rw-r--r--xs/src/igl/qslim.h41
-rw-r--r--xs/src/igl/qslim_optimal_collapse_edge_callbacks.cpp130
-rw-r--r--xs/src/igl/qslim_optimal_collapse_edge_callbacks.h81
-rw-r--r--xs/src/igl/quad_planarity.cpp39
-rw-r--r--xs/src/igl/quad_planarity.h32
-rw-r--r--xs/src/igl/quadric_binary_plus_operator.cpp24
-rw-r--r--xs/src/igl/quadric_binary_plus_operator.h35
-rw-r--r--xs/src/igl/quat_conjugate.cpp27
-rw-r--r--xs/src/igl/quat_conjugate.h32
-rw-r--r--xs/src/igl/quat_mult.cpp34
-rw-r--r--xs/src/igl/quat_mult.h33
-rw-r--r--xs/src/igl/quat_to_axis_angle.cpp75
-rw-r--r--xs/src/igl/quat_to_axis_angle.h40
-rw-r--r--xs/src/igl/quat_to_mat.cpp44
-rw-r--r--xs/src/igl/quat_to_mat.h30
-rw-r--r--xs/src/igl/quats_to_column.cpp33
-rw-r--r--xs/src/igl/quats_to_column.h37
-rw-r--r--xs/src/igl/ramer_douglas_peucker.cpp150
-rw-r--r--xs/src/igl/ramer_douglas_peucker.h49
-rw-r--r--xs/src/igl/random_dir.cpp52
-rw-r--r--xs/src/igl/random_dir.h31
-rw-r--r--xs/src/igl/random_points_on_mesh.cpp83
-rw-r--r--xs/src/igl/random_points_on_mesh.h52
-rw-r--r--xs/src/igl/random_quaternion.cpp84
-rw-r--r--xs/src/igl/random_quaternion.h21
-rw-r--r--xs/src/igl/random_search.cpp36
-rw-r--r--xs/src/igl/random_search.h42
-rw-r--r--xs/src/igl/randperm.cpp27
-rw-r--r--xs/src/igl/randperm.h28
-rw-r--r--xs/src/igl/ray_box_intersect.cpp149
-rw-r--r--xs/src/igl/ray_box_intersect.h44
-rw-r--r--xs/src/igl/ray_mesh_intersect.cpp86
-rw-r--r--xs/src/igl/ray_mesh_intersect.h56
-rw-r--r--xs/src/igl/ray_sphere_intersect.cpp74
-rw-r--r--xs/src/igl/ray_sphere_intersect.h46
-rw-r--r--xs/src/igl/raytri.c267
-rw-r--r--xs/src/igl/readBF.cpp114
-rw-r--r--xs/src/igl/readBF.h67
-rw-r--r--xs/src/igl/readCSV.cpp68
-rw-r--r--xs/src/igl/readCSV.h35
-rw-r--r--xs/src/igl/readDMAT.cpp229
-rw-r--r--xs/src/igl/readDMAT.h53
-rw-r--r--xs/src/igl/readMESH.cpp506
-rw-r--r--xs/src/igl/readMESH.h78
-rw-r--r--xs/src/igl/readMSH.cpp500
-rw-r--r--xs/src/igl/readMSH.h38
-rw-r--r--xs/src/igl/readNODE.cpp161
-rw-r--r--xs/src/igl/readNODE.h50
-rw-r--r--xs/src/igl/readOBJ.cpp366
-rw-r--r--xs/src/igl/readOBJ.h101
-rw-r--r--xs/src/igl/readOFF.cpp268
-rw-r--r--xs/src/igl/readOFF.h86
-rw-r--r--xs/src/igl/readPLY.cpp224
-rw-r--r--xs/src/igl/readPLY.h77
-rw-r--r--xs/src/igl/readSTL.cpp290
-rw-r--r--xs/src/igl/readSTL.h68
-rw-r--r--xs/src/igl/readTGF.cpp200
-rw-r--r--xs/src/igl/readTGF.h66
-rw-r--r--xs/src/igl/readWRL.cpp121
-rw-r--r--xs/src/igl/readWRL.h53
-rw-r--r--xs/src/igl/read_triangle_mesh.cpp183
-rw-r--r--xs/src/igl/read_triangle_mesh.h80
-rw-r--r--xs/src/igl/redux.h70
-rw-r--r--xs/src/igl/remesh_along_isoline.cpp160
-rw-r--r--xs/src/igl/remesh_along_isoline.h81
-rw-r--r--xs/src/igl/remove_duplicate_vertices.cpp83
-rw-r--r--xs/src/igl/remove_duplicate_vertices.h65
-rw-r--r--xs/src/igl/remove_duplicates.cpp88
-rw-r--r--xs/src/igl/remove_duplicates.h49
-rw-r--r--xs/src/igl/remove_unreferenced.cpp122
-rw-r--r--xs/src/igl/remove_unreferenced.h82
-rw-r--r--xs/src/igl/reorder.cpp45
-rw-r--r--xs/src/igl/reorder.h34
-rw-r--r--xs/src/igl/repdiag.cpp97
-rw-r--r--xs/src/igl/repdiag.h54
-rw-r--r--xs/src/igl/repmat.cpp67
-rw-r--r--xs/src/igl/repmat.h53
-rw-r--r--xs/src/igl/resolve_duplicated_faces.cpp96
-rw-r--r--xs/src/igl/resolve_duplicated_faces.h52
-rw-r--r--xs/src/igl/rgb_to_hsv.cpp102
-rw-r--r--xs/src/igl/rgb_to_hsv.h37
-rw-r--r--xs/src/igl/rotate_by_quat.cpp55
-rw-r--r--xs/src/igl/rotate_by_quat.h33
-rw-r--r--xs/src/igl/rotate_vectors.cpp37
-rw-r--r--xs/src/igl/rotate_vectors.h40
-rw-r--r--xs/src/igl/rotation_matrix_from_directions.cpp63
-rw-r--r--xs/src/igl/rotation_matrix_from_directions.h34
-rw-r--r--xs/src/igl/round.cpp49
-rw-r--r--xs/src/igl/round.h37
-rw-r--r--xs/src/igl/rows_to_matrix.cpp54
-rw-r--r--xs/src/igl/rows_to_matrix.h34
-rw-r--r--xs/src/igl/sample_edges.cpp33
-rw-r--r--xs/src/igl/sample_edges.h37
-rw-r--r--xs/src/igl/seam_edges.cpp211
-rw-r--r--xs/src/igl/seam_edges.h64
-rw-r--r--xs/src/igl/segment_segment_intersect.cpp67
-rw-r--r--xs/src/igl/segment_segment_intersect.h46
-rw-r--r--xs/src/igl/serialize.h1258
-rw-r--r--xs/src/igl/setdiff.cpp83
-rw-r--r--xs/src/igl/setdiff.h38
-rw-r--r--xs/src/igl/setunion.cpp74
-rw-r--r--xs/src/igl/setunion.h43
-rw-r--r--xs/src/igl/setxor.cpp32
-rw-r--r--xs/src/igl/setxor.h43
-rw-r--r--xs/src/igl/shape_diameter_function.cpp182
-rw-r--r--xs/src/igl/shape_diameter_function.h95
-rw-r--r--xs/src/igl/shapeup.cpp238
-rw-r--r--xs/src/igl/shapeup.h128
-rw-r--r--xs/src/igl/shortest_edge_and_midpoint.cpp23
-rw-r--r--xs/src/igl/shortest_edge_and_midpoint.h48
-rw-r--r--xs/src/igl/signed_angle.cpp74
-rw-r--r--xs/src/igl/signed_angle.h27
-rw-r--r--xs/src/igl/signed_distance.cpp463
-rw-r--r--xs/src/igl/signed_distance.h245
-rw-r--r--xs/src/igl/simplify_polyhedron.cpp107
-rw-r--r--xs/src/igl/simplify_polyhedron.h37
-rw-r--r--xs/src/igl/slice.cpp362
-rw-r--r--xs/src/igl/slice.h87
-rw-r--r--xs/src/igl/slice_cached.cpp57
-rw-r--r--xs/src/igl/slice_cached.h69
-rw-r--r--xs/src/igl/slice_into.cpp153
-rw-r--r--xs/src/igl/slice_into.h63
-rw-r--r--xs/src/igl/slice_mask.cpp168
-rw-r--r--xs/src/igl/slice_mask.h74
-rw-r--r--xs/src/igl/slice_tets.cpp356
-rw-r--r--xs/src/igl/slice_tets.h96
-rw-r--r--xs/src/igl/slim.cpp961
-rw-r--r--xs/src/igl/slim.h113
-rw-r--r--xs/src/igl/snap_points.cpp89
-rw-r--r--xs/src/igl/snap_points.h67
-rw-r--r--xs/src/igl/snap_to_canonical_view_quat.cpp117
-rw-r--r--xs/src/igl/snap_to_canonical_view_quat.h44
-rw-r--r--xs/src/igl/snap_to_fixed_up.cpp33
-rw-r--r--xs/src/igl/snap_to_fixed_up.h39
-rw-r--r--xs/src/igl/solid_angle.cpp81
-rw-r--r--xs/src/igl/solid_angle.h29
-rw-r--r--xs/src/igl/sort.cpp351
-rw-r--r--xs/src/igl/sort.h88
-rw-r--r--xs/src/igl/sort_angles.cpp114
-rw-r--r--xs/src/igl/sort_angles.h35
-rw-r--r--xs/src/igl/sort_triangles.cpp498
-rw-r--r--xs/src/igl/sort_triangles.h44
-rw-r--r--xs/src/igl/sort_vectors_ccw.cpp103
-rw-r--r--xs/src/igl/sort_vectors_ccw.h68
-rw-r--r--xs/src/igl/sortrows.cpp142
-rw-r--r--xs/src/igl/sortrows.h42
-rw-r--r--xs/src/igl/sparse.cpp123
-rw-r--r--xs/src/igl/sparse.h78
-rw-r--r--xs/src/igl/sparse_cached.cpp127
-rw-r--r--xs/src/igl/sparse_cached.h85
-rw-r--r--xs/src/igl/speye.cpp35
-rw-r--r--xs/src/igl/speye.h42
-rw-r--r--xs/src/igl/squared_edge_lengths.cpp106
-rw-r--r--xs/src/igl/squared_edge_lengths.h49
-rw-r--r--xs/src/igl/stdin_to_temp.cpp38
-rw-r--r--xs/src/igl/stdin_to_temp.h36
-rw-r--r--xs/src/igl/straighten_seams.cpp370
-rw-r--r--xs/src/igl/straighten_seams.h57
-rw-r--r--xs/src/igl/sum.cpp64
-rw-r--r--xs/src/igl/sum.h47
-rw-r--r--xs/src/igl/svd3x3.cpp69
-rw-r--r--xs/src/igl/svd3x3.h40
-rw-r--r--xs/src/igl/svd3x3_avx.cpp108
-rw-r--r--xs/src/igl/svd3x3_avx.h40
-rw-r--r--xs/src/igl/svd3x3_sse.cpp108
-rw-r--r--xs/src/igl/svd3x3_sse.h37
-rw-r--r--xs/src/igl/swept_volume_bounding_box.cpp28
-rw-r--r--xs/src/igl/swept_volume_bounding_box.h38
-rw-r--r--xs/src/igl/swept_volume_signed_distance.cpp122
-rw-r--r--xs/src/igl/swept_volume_signed_distance.h64
-rw-r--r--xs/src/igl/trackball.cpp168
-rw-r--r--xs/src/igl/trackball.h80
-rw-r--r--xs/src/igl/transpose_blocks.cpp63
-rw-r--r--xs/src/igl/transpose_blocks.h61
-rw-r--r--xs/src/igl/triangle/cdt.cpp58
-rw-r--r--xs/src/igl/triangle/cdt.h54
-rw-r--r--xs/src/igl/triangle/triangulate.cpp181
-rw-r--r--xs/src/igl/triangle/triangulate.h87
-rw-r--r--xs/src/igl/triangle_fan.cpp54
-rw-r--r--xs/src/igl/triangle_fan.h30
-rw-r--r--xs/src/igl/triangle_triangle_adjacency.cpp274
-rw-r--r--xs/src/igl/triangle_triangle_adjacency.h115
-rw-r--r--xs/src/igl/triangles_from_strip.cpp36
-rw-r--r--xs/src/igl/triangles_from_strip.h33
-rw-r--r--xs/src/igl/two_axis_valuator_fixed_up.cpp49
-rw-r--r--xs/src/igl/two_axis_valuator_fixed_up.h51
-rw-r--r--xs/src/igl/uniformly_sample_two_manifold.cpp427
-rw-r--r--xs/src/igl/uniformly_sample_two_manifold.h44
-rw-r--r--xs/src/igl/unique.cpp222
-rw-r--r--xs/src/igl/unique.h58
-rw-r--r--xs/src/igl/unique_edge_map.cpp69
-rw-r--r--xs/src/igl/unique_edge_map.h44
-rw-r--r--xs/src/igl/unique_rows.cpp111
-rw-r--r--xs/src/igl/unique_rows.h41
-rw-r--r--xs/src/igl/unique_simplices.cpp64
-rw-r--r--xs/src/igl/unique_simplices.h44
-rw-r--r--xs/src/igl/unproject.cpp74
-rw-r--r--xs/src/igl/unproject.h47
-rw-r--r--xs/src/igl/unproject_in_mesh.cpp97
-rw-r--r--xs/src/igl/unproject_in_mesh.h88
-rw-r--r--xs/src/igl/unproject_onto_mesh.cpp78
-rw-r--r--xs/src/igl/unproject_onto_mesh.h74
-rw-r--r--xs/src/igl/unproject_ray.cpp41
-rw-r--r--xs/src/igl/unproject_ray.h44
-rw-r--r--xs/src/igl/unzip_corners.cpp48
-rw-r--r--xs/src/igl/unzip_corners.h54
-rw-r--r--xs/src/igl/upsample.cpp145
-rw-r--r--xs/src/igl/upsample.h82
-rw-r--r--xs/src/igl/vector_area_matrix.cpp54
-rw-r--r--xs/src/igl/vector_area_matrix.h41
-rw-r--r--xs/src/igl/verbose.h46
-rw-r--r--xs/src/igl/vertex_triangle_adjacency.cpp102
-rw-r--r--xs/src/igl/vertex_triangle_adjacency.h71
-rw-r--r--xs/src/igl/volume.cpp120
-rw-r--r--xs/src/igl/volume.h74
-rw-r--r--xs/src/igl/voxel_grid.cpp73
-rw-r--r--xs/src/igl/voxel_grid.h39
-rw-r--r--xs/src/igl/winding_number.cpp117
-rw-r--r--xs/src/igl/winding_number.h64
-rw-r--r--xs/src/igl/writeBF.cpp49
-rw-r--r--xs/src/igl/writeBF.h37
-rw-r--r--xs/src/igl/writeDMAT.cpp92
-rw-r--r--xs/src/igl/writeDMAT.h48
-rw-r--r--xs/src/igl/writeMESH.cpp152
-rw-r--r--xs/src/igl/writeMESH.h58
-rw-r--r--xs/src/igl/writeOBJ.cpp136
-rw-r--r--xs/src/igl/writeOBJ.h59
-rw-r--r--xs/src/igl/writeOFF.cpp94
-rw-r--r--xs/src/igl/writeOFF.h50
-rw-r--r--xs/src/igl/writePLY.cpp182
-rw-r--r--xs/src/igl/writePLY.h49
-rw-r--r--xs/src/igl/writeSTL.cpp121
-rw-r--r--xs/src/igl/writeSTL.h52
-rw-r--r--xs/src/igl/writeTGF.cpp73
-rw-r--r--xs/src/igl/writeTGF.h48
-rw-r--r--xs/src/igl/writeWRL.cpp126
-rw-r--r--xs/src/igl/writeWRL.h46
-rw-r--r--xs/src/igl/write_triangle_mesh.cpp70
-rw-r--r--xs/src/igl/write_triangle_mesh.h42
-rw-r--r--xs/src/igl/xml/ReAntTweakBarXMLSerialization.h269
-rw-r--r--xs/src/igl/xml/XMLSerializable.h225
-rw-r--r--xs/src/igl/xml/serialization_test.skip489
-rw-r--r--xs/src/igl/xml/serialize_xml.cpp912
-rw-r--r--xs/src/igl/xml/serialize_xml.h247
-rw-r--r--xs/src/igl/xml/writeDAE.cpp138
-rw-r--r--xs/src/igl/xml/writeDAE.h38
-rw-r--r--xs/src/igl/xml/write_triangle_mesh.cpp33
-rw-r--r--xs/src/igl/xml/write_triangle_mesh.h45
1087 files changed, 118219 insertions, 0 deletions
diff --git a/xs/src/igl/AABB.cpp b/xs/src/igl/AABB.cpp
new file mode 100644
index 000000000..095373354
--- /dev/null
+++ b/xs/src/igl/AABB.cpp
@@ -0,0 +1,1075 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "AABB.h"
+#include "EPS.h"
+#include "barycenter.h"
+#include "colon.h"
+#include "doublearea.h"
+#include "point_simplex_squared_distance.h"
+#include "project_to_line_segment.h"
+#include "sort.h"
+#include "volume.h"
+#include "ray_box_intersect.h"
+#include "parallel_for.h"
+#include "ray_mesh_intersect.h"
+#include <iostream>
+#include <iomanip>
+#include <limits>
+#include <list>
+#include <queue>
+#include <stack>
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle, typename Derivedbb_mins, typename Derivedbb_maxs, typename Derivedelements>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const Eigen::MatrixBase<Derivedbb_mins> & bb_mins,
+ const Eigen::MatrixBase<Derivedbb_maxs> & bb_maxs,
+ const Eigen::MatrixBase<Derivedelements> & elements,
+ const int i)
+{
+ using namespace std;
+ using namespace Eigen;
+ deinit();
+ if(bb_mins.size() > 0)
+ {
+ assert(bb_mins.rows() == bb_maxs.rows() && "Serial tree arrays must match");
+ assert(bb_mins.cols() == V.cols() && "Serial tree array dim must match V");
+ assert(bb_mins.cols() == bb_maxs.cols() && "Serial tree arrays must match");
+ assert(bb_mins.rows() == elements.rows() &&
+ "Serial tree arrays must match");
+ // construct from serialization
+ m_box.extend(bb_mins.row(i).transpose());
+ m_box.extend(bb_maxs.row(i).transpose());
+ m_primitive = elements(i);
+ // Not leaf then recurse
+ if(m_primitive == -1)
+ {
+ m_left = new AABB();
+ m_left->init( V,Ele,bb_mins,bb_maxs,elements,2*i+1);
+ m_right = new AABB();
+ m_right->init( V,Ele,bb_mins,bb_maxs,elements,2*i+2);
+ //m_depth = std::max( m_left->m_depth, m_right->m_depth)+1;
+ }
+ }else
+ {
+ VectorXi allI = colon<int>(0,Ele.rows()-1);
+ MatrixXDIMS BC;
+ if(Ele.cols() == 1)
+ {
+ // points
+ BC = V;
+ }else
+ {
+ // Simplices
+ barycenter(V,Ele,BC);
+ }
+ MatrixXi SI(BC.rows(),BC.cols());
+ {
+ MatrixXDIMS _;
+ MatrixXi IS;
+ igl::sort(BC,1,true,_,IS);
+ // Need SI(i) to tell which place i would be sorted into
+ const int dim = IS.cols();
+ for(int i = 0;i<IS.rows();i++)
+ {
+ for(int d = 0;d<dim;d++)
+ {
+ SI(IS(i,d),d) = i;
+ }
+ }
+ }
+ init(V,Ele,SI,allI);
+ }
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+void igl::AABB<DerivedV,DIM>::init(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele)
+{
+ using namespace Eigen;
+ // deinit will be immediately called...
+ return init(V,Ele,MatrixXDIMS(),MatrixXDIMS(),VectorXi(),0);
+}
+
+ template <typename DerivedV, int DIM>
+template <
+ typename DerivedEle,
+ typename DerivedSI,
+ typename DerivedI>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::init(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const Eigen::MatrixBase<DerivedSI> & SI,
+ const Eigen::MatrixBase<DerivedI> & I)
+{
+ using namespace Eigen;
+ using namespace std;
+ deinit();
+ if(V.size() == 0 || Ele.size() == 0 || I.size() == 0)
+ {
+ return;
+ }
+ assert(DIM == V.cols() && "V.cols() should matched declared dimension");
+ //const Scalar inf = numeric_limits<Scalar>::infinity();
+ m_box = AlignedBox<Scalar,DIM>();
+ // Compute bounding box
+ for(int i = 0;i<I.rows();i++)
+ {
+ for(int c = 0;c<Ele.cols();c++)
+ {
+ m_box.extend(V.row(Ele(I(i),c)).transpose());
+ m_box.extend(V.row(Ele(I(i),c)).transpose());
+ }
+ }
+ switch(I.size())
+ {
+ case 0:
+ {
+ assert(false);
+ }
+ case 1:
+ {
+ m_primitive = I(0);
+ break;
+ }
+ default:
+ {
+ // Compute longest direction
+ int max_d = -1;
+ m_box.diagonal().maxCoeff(&max_d);
+ // Can't use median on BC directly because many may have same value,
+ // but can use median on sorted BC indices
+ VectorXi SIdI(I.rows());
+ for(int i = 0;i<I.rows();i++)
+ {
+ SIdI(i) = SI(I(i),max_d);
+ }
+ // Pass by copy to avoid changing input
+ const auto median = [](VectorXi A)->int
+ {
+ size_t n = (A.size()-1)/2;
+ nth_element(A.data(),A.data()+n,A.data()+A.size());
+ return A(n);
+ };
+ const int med = median(SIdI);
+ VectorXi LI((I.rows()+1)/2),RI(I.rows()/2);
+ assert(LI.rows()+RI.rows() == I.rows());
+ // Distribute left and right
+ {
+ int li = 0;
+ int ri = 0;
+ for(int i = 0;i<I.rows();i++)
+ {
+ if(SIdI(i)<=med)
+ {
+ LI(li++) = I(i);
+ }else
+ {
+ RI(ri++) = I(i);
+ }
+ }
+ }
+ //m_depth = 0;
+ if(LI.rows()>0)
+ {
+ m_left = new AABB();
+ m_left->init(V,Ele,SI,LI);
+ //m_depth = std::max(m_depth, m_left->m_depth+1);
+ }
+ if(RI.rows()>0)
+ {
+ m_right = new AABB();
+ m_right->init(V,Ele,SI,RI);
+ //m_depth = std::max(m_depth, m_right->m_depth+1);
+ }
+ }
+ }
+}
+
+template <typename DerivedV, int DIM>
+IGL_INLINE bool igl::AABB<DerivedV,DIM>::is_leaf() const
+{
+ return m_primitive != -1;
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle, typename Derivedq>
+IGL_INLINE std::vector<int> igl::AABB<DerivedV,DIM>::find(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const Eigen::MatrixBase<Derivedq> & q,
+ const bool first) const
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(q.size() == DIM &&
+ "Query dimension should match aabb dimension");
+ assert(Ele.cols() == V.cols()+1 &&
+ "AABB::find only makes sense for (d+1)-simplices");
+ const Scalar epsilon = igl::EPS<Scalar>();
+ // Check if outside bounding box
+ bool inside = m_box.contains(q.transpose());
+ if(!inside)
+ {
+ return std::vector<int>();
+ }
+ assert(m_primitive==-1 || (m_left == NULL && m_right == NULL));
+ if(is_leaf())
+ {
+ // Initialize to some value > -epsilon
+ Scalar a1=0,a2=0,a3=0,a4=0;
+ switch(DIM)
+ {
+ case 3:
+ {
+ // Barycentric coordinates
+ typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
+ const RowVector3S V1 = V.row(Ele(m_primitive,0));
+ const RowVector3S V2 = V.row(Ele(m_primitive,1));
+ const RowVector3S V3 = V.row(Ele(m_primitive,2));
+ const RowVector3S V4 = V.row(Ele(m_primitive,3));
+ a1 = volume_single(V2,V4,V3,(RowVector3S)q);
+ a2 = volume_single(V1,V3,V4,(RowVector3S)q);
+ a3 = volume_single(V1,V4,V2,(RowVector3S)q);
+ a4 = volume_single(V1,V2,V3,(RowVector3S)q);
+ break;
+ }
+ case 2:
+ {
+ // Barycentric coordinates
+ typedef Eigen::Matrix<Scalar,2,1> Vector2S;
+ const Vector2S V1 = V.row(Ele(m_primitive,0));
+ const Vector2S V2 = V.row(Ele(m_primitive,1));
+ const Vector2S V3 = V.row(Ele(m_primitive,2));
+ // Hack for now to keep templates simple. If becomes bottleneck
+ // consider using std::enable_if_t
+ const Vector2S q2 = q.head(2);
+ a1 = doublearea_single(V1,V2,q2);
+ a2 = doublearea_single(V2,V3,q2);
+ a3 = doublearea_single(V3,V1,q2);
+ break;
+ }
+ default:assert(false);
+ }
+ // Normalization is important for correcting sign
+ Scalar sum = a1+a2+a3+a4;
+ a1 /= sum;
+ a2 /= sum;
+ a3 /= sum;
+ a4 /= sum;
+ if(
+ a1>=-epsilon &&
+ a2>=-epsilon &&
+ a3>=-epsilon &&
+ a4>=-epsilon)
+ {
+ return std::vector<int>(1,m_primitive);
+ }else
+ {
+ return std::vector<int>();
+ }
+ }
+ std::vector<int> left = m_left->find(V,Ele,q,first);
+ if(first && !left.empty())
+ {
+ return left;
+ }
+ std::vector<int> right = m_right->find(V,Ele,q,first);
+ if(first)
+ {
+ return right;
+ }
+ left.insert(left.end(),right.begin(),right.end());
+ return left;
+}
+
+template <typename DerivedV, int DIM>
+IGL_INLINE int igl::AABB<DerivedV,DIM>::subtree_size() const
+{
+ // 1 for self
+ int n = 1;
+ int n_left = 0,n_right = 0;
+ if(m_left != NULL)
+ {
+ n_left = m_left->subtree_size();
+ }
+ if(m_right != NULL)
+ {
+ n_right = m_right->subtree_size();
+ }
+ n += 2*std::max(n_left,n_right);
+ return n;
+}
+
+
+template <typename DerivedV, int DIM>
+template <typename Derivedbb_mins, typename Derivedbb_maxs, typename Derivedelements>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::serialize(
+ Eigen::PlainObjectBase<Derivedbb_mins> & bb_mins,
+ Eigen::PlainObjectBase<Derivedbb_maxs> & bb_maxs,
+ Eigen::PlainObjectBase<Derivedelements> & elements,
+ const int i) const
+{
+ using namespace std;
+ using namespace Eigen;
+ // Calling for root then resize output
+ if(i==0)
+ {
+ const int m = subtree_size();
+ //cout<<"m: "<<m<<endl;
+ bb_mins.resize(m,DIM);
+ bb_maxs.resize(m,DIM);
+ elements.resize(m,1);
+ }
+ //cout<<i<<" ";
+ bb_mins.row(i) = m_box.min();
+ bb_maxs.row(i) = m_box.max();
+ elements(i) = m_primitive;
+ if(m_left != NULL)
+ {
+ m_left->serialize(bb_mins,bb_maxs,elements,2*i+1);
+ }
+ if(m_right != NULL)
+ {
+ m_right->serialize(bb_mins,bb_maxs,elements,2*i+2);
+ }
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
+igl::AABB<DerivedV,DIM>::squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const
+{
+ return squared_distance(V,Ele,p,std::numeric_limits<Scalar>::infinity(),i,c);
+}
+
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
+igl::AABB<DerivedV,DIM>::squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ Scalar low_sqr_d,
+ Scalar up_sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const
+{
+ using namespace Eigen;
+ using namespace std;
+ //assert(low_sqr_d <= up_sqr_d);
+ if(low_sqr_d > up_sqr_d)
+ {
+ return low_sqr_d;
+ }
+ Scalar sqr_d = up_sqr_d;
+ //assert(DIM == 3 && "Code has only been tested for DIM == 3");
+ assert((Ele.cols() == 3 || Ele.cols() == 2 || Ele.cols() == 1)
+ && "Code has only been tested for simplex sizes 3,2,1");
+
+ assert(m_primitive==-1 || (m_left == NULL && m_right == NULL));
+ if(is_leaf())
+ {
+ leaf_squared_distance(V,Ele,p,low_sqr_d,sqr_d,i,c);
+ }else
+ {
+ bool looked_left = false;
+ bool looked_right = false;
+ const auto & look_left = [&]()
+ {
+ int i_left;
+ RowVectorDIMS c_left = c;
+ Scalar sqr_d_left =
+ m_left->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_left,c_left);
+ this->set_min(p,sqr_d_left,i_left,c_left,sqr_d,i,c);
+ looked_left = true;
+ };
+ const auto & look_right = [&]()
+ {
+ int i_right;
+ RowVectorDIMS c_right = c;
+ Scalar sqr_d_right =
+ m_right->squared_distance(V,Ele,p,low_sqr_d,sqr_d,i_right,c_right);
+ this->set_min(p,sqr_d_right,i_right,c_right,sqr_d,i,c);
+ looked_right = true;
+ };
+
+ // must look left or right if in box
+ if(m_left->m_box.contains(p.transpose()))
+ {
+ look_left();
+ }
+ if(m_right->m_box.contains(p.transpose()))
+ {
+ look_right();
+ }
+ // if haven't looked left and could be less than current min, then look
+ Scalar left_up_sqr_d =
+ m_left->m_box.squaredExteriorDistance(p.transpose());
+ Scalar right_up_sqr_d =
+ m_right->m_box.squaredExteriorDistance(p.transpose());
+ if(left_up_sqr_d < right_up_sqr_d)
+ {
+ if(!looked_left && left_up_sqr_d<sqr_d)
+ {
+ look_left();
+ }
+ if( !looked_right && right_up_sqr_d<sqr_d)
+ {
+ look_right();
+ }
+ }else
+ {
+ if( !looked_right && right_up_sqr_d<sqr_d)
+ {
+ look_right();
+ }
+ if(!looked_left && left_up_sqr_d<sqr_d)
+ {
+ look_left();
+ }
+ }
+ }
+ return sqr_d;
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
+igl::AABB<DerivedV,DIM>::squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ Scalar up_sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const
+{
+ return squared_distance(V,Ele,p,0.0,up_sqr_d,i,c);
+}
+
+template <typename DerivedV, int DIM>
+template <
+ typename DerivedEle,
+ typename DerivedP,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const Eigen::MatrixBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C) const
+{
+ assert(P.cols() == V.cols() && "cols in P should match dim of cols in V");
+ sqrD.resize(P.rows(),1);
+ I.resize(P.rows(),1);
+ C.resizeLike(P);
+ // O( #P * log #Ele ), where log #Ele is really the depth of this AABB
+ // hierarchy
+ //for(int p = 0;p<P.rows();p++)
+ igl::parallel_for(P.rows(),[&](int p)
+ {
+ RowVectorDIMS Pp = P.row(p), c;
+ int Ip;
+ sqrD(p) = squared_distance(V,Ele,Pp,Ip,c);
+ I(p) = Ip;
+ C.row(p).head(DIM) = c;
+ },
+ 10000);
+}
+
+template <typename DerivedV, int DIM>
+template <
+ typename DerivedEle,
+ typename Derivedother_V,
+ typename Derivedother_Ele,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const AABB<Derivedother_V,DIM> & other,
+ const Eigen::MatrixBase<Derivedother_V> & other_V,
+ const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C) const
+{
+ assert(other_Ele.cols() == 1 &&
+ "Only implemented for other as list of points");
+ assert(other_V.cols() == V.cols() && "other must match this dimension");
+ sqrD.setConstant(other_Ele.rows(),1,std::numeric_limits<double>::infinity());
+ I.resize(other_Ele.rows(),1);
+ C.resize(other_Ele.rows(),other_V.cols());
+ // All points in other_V currently think they need to check against root of
+ // this. The point of using another AABB is to quickly prune chunks of
+ // other_V so that most points just check some subtree of this.
+
+ // This holds a conservative estimate of max(sqr_D) where sqr_D is the
+ // current best minimum squared distance for all points in this subtree
+ double up_sqr_d = std::numeric_limits<double>::infinity();
+ squared_distance_helper(
+ V,Ele,&other,other_V,other_Ele,0,up_sqr_d,sqrD,I,C);
+}
+
+template <typename DerivedV, int DIM>
+template <
+ typename DerivedEle,
+ typename Derivedother_V,
+ typename Derivedother_Ele,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+IGL_INLINE typename igl::AABB<DerivedV,DIM>::Scalar
+ igl::AABB<DerivedV,DIM>::squared_distance_helper(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const AABB<Derivedother_V,DIM> * other,
+ const Eigen::MatrixBase<Derivedother_V> & other_V,
+ const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
+ const Scalar /*up_sqr_d*/,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C) const
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // This implementation is a bit disappointing. There's no major speed up. Any
+ // performance gains seem to come from accidental cache coherency and
+ // diminish for larger "other" (the opposite of what was intended).
+
+ // Base case
+ if(other->is_leaf() && this->is_leaf())
+ {
+ Scalar sqr_d = sqrD(other->m_primitive);
+ int i = I(other->m_primitive);
+ RowVectorDIMS c = C.row( other->m_primitive);
+ RowVectorDIMS p = other_V.row(other->m_primitive);
+ leaf_squared_distance(V,Ele,p,sqr_d,i,c);
+ sqrD( other->m_primitive) = sqr_d;
+ I( other->m_primitive) = i;
+ C.row(other->m_primitive) = c;
+ //cout<<"leaf: "<<sqr_d<<endl;
+ //other->m_low_sqr_d = sqr_d;
+ return sqr_d;
+ }
+
+ if(other->is_leaf())
+ {
+ Scalar sqr_d = sqrD(other->m_primitive);
+ int i = I(other->m_primitive);
+ RowVectorDIMS c = C.row( other->m_primitive);
+ RowVectorDIMS p = other_V.row(other->m_primitive);
+ sqr_d = squared_distance(V,Ele,p,sqr_d,i,c);
+ sqrD( other->m_primitive) = sqr_d;
+ I( other->m_primitive) = i;
+ C.row(other->m_primitive) = c;
+ //other->m_low_sqr_d = sqr_d;
+ return sqr_d;
+ }
+
+ //// Exact minimum squared distance between arbitrary primitives inside this and
+ //// othre's bounding boxes
+ //const auto & min_squared_distance = [&](
+ // const AABB<DerivedV,DIM> * A,
+ // const AABB<Derivedother_V,DIM> * B)->Scalar
+ //{
+ // return A->m_box.squaredExteriorDistance(B->m_box);
+ //};
+
+ if(this->is_leaf())
+ {
+ //if(min_squared_distance(this,other) < other->m_low_sqr_d)
+ if(true)
+ {
+ this->squared_distance_helper(
+ V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C);
+ this->squared_distance_helper(
+ V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C);
+ }else
+ {
+ // This is never reached...
+ }
+ //// we know other is not a leaf
+ //other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d);
+ return 0;
+ }
+
+ // FORCE DOWN TO OTHER LEAF EVAL
+ //if(min_squared_distance(this,other) < other->m_low_sqr_d)
+ if(true)
+ {
+ if(true)
+ {
+ this->squared_distance_helper(
+ V,Ele,other->m_left,other_V,other_Ele,0,sqrD,I,C);
+ this->squared_distance_helper(
+ V,Ele,other->m_right,other_V,other_Ele,0,sqrD,I,C);
+ }else // this direction never seems to be faster
+ {
+ this->m_left->squared_distance_helper(
+ V,Ele,other,other_V,other_Ele,0,sqrD,I,C);
+ this->m_right->squared_distance_helper(
+ V,Ele,other,other_V,other_Ele,0,sqrD,I,C);
+ }
+ }else
+ {
+ // this is never reached ... :-(
+ }
+ //// we know other is not a leaf
+ //other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d);
+
+ return 0;
+#if 0 // False
+
+ // _Very_ conservative approximation of maximum squared distance between
+ // primitives inside this and other's bounding boxes
+ const auto & max_squared_distance = [](
+ const AABB<DerivedV,DIM> * A,
+ const AABB<Derivedother_V,DIM> * B)->Scalar
+ {
+ AlignedBox<Scalar,DIM> combo = A->m_box;
+ combo.extend(B->m_box);
+ return combo.diagonal().squaredNorm();
+ };
+
+ //// other base-case
+ //if(other->is_leaf())
+ //{
+ // double sqr_d = sqrD(other->m_primitive);
+ // int i = I(other->m_primitive);
+ // RowVectorDIMS c = C.row(m_primitive);
+ // RowVectorDIMS p = other_V.row(m_primitive);
+ // leaf_squared_distance(V,Ele,p,sqr_d,i,c);
+ // sqrD(other->m_primitive) = sqr_d;
+ // I(other->m_primitive) = i;
+ // C.row(m_primitive) = c;
+ // return;
+ //}
+ std::vector<const AABB<DerivedV,DIM> * > this_list;
+ if(this->is_leaf())
+ {
+ this_list.push_back(this);
+ }else
+ {
+ assert(this->m_left);
+ this_list.push_back(this->m_left);
+ assert(this->m_right);
+ this_list.push_back(this->m_right);
+ }
+ std::vector<AABB<Derivedother_V,DIM> *> other_list;
+ if(other->is_leaf())
+ {
+ other_list.push_back(other);
+ }else
+ {
+ assert(other->m_left);
+ other_list.push_back(other->m_left);
+ assert(other->m_right);
+ other_list.push_back(other->m_right);
+ }
+
+ //const std::function<Scalar(
+ // const AABB<Derivedother_V,DIM> * other)
+ // > low_sqr_d = [&sqrD,&low_sqr_d](const AABB<Derivedother_V,DIM> * other)->Scalar
+ // {
+ // if(other->is_leaf())
+ // {
+ // return sqrD(other->m_primitive);
+ // }else
+ // {
+ // return std::max(low_sqr_d(other->m_left),low_sqr_d(other->m_right));
+ // }
+ // };
+
+ //// Potentially recurse on all pairs, if minimum distance is less than running
+ //// bound
+ //Eigen::Matrix<Scalar,Eigen::Dynamic,1> other_low_sqr_d =
+ // Eigen::Matrix<Scalar,Eigen::Dynamic,1>::Constant(other_list.size(),1,up_sqr_d);
+ for(size_t child = 0;child<other_list.size();child++)
+ {
+ auto other_tree = other_list[child];
+
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1> this_low_sqr_d(this_list.size(),1);
+ for(size_t t = 0;t<this_list.size();t++)
+ {
+ const auto this_tree = this_list[t];
+ this_low_sqr_d(t) = max_squared_distance(this_tree,other_tree);
+ }
+ if(this_list.size() ==2 &&
+ ( this_low_sqr_d(0) > this_low_sqr_d(1))
+ )
+ {
+ std::swap(this_list[0],this_list[1]);
+ //std::swap(this_low_sqr_d(0),this_low_sqr_d(1));
+ }
+ const Scalar sqr_d = this_low_sqr_d.minCoeff();
+
+
+ for(size_t t = 0;t<this_list.size();t++)
+ {
+ const auto this_tree = this_list[t];
+
+ //const auto mm = low_sqr_d(other_tree);
+ //const Scalar mc = other_low_sqr_d(child);
+ //assert(mc == mm);
+ // Only look left/right in this_list if can possible decrease somebody's
+ // distance in this_tree.
+ const Scalar min_this_other = min_squared_distance(this_tree,other_tree);
+ if(
+ min_this_other < sqr_d &&
+ min_this_other < other_tree->m_low_sqr_d)
+ {
+ //cout<<"before: "<<other_low_sqr_d(child)<<endl;
+ //other_low_sqr_d(child) = std::min(
+ // other_low_sqr_d(child),
+ // this_tree->squared_distance_helper(
+ // V,Ele,other_tree,other_V,other_Ele,other_low_sqr_d(child),sqrD,I,C));
+ //cout<<"after: "<<other_low_sqr_d(child)<<endl;
+ this_tree->squared_distance_helper(
+ V,Ele,other_tree,other_V,other_Ele,0,sqrD,I,C);
+ }
+ }
+ }
+ //const Scalar ret = other_low_sqr_d.maxCoeff();
+ //const auto mm = low_sqr_d(other);
+ //assert(mm == ret);
+ //cout<<"non-leaf: "<<ret<<endl;
+ //return ret;
+ if(!other->is_leaf())
+ {
+ other->m_low_sqr_d = std::max(other->m_left->m_low_sqr_d,other->m_right->m_low_sqr_d);
+ }
+ return 0;
+#endif
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ const Scalar low_sqr_d,
+ Scalar & sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const
+{
+ using namespace Eigen;
+ using namespace std;
+ if(low_sqr_d > sqr_d)
+ {
+ sqr_d = low_sqr_d;
+ return;
+ }
+ RowVectorDIMS c_candidate;
+ Scalar sqr_d_candidate;
+ igl::point_simplex_squared_distance<DIM>(
+ p,V,Ele,m_primitive,sqr_d_candidate,c_candidate);
+ set_min(p,sqr_d_candidate,m_primitive,c_candidate,sqr_d,i,c);
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::leaf_squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ Scalar & sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const
+{
+ return leaf_squared_distance(V,Ele,p,0,sqr_d,i,c);
+}
+
+
+template <typename DerivedV, int DIM>
+IGL_INLINE void igl::AABB<DerivedV,DIM>::set_min(
+ const RowVectorDIMS &
+#ifndef NDEBUG
+ p
+#endif
+ ,
+ const Scalar sqr_d_candidate,
+ const int i_candidate,
+ const RowVectorDIMS & c_candidate,
+ Scalar & sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const
+{
+#ifndef NDEBUG
+ //std::cout<<matlab_format(c_candidate,"c_candidate")<<std::endl;
+ //// This doesn't quite make sense to check with bounds
+ // const Scalar pc_norm = (p-c_candidate).squaredNorm();
+ // const Scalar diff = fabs(sqr_d_candidate - pc_norm);
+ // assert(diff<=1e-10 && "distance should match norm of difference");
+#endif
+ if(sqr_d_candidate < sqr_d)
+ {
+ i = i_candidate;
+ c = c_candidate;
+ sqr_d = sqr_d_candidate;
+ }
+}
+
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE bool
+igl::AABB<DerivedV,DIM>::intersect_ray(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & origin,
+ const RowVectorDIMS & dir,
+ std::vector<igl::Hit> & hits) const
+{
+ hits.clear();
+ const Scalar t0 = 0;
+ const Scalar t1 = std::numeric_limits<Scalar>::infinity();
+ {
+ Scalar _1,_2;
+ if(!ray_box_intersect(origin,dir,m_box,t0,t1,_1,_2))
+ {
+ return false;
+ }
+ }
+ if(this->is_leaf())
+ {
+ // Actually process elements
+ assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles");
+ // Cheesecake way of hitting element
+ bool ret = ray_mesh_intersect(origin,dir,V,Ele.row(m_primitive),hits);
+ // Since we only gave ray_mesh_intersect a single face, it will have set
+ // any hits to id=0. Set these to this primitive's id
+ for(auto & hit : hits)
+ {
+ hit.id = m_primitive;
+ }
+ return ret;
+ }
+ std::vector<igl::Hit> left_hits;
+ std::vector<igl::Hit> right_hits;
+ const bool left_ret = m_left->intersect_ray(V,Ele,origin,dir,left_hits);
+ const bool right_ret = m_right->intersect_ray(V,Ele,origin,dir,right_hits);
+ hits.insert(hits.end(),left_hits.begin(),left_hits.end());
+ hits.insert(hits.end(),right_hits.begin(),right_hits.end());
+ return left_ret || right_ret;
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE bool
+igl::AABB<DerivedV,DIM>::intersect_ray(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & origin,
+ const RowVectorDIMS & dir,
+ igl::Hit & hit) const
+{
+#if false
+ // BFS
+ std::queue<const AABB *> Q;
+ // Or DFS
+ //std::stack<const AABB *> Q;
+ Q.push(this);
+ bool any_hit = false;
+ hit.t = std::numeric_limits<Scalar>::infinity();
+ while(!Q.empty())
+ {
+ const AABB * tree = Q.front();
+ //const AABB * tree = Q.top();
+ Q.pop();
+ {
+ Scalar _1,_2;
+ if(!ray_box_intersect(
+ origin,dir,tree->m_box,Scalar(0),Scalar(hit.t),_1,_2))
+ {
+ continue;
+ }
+ }
+ if(tree->is_leaf())
+ {
+ // Actually process elements
+ assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles");
+ igl::Hit leaf_hit;
+ if(
+ ray_mesh_intersect(origin,dir,V,Ele.row(tree->m_primitive),leaf_hit)&&
+ leaf_hit.t < hit.t)
+ {
+ // correct the id
+ leaf_hit.id = tree->m_primitive;
+ hit = leaf_hit;
+ }
+ continue;
+ }
+ // Add children to queue
+ Q.push(tree->m_left);
+ Q.push(tree->m_right);
+ }
+ return any_hit;
+#else
+ // DFS
+ return intersect_ray(
+ V,Ele,origin,dir,std::numeric_limits<Scalar>::infinity(),hit);
+#endif
+}
+
+template <typename DerivedV, int DIM>
+template <typename DerivedEle>
+IGL_INLINE bool
+igl::AABB<DerivedV,DIM>::intersect_ray(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & origin,
+ const RowVectorDIMS & dir,
+ const Scalar _min_t,
+ igl::Hit & hit) const
+{
+ //// Naive, slow
+ //std::vector<igl::Hit> hits;
+ //intersect_ray(V,Ele,origin,dir,hits);
+ //if(hits.size() > 0)
+ //{
+ // hit = hits.front();
+ // return true;
+ //}else
+ //{
+ // return false;
+ //}
+ Scalar min_t = _min_t;
+ const Scalar t0 = 0;
+ {
+ Scalar _1,_2;
+ if(!ray_box_intersect(origin,dir,m_box,t0,min_t,_1,_2))
+ {
+ return false;
+ }
+ }
+ if(this->is_leaf())
+ {
+ // Actually process elements
+ assert((Ele.size() == 0 || Ele.cols() == 3) && "Elements should be triangles");
+ // Cheesecake way of hitting element
+ bool ret = ray_mesh_intersect(origin,dir,V,Ele.row(m_primitive),hit);
+ hit.id = m_primitive;
+ return ret;
+ }
+
+ // Doesn't seem like smartly choosing left before/after right makes a
+ // differnce
+ igl::Hit left_hit;
+ igl::Hit right_hit;
+ bool left_ret = m_left->intersect_ray(V,Ele,origin,dir,min_t,left_hit);
+ if(left_ret && left_hit.t<min_t)
+ {
+ // It's scary that this line doesn't seem to matter....
+ min_t = left_hit.t;
+ hit = left_hit;
+ left_ret = true;
+ }else
+ {
+ left_ret = false;
+ }
+ bool right_ret = m_right->intersect_ray(V,Ele,origin,dir,min_t,right_hit);
+ if(right_ret && right_hit.t<min_t)
+ {
+ min_t = right_hit.t;
+ hit = right_hit;
+ right_ret = true;
+ }else
+ {
+ right_ret = false;
+ }
+ return left_ret || right_ret;
+}
+
+// This is a bullshit template because AABB annoyingly needs templates for bad
+// combinations of 3D V with DIM=2 AABB
+//
+// _Define_ as a no-op rather than monkeying around with the proper code above
+//
+// Meanwhile, GCC seems to have a bug. Let's see if GCC likes using explicit
+// namespace block instead. https://stackoverflow.com/a/25594681/148668
+namespace igl
+{
+ template<> template<> IGL_INLINE float AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 2>::squared_distance( Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<float, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&) const { assert(false);return -1;};
+ template<> template<> IGL_INLINE float igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 2>::squared_distance( Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<float, 1, 2, 1, 1, 2> const&, float, float, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&) const { assert(false);return -1;};
+ template<> template<> IGL_INLINE void igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 2>::init (Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&) { assert(false);};
+ template<> template<> IGL_INLINE double AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 2>::squared_distance( Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const { assert(false);return -1;};
+ template<> template<> IGL_INLINE double igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 2>::squared_distance( Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, double, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const { assert(false);return -1;};
+ template<> template<> IGL_INLINE void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 2>::init (Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&) { assert(false);};
+ template<> template<> IGL_INLINE void igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 2>::init(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&) {assert(false);};
+ template<> template<> IGL_INLINE float igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 2>::squared_distance(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<float, 1, 2, 1, 1, 2> const&, float, float, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&) const { assert(false);return -1;};
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template double igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+template float igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, float, float, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<float, -1, 3, 0, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::serialize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
+// generated by autoexplicit.sh
+template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::serialize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, int) const;
+// generated by autoexplicit.sh
+template std::vector<int, std::allocator<int> > igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::find<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, bool) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int);
+// generated by autoexplicit.sh
+template float igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::squared_distance<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
+// generated by autoexplicit.sh
+template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&) const;
+// generated by autoexplicit.sh
+template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 2, 1, 1, 2> const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) const;
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<float, -1, 3, 1, -1, 3>, 3>::init<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+// generated by autoexplicit.sh
+template void igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>::init<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template double igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::squared_distance<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, double, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&) const;
+template bool igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>::intersect_ray<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, igl::Hit&) const;
+#endif
diff --git a/xs/src/igl/AABB.h b/xs/src/igl/AABB.h
new file mode 100644
index 000000000..891481aa0
--- /dev/null
+++ b/xs/src/igl/AABB.h
@@ -0,0 +1,413 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_AABB_H
+#define IGL_AABB_H
+
+#include "Hit.h"
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#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).
+ template <typename DerivedV, int DIM>
+ class AABB
+ {
+public:
+ typedef typename DerivedV::Scalar Scalar;
+ typedef Eigen::Matrix<Scalar,1,DIM> RowVectorDIMS;
+ typedef Eigen::Matrix<Scalar,DIM,1> VectorDIMS;
+ typedef Eigen::Matrix<Scalar,Eigen::Dynamic,DIM> MatrixXDIMS;
+ // Shared pointers are slower...
+ AABB * m_left;
+ AABB * m_right;
+ Eigen::AlignedBox<Scalar,DIM> m_box;
+ // -1 non-leaf
+ int m_primitive;
+ //Scalar m_low_sqr_d;
+ //int m_depth;
+ AABB():
+ m_left(NULL), m_right(NULL),
+ m_box(), m_primitive(-1)
+ //m_low_sqr_d(std::numeric_limits<double>::infinity()),
+ //m_depth(0)
+ {}
+ // http://stackoverflow.com/a/3279550/148668
+ AABB(const AABB& other):
+ m_left(other.m_left ? new AABB(*other.m_left) : NULL),
+ m_right(other.m_right ? new AABB(*other.m_right) : NULL),
+ m_box(other.m_box),
+ m_primitive(other.m_primitive)
+ //m_low_sqr_d(other.m_low_sqr_d),
+ //m_depth(std::max(
+ // m_left ? m_left->m_depth + 1 : 0,
+ // m_right ? m_right->m_depth + 1 : 0))
+ {
+ }
+ // copy-swap idiom
+ friend void swap(AABB& first, AABB& second)
+ {
+ // Enable ADL
+ using std::swap;
+ swap(first.m_left,second.m_left);
+ swap(first.m_right,second.m_right);
+ swap(first.m_box,second.m_box);
+ swap(first.m_primitive,second.m_primitive);
+ //swap(first.m_low_sqr_d,second.m_low_sqr_d);
+ //swap(first.m_depth,second.m_depth);
+ }
+ // Pass-by-value (aka copy)
+ AABB& operator=(AABB other)
+ {
+ swap(*this,other);
+ return *this;
+ }
+ AABB(AABB&& other):
+ // initialize via default constructor
+ AABB()
+ {
+ swap(*this,other);
+ }
+ // Seems like there should have been an elegant solution to this using
+ // the copy-swap idiom above:
+ IGL_INLINE void deinit()
+ {
+ m_primitive = -1;
+ m_box = Eigen::AlignedBox<Scalar,DIM>();
+ delete m_left;
+ m_left = NULL;
+ delete m_right;
+ m_right = NULL;
+ }
+ ~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}
+ template <
+ typename DerivedEle,
+ typename Derivedbb_mins,
+ typename Derivedbb_maxs,
+ typename Derivedelements>
+ IGL_INLINE void init(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const Eigen::MatrixBase<Derivedbb_mins> & bb_mins,
+ const Eigen::MatrixBase<Derivedbb_maxs> & bb_maxs,
+ const Eigen::MatrixBase<Derivedelements> & elements,
+ const int i = 0);
+ // Wrapper for root with empty serialization
+ 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)
+ //
+ 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
+ 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
+ template <typename DerivedEle, typename Derivedq>
+ IGL_INLINE std::vector<int> find(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ 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))
+ 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}
+ template <
+ typename Derivedbb_mins,
+ typename Derivedbb_maxs,
+ typename Derivedelements>
+ IGL_INLINE void serialize(
+ Eigen::PlainObjectBase<Derivedbb_mins> & bb_mins,
+ 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.
+ template <typename DerivedEle>
+ IGL_INLINE Scalar squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ 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.
+ template <typename DerivedEle>
+ IGL_INLINE Scalar squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ const Scalar low_sqr_d,
+ const Scalar up_sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
+ // Default low_sqr_d
+ template <typename DerivedEle>
+ IGL_INLINE Scalar squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ const Scalar up_sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
+ // All hits
+ template <typename DerivedEle>
+ IGL_INLINE bool intersect_ray(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & origin,
+ const RowVectorDIMS & dir,
+ std::vector<igl::Hit> & hits) const;
+ // First hit
+ template <typename DerivedEle>
+ IGL_INLINE bool intersect_ray(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & origin,
+ const RowVectorDIMS & dir,
+ igl::Hit & hit) const;
+//private:
+ template <typename DerivedEle>
+ IGL_INLINE bool intersect_ray(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & origin,
+ const RowVectorDIMS & dir,
+ 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
+ template <
+ typename DerivedEle,
+ typename DerivedP,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+ IGL_INLINE void squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const Eigen::MatrixBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ 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
+ template <
+ typename DerivedEle,
+ typename Derivedother_V,
+ typename Derivedother_Ele,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+ IGL_INLINE void squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const AABB<Derivedother_V,DIM> & other,
+ const Eigen::MatrixBase<Derivedother_V> & other_V,
+ const Eigen::MatrixBase<Derivedother_Ele> & other_Ele,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C) const;
+private:
+ template <
+ typename DerivedEle,
+ typename Derivedother_V,
+ typename Derivedother_Ele,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+ IGL_INLINE Scalar squared_distance_helper(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const AABB<Derivedother_V,DIM> * other,
+ const Eigen::MatrixBase<Derivedother_V> & other_V,
+ const Eigen::MatrixBase<Derivedother_Ele>& other_Ele,
+ const Scalar up_sqr_d,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C) const;
+ // Compute the squared distance to the primitive in this node: assumes
+ // that this is indeed a leaf node.
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // Ele #Ele by dim list of simplex indices
+ // p dim-long query point
+ // sqr_d current minimum distance for this query, see output
+ // i current index into Ele of closest point, see output
+ // c dim-long current closest point, see output
+ // Outputs:
+ // sqr_d minimum of initial value and squared distance to this
+ // primitive
+ // i possibly updated index into Ele of closest point
+ // c dim-long possibly updated closest point
+ template <typename DerivedEle>
+ IGL_INLINE void leaf_squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ const Scalar low_sqr_d,
+ Scalar & sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
+ // Default low_sqr_d
+ template <typename DerivedEle>
+ IGL_INLINE void leaf_squared_distance(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const RowVectorDIMS & p,
+ Scalar & sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
+ // If new distance (sqr_d_candidate) is less than current distance
+ // (sqr_d), then update this distance and its associated values
+ // _in-place_:
+ //
+ // Inputs:
+ // p dim-long query point (only used in DEBUG mode)
+ // sqr_d candidate minimum distance for this query, see output
+ // i candidate index into Ele of closest point, see output
+ // c dim-long candidate closest point, see output
+ // sqr_d current minimum distance for this query, see output
+ // i current index into Ele of closest point, see output
+ // c dim-long current closest point, see output
+ // Outputs:
+ // sqr_d minimum of initial value and squared distance to this
+ // primitive
+ // i possibly updated index into Ele of closest point
+ // c dim-long possibly updated closest point
+ IGL_INLINE void set_min(
+ const RowVectorDIMS & p,
+ const Scalar sqr_d_candidate,
+ const int i_candidate,
+ const RowVectorDIMS & c_candidate,
+ Scalar & sqr_d,
+ int & i,
+ Eigen::PlainObjectBase<RowVectorDIMS> & c) const;
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ };
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "AABB.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/ARAPEnergyType.h b/xs/src/igl/ARAPEnergyType.h
new file mode 100644
index 000000000..68be24f5d
--- /dev/null
+++ b/xs/src/igl/ARAPEnergyType.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ARAPENERGYTYPE_H
+#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 ARAPEnergyType
+ {
+ ARAP_ENERGY_TYPE_SPOKES = 0,
+ ARAP_ENERGY_TYPE_SPOKES_AND_RIMS = 1,
+ ARAP_ENERGY_TYPE_ELEMENTS = 2,
+ ARAP_ENERGY_TYPE_DEFAULT = 3,
+ NUM_ARAP_ENERGY_TYPES = 4
+ };
+}
+#endif
diff --git a/xs/src/igl/AtA_cached.cpp b/xs/src/igl/AtA_cached.cpp
new file mode 100644
index 000000000..af7d0ad86
--- /dev/null
+++ b/xs/src/igl/AtA_cached.cpp
@@ -0,0 +1,130 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "AtA_cached.h"
+
+#include <iostream>
+#include <vector>
+#include <utility>
+
+template <typename Scalar>
+IGL_INLINE void igl::AtA_cached_precompute(
+ const Eigen::SparseMatrix<Scalar>& A,
+ igl::AtA_cached_data& data,
+ Eigen::SparseMatrix<Scalar>& AtA)
+{
+ // 1 Compute At (this could be avoided, but performance-wise it will not make a difference)
+ std::vector<std::vector<int> > Col_RowPtr;
+ std::vector<std::vector<int> > Col_IndexPtr;
+
+ Col_RowPtr.resize(A.cols());
+ Col_IndexPtr.resize(A.cols());
+
+ for (unsigned k=0; k<A.outerSize(); ++k)
+ {
+ unsigned outer_index = *(A.outerIndexPtr()+k);
+ unsigned next_outer_index = (k+1 == A.outerSize()) ? A.nonZeros() : *(A.outerIndexPtr()+k+1);
+
+ for (unsigned l=outer_index; l<next_outer_index; ++l)
+ {
+ int col = k;
+ int row = *(A.innerIndexPtr()+l);
+ int value_index = l;
+ assert(col < A.cols());
+ assert(col >= 0);
+ assert(row < A.rows());
+ assert(row >= 0);
+ assert(value_index >= 0);
+ assert(value_index < A.nonZeros());
+
+ Col_RowPtr[col].push_back(row);
+ Col_IndexPtr[col].push_back(value_index);
+ }
+ }
+
+ Eigen::SparseMatrix<Scalar> At = A.transpose();
+ At.makeCompressed();
+ AtA = At * A;
+ AtA.makeCompressed();
+
+ assert(AtA.isCompressed());
+
+ // If weights are not provided, use 1
+ if (data.W.size() == 0)
+ data.W = Eigen::VectorXd::Ones(A.rows());
+ assert(data.W.size() == A.rows());
+
+ data.I_outer.reserve(AtA.outerSize());
+ data.I_row.reserve(2*AtA.nonZeros());
+ data.I_col.reserve(2*AtA.nonZeros());
+ data.I_w.reserve(2*AtA.nonZeros());
+
+ // 2 Construct the rules
+ for (unsigned k=0; k<AtA.outerSize(); ++k)
+ {
+ unsigned outer_index = *(AtA.outerIndexPtr()+k);
+ unsigned next_outer_index = (k+1 == AtA.outerSize()) ? AtA.nonZeros() : *(AtA.outerIndexPtr()+k+1);
+
+ for (unsigned l=outer_index; l<next_outer_index; ++l)
+ {
+ int col = k;
+ int row = *(AtA.innerIndexPtr()+l);
+ int value_index = l;
+ assert(col < AtA.cols());
+ assert(col >= 0);
+ assert(row < AtA.rows());
+ assert(row >= 0);
+ assert(value_index >= 0);
+ assert(value_index < AtA.nonZeros());
+
+ data.I_outer.push_back(data.I_row.size());
+
+ // Find correspondences
+ unsigned i=0;
+ unsigned j=0;
+ while (i<Col_RowPtr[row].size() && j<Col_RowPtr[col].size())
+ {
+ if (Col_RowPtr[row][i] == Col_RowPtr[col][j])
+ {
+ data.I_row.push_back(Col_IndexPtr[row][i]);
+ data.I_col.push_back(Col_IndexPtr[col][j]);
+ data.I_w.push_back(Col_RowPtr[col][j]);
+ ++i;
+ ++j;
+ } else
+ if (Col_RowPtr[row][i] > Col_RowPtr[col][j])
+ ++j;
+ else
+ ++i;
+
+ }
+ }
+ }
+ data.I_outer.push_back(data.I_row.size()); // makes it more efficient to iterate later on
+
+ igl::AtA_cached(A,data,AtA);
+}
+
+template <typename Scalar>
+IGL_INLINE void igl::AtA_cached(
+ const Eigen::SparseMatrix<Scalar>& A,
+ const igl::AtA_cached_data& data,
+ Eigen::SparseMatrix<Scalar>& AtA)
+{
+ for (unsigned i=0; i<data.I_outer.size()-1; ++i)
+ {
+ *(AtA.valuePtr() + i) = 0;
+ for (unsigned j=data.I_outer[i]; j<data.I_outer[i+1]; ++j)
+ *(AtA.valuePtr() + i) += *(A.valuePtr() + data.I_row[j]) * data.W[data.I_w[j]] * *(A.valuePtr() + data.I_col[j]);
+ }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::AtA_cached<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::AtA_cached_precompute<double>(Eigen::SparseMatrix<double, 0, int> const&, igl::AtA_cached_data&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/AtA_cached.h b/xs/src/igl/AtA_cached.h
new file mode 100644
index 000000000..776825411
--- /dev/null
+++ b/xs/src/igl/AtA_cached.h
@@ -0,0 +1,70 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ATA_CACHED_H
+#define IGL_ATA_CACHED_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ struct AtA_cached_data
+ {
+ // Weights
+ Eigen::VectorXd W;
+
+ // Flatten composition rules
+ std::vector<int> I_row;
+ std::vector<int> I_col;
+ std::vector<int> I_w;
+
+ // For each entry of AtA, points to the beginning
+ // of the composition rules
+ 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);
+ template <typename Scalar>
+ IGL_INLINE void AtA_cached_precompute(
+ const Eigen::SparseMatrix<Scalar>& A,
+ AtA_cached_data& data,
+ Eigen::SparseMatrix<Scalar>& AtA
+ );
+
+ template <typename Scalar>
+ IGL_INLINE void AtA_cached(
+ const Eigen::SparseMatrix<Scalar>& A,
+ const AtA_cached_data& data,
+ Eigen::SparseMatrix<Scalar>& AtA
+ );
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "AtA_cached.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/C_STR.h b/xs/src/igl/C_STR.h
new file mode 100644
index 000000000..9844b35a5
--- /dev/null
+++ b/xs/src/igl/C_STR.h
@@ -0,0 +1,18 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_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>
+#define C_STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str().c_str()
+#endif
diff --git a/xs/src/igl/Camera.h b/xs/src/igl/Camera.h
new file mode 100644
index 000000000..79ebf603e
--- /dev/null
+++ b/xs/src/igl/Camera.h
@@ -0,0 +1,359 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CAMERA_H
+#define IGL_CAMERA_H
+
+// you're idiot, M$!
+#if defined(_WIN32)
+#undef far
+#undef near
+#endif
+
+#include <Eigen/Geometry>
+#include <Eigen/Core>
+#include <PI.h>
+
+#define IGL_CAMERA_MIN_ANGLE 5.0
+namespace igl
+{
+
+ // A simple camera class. The camera stores projection parameters (field of
+ // view angle, aspect ratio, near and far clips) as well as a rigid
+ // transformation *of the camera as if it were also a scene object*. Thus, the
+ // **inverse** of this rigid transformation is the modelview transformation.
+ class Camera
+ {
+ public:
+ // On windows you might need: -fno-delayed-template-parsing
+ //static constexpr double IGL_CAMERA_MIN_ANGLE = 5.;
+ // m_angle Field of view angle in degrees {45}
+ // m_aspect Aspect ratio {1}
+ // m_near near clipping plane {1e-2}
+ // m_far far clipping plane {100}
+ // m_at_dist distance of looking at point {1}
+ // m_orthographic whether to use othrographic projection {false}
+ // m_rotation_conj Conjugate of rotation part of rigid transformation of
+ // camera {identity}. Note: we purposefully store the conjugate because
+ // this is what TW_TYPE_QUAT4D is expecting.
+ // m_translation Translation part of rigid transformation of camera
+ // {(0,0,1)}
+ double m_angle, m_aspect, m_near, m_far, m_at_dist;
+ bool m_orthographic;
+ Eigen::Quaterniond m_rotation_conj;
+ Eigen::Vector3d m_translation;
+ public:
+ inline Camera();
+ inline virtual ~Camera(){}
+ // Return projection matrix that takes relative camera coordinates and
+ // transforms it to viewport coordinates
+ //
+ // Note:
+ //
+ // if(m_angle > 0)
+ // {
+ // gluPerspective(m_angle,m_aspect,m_near,m_at_dist+m_far);
+ // }else
+ // {
+ // gluOrtho(-0.5*aspect,0.5*aspect,-0.5,0.5,m_at_dist+m_near,m_far);
+ // }
+ //
+ // Is equivalent to
+ //
+ // glMultMatrixd(projection().data());
+ //
+ inline Eigen::Matrix4d projection() const;
+ // Return an Affine transformation (rigid actually) that
+ // takes relative coordinates and tramsforms them into world 3d
+ // coordinates: moves the camera into the scene.
+ inline Eigen::Affine3d affine() const;
+ // Return an Affine transformation (rigid actually) that puts the takes a
+ // world 3d coordinate and transforms it into the relative camera
+ // coordinates: moves the scene in front of the camera.
+ //
+ // Note:
+ //
+ // gluLookAt(
+ // eye()(0), eye()(1), eye()(2),
+ // at()(0), at()(1), at()(2),
+ // up()(0), up()(1), up()(2));
+ //
+ // Is equivalent to
+ //
+ // glMultMatrixd(camera.inverse().matrix().data());
+ //
+ // See also: affine, eye, at, up
+ inline Eigen::Affine3d inverse() const;
+ // Returns world coordinates position of center or "eye" of camera.
+ inline Eigen::Vector3d eye() const;
+ // Returns world coordinate position of a point "eye" is looking at.
+ inline Eigen::Vector3d at() const;
+ // Returns world coordinate unit vector of "up" vector
+ inline Eigen::Vector3d up() const;
+ // Return top right corner of unit plane in relative coordinates, that is
+ // (w/2,h/2,1)
+ inline Eigen::Vector3d unit_plane() const;
+ // Move dv in the relative coordinate frame of the camera (move the FPS)
+ //
+ // Inputs:
+ // dv (x,y,z) displacement vector
+ //
+ inline void dolly(const Eigen::Vector3d & dv);
+ // "Scale zoom": Move `eye`, but leave `at`
+ //
+ // Input:
+ // s amount to scale distance to at
+ inline void push_away(const double s);
+ // Aka "Hitchcock", "Vertigo", "Spielberg" or "Trombone" zoom:
+ // simultaneously dolly while changing angle so that `at` not only stays
+ // put in relative coordinates but also projected coordinates. That is
+ //
+ // Inputs:
+ // da change in angle in degrees
+ inline void dolly_zoom(const double da);
+ // Turn around eye so that rotation is now q
+ //
+ // Inputs:
+ // q new rotation as quaternion
+ inline void turn_eye(const Eigen::Quaterniond & q);
+ // Orbit around at so that rotation is now q
+ //
+ // Inputs:
+ // q new rotation as quaternion
+ inline void orbit(const Eigen::Quaterniond & q);
+ // Rotate and translate so that camera is situated at "eye" looking at "at"
+ // with "up" pointing up.
+ //
+ // Inputs:
+ // eye (x,y,z) coordinates of eye position
+ // at (x,y,z) coordinates of at position
+ // up (x,y,z) coordinates of up vector
+ inline void look_at(
+ const Eigen::Vector3d & eye,
+ const Eigen::Vector3d & at,
+ const Eigen::Vector3d & up);
+ // Needed any time Eigen Structures are used as class members
+ // http://eigen.tuxfamily.org/dox-devel/group__TopicStructHavingEigenMembers.html
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ };
+}
+
+// Implementation
+#include "PI.h"
+#include "EPS.h"
+#include <cmath>
+#include <iostream>
+#include <cassert>
+
+inline igl::Camera::Camera():
+ m_angle(45.0),m_aspect(1),m_near(1e-2),m_far(100),m_at_dist(1),
+ m_orthographic(false),
+ m_rotation_conj(1,0,0,0),
+ m_translation(0,0,1)
+{
+}
+
+inline Eigen::Matrix4d igl::Camera::projection() const
+{
+ Eigen::Matrix4d P;
+ using namespace std;
+ const double far = m_at_dist + m_far;
+ const double near = m_near;
+ // http://stackoverflow.com/a/3738696/148668
+ if(m_orthographic)
+ {
+ const double f = 0.5;
+ const double left = -f*m_aspect;
+ const double right = f*m_aspect;
+ const double bottom = -f;
+ const double top = f;
+ const double tx = (right+left)/(right-left);
+ const double ty = (top+bottom)/(top-bottom);
+ const double tz = (far+near)/(far-near);
+ const double z_fix = 0.5 /m_at_dist / tan(m_angle*0.5 * (igl::PI/180.) );
+ P<<
+ z_fix*2./(right-left), 0, 0, -tx,
+ 0, z_fix*2./(top-bottom), 0, -ty,
+ 0, 0, -z_fix*2./(far-near), -tz,
+ 0, 0, 0, 1;
+ }else
+ {
+ const double yScale = tan(PI*0.5 - 0.5*m_angle*PI/180.);
+ // http://stackoverflow.com/a/14975139/148668
+ const double xScale = yScale/m_aspect;
+ P<<
+ xScale, 0, 0, 0,
+ 0, yScale, 0, 0,
+ 0, 0, -(far+near)/(far-near), -1,
+ 0, 0, -2.*near*far/(far-near), 0;
+ P = P.transpose().eval();
+ }
+ return P;
+}
+
+inline Eigen::Affine3d igl::Camera::affine() const
+{
+ using namespace Eigen;
+ Affine3d t = Affine3d::Identity();
+ t.rotate(m_rotation_conj.conjugate());
+ t.translate(m_translation);
+ return t;
+}
+
+inline Eigen::Affine3d igl::Camera::inverse() const
+{
+ using namespace Eigen;
+ Affine3d t = Affine3d::Identity();
+ t.translate(-m_translation);
+ t.rotate(m_rotation_conj);
+ return t;
+}
+
+inline Eigen::Vector3d igl::Camera::eye() const
+{
+ using namespace Eigen;
+ return affine() * Vector3d(0,0,0);
+}
+
+inline Eigen::Vector3d igl::Camera::at() const
+{
+ using namespace Eigen;
+ return affine() * (Vector3d(0,0,-1)*m_at_dist);
+}
+
+inline Eigen::Vector3d igl::Camera::up() const
+{
+ using namespace Eigen;
+ Affine3d t = Affine3d::Identity();
+ t.rotate(m_rotation_conj.conjugate());
+ return t * Vector3d(0,1,0);
+}
+
+inline Eigen::Vector3d igl::Camera::unit_plane() const
+{
+ // Distance of center pixel to eye
+ const double d = 1.0;
+ const double a = m_aspect;
+ const double theta = m_angle*PI/180.;
+ const double w =
+ 2.*sqrt(-d*d/(a*a*pow(tan(0.5*theta),2.)-1.))*a*tan(0.5*theta);
+ const double h = w/a;
+ return Eigen::Vector3d(w*0.5,h*0.5,-d);
+}
+
+inline void igl::Camera::dolly(const Eigen::Vector3d & dv)
+{
+ m_translation += dv;
+}
+
+inline void igl::Camera::push_away(const double s)
+{
+ using namespace Eigen;
+#ifndef NDEBUG
+ Vector3d old_at = at();
+#endif
+ const double old_at_dist = m_at_dist;
+ m_at_dist = old_at_dist * s;
+ dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
+ assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
+}
+
+inline void igl::Camera::dolly_zoom(const double da)
+{
+ using namespace std;
+ using namespace Eigen;
+#ifndef NDEBUG
+ Vector3d old_at = at();
+#endif
+ const double old_angle = m_angle;
+ if(old_angle + da < IGL_CAMERA_MIN_ANGLE)
+ {
+ m_orthographic = true;
+ }else if(old_angle + da > IGL_CAMERA_MIN_ANGLE)
+ {
+ m_orthographic = false;
+ }
+ if(!m_orthographic)
+ {
+ m_angle += da;
+ m_angle = min(89.,max(IGL_CAMERA_MIN_ANGLE,m_angle));
+ // change in distance
+ const double s =
+ (2.*tan(old_angle/2./180.*igl::PI)) /
+ (2.*tan(m_angle/2./180.*igl::PI)) ;
+ const double old_at_dist = m_at_dist;
+ m_at_dist = old_at_dist * s;
+ dolly(Vector3d(0,0,1)*(m_at_dist - old_at_dist));
+ assert((old_at-at()).squaredNorm() < DOUBLE_EPS);
+ }
+}
+
+inline void igl::Camera::turn_eye(const Eigen::Quaterniond & q)
+{
+ using namespace Eigen;
+ Vector3d old_eye = eye();
+ // eye should be fixed
+ //
+ // eye_1 = R_1 * t_1 = eye_0
+ // t_1 = R_1' * eye_0
+ m_rotation_conj = q.conjugate();
+ m_translation = m_rotation_conj * old_eye;
+ assert((old_eye - eye()).squaredNorm() < DOUBLE_EPS);
+}
+
+inline void igl::Camera::orbit(const Eigen::Quaterniond & q)
+{
+ using namespace Eigen;
+ Vector3d old_at = at();
+ // at should be fixed
+ //
+ // at_1 = R_1 * t_1 - R_1 * z = at_0
+ // t_1 = R_1' * (at_0 + R_1 * z)
+ m_rotation_conj = q.conjugate();
+ m_translation =
+ m_rotation_conj *
+ (old_at +
+ m_rotation_conj.conjugate() * Vector3d(0,0,1) * m_at_dist);
+ assert((old_at - at()).squaredNorm() < DOUBLE_EPS);
+}
+
+inline void igl::Camera::look_at(
+ const Eigen::Vector3d & eye,
+ const Eigen::Vector3d & at,
+ const Eigen::Vector3d & up)
+{
+ using namespace Eigen;
+ using namespace std;
+ // http://www.opengl.org/sdk/docs/man2/xhtml/gluLookAt.xml
+ // Normalize vector from at to eye
+ Vector3d F = eye-at;
+ m_at_dist = F.norm();
+ F.normalize();
+ // Project up onto plane orthogonal to F and normalize
+ assert(up.cross(F).norm() > DOUBLE_EPS && "(eye-at) x up ≈ 0");
+ const Vector3d proj_up = (up-(up.dot(F))*F).normalized();
+ Quaterniond a,b;
+ a.setFromTwoVectors(Vector3d(0,0,-1),-F);
+ b.setFromTwoVectors(a*Vector3d(0,1,0),proj_up);
+ m_rotation_conj = (b*a).conjugate();
+ m_translation = m_rotation_conj * eye;
+ //cout<<"m_at_dist: "<<m_at_dist<<endl;
+ //cout<<"proj_up: "<<proj_up.transpose()<<endl;
+ //cout<<"F: "<<F.transpose()<<endl;
+ //cout<<"eye(): "<<this->eye().transpose()<<endl;
+ //cout<<"at(): "<<this->at().transpose()<<endl;
+ //cout<<"eye()-at(): "<<(this->eye()-this->at()).normalized().transpose()<<endl;
+ //cout<<"eye-this->eye(): "<<(eye-this->eye()).squaredNorm()<<endl;
+ assert( (eye-this->eye()).squaredNorm() < DOUBLE_EPS);
+ //assert((F-(this->eye()-this->at()).normalized()).squaredNorm() <
+ // DOUBLE_EPS);
+ assert( (at-this->at()).squaredNorm() < DOUBLE_EPS);
+ //assert( (proj_up-this->up()).squaredNorm() < DOUBLE_EPS);
+}
+
+#endif
diff --git a/xs/src/igl/EPS.cpp b/xs/src/igl/EPS.cpp
new file mode 100644
index 000000000..fc592cc2a
--- /dev/null
+++ b/xs/src/igl/EPS.cpp
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "EPS.h"
+
+template <> IGL_INLINE float igl::EPS()
+{
+ return igl::FLOAT_EPS;
+}
+template <> IGL_INLINE double igl::EPS()
+{
+ return igl::DOUBLE_EPS;
+}
+
+template <> IGL_INLINE float igl::EPS_SQ()
+{
+ return igl::FLOAT_EPS_SQ;
+}
+template <> IGL_INLINE double igl::EPS_SQ()
+{
+ return igl::DOUBLE_EPS_SQ;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/EPS.h b/xs/src/igl/EPS.h
new file mode 100644
index 000000000..17f3b8c25
--- /dev/null
+++ b/xs/src/igl/EPS.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EPS_H
+#define IGL_EPS_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Define a standard value for double epsilon
+ const double DOUBLE_EPS = 1.0e-14;
+ const double DOUBLE_EPS_SQ = 1.0e-28;
+ const float FLOAT_EPS = 1.0e-7;
+ const float FLOAT_EPS_SQ = 1.0e-14;
+ // Function returning EPS for corresponding type
+ template <typename S_type> IGL_INLINE S_type EPS();
+ template <typename S_type> IGL_INLINE S_type EPS_SQ();
+ // Template specializations for float and double
+ template <> IGL_INLINE float EPS<float>();
+ template <> IGL_INLINE double EPS<double>();
+ template <> IGL_INLINE float EPS_SQ<float>();
+ template <> IGL_INLINE double EPS_SQ<double>();
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "EPS.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/HalfEdgeIterator.cpp b/xs/src/igl/HalfEdgeIterator.cpp
new file mode 100644
index 000000000..7c3b9a886
--- /dev/null
+++ b/xs/src/igl/HalfEdgeIterator.cpp
@@ -0,0 +1,158 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "HalfEdgeIterator.h"
+
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::HalfEdgeIterator(
+ const Eigen::PlainObjectBase<DerivedF>& _F,
+ const Eigen::PlainObjectBase<DerivedFF>& _FF,
+ const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
+ int _fi,
+ int _ei,
+ bool _reverse
+)
+: fi(_fi), ei(_ei), reverse(_reverse), F(_F), FF(_FF), FFi(_FFi)
+{}
+
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipF()
+{
+ if (isBorder())
+ return;
+
+ int fin = (FF)(fi,ei);
+ int ein = (FFi)(fi,ei);
+
+ fi = fin;
+ ei = ein;
+ reverse = !reverse;
+}
+
+
+// Change Edge
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipE()
+{
+ if (!reverse)
+ ei = (ei+2)%3; // ei-1
+ else
+ ei = (ei+1)%3;
+
+ reverse = !reverse;
+}
+
+// Change Vertex
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE void igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::flipV()
+{
+ reverse = !reverse;
+}
+
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::isBorder()
+{
+ return (FF)(fi,ei) == -1;
+}
+
+/*!
+ * 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, ...
+ */
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::NextFE()
+{
+ if ( isBorder() ) // we are on a border
+ {
+ do
+ {
+ flipF();
+ flipE();
+ } while (!isBorder());
+ flipE();
+ return false;
+ }
+ else
+ {
+ flipF();
+ flipE();
+ return true;
+ }
+}
+
+// Get vertex index
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Vi()
+{
+ assert(fi >= 0);
+ assert(fi < F.rows());
+ assert(ei >= 0);
+ assert(ei <= 2);
+
+ if (!reverse)
+ return (F)(fi,ei);
+ else
+ return (F)(fi,(ei+1)%3);
+}
+
+// Get face index
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Fi()
+{
+ return fi;
+}
+
+// Get edge index
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE int igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::Ei()
+{
+ return ei;
+}
+
+
+template <typename DerivedF, typename DerivedFF, typename DerivedFFi>
+IGL_INLINE bool igl::HalfEdgeIterator<DerivedF,DerivedFF,DerivedFFi>::operator==(HalfEdgeIterator& p2)
+{
+ return
+ (
+ (fi == p2.fi) &&
+ (ei == p2.ei) &&
+ (reverse == p2.reverse) &&
+ (F == p2.F) &&
+ (FF == p2.FF) &&
+ (FFi == p2.FFi)
+ );
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, int, bool);
+template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
+template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
+template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Ei();
+template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::Ei();
+template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::Fi();
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> ,Eigen::Matrix<int, -1, 3, 0, -1, 3> >::NextFE();
+template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Vi();
+template igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::HalfEdgeIterator(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool);
+template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
+template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipE();
+template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipF();
+template void igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::flipV();
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >::operator==(igl::HalfEdgeIterator<Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template int igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::Fi();
+template bool igl::HalfEdgeIterator<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >::NextFE();
+#endif
diff --git a/xs/src/igl/HalfEdgeIterator.h b/xs/src/igl/HalfEdgeIterator.h
new file mode 100644
index 000000000..3c429e1d1
--- /dev/null
+++ b/xs/src/igl/HalfEdgeIterator.h
@@ -0,0 +1,114 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HALFEDGEITERATOR_H
+#define IGL_HALFEDGEITERATOR_H
+
+#include <Eigen/Core>
+
+#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.
+ //
+ template <
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedFFi>
+ class HalfEdgeIterator
+ {
+ public:
+ // Init the HalfEdgeIterator by specifying Face,Edge Index and Orientation
+ IGL_INLINE HalfEdgeIterator(
+ const Eigen::PlainObjectBase<DerivedF>& _F,
+ const Eigen::PlainObjectBase<DerivedFF>& _FF,
+ const Eigen::PlainObjectBase<DerivedFFi>& _FFi,
+ int _fi,
+ int _ei,
+ bool _reverse = false
+ );
+
+ // Change Face
+ IGL_INLINE void flipF();
+
+ // Change Edge
+ IGL_INLINE void flipE();
+
+ // Change Vertex
+ IGL_INLINE void flipV();
+
+ 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, ...
+ */
+ IGL_INLINE bool NextFE();
+
+ // Get vertex index
+ IGL_INLINE int Vi();
+
+ // Get face index
+ IGL_INLINE int Fi();
+
+ // Get edge index
+ IGL_INLINE int Ei();
+
+ IGL_INLINE bool operator==(HalfEdgeIterator& p2);
+
+ private:
+ int fi;
+ int ei;
+ bool reverse;
+
+ // All the same type? This is likely to break.
+ const Eigen::PlainObjectBase<DerivedF> & F;
+ const Eigen::PlainObjectBase<DerivedFF> & FF;
+ const Eigen::PlainObjectBase<DerivedFFi> & FFi;
+ };
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "HalfEdgeIterator.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/Hit.h b/xs/src/igl/Hit.h
new file mode 100644
index 000000000..8bffcc843
--- /dev/null
+++ b/xs/src/igl/Hit.h
@@ -0,0 +1,25 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HIT_H
+#define IGL_HIT_H
+
+namespace igl
+{
+ // 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
+ float u,v; // barycentric coordinates
+ float t; // distance = direction*t to intersection
+ };
+}
+#endif
diff --git a/xs/src/igl/IO b/xs/src/igl/IO
new file mode 100644
index 000000000..f054d8c99
--- /dev/null
+++ b/xs/src/igl/IO
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IO
+#define IGL_IO
+// Input and output functions
+#include "read_triangle_mesh.h"
+#include "readDMAT.h"
+#include "readMESH.h"
+#include "readNODE.h"
+#include "readOBJ.h"
+#include "readOFF.h"
+#include "readTGF.h"
+#include "readWRL.h"
+#include "readCSV.h"
+#include "file_contents_as_string.h"
+#include "write_triangle_mesh.h"
+#include "writeDMAT.h"
+#include "writeMESH.h"
+#include "writeOBJ.h"
+#include "writeOFF.h"
+#include "writeTGF.h"
+
+#endif
diff --git a/xs/src/igl/IndexComparison.h b/xs/src/igl/IndexComparison.h
new file mode 100644
index 000000000..44515df51
--- /dev/null
+++ b/xs/src/igl/IndexComparison.h
@@ -0,0 +1,117 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_INDEXCOMPARISON_H
+#define IGL_INDEXCOMPARISON_H
+#include <iostream>
+namespace igl{
+ // Comparison struct used by sort
+ // http://bytes.com/topic/c/answers/132045-sort-get-index
+
+ // For use with functions like std::sort
+ template<class T> struct IndexLessThan
+ {
+ IndexLessThan(const T arr) : arr(arr) {}
+ bool operator()(const size_t a, const size_t b) const
+ {
+ return arr[a] < arr[b];
+ }
+ const T arr;
+ };
+
+ // For use with functions like std::unique
+ template<class T> struct IndexEquals
+ {
+ IndexEquals(const T arr) : arr(arr) {}
+ bool operator()(const size_t a, const size_t b) const
+ {
+ return arr[a] == arr[b];
+ }
+ const T arr;
+ };
+
+ // For use with functions like std::sort
+ template<class T> struct IndexVectorLessThan
+ {
+ IndexVectorLessThan(const T & vec) : vec ( vec) {}
+ bool operator()(const size_t a, const size_t b) const
+ {
+ return vec(a) < vec(b);
+ }
+ const T & vec;
+ };
+
+ // For use with functions like std::sort
+ template<class T> struct IndexDimLessThan
+ {
+ IndexDimLessThan(const T & mat,const int & dim, const int & j) :
+ mat(mat),
+ dim(dim),
+ j(j)
+ {}
+ bool operator()(const size_t a, const size_t b) const
+ {
+ if(dim == 1)
+ {
+ return mat(a,j) < mat(b,j);
+ }else
+ {
+ return mat(j,a) < mat(j,b);
+ }
+ }
+ const T & mat;
+ const int & dim;
+ const int & j;
+ };
+
+ // For use with functions like std::sort
+ template<class T> struct IndexRowLessThan
+ {
+ IndexRowLessThan(const T & mat) : mat ( mat) {}
+ bool operator()(const size_t a, const size_t b) const
+ {
+ const int cols = mat.cols();
+ // Lexicographical order
+ for(int j = 0;j<cols;j++)
+ {
+ if(mat(a,j) > mat(b,j))
+ {
+ return false;
+ } else if(mat(a,j) < mat(b,j))
+ {
+ return true;
+ }
+ }
+ // equality is false
+ return false;
+ }
+ const T & mat;
+ };
+
+ // For use with functions like std::sort
+ template<class T> struct IndexRowEquals
+ {
+ IndexRowEquals(const T & mat) : mat ( mat) {}
+ bool operator()(const size_t a, const size_t b) const
+ {
+ const int cols = mat.cols();
+ // Lexicographical order
+ for(int j = 0;j<cols;j++)
+ {
+ if(mat(a,j) != mat(b,j))
+ {
+ return false;
+ }
+ }
+ return true;
+ }
+ const T & mat;
+ };
+
+}
+
+#endif
diff --git a/xs/src/igl/LinSpaced.h b/xs/src/igl/LinSpaced.h
new file mode 100644
index 000000000..d40db33d3
--- /dev/null
+++ b/xs/src/igl/LinSpaced.h
@@ -0,0 +1,61 @@
+#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);
+//
+namespace igl
+{
+ template <typename Derived>
+ //inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType
+ inline Derived LinSpaced(
+ typename Derived::Index size,
+ const typename Derived::Scalar & low,
+ const typename Derived::Scalar & high);
+}
+
+// Implementation
+
+template <typename Derived>
+//inline typename Eigen::DenseBase< Derived >::RandomAccessLinSpacedReturnType
+inline Derived
+igl::LinSpaced(
+ typename Derived::Index size,
+ const typename Derived::Scalar & low,
+ const typename Derived::Scalar & high)
+{
+ if(size == 0)
+ {
+ // Force empty vector with correct "RandomAccessLinSpacedReturnType" type.
+ return Derived::LinSpaced(0,0,1);
+ }else if(high < low)
+ {
+ return low-Derived::LinSpaced(size,low-low,low-high).array();
+ }else{
+ return Derived::LinSpaced(size,low,high);
+ }
+}
+
+#endif
diff --git a/xs/src/igl/MeshBooleanType.h b/xs/src/igl/MeshBooleanType.h
new file mode 100644
index 000000000..2eb293624
--- /dev/null
+++ b/xs/src/igl/MeshBooleanType.h
@@ -0,0 +1,23 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MESH_BOOLEAN_TYPE_H
+#define IGL_MESH_BOOLEAN_TYPE_H
+namespace igl
+{
+ enum MeshBooleanType
+ {
+ MESH_BOOLEAN_TYPE_UNION = 0,
+ MESH_BOOLEAN_TYPE_INTERSECT = 1,
+ MESH_BOOLEAN_TYPE_MINUS = 2,
+ MESH_BOOLEAN_TYPE_XOR = 3,
+ MESH_BOOLEAN_TYPE_RESOLVE = 4,
+ NUM_MESH_BOOLEAN_TYPES = 5
+ };
+};
+
+#endif
diff --git a/xs/src/igl/NormalType.h b/xs/src/igl/NormalType.h
new file mode 100644
index 000000000..b74b57b6a
--- /dev/null
+++ b/xs/src/igl/NormalType.h
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NORMALTYPE_H
+#define IGL_NORMALTYPE_H
+
+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
+ enum NormalType
+ {
+ PER_VERTEX_NORMALS,
+ PER_FACE_NORMALS,
+ PER_CORNER_NORMALS
+ };
+# define NUM_NORMAL_TYPE 3
+}
+
+#endif
+
diff --git a/xs/src/igl/ONE.h b/xs/src/igl/ONE.h
new file mode 100644
index 000000000..93c509d4e
--- /dev/null
+++ b/xs/src/igl/ONE.h
@@ -0,0 +1,22 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ONE_H
+#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);
+ const char CHAR_ONE = 1;
+ const int INT_ONE = 1;
+ const unsigned int UNSIGNED_INT_ONE = 1;
+ const double DOUBLE_ONE = 1;
+ const float FLOAT_ONE = 1;
+}
+#endif
+
diff --git a/xs/src/igl/PI.h b/xs/src/igl/PI.h
new file mode 100644
index 000000000..f1ef4359d
--- /dev/null
+++ b/xs/src/igl/PI.h
@@ -0,0 +1,19 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PI_H
+#define IGL_PI_H
+namespace igl
+{
+ // Use standard mathematical constants' M_PI if available
+#ifdef M_PI
+ const double PI = M_PI;
+#else
+ const double PI = 3.1415926535897932384626433832795;
+#endif
+}
+#endif
diff --git a/xs/src/igl/REDRUM.h b/xs/src/igl/REDRUM.h
new file mode 100644
index 000000000..79ab72ffd
--- /dev/null
+++ b/xs/src/igl/REDRUM.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REDRUM_H
+#define IGL_REDRUM_H
+
+// Q: These should probably be inside the igl namespace. What's the correct
+// way to do that?
+// A: I guess the right way is to not use a macro but a proper function with
+// streams as input and output.
+
+// ANSI color codes for formatting iostream style output
+
+#ifdef IGL_REDRUM_NOOP
+
+// Bold Red, etc.
+#define NORUM(X) X
+#define REDRUM(X) X
+#define GREENRUM(X) X
+#define YELLOWRUM(X) X
+#define BLUERUM(X) X
+#define MAGENTARUM(X) X
+#define CYANRUM(X) X
+// Regular Red, etc.
+#define REDGIN(X) X
+#define GREENGIN(X) X
+#define YELLOWGIN(X) X
+#define BLUEGIN(X) X
+#define MAGENTAGIN(X) X
+#define CYANGIN(X) X
+
+#else
+
+// 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"
+#define MAGENTARUM(X) "\e[1m\e[35m"<<X<<"\e[m"
+#define CYANRUM(X) "\e[1m\e[36m"<<X<<"\e[m"
+// Regular Red, etc.
+#define REDGIN(X) "\e[31m"<<X<<"\e[m"
+#define GREENGIN(X) "\e[32m"<<X<<"\e[m"
+#define YELLOWGIN(X) "\e[33m"<<X<<"\e[m"
+#define BLUEGIN(X) "\e[34m"<<X<<"\e[m"
+#define MAGENTAGIN(X) "\e[35m"<<X<<"\e[m"
+#define CYANGIN(X) "\e[36m"<<X<<"\e[m"
+#endif
+
+#endif
diff --git a/xs/src/igl/STR.h b/xs/src/igl/STR.h
new file mode 100644
index 000000000..0e937167b
--- /dev/null
+++ b/xs/src/igl/STR.h
@@ -0,0 +1,18 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_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"));
+#define STR(X) static_cast<std::ostringstream&>(std::ostringstream().flush() << X).str()
+#endif
diff --git a/xs/src/igl/Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp b/xs/src/igl/Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp
new file mode 100644
index 000000000..2207285aa
--- /dev/null
+++ b/xs/src/igl/Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp
@@ -0,0 +1,128 @@
+//#####################################################################
+// Copyright (c) 2010-2011, Eftychios Sifakis.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//#####################################################################
+
+//###########################################################
+// Compute the Givens half-angle, construct the Givens quaternion and the rotation sine/cosine (for the full angle)
+//###########################################################
+
+#ifdef _WIN32
+ #undef max
+ #undef min
+#endif
+
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=SANPIVOT.f*SANPIVOT.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(VANPIVOT,VANPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(VANPIVOT,VANPIVOT);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=(Ssh.f>=Ssmall_number.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_cmpge_ps(Vsh,Vsmall_number);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_cmp_ps(Vsh,Vsmall_number, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_cmpge_ps(Vsh,Vsmall_number);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui&SANPIVOT.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vsh,VANPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_and_ps(Vsh,VANPIVOT);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vtmp5,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vtmp5,Vtmp5);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Stmp5.f-SAPIVOT.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_sub_ps(Vtmp5,VAPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_sub_ps(Vtmp5,VAPIVOT);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.f=std::max(Sch.f,SAPIVOT.f);) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_max_ps(Vch,VAPIVOT);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_max_ps(Vch,VAPIVOT);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.f=std::max(Sch.f,Ssmall_number.f);) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_max_ps(Vch,Vsmall_number);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_max_ps(Vch,Vsmall_number);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=(SAPIVOT.f>=Stmp5.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_cmpge_ps(VAPIVOT,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_cmp_ps(VAPIVOT,Vtmp5, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_cmpge_ps(VAPIVOT,Vtmp5);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vch,Vch);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vtmp1,Vtmp2);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Sch.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_add_ps(Vch,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_add_ps(Vch,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=~Stmp5.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_andnot_ps(Vtmp5,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=Vch;)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=~Stmp5.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_andnot_ps(Vtmp5,Vch);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vsh,Vch,Vtmp5);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Stmp5.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_and_ps(Vtmp5,Vch);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_blendv_ps(Vtmp1,Vsh,Vtmp5);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Stmp5.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vtmp5,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_or_ps(Vsh,Vtmp2);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vch,Vch);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Sch.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_mul_ps(Vch,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_mul_ps(Vch,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vch,Vch);)ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vsh,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Sc.f-Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_sub_ps(Vc,Vs);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_sub_ps(Vc,Vs);)
+ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ssh.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vsh,Vch);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vsh,Vch);)
+ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ss.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_add_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_add_ps(Vs,Vs);)
+
+//###########################################################
+// Rotate matrix A
+//###########################################################
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA11.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA11);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA11);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA21);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA21);)
+ENABLE_SCALAR_IMPLEMENTATION(SA11.f=Sc.f*SA11.f;) ENABLE_SSE_IMPLEMENTATION(VA11=_mm_mul_ps(Vc,VA11);) ENABLE_AVX_IMPLEMENTATION(VA11=_mm256_mul_ps(Vc,VA11);)
+ENABLE_SCALAR_IMPLEMENTATION(SA21.f=Sc.f*SA21.f;) ENABLE_SSE_IMPLEMENTATION(VA21=_mm_mul_ps(Vc,VA21);) ENABLE_AVX_IMPLEMENTATION(VA21=_mm256_mul_ps(Vc,VA21);)
+ENABLE_SCALAR_IMPLEMENTATION(SA11.f=SA11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA11=_mm_add_ps(VA11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA11=_mm256_add_ps(VA11,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SA21.f=SA21.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA21=_mm_sub_ps(VA21,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA21=_mm256_sub_ps(VA21,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA12);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA12);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA22);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA22);)
+ENABLE_SCALAR_IMPLEMENTATION(SA12.f=Sc.f*SA12.f;) ENABLE_SSE_IMPLEMENTATION(VA12=_mm_mul_ps(Vc,VA12);) ENABLE_AVX_IMPLEMENTATION(VA12=_mm256_mul_ps(Vc,VA12);)
+ENABLE_SCALAR_IMPLEMENTATION(SA22.f=Sc.f*SA22.f;) ENABLE_SSE_IMPLEMENTATION(VA22=_mm_mul_ps(Vc,VA22);) ENABLE_AVX_IMPLEMENTATION(VA22=_mm256_mul_ps(Vc,VA22);)
+ENABLE_SCALAR_IMPLEMENTATION(SA12.f=SA12.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA12=_mm_add_ps(VA12,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA12=_mm256_add_ps(VA12,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SA22.f=SA22.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA22=_mm_sub_ps(VA22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA22=_mm256_sub_ps(VA22,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SA13.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VA13);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VA13);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SA23.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VA23);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VA23);)
+ENABLE_SCALAR_IMPLEMENTATION(SA13.f=Sc.f*SA13.f;) ENABLE_SSE_IMPLEMENTATION(VA13=_mm_mul_ps(Vc,VA13);) ENABLE_AVX_IMPLEMENTATION(VA13=_mm256_mul_ps(Vc,VA13);)
+ENABLE_SCALAR_IMPLEMENTATION(SA23.f=Sc.f*SA23.f;) ENABLE_SSE_IMPLEMENTATION(VA23=_mm_mul_ps(Vc,VA23);) ENABLE_AVX_IMPLEMENTATION(VA23=_mm256_mul_ps(Vc,VA23);)
+ENABLE_SCALAR_IMPLEMENTATION(SA13.f=SA13.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VA13=_mm_add_ps(VA13,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VA13=_mm256_add_ps(VA13,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SA23.f=SA23.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VA23=_mm_sub_ps(VA23,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VA23=_mm256_sub_ps(VA23,Vtmp1);)
+
+//###########################################################
+// Update matrix U
+//###########################################################
+
+#ifdef COMPUTE_U_AS_MATRIX
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU11.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU11);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU11);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU12);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU12);)
+ENABLE_SCALAR_IMPLEMENTATION(SU11.f=Sc.f*SU11.f;) ENABLE_SSE_IMPLEMENTATION(VU11=_mm_mul_ps(Vc,VU11);) ENABLE_AVX_IMPLEMENTATION(VU11=_mm256_mul_ps(Vc,VU11);)
+ENABLE_SCALAR_IMPLEMENTATION(SU12.f=Sc.f*SU12.f;) ENABLE_SSE_IMPLEMENTATION(VU12=_mm_mul_ps(Vc,VU12);) ENABLE_AVX_IMPLEMENTATION(VU12=_mm256_mul_ps(Vc,VU12);)
+ENABLE_SCALAR_IMPLEMENTATION(SU11.f=SU11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU11=_mm_add_ps(VU11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU11=_mm256_add_ps(VU11,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SU12.f=SU12.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU12=_mm_sub_ps(VU12,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU12=_mm256_sub_ps(VU12,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU21);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU22);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU22);)
+ENABLE_SCALAR_IMPLEMENTATION(SU21.f=Sc.f*SU21.f;) ENABLE_SSE_IMPLEMENTATION(VU21=_mm_mul_ps(Vc,VU21);) ENABLE_AVX_IMPLEMENTATION(VU21=_mm256_mul_ps(Vc,VU21);)
+ENABLE_SCALAR_IMPLEMENTATION(SU22.f=Sc.f*SU22.f;) ENABLE_SSE_IMPLEMENTATION(VU22=_mm_mul_ps(Vc,VU22);) ENABLE_AVX_IMPLEMENTATION(VU22=_mm256_mul_ps(Vc,VU22);)
+ENABLE_SCALAR_IMPLEMENTATION(SU21.f=SU21.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU21=_mm_add_ps(VU21,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU21=_mm256_add_ps(VU21,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SU22.f=SU22.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU22=_mm_sub_ps(VU22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU22=_mm256_sub_ps(VU22,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SU31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VU31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VU31);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SU32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VU32);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VU32);)
+ENABLE_SCALAR_IMPLEMENTATION(SU31.f=Sc.f*SU31.f;) ENABLE_SSE_IMPLEMENTATION(VU31=_mm_mul_ps(Vc,VU31);) ENABLE_AVX_IMPLEMENTATION(VU31=_mm256_mul_ps(Vc,VU31);)
+ENABLE_SCALAR_IMPLEMENTATION(SU32.f=Sc.f*SU32.f;) ENABLE_SSE_IMPLEMENTATION(VU32=_mm_mul_ps(Vc,VU32);) ENABLE_AVX_IMPLEMENTATION(VU32=_mm256_mul_ps(Vc,VU32);)
+ENABLE_SCALAR_IMPLEMENTATION(SU31.f=SU31.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VU31=_mm_add_ps(VU31,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VU31=_mm256_add_ps(VU31,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SU32.f=SU32.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VU32=_mm_sub_ps(VU32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VU32=_mm256_sub_ps(VU32,Vtmp1);)
+#endif
diff --git a/xs/src/igl/Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp b/xs/src/igl/Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp
new file mode 100644
index 000000000..70b437131
--- /dev/null
+++ b/xs/src/igl/Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp
@@ -0,0 +1,118 @@
+//#####################################################################
+// Copyright (c) 2010-2011, Eftychios Sifakis.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//#####################################################################
+
+//###########################################################
+// Compute the Givens angle (and half-angle)
+//###########################################################
+
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=SS21.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(VS21,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(VS21,Vone_half);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=SS11.f-SS22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_sub_ps(VS11,VS22);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_sub_ps(VS11,VS22);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=(Stmp2.f>=Stiny_number.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_cmpge_ps(Vtmp2,Vtiny_number);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmp_ps(Vtmp2,Vtiny_number, _CMP_GE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmpge_ps(Vtmp2,Vtiny_number);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Stmp1.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_and_ps(Vtmp1,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_and_ps(Vtmp1,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Stmp1.ui&Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_and_ps(Vtmp1,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vone,Vtmp5,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=~Stmp1.ui&Sone.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_andnot_ps(Vtmp1,Vone);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp2);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vch,Vch);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp1,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=rsqrt(Stmp3.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_rsqrt_ps(Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_rsqrt_ps(Vtmp3);)
+
+#ifdef USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION
+ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Stmp4.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vtmp4,Vone_half);)
+ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp4.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp4,Vs);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp4,Vs);)
+ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp4.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp4,Vc);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp4,Vc);)
+ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp3.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_mul_ps(Vtmp3,Vc);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_mul_ps(Vtmp3,Vc);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_add_ps(Vtmp4,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_add_ps(Vtmp4,Vs);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vc);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vc);)
+#endif
+
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Stmp4.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vtmp4,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vtmp4,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.f=Stmp4.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_mul_ps(Vtmp4,Vch);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_mul_ps(Vtmp4,Vch);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sfour_gamma_squared.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vfour_gamma_squared,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vfour_gamma_squared,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=(Stmp2.f<=Stmp1.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_cmple_ps(Vtmp2,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmp_ps(Vtmp2,Vtmp1, _CMP_LE_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_cmple_ps(Vtmp2,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Ssine_pi_over_eight.ui&Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_and_ps(Vsine_pi_over_eight,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_blendv_ps(Vsh,Vsine_pi_over_eight,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=~Stmp1.ui&Ssh.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_andnot_ps(Vtmp1,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.ui=Ssh.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_or_ps(Vsh,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Scosine_pi_over_eight.ui&Stmp1.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_and_ps(Vcosine_pi_over_eight,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vch=_mm256_blendv_ps(Vch,Vcosine_pi_over_eight,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=~Stmp1.ui&Sch.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_andnot_ps(Vtmp1,Vch);)
+ENABLE_SCALAR_IMPLEMENTATION(Sch.ui=Sch.ui|Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vch=_mm_or_ps(Vch,Vtmp2);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sch.f*Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vch,Vch);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vch,Vch);)
+ENABLE_SCALAR_IMPLEMENTATION(Sc.f=Stmp2.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vc=_mm_sub_ps(Vtmp2,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vc=_mm256_sub_ps(Vtmp2,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Sch.f*Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_mul_ps(Vch,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_mul_ps(Vch,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Ss.f=Ss.f+Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vs=_mm_add_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vs=_mm256_add_ps(Vs,Vs);)
+
+//###########################################################
+// Perform the actual Givens conjugation
+//###########################################################
+
+#ifndef USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp1,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SS33.f=SS33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS33=_mm_mul_ps(VS33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS33=_mm256_mul_ps(VS33,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(SS31.f=SS31.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_mul_ps(VS31,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_mul_ps(VS31,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(SS32.f=SS32.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_mul_ps(VS32,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_mul_ps(VS32,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(SS33.f=SS33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS33=_mm_mul_ps(VS33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS33=_mm256_mul_ps(VS33,Vtmp3);)
+#endif
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ss.f*SS31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vs,VS31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vs,VS31);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*SS32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,VS32);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,VS32);)
+ENABLE_SCALAR_IMPLEMENTATION(SS31.f=Sc.f*SS31.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_mul_ps(Vc,VS31);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_mul_ps(Vc,VS31);)
+ENABLE_SCALAR_IMPLEMENTATION(SS32.f=Sc.f*SS32.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_mul_ps(Vc,VS32);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_mul_ps(Vc,VS32);)
+ENABLE_SCALAR_IMPLEMENTATION(SS31.f=Stmp2.f+SS31.f;) ENABLE_SSE_IMPLEMENTATION(VS31=_mm_add_ps(Vtmp2,VS31);) ENABLE_AVX_IMPLEMENTATION(VS31=_mm256_add_ps(Vtmp2,VS31);)
+ENABLE_SCALAR_IMPLEMENTATION(SS32.f=SS32.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VS32=_mm_sub_ps(VS32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VS32=_mm256_sub_ps(VS32,Vtmp1);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ss.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vs,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vs,Vs);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=SS22.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(VS22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(VS22,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=SS11.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(VS11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(VS11,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sc.f*Sc.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vc,Vc);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vc,Vc);)
+ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_mul_ps(VS11,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_mul_ps(VS11,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_mul_ps(VS22,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_mul_ps(VS22,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_add_ps(VS11,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_add_ps(VS11,Vtmp1);)
+ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f+Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_add_ps(VS22,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_add_ps(VS22,Vtmp3);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=SS21.f+SS21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(VS21,VS21);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(VS21,VS21);)
+ENABLE_SCALAR_IMPLEMENTATION(SS21.f=SS21.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(VS21=_mm_mul_ps(VS21,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(VS21=_mm256_mul_ps(VS21,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sc.f*Ss.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vc,Vs);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vc,Vs);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp2.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vtmp2,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vtmp2,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp5,Vtmp4);)
+ENABLE_SCALAR_IMPLEMENTATION(SS11.f=SS11.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VS11=_mm_add_ps(VS11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VS11=_mm256_add_ps(VS11,Vtmp2);)
+ENABLE_SCALAR_IMPLEMENTATION(SS21.f=SS21.f-Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(VS21=_mm_sub_ps(VS21,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(VS21=_mm256_sub_ps(VS21,Vtmp5);)
+ENABLE_SCALAR_IMPLEMENTATION(SS22.f=SS22.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(VS22=_mm_sub_ps(VS22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(VS22=_mm256_sub_ps(VS22,Vtmp2);)
+
+//###########################################################
+// Compute the cumulative rotation, in quaternion form
+//###########################################################
+
+ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vqvvx);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vqvvy);)
+ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Ssh.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vsh,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vsh,Vqvvz);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vqvs);)
+
+ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sch.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vch,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vch,Vqvs);)
+ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sch.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_mul_ps(Vch,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_mul_ps(Vch,Vqvvx);)
+ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sch.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_mul_ps(Vch,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_mul_ps(Vch,Vqvvy);)
+ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sch.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_mul_ps(Vch,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_mul_ps(Vch,Vqvvz);)
+
+ENABLE_SCALAR_IMPLEMENTATION(SQVVZ.f=SQVVZ.f+Ssh.f;) ENABLE_SSE_IMPLEMENTATION(VQVVZ=_mm_add_ps(VQVVZ,Vsh);) ENABLE_AVX_IMPLEMENTATION(VQVVZ=_mm256_add_ps(VQVVZ,Vsh);)
+ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f-STMP3.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_sub_ps(Vqvs,VTMP3);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_sub_ps(Vqvs,VTMP3);)
+ENABLE_SCALAR_IMPLEMENTATION(SQVVX.f=SQVVX.f+STMP2.f;) ENABLE_SSE_IMPLEMENTATION(VQVVX=_mm_add_ps(VQVVX,VTMP2);) ENABLE_AVX_IMPLEMENTATION(VQVVX=_mm256_add_ps(VQVVX,VTMP2);)
+ENABLE_SCALAR_IMPLEMENTATION(SQVVY.f=SQVVY.f-STMP1.f;) ENABLE_SSE_IMPLEMENTATION(VQVVY=_mm_sub_ps(VQVVY,VTMP1);) ENABLE_AVX_IMPLEMENTATION(VQVVY=_mm256_sub_ps(VQVVY,VTMP1);)
diff --git a/xs/src/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp b/xs/src/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp
new file mode 100644
index 000000000..0c3b3ff87
--- /dev/null
+++ b/xs/src/igl/Singular_Value_Decomposition_Kernel_Declarations.hpp
@@ -0,0 +1,137 @@
+//#####################################################################
+// Copyright (c) 2010-2011, Eftychios Sifakis.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//#####################################################################
+
+//###########################################################
+// Local variable declarations
+//###########################################################
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+
+#ifdef USE_SSE_IMPLEMENTATION
+ float buf[4];
+ float A11,A21,A31,A12,A22,A32,A13,A23,A33;
+ float S11,S21,S31,S22,S32,S33;
+#ifdef COMPUTE_V_AS_QUATERNION
+ float QVS,QVVX,QVVY,QVVZ;
+#endif
+#ifdef COMPUTE_V_AS_MATRIX
+ float V11,V21,V31,V12,V22,V32,V13,V23,V33;
+#endif
+#ifdef COMPUTE_U_AS_QUATERNION
+ float QUS,QUVX,QUVY,QUVZ;
+#endif
+#ifdef COMPUTE_U_AS_MATRIX
+ float U11,U21,U31,U12,U22,U32,U13,U23,U33;
+#endif
+#endif
+
+#ifdef USE_AVX_IMPLEMENTATION
+ float buf[8];
+ float A11,A21,A31,A12,A22,A32,A13,A23,A33;
+ float S11,S21,S31,S22,S32,S33;
+#ifdef COMPUTE_V_AS_QUATERNION
+ float QVS,QVVX,QVVY,QVVZ;
+#endif
+#ifdef COMPUTE_V_AS_MATRIX
+ float V11,V21,V31,V12,V22,V32,V13,V23,V33;
+#endif
+#ifdef COMPUTE_U_AS_QUATERNION
+ float QUS,QUVX,QUVY,QUVZ;
+#endif
+#ifdef COMPUTE_U_AS_MATRIX
+ float U11,U21,U31,U12,U22,U32,U13,U23,U33;
+#endif
+#endif
+
+#endif
+
+const float Four_Gamma_Squared=sqrt(8.)+3.;
+const float Sine_Pi_Over_Eight=.5*sqrt(2.-sqrt(2.));
+const float Cosine_Pi_Over_Eight=.5*sqrt(2.+sqrt(2.));
+
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sfour_gamma_squared;) ENABLE_SSE_IMPLEMENTATION(__m128 Vfour_gamma_squared;) ENABLE_AVX_IMPLEMENTATION(__m256 Vfour_gamma_squared;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssine_pi_over_eight;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsine_pi_over_eight;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsine_pi_over_eight;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Scosine_pi_over_eight;) ENABLE_SSE_IMPLEMENTATION(__m128 Vcosine_pi_over_eight;) ENABLE_AVX_IMPLEMENTATION(__m256 Vcosine_pi_over_eight;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sone_half;) ENABLE_SSE_IMPLEMENTATION(__m128 Vone_half;) ENABLE_AVX_IMPLEMENTATION(__m256 Vone_half;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sone;) ENABLE_SSE_IMPLEMENTATION(__m128 Vone;) ENABLE_AVX_IMPLEMENTATION(__m256 Vone;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stiny_number;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtiny_number;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtiny_number;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssmall_number;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsmall_number;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsmall_number;)
+
+ENABLE_SCALAR_IMPLEMENTATION(Sfour_gamma_squared.f=Four_Gamma_Squared;) ENABLE_SSE_IMPLEMENTATION(Vfour_gamma_squared=_mm_set1_ps(Four_Gamma_Squared);) ENABLE_AVX_IMPLEMENTATION(Vfour_gamma_squared=_mm256_set1_ps(Four_Gamma_Squared);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssine_pi_over_eight.f=Sine_Pi_Over_Eight;) ENABLE_SSE_IMPLEMENTATION(Vsine_pi_over_eight=_mm_set1_ps(Sine_Pi_Over_Eight);) ENABLE_AVX_IMPLEMENTATION(Vsine_pi_over_eight=_mm256_set1_ps(Sine_Pi_Over_Eight);)
+ENABLE_SCALAR_IMPLEMENTATION(Scosine_pi_over_eight.f=Cosine_Pi_Over_Eight;) ENABLE_SSE_IMPLEMENTATION(Vcosine_pi_over_eight=_mm_set1_ps(Cosine_Pi_Over_Eight);) ENABLE_AVX_IMPLEMENTATION(Vcosine_pi_over_eight=_mm256_set1_ps(Cosine_Pi_Over_Eight);)
+ENABLE_SCALAR_IMPLEMENTATION(Sone_half.f=.5;) ENABLE_SSE_IMPLEMENTATION(Vone_half=_mm_set1_ps(.5);) ENABLE_AVX_IMPLEMENTATION(Vone_half=_mm256_set1_ps(.5);)
+ENABLE_SCALAR_IMPLEMENTATION(Sone.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vone=_mm_set1_ps(1.);) ENABLE_AVX_IMPLEMENTATION(Vone=_mm256_set1_ps(1.);)
+ENABLE_SCALAR_IMPLEMENTATION(Stiny_number.f=1.e-20;) ENABLE_SSE_IMPLEMENTATION(Vtiny_number=_mm_set1_ps(1.e-20);) ENABLE_AVX_IMPLEMENTATION(Vtiny_number=_mm256_set1_ps(1.e-20);)
+ENABLE_SCALAR_IMPLEMENTATION(Ssmall_number.f=1.e-12;) ENABLE_SSE_IMPLEMENTATION(Vsmall_number=_mm_set1_ps(1.e-12);) ENABLE_AVX_IMPLEMENTATION(Vsmall_number=_mm256_set1_ps(1.e-12);)
+
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa11;) ENABLE_SSE_IMPLEMENTATION(__m128 Va11;) ENABLE_AVX_IMPLEMENTATION(__m256 Va11;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa21;) ENABLE_SSE_IMPLEMENTATION(__m128 Va21;) ENABLE_AVX_IMPLEMENTATION(__m256 Va21;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa31;) ENABLE_SSE_IMPLEMENTATION(__m128 Va31;) ENABLE_AVX_IMPLEMENTATION(__m256 Va31;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa12;) ENABLE_SSE_IMPLEMENTATION(__m128 Va12;) ENABLE_AVX_IMPLEMENTATION(__m256 Va12;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa22;) ENABLE_SSE_IMPLEMENTATION(__m128 Va22;) ENABLE_AVX_IMPLEMENTATION(__m256 Va22;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa32;) ENABLE_SSE_IMPLEMENTATION(__m128 Va32;) ENABLE_AVX_IMPLEMENTATION(__m256 Va32;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa13;) ENABLE_SSE_IMPLEMENTATION(__m128 Va13;) ENABLE_AVX_IMPLEMENTATION(__m256 Va13;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa23;) ENABLE_SSE_IMPLEMENTATION(__m128 Va23;) ENABLE_AVX_IMPLEMENTATION(__m256 Va23;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sa33;) ENABLE_SSE_IMPLEMENTATION(__m128 Va33;) ENABLE_AVX_IMPLEMENTATION(__m256 Va33;)
+
+#ifdef COMPUTE_V_AS_MATRIX
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv11;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv21;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv31;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv12;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv12;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv12;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv22;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv32;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv13;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv13;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv13;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv23;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv23;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv23;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vv33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vv33;)
+#endif
+
+#ifdef COMPUTE_V_AS_QUATERNION
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvs;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvx;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvy;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvz;)
+#endif
+
+#ifdef COMPUTE_U_AS_MATRIX
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu11;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu21;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu31;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su12;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu12;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu12;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu22;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu32;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su13;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu13;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu13;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su23;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu23;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu23;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Su33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vu33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vu33;)
+#endif
+
+#ifdef COMPUTE_U_AS_QUATERNION
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqus;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqus;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvx;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvy;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Squvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vquvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vquvz;)
+#endif
+
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sc;) ENABLE_SSE_IMPLEMENTATION(__m128 Vc;) ENABLE_AVX_IMPLEMENTATION(__m256 Vc;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sch;) ENABLE_SSE_IMPLEMENTATION(__m128 Vch;) ENABLE_AVX_IMPLEMENTATION(__m256 Vch;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ssh;) ENABLE_SSE_IMPLEMENTATION(__m128 Vsh;) ENABLE_AVX_IMPLEMENTATION(__m256 Vsh;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp1;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp1;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp1;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp2;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp2;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp2;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp3;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp3;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp3;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp4;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp4;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp4;)
+ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Stmp5;) ENABLE_SSE_IMPLEMENTATION(__m128 Vtmp5;) ENABLE_AVX_IMPLEMENTATION(__m256 Vtmp5;)
diff --git a/xs/src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp b/xs/src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp
new file mode 100644
index 000000000..e8898a8aa
--- /dev/null
+++ b/xs/src/igl/Singular_Value_Decomposition_Main_Kernel_Body.hpp
@@ -0,0 +1,1277 @@
+//#####################################################################
+// Copyright (c) 2010-2011, Eftychios Sifakis.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//#####################################################################
+
+#ifdef __INTEL_COMPILER
+#pragma warning( disable : 592 )
+#endif
+
+// #define USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION
+// #define PERFORM_STRICT_QUATERNION_RENORMALIZATION
+
+{ // Begin block : Scope of qV (if not maintained)
+
+#ifndef COMPUTE_V_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvs;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvs;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvs;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvx;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvx;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvx;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvy;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvy;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvy;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sqvvz;) ENABLE_SSE_IMPLEMENTATION(__m128 Vqvvz;) ENABLE_AVX_IMPLEMENTATION(__m256 Vqvvz;)
+#endif
+
+{ // Begin block : Symmetric eigenanalysis
+
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss11;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs11;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs11;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss21;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs21;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs21;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss31;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs31;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs31;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss22;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs22;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs22;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss32;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs32;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs32;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Ss33;) ENABLE_SSE_IMPLEMENTATION(__m128 Vs33;) ENABLE_AVX_IMPLEMENTATION(__m256 Vs33;)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vqvs=Vone;) ENABLE_AVX_IMPLEMENTATION(Vqvs=Vone;)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_xor_ps(Vqvvx,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_xor_ps(Vqvvx,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_xor_ps(Vqvvy,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_xor_ps(Vqvvy,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_xor_ps(Vqvvz,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_xor_ps(Vqvvz,Vqvvz);)
+
+ //###########################################################
+ // Compute normal equations matrix
+ //###########################################################
+
+ ENABLE_SCALAR_IMPLEMENTATION(Ss11.f=Sa11.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Vs11=_mm_mul_ps(Va11,Va11);) ENABLE_AVX_IMPLEMENTATION(Vs11=_mm256_mul_ps(Va11,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa21.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va21,Va21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va21,Va21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss11.f=Stmp1.f+Ss11.f;) ENABLE_SSE_IMPLEMENTATION(Vs11=_mm_add_ps(Vtmp1,Vs11);) ENABLE_AVX_IMPLEMENTATION(Vs11=_mm256_add_ps(Vtmp1,Vs11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa31.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va31,Va31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va31,Va31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss11.f=Stmp1.f+Ss11.f;) ENABLE_SSE_IMPLEMENTATION(Vs11=_mm_add_ps(Vtmp1,Vs11);) ENABLE_AVX_IMPLEMENTATION(Vs11=_mm256_add_ps(Vtmp1,Vs11);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Ss21.f=Sa12.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Vs21=_mm_mul_ps(Va12,Va11);) ENABLE_AVX_IMPLEMENTATION(Vs21=_mm256_mul_ps(Va12,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa22.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va22,Va21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va22,Va21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss21.f=Stmp1.f+Ss21.f;) ENABLE_SSE_IMPLEMENTATION(Vs21=_mm_add_ps(Vtmp1,Vs21);) ENABLE_AVX_IMPLEMENTATION(Vs21=_mm256_add_ps(Vtmp1,Vs21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa32.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va32,Va31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va32,Va31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss21.f=Stmp1.f+Ss21.f;) ENABLE_SSE_IMPLEMENTATION(Vs21=_mm_add_ps(Vtmp1,Vs21);) ENABLE_AVX_IMPLEMENTATION(Vs21=_mm256_add_ps(Vtmp1,Vs21);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Ss31.f=Sa13.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Vs31=_mm_mul_ps(Va13,Va11);) ENABLE_AVX_IMPLEMENTATION(Vs31=_mm256_mul_ps(Va13,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa23.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va23,Va21);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va23,Va21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss31.f=Stmp1.f+Ss31.f;) ENABLE_SSE_IMPLEMENTATION(Vs31=_mm_add_ps(Vtmp1,Vs31);) ENABLE_AVX_IMPLEMENTATION(Vs31=_mm256_add_ps(Vtmp1,Vs31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa33.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va33,Va31);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va33,Va31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss31.f=Stmp1.f+Ss31.f;) ENABLE_SSE_IMPLEMENTATION(Vs31=_mm_add_ps(Vtmp1,Vs31);) ENABLE_AVX_IMPLEMENTATION(Vs31=_mm256_add_ps(Vtmp1,Vs31);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Ss22.f=Sa12.f*Sa12.f;) ENABLE_SSE_IMPLEMENTATION(Vs22=_mm_mul_ps(Va12,Va12);) ENABLE_AVX_IMPLEMENTATION(Vs22=_mm256_mul_ps(Va12,Va12);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa22.f*Sa22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va22,Va22);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va22,Va22);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss22.f=Stmp1.f+Ss22.f;) ENABLE_SSE_IMPLEMENTATION(Vs22=_mm_add_ps(Vtmp1,Vs22);) ENABLE_AVX_IMPLEMENTATION(Vs22=_mm256_add_ps(Vtmp1,Vs22);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa32.f*Sa32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va32,Va32);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va32,Va32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss22.f=Stmp1.f+Ss22.f;) ENABLE_SSE_IMPLEMENTATION(Vs22=_mm_add_ps(Vtmp1,Vs22);) ENABLE_AVX_IMPLEMENTATION(Vs22=_mm256_add_ps(Vtmp1,Vs22);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Ss32.f=Sa13.f*Sa12.f;) ENABLE_SSE_IMPLEMENTATION(Vs32=_mm_mul_ps(Va13,Va12);) ENABLE_AVX_IMPLEMENTATION(Vs32=_mm256_mul_ps(Va13,Va12);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa23.f*Sa22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va23,Va22);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va23,Va22);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss32.f=Stmp1.f+Ss32.f;) ENABLE_SSE_IMPLEMENTATION(Vs32=_mm_add_ps(Vtmp1,Vs32);) ENABLE_AVX_IMPLEMENTATION(Vs32=_mm256_add_ps(Vtmp1,Vs32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa33.f*Sa32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va33,Va32);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va33,Va32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss32.f=Stmp1.f+Ss32.f;) ENABLE_SSE_IMPLEMENTATION(Vs32=_mm_add_ps(Vtmp1,Vs32);) ENABLE_AVX_IMPLEMENTATION(Vs32=_mm256_add_ps(Vtmp1,Vs32);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Ss33.f=Sa13.f*Sa13.f;) ENABLE_SSE_IMPLEMENTATION(Vs33=_mm_mul_ps(Va13,Va13);) ENABLE_AVX_IMPLEMENTATION(Vs33=_mm256_mul_ps(Va13,Va13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa23.f*Sa23.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va23,Va23);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va23,Va23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss33.f=Stmp1.f+Ss33.f;) ENABLE_SSE_IMPLEMENTATION(Vs33=_mm_add_ps(Vtmp1,Vs33);) ENABLE_AVX_IMPLEMENTATION(Vs33=_mm256_add_ps(Vtmp1,Vs33);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa33.f*Sa33.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va33,Va33);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va33,Va33);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ss33.f=Stmp1.f+Ss33.f;) ENABLE_SSE_IMPLEMENTATION(Vs33=_mm_add_ps(Vtmp1,Vs33);) ENABLE_AVX_IMPLEMENTATION(Vs33=_mm256_add_ps(Vtmp1,Vs33);)
+
+ //###########################################################
+ // Solve symmetric eigenproblem using Jacobi iteration
+ //###########################################################
+
+ for(int sweep=1;sweep<=4;sweep++){
+
+ // First Jacobi conjugation
+
+#define SS11 Ss11
+#define SS21 Ss21
+#define SS31 Ss31
+#define SS22 Ss22
+#define SS32 Ss32
+#define SS33 Ss33
+#define SQVVX Sqvvx
+#define SQVVY Sqvvy
+#define SQVVZ Sqvvz
+#define STMP1 Stmp1
+#define STMP2 Stmp2
+#define STMP3 Stmp3
+
+#define VS11 Vs11
+#define VS21 Vs21
+#define VS31 Vs31
+#define VS22 Vs22
+#define VS32 Vs32
+#define VS33 Vs33
+#define VQVVX Vqvvx
+#define VQVVY Vqvvy
+#define VQVVZ Vqvvz
+#define VTMP1 Vtmp1
+#define VTMP2 Vtmp2
+#define VTMP3 Vtmp3
+
+#include "Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp"
+
+#undef SS11
+#undef SS21
+#undef SS31
+#undef SS22
+#undef SS32
+#undef SS33
+#undef SQVVX
+#undef SQVVY
+#undef SQVVZ
+#undef STMP1
+#undef STMP2
+#undef STMP3
+
+#undef VS11
+#undef VS21
+#undef VS31
+#undef VS22
+#undef VS32
+#undef VS33
+#undef VQVVX
+#undef VQVVY
+#undef VQVVZ
+#undef VTMP1
+#undef VTMP2
+#undef VTMP3
+
+ // Second Jacobi conjugation
+
+#define SS11 Ss22
+#define SS21 Ss32
+#define SS31 Ss21
+#define SS22 Ss33
+#define SS32 Ss31
+#define SS33 Ss11
+#define SQVVX Sqvvy
+#define SQVVY Sqvvz
+#define SQVVZ Sqvvx
+#define STMP1 Stmp2
+#define STMP2 Stmp3
+#define STMP3 Stmp1
+
+#define VS11 Vs22
+#define VS21 Vs32
+#define VS31 Vs21
+#define VS22 Vs33
+#define VS32 Vs31
+#define VS33 Vs11
+#define VQVVX Vqvvy
+#define VQVVY Vqvvz
+#define VQVVZ Vqvvx
+#define VTMP1 Vtmp2
+#define VTMP2 Vtmp3
+#define VTMP3 Vtmp1
+
+#include "Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp"
+
+#undef SS11
+#undef SS21
+#undef SS31
+#undef SS22
+#undef SS32
+#undef SS33
+#undef SQVVX
+#undef SQVVY
+#undef SQVVZ
+#undef STMP1
+#undef STMP2
+#undef STMP3
+
+#undef VS11
+#undef VS21
+#undef VS31
+#undef VS22
+#undef VS32
+#undef VS33
+#undef VQVVX
+#undef VQVVY
+#undef VQVVZ
+#undef VTMP1
+#undef VTMP2
+#undef VTMP3
+
+ // Third Jacobi conjugation
+
+#define SS11 Ss33
+#define SS21 Ss31
+#define SS31 Ss32
+#define SS22 Ss11
+#define SS32 Ss21
+#define SS33 Ss22
+#define SQVVX Sqvvz
+#define SQVVY Sqvvx
+#define SQVVZ Sqvvy
+#define STMP1 Stmp3
+#define STMP2 Stmp1
+#define STMP3 Stmp2
+
+#define VS11 Vs33
+#define VS21 Vs31
+#define VS31 Vs32
+#define VS22 Vs11
+#define VS32 Vs21
+#define VS33 Vs22
+#define VQVVX Vqvvz
+#define VQVVY Vqvvx
+#define VQVVZ Vqvvy
+#define VTMP1 Vtmp3
+#define VTMP2 Vtmp1
+#define VTMP3 Vtmp2
+
+#include "Singular_Value_Decomposition_Jacobi_Conjugation_Kernel.hpp"
+
+#undef SS11
+#undef SS21
+#undef SS31
+#undef SS22
+#undef SS32
+#undef SS33
+#undef SQVVX
+#undef SQVVY
+#undef SQVVZ
+#undef STMP1
+#undef STMP2
+#undef STMP3
+
+#undef VS11
+#undef VS21
+#undef VS31
+#undef VS22
+#undef VS32
+#undef VS33
+#undef VQVVX
+#undef VQVVY
+#undef VQVVZ
+#undef VTMP1
+#undef VTMP2
+#undef VTMP3
+ }
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar S ="<<std::endl;
+ std::cout<<std::setw(12)<<Ss11.f<<std::endl;
+ std::cout<<std::setw(12)<<Ss21.f<<" "<<std::setw(12)<<Ss22.f<<std::endl;
+ std::cout<<std::setw(12)<<Ss31.f<<" "<<std::setw(12)<<Ss32.f<<" "<<std::setw(12)<<Ss33.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Vs11);S11=buf[0];
+ _mm_storeu_ps(buf,Vs21);S21=buf[0];
+ _mm_storeu_ps(buf,Vs31);S31=buf[0];
+ _mm_storeu_ps(buf,Vs22);S22=buf[0];
+ _mm_storeu_ps(buf,Vs32);S32=buf[0];
+ _mm_storeu_ps(buf,Vs33);S33=buf[0];
+ std::cout<<"Vector S ="<<std::endl;
+ std::cout<<std::setw(12)<<S11<<std::endl;
+ std::cout<<std::setw(12)<<S21<<" "<<std::setw(12)<<S22<<std::endl;
+ std::cout<<std::setw(12)<<S31<<" "<<std::setw(12)<<S32<<" "<<std::setw(12)<<S33<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Vs11);S11=buf[0];
+ _mm256_storeu_ps(buf,Vs21);S21=buf[0];
+ _mm256_storeu_ps(buf,Vs31);S31=buf[0];
+ _mm256_storeu_ps(buf,Vs22);S22=buf[0];
+ _mm256_storeu_ps(buf,Vs32);S32=buf[0];
+ _mm256_storeu_ps(buf,Vs33);S33=buf[0];
+ std::cout<<"Vector S ="<<std::endl;
+ std::cout<<std::setw(12)<<S11<<std::endl;
+ std::cout<<std::setw(12)<<S21<<" "<<std::setw(12)<<S22<<std::endl;
+ std::cout<<std::setw(12)<<S31<<" "<<std::setw(12)<<S32<<" "<<std::setw(12)<<S33<<std::endl;
+#endif
+#endif
+
+} // End block : Symmetric eigenanalysis
+
+ //###########################################################
+ // Normalize quaternion for matrix V
+ //###########################################################
+
+#if !defined(USE_ACCURATE_RSQRT_IN_JACOBI_CONJUGATION) || defined(PERFORM_STRICT_QUATERNION_RENORMALIZATION)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sqvs.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vqvs,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vqvs,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvx.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvx,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvx,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvy.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvy,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvy,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvz.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvz,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvz,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vqvs,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vqvs,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sqvvx.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_mul_ps(Vqvvx,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_mul_ps(Vqvvx,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sqvvy.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_mul_ps(Vqvvy,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_mul_ps(Vqvvy,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sqvvz.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_mul_ps(Vqvvz,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_mul_ps(Vqvvz,Vtmp1);)
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar qV ="<<std::endl;
+ std::cout<<std::setw(12)<<Sqvs.f<<" "<<std::setw(12)<<Sqvvx.f<<" "<<std::setw(12)<<Sqvvy.f<<" "<<std::setw(12)<<Sqvvz.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Vqvs);QVS=buf[0];
+ _mm_storeu_ps(buf,Vqvvx);QVVX=buf[0];
+ _mm_storeu_ps(buf,Vqvvy);QVVY=buf[0];
+ _mm_storeu_ps(buf,Vqvvz);QVVZ=buf[0];
+ std::cout<<"Vector qV ="<<std::endl;
+ std::cout<<std::setw(12)<<QVS<<" "<<std::setw(12)<<QVVX<<" "<<std::setw(12)<<QVVY<<" "<<std::setw(12)<<QVVZ<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Vqvs);QVS=buf[0];
+ _mm256_storeu_ps(buf,Vqvvx);QVVX=buf[0];
+ _mm256_storeu_ps(buf,Vqvvy);QVVY=buf[0];
+ _mm256_storeu_ps(buf,Vqvvz);QVVZ=buf[0];
+ std::cout<<"Vector qV ="<<std::endl;
+ std::cout<<std::setw(12)<<QVS<<" "<<std::setw(12)<<QVVX<<" "<<std::setw(12)<<QVVY<<" "<<std::setw(12)<<QVVZ<<std::endl;
+#endif
+#endif
+
+#endif
+
+{ // Begin block : Conjugation with V
+
+ //###########################################################
+ // Transform quaternion to matrix V
+ //###########################################################
+
+#ifndef COMPUTE_V_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv11;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv11;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv21;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv21;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv31;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv31;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv12;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv12;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv22;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv22;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv32;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv32;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv13;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv13;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv23;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv23;)
+ ENABLE_SCALAR_IMPLEMENTATION(union {float f;unsigned int ui;} Sv33;) ENABLE_VECTOR_IMPLEMENTATION(__m128 Vv33;)
+#endif
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvx.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvx,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvx,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sqvvy.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vqvvy,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vqvvy,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Sqvvz.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vqvvz,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vqvvz,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv11.f=Sqvs.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vv11=_mm_mul_ps(Vqvs,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vv11=_mm256_mul_ps(Vqvs,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv22.f=Sv11.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vv22=_mm_sub_ps(Vv11,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vv22=_mm256_sub_ps(Vv11,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv33.f=Sv22.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vv33=_mm_sub_ps(Vv22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vv33=_mm256_sub_ps(Vv22,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv33.f=Sv33.f+Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vv33=_mm_add_ps(Vv33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vv33=_mm256_add_ps(Vv33,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv22.f=Sv22.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vv22=_mm_add_ps(Vv22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vv22=_mm256_add_ps(Vv22,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv22.f=Sv22.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vv22=_mm_sub_ps(Vv22,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vv22=_mm256_sub_ps(Vv22,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv11.f=Sv11.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vv11=_mm_add_ps(Vv11,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vv11=_mm256_add_ps(Vv11,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv11.f=Sv11.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vv11=_mm_sub_ps(Vv11,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vv11=_mm256_sub_ps(Vv11,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv11.f=Sv11.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vv11=_mm_sub_ps(Vv11,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vv11=_mm256_sub_ps(Vv11,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvx.f+Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vqvvx,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vqvvx,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sqvvy.f+Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vqvvy,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vqvvy,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Sqvvz.f+Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vqvvz,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vqvvz,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv32.f=Sqvs.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vv32=_mm_mul_ps(Vqvs,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vv32=_mm256_mul_ps(Vqvs,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv13.f=Sqvs.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vv13=_mm_mul_ps(Vqvs,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vv13=_mm256_mul_ps(Vqvs,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv21.f=Sqvs.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vv21=_mm_mul_ps(Vqvs,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vv21=_mm256_mul_ps(Vqvs,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvy.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvy,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvy,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sqvvz.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vqvvz,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vqvvz,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Sqvvx.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vqvvx,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vqvvx,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv12.f=Stmp1.f-Sv21.f;) ENABLE_SSE_IMPLEMENTATION(Vv12=_mm_sub_ps(Vtmp1,Vv21);) ENABLE_AVX_IMPLEMENTATION(Vv12=_mm256_sub_ps(Vtmp1,Vv21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv23.f=Stmp2.f-Sv32.f;) ENABLE_SSE_IMPLEMENTATION(Vv23=_mm_sub_ps(Vtmp2,Vv32);) ENABLE_AVX_IMPLEMENTATION(Vv23=_mm256_sub_ps(Vtmp2,Vv32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv31.f=Stmp3.f-Sv13.f;) ENABLE_SSE_IMPLEMENTATION(Vv31=_mm_sub_ps(Vtmp3,Vv13);) ENABLE_AVX_IMPLEMENTATION(Vv31=_mm256_sub_ps(Vtmp3,Vv13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv21.f=Stmp1.f+Sv21.f;) ENABLE_SSE_IMPLEMENTATION(Vv21=_mm_add_ps(Vtmp1,Vv21);) ENABLE_AVX_IMPLEMENTATION(Vv21=_mm256_add_ps(Vtmp1,Vv21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv32.f=Stmp2.f+Sv32.f;) ENABLE_SSE_IMPLEMENTATION(Vv32=_mm_add_ps(Vtmp2,Vv32);) ENABLE_AVX_IMPLEMENTATION(Vv32=_mm256_add_ps(Vtmp2,Vv32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv13.f=Stmp3.f+Sv13.f;) ENABLE_SSE_IMPLEMENTATION(Vv13=_mm_add_ps(Vtmp3,Vv13);) ENABLE_AVX_IMPLEMENTATION(Vv13=_mm256_add_ps(Vtmp3,Vv13);)
+
+#ifdef COMPUTE_V_AS_MATRIX
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar V ="<<std::endl;
+ std::cout<<std::setw(12)<<Sv11.f<<" "<<std::setw(12)<<Sv12.f<<" "<<std::setw(12)<<Sv13.f<<std::endl;
+ std::cout<<std::setw(12)<<Sv21.f<<" "<<std::setw(12)<<Sv22.f<<" "<<std::setw(12)<<Sv23.f<<std::endl;
+ std::cout<<std::setw(12)<<Sv31.f<<" "<<std::setw(12)<<Sv32.f<<" "<<std::setw(12)<<Sv33.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Vv11);V11=buf[0];
+ _mm_storeu_ps(buf,Vv21);V21=buf[0];
+ _mm_storeu_ps(buf,Vv31);V31=buf[0];
+ _mm_storeu_ps(buf,Vv12);V12=buf[0];
+ _mm_storeu_ps(buf,Vv22);V22=buf[0];
+ _mm_storeu_ps(buf,Vv32);V32=buf[0];
+ _mm_storeu_ps(buf,Vv13);V13=buf[0];
+ _mm_storeu_ps(buf,Vv23);V23=buf[0];
+ _mm_storeu_ps(buf,Vv33);V33=buf[0];
+ std::cout<<"Vector V ="<<std::endl;
+ std::cout<<std::setw(12)<<V11<<" "<<std::setw(12)<<V12<<" "<<std::setw(12)<<V13<<std::endl;
+ std::cout<<std::setw(12)<<V21<<" "<<std::setw(12)<<V22<<" "<<std::setw(12)<<V23<<std::endl;
+ std::cout<<std::setw(12)<<V31<<" "<<std::setw(12)<<V32<<" "<<std::setw(12)<<V33<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Vv11);V11=buf[0];
+ _mm256_storeu_ps(buf,Vv21);V21=buf[0];
+ _mm256_storeu_ps(buf,Vv31);V31=buf[0];
+ _mm256_storeu_ps(buf,Vv12);V12=buf[0];
+ _mm256_storeu_ps(buf,Vv22);V22=buf[0];
+ _mm256_storeu_ps(buf,Vv32);V32=buf[0];
+ _mm256_storeu_ps(buf,Vv13);V13=buf[0];
+ _mm256_storeu_ps(buf,Vv23);V23=buf[0];
+ _mm256_storeu_ps(buf,Vv33);V33=buf[0];
+ std::cout<<"Vector V ="<<std::endl;
+ std::cout<<std::setw(12)<<V11<<" "<<std::setw(12)<<V12<<" "<<std::setw(12)<<V13<<std::endl;
+ std::cout<<std::setw(12)<<V21<<" "<<std::setw(12)<<V22<<" "<<std::setw(12)<<V23<<std::endl;
+ std::cout<<std::setw(12)<<V31<<" "<<std::setw(12)<<V32<<" "<<std::setw(12)<<V33<<std::endl;
+#endif
+#endif
+#endif
+
+ //###########################################################
+ // Multiply (from the right) with V
+ //###########################################################
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sa12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=Va12;) ENABLE_AVX_IMPLEMENTATION(Vtmp2=Va12;)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Sa13.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=Va13;) ENABLE_AVX_IMPLEMENTATION(Vtmp3=Va13;)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa12.f=Sv12.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_mul_ps(Vv12,Va11);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_mul_ps(Vv12,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa13.f=Sv13.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_mul_ps(Vv13,Va11);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_mul_ps(Vv13,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa11.f=Sv11.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_mul_ps(Vv11,Va11);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_mul_ps(Vv11,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv21.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv21,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv21,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa11.f=Sa11.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_add_ps(Va11,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_add_ps(Va11,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv31.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv31,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv31,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa11.f=Sa11.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_add_ps(Va11,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_add_ps(Va11,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv22.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv22,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa12.f=Sa12.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_add_ps(Va12,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_add_ps(Va12,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv32.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv32,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv32,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa12.f=Sa12.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_add_ps(Va12,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_add_ps(Va12,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv23.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv23,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv23,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa13.f=Sa13.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_add_ps(Va13,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_add_ps(Va13,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv33,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa13.f=Sa13.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_add_ps(Va13,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_add_ps(Va13,Vtmp1);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sa22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=Va22;) ENABLE_AVX_IMPLEMENTATION(Vtmp2=Va22;)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Sa23.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=Va23;) ENABLE_AVX_IMPLEMENTATION(Vtmp3=Va23;)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa22.f=Sv12.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_mul_ps(Vv12,Va21);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_mul_ps(Vv12,Va21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa23.f=Sv13.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_mul_ps(Vv13,Va21);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_mul_ps(Vv13,Va21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa21.f=Sv11.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_mul_ps(Vv11,Va21);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_mul_ps(Vv11,Va21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv21.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv21,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv21,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa21.f=Sa21.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_add_ps(Va21,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_add_ps(Va21,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv31.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv31,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv31,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa21.f=Sa21.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_add_ps(Va21,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_add_ps(Va21,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv22.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv22,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa22.f=Sa22.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_add_ps(Va22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_add_ps(Va22,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv32.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv32,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv32,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa22.f=Sa22.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_add_ps(Va22,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_add_ps(Va22,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv23.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv23,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv23,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa23.f=Sa23.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_add_ps(Va23,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_add_ps(Va23,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv33,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa23.f=Sa23.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_add_ps(Va23,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_add_ps(Va23,Vtmp1);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sa32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=Va32;) ENABLE_AVX_IMPLEMENTATION(Vtmp2=Va32;)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Sa33.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=Va33;) ENABLE_AVX_IMPLEMENTATION(Vtmp3=Va33;)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa32.f=Sv12.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_mul_ps(Vv12,Va31);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_mul_ps(Vv12,Va31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa33.f=Sv13.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_mul_ps(Vv13,Va31);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_mul_ps(Vv13,Va31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa31.f=Sv11.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_mul_ps(Vv11,Va31);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_mul_ps(Vv11,Va31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv21.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv21,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv21,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa31.f=Sa31.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_add_ps(Va31,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_add_ps(Va31,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv31.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv31,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv31,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa31.f=Sa31.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_add_ps(Va31,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_add_ps(Va31,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv22.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv22,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv22,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa32.f=Sa32.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_add_ps(Va32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_add_ps(Va32,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv32.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv32,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv32,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa32.f=Sa32.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_add_ps(Va32,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_add_ps(Va32,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv23.f*Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv23,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv23,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa33.f=Sa33.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_add_ps(Va33,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_add_ps(Va33,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sv33.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vv33,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vv33,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa33.f=Sa33.f+Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_add_ps(Va33,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_add_ps(Va33,Vtmp1);)
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar A (after multiplying with V) ="<<std::endl;
+ std::cout<<std::setw(12)<<Sa11.f<<" "<<std::setw(12)<<Sa12.f<<" "<<std::setw(12)<<Sa13.f<<std::endl;
+ std::cout<<std::setw(12)<<Sa21.f<<" "<<std::setw(12)<<Sa22.f<<" "<<std::setw(12)<<Sa23.f<<std::endl;
+ std::cout<<std::setw(12)<<Sa31.f<<" "<<std::setw(12)<<Sa32.f<<" "<<std::setw(12)<<Sa33.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Va11);A11=buf[0];
+ _mm_storeu_ps(buf,Va21);A21=buf[0];
+ _mm_storeu_ps(buf,Va31);A31=buf[0];
+ _mm_storeu_ps(buf,Va12);A12=buf[0];
+ _mm_storeu_ps(buf,Va22);A22=buf[0];
+ _mm_storeu_ps(buf,Va32);A32=buf[0];
+ _mm_storeu_ps(buf,Va13);A13=buf[0];
+ _mm_storeu_ps(buf,Va23);A23=buf[0];
+ _mm_storeu_ps(buf,Va33);A33=buf[0];
+ std::cout<<"Vector A (after multiplying with V) ="<<std::endl;
+ std::cout<<std::setw(12)<<A11<<" "<<std::setw(12)<<A12<<" "<<std::setw(12)<<A13<<std::endl;
+ std::cout<<std::setw(12)<<A21<<" "<<std::setw(12)<<A22<<" "<<std::setw(12)<<A23<<std::endl;
+ std::cout<<std::setw(12)<<A31<<" "<<std::setw(12)<<A32<<" "<<std::setw(12)<<A33<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Va11);A11=buf[0];
+ _mm256_storeu_ps(buf,Va21);A21=buf[0];
+ _mm256_storeu_ps(buf,Va31);A31=buf[0];
+ _mm256_storeu_ps(buf,Va12);A12=buf[0];
+ _mm256_storeu_ps(buf,Va22);A22=buf[0];
+ _mm256_storeu_ps(buf,Va32);A32=buf[0];
+ _mm256_storeu_ps(buf,Va13);A13=buf[0];
+ _mm256_storeu_ps(buf,Va23);A23=buf[0];
+ _mm256_storeu_ps(buf,Va33);A33=buf[0];
+ std::cout<<"Vector A (after multiplying with V) ="<<std::endl;
+ std::cout<<std::setw(12)<<A11<<" "<<std::setw(12)<<A12<<" "<<std::setw(12)<<A13<<std::endl;
+ std::cout<<std::setw(12)<<A21<<" "<<std::setw(12)<<A22<<" "<<std::setw(12)<<A23<<std::endl;
+ std::cout<<std::setw(12)<<A31<<" "<<std::setw(12)<<A32<<" "<<std::setw(12)<<A33<<std::endl;
+#endif
+#endif
+
+} // End block : Conjugation with V
+
+} // End block : Scope of qV (if not maintained)
+
+ //###########################################################
+ // Permute columns such that the singular values are sorted
+ //###########################################################
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sa11.f*Sa11.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Va11,Va11);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Va11,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sa21.f*Sa21.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Va21,Va21);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Va21,Va21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sa31.f*Sa31.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Va31,Va31);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Va31,Va31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sa12.f*Sa12.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Va12,Va12);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Va12,Va12);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sa22.f*Sa22.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Va22,Va22);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Va22,Va22);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp2.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp2,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp2,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sa32.f*Sa32.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Va32,Va32);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Va32,Va32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp2.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp2,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp2,Vtmp4);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Sa13.f*Sa13.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Va13,Va13);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Va13,Va13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sa23.f*Sa23.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Va23,Va23);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Va23,Va23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp3.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp3,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp3,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Sa33.f*Sa33.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Va33,Va33);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Va33,Va33);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp3.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_add_ps(Vtmp3,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_add_ps(Vtmp3,Vtmp4);)
+
+ // Swap columns 1-2 if necessary
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.ui=(Stmp1.f<Stmp2.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_cmplt_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_cmp_ps(Vtmp1,Vtmp2, _CMP_LT_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_cmplt_ps(Vtmp1,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa11.ui^Sa12.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va11,Va12);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va11,Va12);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa11.ui=Sa11.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_xor_ps(Va11,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_xor_ps(Va11,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa12.ui=Sa12.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_xor_ps(Va12,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_xor_ps(Va12,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa21.ui^Sa22.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va21,Va22);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va21,Va22);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa21.ui=Sa21.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_xor_ps(Va21,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_xor_ps(Va21,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa22.ui=Sa22.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_xor_ps(Va22,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_xor_ps(Va22,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa31.ui^Sa32.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va31,Va32);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va31,Va32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa31.ui=Sa31.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_xor_ps(Va31,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_xor_ps(Va31,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa32.ui=Sa32.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_xor_ps(Va32,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_xor_ps(Va32,Vtmp5);)
+
+#ifdef COMPUTE_V_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv11.ui^Sv12.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv11,Vv12);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv11,Vv12);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv11.ui=Sv11.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv11=_mm_xor_ps(Vv11,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv11=_mm256_xor_ps(Vv11,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv12.ui=Sv12.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv12=_mm_xor_ps(Vv12,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv12=_mm256_xor_ps(Vv12,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv21.ui^Sv22.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv21,Vv22);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv21,Vv22);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv21.ui=Sv21.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv21=_mm_xor_ps(Vv21,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv21=_mm256_xor_ps(Vv21,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv22.ui=Sv22.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv22=_mm_xor_ps(Vv22,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv22=_mm256_xor_ps(Vv22,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv31.ui^Sv32.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv31,Vv32);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv31,Vv32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv31.ui=Sv31.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv31=_mm_xor_ps(Vv31,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv31=_mm256_xor_ps(Vv31,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv32.ui=Sv32.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv32=_mm_xor_ps(Vv32,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv32=_mm256_xor_ps(Vv32,Vtmp5);)
+#endif
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp1.ui^Stmp2.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vtmp1,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=Stmp1.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_xor_ps(Vtmp1,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_xor_ps(Vtmp1,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Stmp2.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_xor_ps(Vtmp2,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_xor_ps(Vtmp2,Vtmp5);)
+
+ // If columns 1-2 have been swapped, negate 2nd column of A and V so that V is still a rotation
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=-2.;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_set1_ps(-2.);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_set1_ps(-2.);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=Vone;) ENABLE_AVX_IMPLEMENTATION(Vtmp4=Vone;)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f+Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_add_ps(Vtmp4,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_add_ps(Vtmp4,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Sa12.f=Sa12.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_mul_ps(Va12,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_mul_ps(Va12,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa22.f=Sa22.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_mul_ps(Va22,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_mul_ps(Va22,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa32.f=Sa32.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_mul_ps(Va32,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_mul_ps(Va32,Vtmp4);)
+
+#ifdef COMPUTE_V_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(Sv12.f=Sv12.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv12=_mm_mul_ps(Vv12,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv12=_mm256_mul_ps(Vv12,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv22.f=Sv22.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv22=_mm_mul_ps(Vv22,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv22=_mm256_mul_ps(Vv22,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv32.f=Sv32.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv32=_mm_mul_ps(Vv32,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv32=_mm256_mul_ps(Vv32,Vtmp4);)
+#endif
+
+ // If columns 1-2 have been swapped, also update quaternion representation of V (the quaternion may become un-normalized after this)
+
+#ifdef COMPUTE_V_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp4,Vone_half);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vone_half);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp4.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp4,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp4,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f+Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_add_ps(Vtmp5,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_add_ps(Vtmp5,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vqvs,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vqvs,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sqvvz.f-Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_sub_ps(Vqvvz,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_sub_ps(Vqvvz,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=Vtmp5;) ENABLE_AVX_IMPLEMENTATION(Vqvs=Vtmp5;)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp4.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp4,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp4,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f+Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_add_ps(Vtmp5,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_add_ps(Vtmp5,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sqvvy.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_mul_ps(Vqvvy,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_mul_ps(Vqvvy,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sqvvx.f-Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_sub_ps(Vqvvx,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_sub_ps(Vqvvx,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=Vtmp5;) ENABLE_AVX_IMPLEMENTATION(Vqvvy=Vtmp5;)
+#endif
+
+ // Swap columns 1-3 if necessary
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.ui=(Stmp1.f<Stmp3.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_cmplt_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_cmp_ps(Vtmp1,Vtmp3, _CMP_LT_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_cmplt_ps(Vtmp1,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa11.ui^Sa13.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va11,Va13);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va11,Va13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa11.ui=Sa11.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_xor_ps(Va11,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_xor_ps(Va11,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa13.ui=Sa13.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_xor_ps(Va13,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_xor_ps(Va13,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa21.ui^Sa23.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va21,Va23);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va21,Va23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa21.ui=Sa21.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_xor_ps(Va21,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_xor_ps(Va21,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa23.ui=Sa23.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_xor_ps(Va23,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_xor_ps(Va23,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa31.ui^Sa33.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va31,Va33);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va31,Va33);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa31.ui=Sa31.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_xor_ps(Va31,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_xor_ps(Va31,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa33.ui=Sa33.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_xor_ps(Va33,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_xor_ps(Va33,Vtmp5);)
+
+#ifdef COMPUTE_V_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv11.ui^Sv13.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv11,Vv13);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv11,Vv13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv11.ui=Sv11.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv11=_mm_xor_ps(Vv11,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv11=_mm256_xor_ps(Vv11,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv13.ui=Sv13.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv13=_mm_xor_ps(Vv13,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv13=_mm256_xor_ps(Vv13,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv21.ui^Sv23.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv21,Vv23);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv21,Vv23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv21.ui=Sv21.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv21=_mm_xor_ps(Vv21,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv21=_mm256_xor_ps(Vv21,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv23.ui=Sv23.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv23=_mm_xor_ps(Vv23,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv23=_mm256_xor_ps(Vv23,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv31.ui^Sv33.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv31,Vv33);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv31,Vv33);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv31.ui=Sv31.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv31=_mm_xor_ps(Vv31,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv31=_mm256_xor_ps(Vv31,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv33.ui=Sv33.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv33=_mm_xor_ps(Vv33,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv33=_mm256_xor_ps(Vv33,Vtmp5);)
+#endif
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp1.ui^Stmp3.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vtmp1,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.ui=Stmp1.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_xor_ps(Vtmp1,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_xor_ps(Vtmp1,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.ui=Stmp3.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_xor_ps(Vtmp3,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_xor_ps(Vtmp3,Vtmp5);)
+
+ // If columns 1-3 have been swapped, negate 1st column of A and V so that V is still a rotation
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=-2.;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_set1_ps(-2.);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_set1_ps(-2.);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=Vone;) ENABLE_AVX_IMPLEMENTATION(Vtmp4=Vone;)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f+Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_add_ps(Vtmp4,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_add_ps(Vtmp4,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Sa11.f=Sa11.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_mul_ps(Va11,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_mul_ps(Va11,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa21.f=Sa21.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_mul_ps(Va21,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_mul_ps(Va21,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa31.f=Sa31.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_mul_ps(Va31,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_mul_ps(Va31,Vtmp4);)
+
+#ifdef COMPUTE_V_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(Sv11.f=Sv11.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv11=_mm_mul_ps(Vv11,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv11=_mm256_mul_ps(Vv11,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv21.f=Sv21.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv21=_mm_mul_ps(Vv21,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv21=_mm256_mul_ps(Vv21,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv31.f=Sv31.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv31=_mm_mul_ps(Vv31,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv31=_mm256_mul_ps(Vv31,Vtmp4);)
+#endif
+
+ // If columns 1-3 have been swapped, also update quaternion representation of V (the quaternion may become un-normalized after this)
+
+#ifdef COMPUTE_V_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp4,Vone_half);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vone_half);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp4.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp4,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp4,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f+Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_add_ps(Vtmp5,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_add_ps(Vtmp5,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vqvs,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vqvs,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sqvvy.f-Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_sub_ps(Vqvvy,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_sub_ps(Vqvvy,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=Vtmp5;) ENABLE_AVX_IMPLEMENTATION(Vqvs=Vtmp5;)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp4.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp4,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp4,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f+Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_add_ps(Vtmp5,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_add_ps(Vtmp5,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sqvvx.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_mul_ps(Vqvvx,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_mul_ps(Vqvvx,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sqvvz.f-Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_sub_ps(Vqvvz,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_sub_ps(Vqvvz,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=Vtmp5;) ENABLE_AVX_IMPLEMENTATION(Vqvvx=Vtmp5;)
+#endif
+
+ // Swap columns 2-3 if necessary
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.ui=(Stmp2.f<Stmp3.f)?0xffffffff:0;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_cmplt_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_cmp_ps(Vtmp2,Vtmp3, _CMP_LT_OS);) //ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_cmplt_ps(Vtmp2,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa12.ui^Sa13.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va12,Va13);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va12,Va13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa12.ui=Sa12.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_xor_ps(Va12,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_xor_ps(Va12,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa13.ui=Sa13.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_xor_ps(Va13,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_xor_ps(Va13,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa22.ui^Sa23.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va22,Va23);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va22,Va23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa22.ui=Sa22.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_xor_ps(Va22,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_xor_ps(Va22,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa23.ui=Sa23.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_xor_ps(Va23,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_xor_ps(Va23,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sa32.ui^Sa33.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Va32,Va33);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Va32,Va33);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa32.ui=Sa32.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_xor_ps(Va32,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_xor_ps(Va32,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa33.ui=Sa33.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_xor_ps(Va33,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_xor_ps(Va33,Vtmp5);)
+
+#ifdef COMPUTE_V_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv12.ui^Sv13.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv12,Vv13);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv12,Vv13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv12.ui=Sv12.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv12=_mm_xor_ps(Vv12,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv12=_mm256_xor_ps(Vv12,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv13.ui=Sv13.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv13=_mm_xor_ps(Vv13,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv13=_mm256_xor_ps(Vv13,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv22.ui^Sv23.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv22,Vv23);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv22,Vv23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv22.ui=Sv22.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv22=_mm_xor_ps(Vv22,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv22=_mm256_xor_ps(Vv22,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv23.ui=Sv23.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv23=_mm_xor_ps(Vv23,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv23=_mm256_xor_ps(Vv23,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Sv32.ui^Sv33.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vv32,Vv33);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vv32,Vv33);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv32.ui=Sv32.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv32=_mm_xor_ps(Vv32,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv32=_mm256_xor_ps(Vv32,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv33.ui=Sv33.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vv33=_mm_xor_ps(Vv33,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vv33=_mm256_xor_ps(Vv33,Vtmp5);)
+#endif
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp2.ui^Stmp3.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_xor_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_xor_ps(Vtmp2,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.ui=Stmp2.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_xor_ps(Vtmp2,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_xor_ps(Vtmp2,Vtmp5);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.ui=Stmp3.ui^Stmp5.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_xor_ps(Vtmp3,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_xor_ps(Vtmp3,Vtmp5);)
+
+ // If columns 2-3 have been swapped, negate 3rd column of A and V so that V is still a rotation
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=-2.;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_set1_ps(-2.);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_set1_ps(-2.);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.ui=Stmp5.ui&Stmp4.ui;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_and_ps(Vtmp5,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_and_ps(Vtmp5,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=Vone;) ENABLE_AVX_IMPLEMENTATION(Vtmp4=Vone;)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f+Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_add_ps(Vtmp4,Vtmp5);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_add_ps(Vtmp4,Vtmp5);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Sa13.f=Sa13.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_mul_ps(Va13,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_mul_ps(Va13,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa23.f=Sa23.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_mul_ps(Va23,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_mul_ps(Va23,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa33.f=Sa33.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_mul_ps(Va33,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_mul_ps(Va33,Vtmp4);)
+
+#ifdef COMPUTE_V_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(Sv13.f=Sv13.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv13=_mm_mul_ps(Vv13,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv13=_mm256_mul_ps(Vv13,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv23.f=Sv23.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv23=_mm_mul_ps(Vv23,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv23=_mm256_mul_ps(Vv23,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sv33.f=Sv33.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vv33=_mm_mul_ps(Vv33,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vv33=_mm256_mul_ps(Vv33,Vtmp4);)
+#endif
+
+ // If columns 2-3 have been swapped, also update quaternion representation of V (the quaternion may become un-normalized after this)
+
+#ifdef COMPUTE_V_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp4,Vone_half);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp4.f-Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_sub_ps(Vtmp4,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_sub_ps(Vtmp4,Vone_half);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp4.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp4,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp4,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f+Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_add_ps(Vtmp5,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_add_ps(Vtmp5,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vqvs,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vqvs,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sqvvx.f-Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_sub_ps(Vqvvx,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_sub_ps(Vqvvx,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=Vtmp5;) ENABLE_AVX_IMPLEMENTATION(Vqvs=Vtmp5;)
+
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp4.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_mul_ps(Vtmp4,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_mul_ps(Vtmp4,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp5.f=Stmp5.f+Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp5=_mm_add_ps(Vtmp5,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp5=_mm256_add_ps(Vtmp5,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sqvvz.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_mul_ps(Vqvvz,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_mul_ps(Vqvvz,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sqvvy.f-Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_sub_ps(Vqvvy,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_sub_ps(Vqvvy,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Stmp5.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=Vtmp5;) ENABLE_AVX_IMPLEMENTATION(Vqvvz=Vtmp5;)
+#endif
+
+#ifdef COMPUTE_V_AS_MATRIX
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar V ="<<std::endl;
+ std::cout<<std::setw(12)<<Sv11.f<<" "<<std::setw(12)<<Sv12.f<<" "<<std::setw(12)<<Sv13.f<<std::endl;
+ std::cout<<std::setw(12)<<Sv21.f<<" "<<std::setw(12)<<Sv22.f<<" "<<std::setw(12)<<Sv23.f<<std::endl;
+ std::cout<<std::setw(12)<<Sv31.f<<" "<<std::setw(12)<<Sv32.f<<" "<<std::setw(12)<<Sv33.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Vv11);V11=buf[0];
+ _mm_storeu_ps(buf,Vv21);V21=buf[0];
+ _mm_storeu_ps(buf,Vv31);V31=buf[0];
+ _mm_storeu_ps(buf,Vv12);V12=buf[0];
+ _mm_storeu_ps(buf,Vv22);V22=buf[0];
+ _mm_storeu_ps(buf,Vv32);V32=buf[0];
+ _mm_storeu_ps(buf,Vv13);V13=buf[0];
+ _mm_storeu_ps(buf,Vv23);V23=buf[0];
+ _mm_storeu_ps(buf,Vv33);V33=buf[0];
+ std::cout<<"Vector V ="<<std::endl;
+ std::cout<<std::setw(12)<<V11<<" "<<std::setw(12)<<V12<<" "<<std::setw(12)<<V13<<std::endl;
+ std::cout<<std::setw(12)<<V21<<" "<<std::setw(12)<<V22<<" "<<std::setw(12)<<V23<<std::endl;
+ std::cout<<std::setw(12)<<V31<<" "<<std::setw(12)<<V32<<" "<<std::setw(12)<<V33<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Vv11);V11=buf[0];
+ _mm256_storeu_ps(buf,Vv21);V21=buf[0];
+ _mm256_storeu_ps(buf,Vv31);V31=buf[0];
+ _mm256_storeu_ps(buf,Vv12);V12=buf[0];
+ _mm256_storeu_ps(buf,Vv22);V22=buf[0];
+ _mm256_storeu_ps(buf,Vv32);V32=buf[0];
+ _mm256_storeu_ps(buf,Vv13);V13=buf[0];
+ _mm256_storeu_ps(buf,Vv23);V23=buf[0];
+ _mm256_storeu_ps(buf,Vv33);V33=buf[0];
+ std::cout<<"Vector V ="<<std::endl;
+ std::cout<<std::setw(12)<<V11<<" "<<std::setw(12)<<V12<<" "<<std::setw(12)<<V13<<std::endl;
+ std::cout<<std::setw(12)<<V21<<" "<<std::setw(12)<<V22<<" "<<std::setw(12)<<V23<<std::endl;
+ std::cout<<std::setw(12)<<V31<<" "<<std::setw(12)<<V32<<" "<<std::setw(12)<<V33<<std::endl;
+#endif
+#endif
+#endif
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar A (after multiplying with V) ="<<std::endl;
+ std::cout<<std::setw(12)<<Sa11.f<<" "<<std::setw(12)<<Sa12.f<<" "<<std::setw(12)<<Sa13.f<<std::endl;
+ std::cout<<std::setw(12)<<Sa21.f<<" "<<std::setw(12)<<Sa22.f<<" "<<std::setw(12)<<Sa23.f<<std::endl;
+ std::cout<<std::setw(12)<<Sa31.f<<" "<<std::setw(12)<<Sa32.f<<" "<<std::setw(12)<<Sa33.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Va11);A11=buf[0];
+ _mm_storeu_ps(buf,Va21);A21=buf[0];
+ _mm_storeu_ps(buf,Va31);A31=buf[0];
+ _mm_storeu_ps(buf,Va12);A12=buf[0];
+ _mm_storeu_ps(buf,Va22);A22=buf[0];
+ _mm_storeu_ps(buf,Va32);A32=buf[0];
+ _mm_storeu_ps(buf,Va13);A13=buf[0];
+ _mm_storeu_ps(buf,Va23);A23=buf[0];
+ _mm_storeu_ps(buf,Va33);A33=buf[0];
+ std::cout<<"Vector A (after multiplying with V) ="<<std::endl;
+ std::cout<<std::setw(12)<<A11<<" "<<std::setw(12)<<A12<<" "<<std::setw(12)<<A13<<std::endl;
+ std::cout<<std::setw(12)<<A21<<" "<<std::setw(12)<<A22<<" "<<std::setw(12)<<A23<<std::endl;
+ std::cout<<std::setw(12)<<A31<<" "<<std::setw(12)<<A32<<" "<<std::setw(12)<<A33<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Va11);A11=buf[0];
+ _mm256_storeu_ps(buf,Va21);A21=buf[0];
+ _mm256_storeu_ps(buf,Va31);A31=buf[0];
+ _mm256_storeu_ps(buf,Va12);A12=buf[0];
+ _mm256_storeu_ps(buf,Va22);A22=buf[0];
+ _mm256_storeu_ps(buf,Va32);A32=buf[0];
+ _mm256_storeu_ps(buf,Va13);A13=buf[0];
+ _mm256_storeu_ps(buf,Va23);A23=buf[0];
+ _mm256_storeu_ps(buf,Va33);A33=buf[0];
+ std::cout<<"Vector A (after multiplying with V) ="<<std::endl;
+ std::cout<<std::setw(12)<<A11<<" "<<std::setw(12)<<A12<<" "<<std::setw(12)<<A13<<std::endl;
+ std::cout<<std::setw(12)<<A21<<" "<<std::setw(12)<<A22<<" "<<std::setw(12)<<A23<<std::endl;
+ std::cout<<std::setw(12)<<A31<<" "<<std::setw(12)<<A32<<" "<<std::setw(12)<<A33<<std::endl;
+#endif
+#endif
+
+ //###########################################################
+ // Re-normalize quaternion for matrix V
+ //###########################################################
+
+#ifdef COMPUTE_V_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Sqvs.f*Sqvs.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vqvs,Vqvs);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vqvs,Vqvs);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvx.f*Sqvvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvx,Vqvvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvx,Vqvvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvy.f*Sqvvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvy,Vqvvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvy,Vqvvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Sqvvz.f*Sqvvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vqvvz,Vqvvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vqvvz,Vqvvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Stmp1.f+Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_add_ps(Vtmp1,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_add_ps(Vtmp1,Vtmp2);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=rsqrt(Stmp2.f);) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_rsqrt_ps(Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_rsqrt_ps(Vtmp2);)
+
+#ifdef PERFORM_STRICT_QUATERNION_RENORMALIZATION
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp4.f=Stmp1.f*Sone_half.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp4=_mm_mul_ps(Vtmp1,Vone_half);) ENABLE_AVX_IMPLEMENTATION(Vtmp4=_mm256_mul_ps(Vtmp1,Vone_half);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp1.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp1,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Stmp2.f*Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vtmp2,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vtmp2,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f+Stmp4.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_add_ps(Vtmp1,Vtmp4);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_add_ps(Vtmp1,Vtmp4);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Stmp1.f-Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_sub_ps(Vtmp1,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_sub_ps(Vtmp1,Vtmp3);)
+#endif
+
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvs.f=Sqvs.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvs=_mm_mul_ps(Vqvs,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvs=_mm256_mul_ps(Vqvs,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvx.f=Sqvvx.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvx=_mm_mul_ps(Vqvvx,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvvx=_mm256_mul_ps(Vqvvx,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvy.f=Sqvvy.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvy=_mm_mul_ps(Vqvvy,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvvy=_mm256_mul_ps(Vqvvy,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sqvvz.f=Sqvvz.f*Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqvvz=_mm_mul_ps(Vqvvz,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqvvz=_mm256_mul_ps(Vqvvz,Vtmp1);)
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar qV ="<<std::endl;
+ std::cout<<std::setw(12)<<Sqvs.f<<" "<<std::setw(12)<<Sqvvx.f<<" "<<std::setw(12)<<Sqvvy.f<<" "<<std::setw(12)<<Sqvvz.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Vqvs);QVS=buf[0];
+ _mm_storeu_ps(buf,Vqvvx);QVVX=buf[0];
+ _mm_storeu_ps(buf,Vqvvy);QVVY=buf[0];
+ _mm_storeu_ps(buf,Vqvvz);QVVZ=buf[0];
+ std::cout<<"Vector qV ="<<std::endl;
+ std::cout<<std::setw(12)<<QVS<<" "<<std::setw(12)<<QVVX<<" "<<std::setw(12)<<QVVY<<" "<<std::setw(12)<<QVVZ<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Vqvs);QVS=buf[0];
+ _mm256_storeu_ps(buf,Vqvvx);QVVX=buf[0];
+ _mm256_storeu_ps(buf,Vqvvy);QVVY=buf[0];
+ _mm256_storeu_ps(buf,Vqvvz);QVVZ=buf[0];
+ std::cout<<"Vector qV ="<<std::endl;
+ std::cout<<std::setw(12)<<QVS<<" "<<std::setw(12)<<QVVX<<" "<<std::setw(12)<<QVVY<<" "<<std::setw(12)<<QVVZ<<std::endl;
+#endif
+#endif
+#endif
+
+ //###########################################################
+ // Construct QR factorization of A*V (=U*D) using Givens rotations
+ //###########################################################
+
+#ifdef COMPUTE_U_AS_MATRIX
+ ENABLE_SCALAR_IMPLEMENTATION(Su11.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vu11=Vone;) ENABLE_AVX_IMPLEMENTATION(Vu11=Vone;)
+ ENABLE_SCALAR_IMPLEMENTATION(Su21.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vu21=_mm_xor_ps(Vu21,Vu21);) ENABLE_AVX_IMPLEMENTATION(Vu21=_mm256_xor_ps(Vu21,Vu21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Su31.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vu31=_mm_xor_ps(Vu31,Vu31);) ENABLE_AVX_IMPLEMENTATION(Vu31=_mm256_xor_ps(Vu31,Vu31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Su12.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vu12=_mm_xor_ps(Vu12,Vu12);) ENABLE_AVX_IMPLEMENTATION(Vu12=_mm256_xor_ps(Vu12,Vu12);)
+ ENABLE_SCALAR_IMPLEMENTATION(Su22.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vu22=Vone;) ENABLE_AVX_IMPLEMENTATION(Vu22=Vone;)
+ ENABLE_SCALAR_IMPLEMENTATION(Su32.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vu32=_mm_xor_ps(Vu32,Vu32);) ENABLE_AVX_IMPLEMENTATION(Vu32=_mm256_xor_ps(Vu32,Vu32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Su13.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vu13=_mm_xor_ps(Vu13,Vu13);) ENABLE_AVX_IMPLEMENTATION(Vu13=_mm256_xor_ps(Vu13,Vu13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Su23.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vu23=_mm_xor_ps(Vu23,Vu23);) ENABLE_AVX_IMPLEMENTATION(Vu23=_mm256_xor_ps(Vu23,Vu23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Su33.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vu33=Vone;) ENABLE_AVX_IMPLEMENTATION(Vu33=Vone;)
+#endif
+
+#ifdef COMPUTE_U_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Squs.f=1.;) ENABLE_SSE_IMPLEMENTATION(Vqus=Vone;) ENABLE_AVX_IMPLEMENTATION(Vqus=Vone;)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvx.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vquvx=_mm_xor_ps(Vquvx,Vquvx);) ENABLE_AVX_IMPLEMENTATION(Vquvx=_mm256_xor_ps(Vquvx,Vquvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvy.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vquvy=_mm_xor_ps(Vquvy,Vquvy);) ENABLE_AVX_IMPLEMENTATION(Vquvy=_mm256_xor_ps(Vquvy,Vquvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvz.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vquvz=_mm_xor_ps(Vquvz,Vquvz);) ENABLE_AVX_IMPLEMENTATION(Vquvz=_mm256_xor_ps(Vquvz,Vquvz);)
+#endif
+
+ // First Givens rotation
+
+#define SAPIVOT Sa11
+#define SANPIVOT Sa21
+#define SA11 Sa11
+#define SA21 Sa21
+#define SA12 Sa12
+#define SA22 Sa22
+#define SA13 Sa13
+#define SA23 Sa23
+#define SU11 Su11
+#define SU12 Su12
+#define SU21 Su21
+#define SU22 Su22
+#define SU31 Su31
+#define SU32 Su32
+
+#define VAPIVOT Va11
+#define VANPIVOT Va21
+#define VA11 Va11
+#define VA21 Va21
+#define VA12 Va12
+#define VA22 Va22
+#define VA13 Va13
+#define VA23 Va23
+#define VU11 Vu11
+#define VU12 Vu12
+#define VU21 Vu21
+#define VU22 Vu22
+#define VU31 Vu31
+#define VU32 Vu32
+
+#include "Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp"
+
+#undef SAPIVOT
+#undef SANPIVOT
+#undef SA11
+#undef SA21
+#undef SA12
+#undef SA22
+#undef SA13
+#undef SA23
+#undef SU11
+#undef SU12
+#undef SU21
+#undef SU22
+#undef SU31
+#undef SU32
+
+#undef VAPIVOT
+#undef VANPIVOT
+#undef VA11
+#undef VA21
+#undef VA12
+#undef VA22
+#undef VA13
+#undef VA23
+#undef VU11
+#undef VU12
+#undef VU21
+#undef VU22
+#undef VU31
+#undef VU32
+
+ // Update quaternion representation of U
+
+#ifdef COMPUTE_U_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Squs.f=Sch.f;) ENABLE_SSE_IMPLEMENTATION(Vqus=Vch;) ENABLE_AVX_IMPLEMENTATION(Vqus=Vch;)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvx.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vquvx=_mm_xor_ps(Vquvx,Vquvx);) ENABLE_AVX_IMPLEMENTATION(Vquvx=_mm256_xor_ps(Vquvx,Vquvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvy.f=0.;) ENABLE_SSE_IMPLEMENTATION(Vquvy=_mm_xor_ps(Vquvy,Vquvy);) ENABLE_AVX_IMPLEMENTATION(Vquvy=_mm256_xor_ps(Vquvy,Vquvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvz.f=Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vquvz=Vsh;) ENABLE_AVX_IMPLEMENTATION(Vquvz=Vsh;)
+#endif
+
+ // Second Givens rotation
+
+#define SAPIVOT Sa11
+#define SANPIVOT Sa31
+#define SA11 Sa11
+#define SA21 Sa31
+#define SA12 Sa12
+#define SA22 Sa32
+#define SA13 Sa13
+#define SA23 Sa33
+#define SU11 Su11
+#define SU12 Su13
+#define SU21 Su21
+#define SU22 Su23
+#define SU31 Su31
+#define SU32 Su33
+
+#define VAPIVOT Va11
+#define VANPIVOT Va31
+#define VA11 Va11
+#define VA21 Va31
+#define VA12 Va12
+#define VA22 Va32
+#define VA13 Va13
+#define VA23 Va33
+#define VU11 Vu11
+#define VU12 Vu13
+#define VU21 Vu21
+#define VU22 Vu23
+#define VU31 Vu31
+#define VU32 Vu33
+
+#include "Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp"
+
+#undef SAPIVOT
+#undef SANPIVOT
+#undef SA11
+#undef SA21
+#undef SA12
+#undef SA22
+#undef SA13
+#undef SA23
+#undef SU11
+#undef SU12
+#undef SU21
+#undef SU22
+#undef SU31
+#undef SU32
+
+#undef VAPIVOT
+#undef VANPIVOT
+#undef VA11
+#undef VA21
+#undef VA12
+#undef VA22
+#undef VA13
+#undef VA23
+#undef VU11
+#undef VU12
+#undef VU21
+#undef VU22
+#undef VU31
+#undef VU32
+
+ // Update quaternion representation of U
+
+#ifdef COMPUTE_U_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Squvx.f=Ssh.f*Squvz.f;) ENABLE_SSE_IMPLEMENTATION(Vquvx=_mm_mul_ps(Vsh,Vquvz);) ENABLE_AVX_IMPLEMENTATION(Vquvx=_mm256_mul_ps(Vsh,Vquvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Squs.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vqus);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vqus);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvy.f=Squvy.f-Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vquvy=_mm_sub_ps(Vquvy,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vquvy=_mm256_sub_ps(Vquvy,Vsh);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squs.f=Sch.f*Squs.f;) ENABLE_SSE_IMPLEMENTATION(Vqus=_mm_mul_ps(Vch,Vqus);) ENABLE_AVX_IMPLEMENTATION(Vqus=_mm256_mul_ps(Vch,Vqus);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvz.f=Sch.f*Squvz.f;) ENABLE_SSE_IMPLEMENTATION(Vquvz=_mm_mul_ps(Vch,Vquvz);) ENABLE_AVX_IMPLEMENTATION(Vquvz=_mm256_mul_ps(Vch,Vquvz);)
+#endif
+
+ // Third Givens rotation
+
+#define SAPIVOT Sa22
+#define SANPIVOT Sa32
+#define SA11 Sa21
+#define SA21 Sa31
+#define SA12 Sa22
+#define SA22 Sa32
+#define SA13 Sa23
+#define SA23 Sa33
+#define SU11 Su12
+#define SU12 Su13
+#define SU21 Su22
+#define SU22 Su23
+#define SU31 Su32
+#define SU32 Su33
+
+#define VAPIVOT Va22
+#define VANPIVOT Va32
+#define VA11 Va21
+#define VA21 Va31
+#define VA12 Va22
+#define VA22 Va32
+#define VA13 Va23
+#define VA23 Va33
+#define VU11 Vu12
+#define VU12 Vu13
+#define VU21 Vu22
+#define VU22 Vu23
+#define VU31 Vu32
+#define VU32 Vu33
+
+#include "Singular_Value_Decomposition_Givens_QR_Factorization_Kernel.hpp"
+
+#undef SAPIVOT
+#undef SANPIVOT
+#undef SA11
+#undef SA21
+#undef SA12
+#undef SA22
+#undef SA13
+#undef SA23
+#undef SU11
+#undef SU12
+#undef SU21
+#undef SU22
+#undef SU31
+#undef SU32
+
+#undef VAPIVOT
+#undef VANPIVOT
+#undef VA11
+#undef VA21
+#undef VA12
+#undef VA22
+#undef VA13
+#undef VA23
+#undef VU11
+#undef VU12
+#undef VU21
+#undef VU22
+#undef VU31
+#undef VU32
+
+ // Update quaternion representation of U
+
+#ifdef COMPUTE_U_AS_QUATERNION
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp1.f=Ssh.f*Squvx.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp1=_mm_mul_ps(Vsh,Vquvx);) ENABLE_AVX_IMPLEMENTATION(Vtmp1=_mm256_mul_ps(Vsh,Vquvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp2.f=Ssh.f*Squvy.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp2=_mm_mul_ps(Vsh,Vquvy);) ENABLE_AVX_IMPLEMENTATION(Vtmp2=_mm256_mul_ps(Vsh,Vquvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Stmp3.f=Ssh.f*Squvz.f;) ENABLE_SSE_IMPLEMENTATION(Vtmp3=_mm_mul_ps(Vsh,Vquvz);) ENABLE_AVX_IMPLEMENTATION(Vtmp3=_mm256_mul_ps(Vsh,Vquvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Ssh.f=Ssh.f*Squs.f;) ENABLE_SSE_IMPLEMENTATION(Vsh=_mm_mul_ps(Vsh,Vqus);) ENABLE_AVX_IMPLEMENTATION(Vsh=_mm256_mul_ps(Vsh,Vqus);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squs.f=Sch.f*Squs.f;) ENABLE_SSE_IMPLEMENTATION(Vqus=_mm_mul_ps(Vch,Vqus);) ENABLE_AVX_IMPLEMENTATION(Vqus=_mm256_mul_ps(Vch,Vqus);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvx.f=Sch.f*Squvx.f;) ENABLE_SSE_IMPLEMENTATION(Vquvx=_mm_mul_ps(Vch,Vquvx);) ENABLE_AVX_IMPLEMENTATION(Vquvx=_mm256_mul_ps(Vch,Vquvx);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvy.f=Sch.f*Squvy.f;) ENABLE_SSE_IMPLEMENTATION(Vquvy=_mm_mul_ps(Vch,Vquvy);) ENABLE_AVX_IMPLEMENTATION(Vquvy=_mm256_mul_ps(Vch,Vquvy);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvz.f=Sch.f*Squvz.f;) ENABLE_SSE_IMPLEMENTATION(Vquvz=_mm_mul_ps(Vch,Vquvz);) ENABLE_AVX_IMPLEMENTATION(Vquvz=_mm256_mul_ps(Vch,Vquvz);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvx.f=Squvx.f+Ssh.f;) ENABLE_SSE_IMPLEMENTATION(Vquvx=_mm_add_ps(Vquvx,Vsh);) ENABLE_AVX_IMPLEMENTATION(Vquvx=_mm256_add_ps(Vquvx,Vsh);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squs.f=Squs.f-Stmp1.f;) ENABLE_SSE_IMPLEMENTATION(Vqus=_mm_sub_ps(Vqus,Vtmp1);) ENABLE_AVX_IMPLEMENTATION(Vqus=_mm256_sub_ps(Vqus,Vtmp1);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvy.f=Squvy.f+Stmp3.f;) ENABLE_SSE_IMPLEMENTATION(Vquvy=_mm_add_ps(Vquvy,Vtmp3);) ENABLE_AVX_IMPLEMENTATION(Vquvy=_mm256_add_ps(Vquvy,Vtmp3);)
+ ENABLE_SCALAR_IMPLEMENTATION(Squvz.f=Squvz.f-Stmp2.f;) ENABLE_SSE_IMPLEMENTATION(Vquvz=_mm_sub_ps(Vquvz,Vtmp2);) ENABLE_AVX_IMPLEMENTATION(Vquvz=_mm256_sub_ps(Vquvz,Vtmp2);)
+#endif
+
+#ifdef COMPUTE_U_AS_MATRIX
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar U ="<<std::endl;
+ std::cout<<std::setw(12)<<Su11.f<<" "<<std::setw(12)<<Su12.f<<" "<<std::setw(12)<<Su13.f<<std::endl;
+ std::cout<<std::setw(12)<<Su21.f<<" "<<std::setw(12)<<Su22.f<<" "<<std::setw(12)<<Su23.f<<std::endl;
+ std::cout<<std::setw(12)<<Su31.f<<" "<<std::setw(12)<<Su32.f<<" "<<std::setw(12)<<Su33.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Vu11);U11=buf[0];
+ _mm_storeu_ps(buf,Vu21);U21=buf[0];
+ _mm_storeu_ps(buf,Vu31);U31=buf[0];
+ _mm_storeu_ps(buf,Vu12);U12=buf[0];
+ _mm_storeu_ps(buf,Vu22);U22=buf[0];
+ _mm_storeu_ps(buf,Vu32);U32=buf[0];
+ _mm_storeu_ps(buf,Vu13);U13=buf[0];
+ _mm_storeu_ps(buf,Vu23);U23=buf[0];
+ _mm_storeu_ps(buf,Vu33);U33=buf[0];
+ std::cout<<"Vector U ="<<std::endl;
+ std::cout<<std::setw(12)<<U11<<" "<<std::setw(12)<<U12<<" "<<std::setw(12)<<U13<<std::endl;
+ std::cout<<std::setw(12)<<U21<<" "<<std::setw(12)<<U22<<" "<<std::setw(12)<<U23<<std::endl;
+ std::cout<<std::setw(12)<<U31<<" "<<std::setw(12)<<U32<<" "<<std::setw(12)<<U33<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Vu11);U11=buf[0];
+ _mm256_storeu_ps(buf,Vu21);U21=buf[0];
+ _mm256_storeu_ps(buf,Vu31);U31=buf[0];
+ _mm256_storeu_ps(buf,Vu12);U12=buf[0];
+ _mm256_storeu_ps(buf,Vu22);U22=buf[0];
+ _mm256_storeu_ps(buf,Vu32);U32=buf[0];
+ _mm256_storeu_ps(buf,Vu13);U13=buf[0];
+ _mm256_storeu_ps(buf,Vu23);U23=buf[0];
+ _mm256_storeu_ps(buf,Vu33);U33=buf[0];
+ std::cout<<"Vector U ="<<std::endl;
+ std::cout<<std::setw(12)<<U11<<" "<<std::setw(12)<<U12<<" "<<std::setw(12)<<U13<<std::endl;
+ std::cout<<std::setw(12)<<U21<<" "<<std::setw(12)<<U22<<" "<<std::setw(12)<<U23<<std::endl;
+ std::cout<<std::setw(12)<<U31<<" "<<std::setw(12)<<U32<<" "<<std::setw(12)<<U33<<std::endl;
+#endif
+#endif
+#endif
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar A (after multiplying with U-transpose and V) ="<<std::endl;
+ std::cout<<std::setw(12)<<Sa11.f<<" "<<std::setw(12)<<Sa12.f<<" "<<std::setw(12)<<Sa13.f<<std::endl;
+ std::cout<<std::setw(12)<<Sa21.f<<" "<<std::setw(12)<<Sa22.f<<" "<<std::setw(12)<<Sa23.f<<std::endl;
+ std::cout<<std::setw(12)<<Sa31.f<<" "<<std::setw(12)<<Sa32.f<<" "<<std::setw(12)<<Sa33.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Va11);A11=buf[0];
+ _mm_storeu_ps(buf,Va21);A21=buf[0];
+ _mm_storeu_ps(buf,Va31);A31=buf[0];
+ _mm_storeu_ps(buf,Va12);A12=buf[0];
+ _mm_storeu_ps(buf,Va22);A22=buf[0];
+ _mm_storeu_ps(buf,Va32);A32=buf[0];
+ _mm_storeu_ps(buf,Va13);A13=buf[0];
+ _mm_storeu_ps(buf,Va23);A23=buf[0];
+ _mm_storeu_ps(buf,Va33);A33=buf[0];
+ std::cout<<"Vector A (after multiplying with U-transpose and V) ="<<std::endl;
+ std::cout<<std::setw(12)<<A11<<" "<<std::setw(12)<<A12<<" "<<std::setw(12)<<A13<<std::endl;
+ std::cout<<std::setw(12)<<A21<<" "<<std::setw(12)<<A22<<" "<<std::setw(12)<<A23<<std::endl;
+ std::cout<<std::setw(12)<<A31<<" "<<std::setw(12)<<A32<<" "<<std::setw(12)<<A33<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Va11);A11=buf[0];
+ _mm256_storeu_ps(buf,Va21);A21=buf[0];
+ _mm256_storeu_ps(buf,Va31);A31=buf[0];
+ _mm256_storeu_ps(buf,Va12);A12=buf[0];
+ _mm256_storeu_ps(buf,Va22);A22=buf[0];
+ _mm256_storeu_ps(buf,Va32);A32=buf[0];
+ _mm256_storeu_ps(buf,Va13);A13=buf[0];
+ _mm256_storeu_ps(buf,Va23);A23=buf[0];
+ _mm256_storeu_ps(buf,Va33);A33=buf[0];
+ std::cout<<"Vector A (after multiplying with U-transpose and V) ="<<std::endl;
+ std::cout<<std::setw(12)<<A11<<" "<<std::setw(12)<<A12<<" "<<std::setw(12)<<A13<<std::endl;
+ std::cout<<std::setw(12)<<A21<<" "<<std::setw(12)<<A22<<" "<<std::setw(12)<<A23<<std::endl;
+ std::cout<<std::setw(12)<<A31<<" "<<std::setw(12)<<A32<<" "<<std::setw(12)<<A33<<std::endl;
+#endif
+#endif
+
+#ifdef COMPUTE_U_AS_QUATERNION
+#ifdef PRINT_DEBUGGING_OUTPUT
+#ifdef USE_SCALAR_IMPLEMENTATION
+ std::cout<<"Scalar qU ="<<std::endl;
+ std::cout<<std::setw(12)<<Squs.f<<" "<<std::setw(12)<<Squvx.f<<" "<<std::setw(12)<<Squvy.f<<" "<<std::setw(12)<<Squvz.f<<std::endl;
+#endif
+#ifdef USE_SSE_IMPLEMENTATION
+ _mm_storeu_ps(buf,Vqus);QUS=buf[0];
+ _mm_storeu_ps(buf,Vquvx);QUVX=buf[0];
+ _mm_storeu_ps(buf,Vquvy);QUVY=buf[0];
+ _mm_storeu_ps(buf,Vquvz);QUVZ=buf[0];
+ std::cout<<"Vector qU ="<<std::endl;
+ std::cout<<std::setw(12)<<QUS<<" "<<std::setw(12)<<QUVX<<" "<<std::setw(12)<<QUVY<<" "<<std::setw(12)<<QUVZ<<std::endl;
+#endif
+#ifdef USE_AVX_IMPLEMENTATION
+ _mm256_storeu_ps(buf,Vqus);QUS=buf[0];
+ _mm256_storeu_ps(buf,Vquvx);QUVX=buf[0];
+ _mm256_storeu_ps(buf,Vquvy);QUVY=buf[0];
+ _mm256_storeu_ps(buf,Vquvz);QUVZ=buf[0];
+ std::cout<<"Vector qU ="<<std::endl;
+ std::cout<<std::setw(12)<<QUS<<" "<<std::setw(12)<<QUVX<<" "<<std::setw(12)<<QUVY<<" "<<std::setw(12)<<QUVZ<<std::endl;
+#endif
+#endif
+#endif
+
+#ifdef __INTEL_COMPILER
+#pragma warning( default : 592 )
+#endif
diff --git a/xs/src/igl/Singular_Value_Decomposition_Preamble.hpp b/xs/src/igl/Singular_Value_Decomposition_Preamble.hpp
new file mode 100644
index 000000000..d55fa86cf
--- /dev/null
+++ b/xs/src/igl/Singular_Value_Decomposition_Preamble.hpp
@@ -0,0 +1,78 @@
+//#####################################################################
+// Copyright (c) 2010-2011, Eftychios Sifakis.
+//
+// Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+// * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+// * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or
+// other materials provided with the distribution.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
+// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
+// SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//#####################################################################
+
+#ifdef PRINT_DEBUGGING_OUTPUT
+#include <iomanip>
+#include <iostream>
+#endif
+
+// Prevent warnings
+#ifdef ENABLE_SCALAR_IMPLEMENTATION
+# undef ENABLE_SCALAR_IMPLEMENTATION
+#endif
+#ifdef ENABLE_SSE_IMPLEMENTATION
+# undef ENABLE_SSE_IMPLEMENTATION
+#endif
+#ifdef ENABLE_AVX_IMPLEMENTATION
+# undef ENABLE_AVX_IMPLEMENTATION
+#endif
+
+#ifdef USE_SCALAR_IMPLEMENTATION
+#define ENABLE_SCALAR_IMPLEMENTATION(X) X
+#else
+#define ENABLE_SCALAR_IMPLEMENTATION(X)
+#endif
+
+#ifdef USE_SSE_IMPLEMENTATION
+#define ENABLE_SSE_IMPLEMENTATION(X) X
+#else
+#define ENABLE_SSE_IMPLEMENTATION(X)
+#endif
+
+#ifdef USE_AVX_IMPLEMENTATION
+#include <immintrin.h>
+#define ENABLE_AVX_IMPLEMENTATION(X) X
+#else
+// Stefan: removed include. Why does it import MMX instructions, shouldn't this be under the #ifdef USE_SSE_IMPLEMENTATION above?
+//#include <xmmintrin.h>
+#define ENABLE_AVX_IMPLEMENTATION(X)
+#endif
+
+#ifdef USE_SCALAR_IMPLEMENTATION
+// Alec: Why is this using sse intrinsics if it's supposed to be the scalar
+// implementation?
+#ifdef __SSE__
+#include <mmintrin.h>
+// Changed to inline
+inline float rsqrt(const float f)
+{
+ float buf[4];
+ buf[0]=f;
+ __m128 v=_mm_loadu_ps(buf);
+ v=_mm_rsqrt_ss(v);
+ _mm_storeu_ps(buf,v);
+ return buf[0];
+}
+#else
+#include <cmath>
+inline float rsqrt(const float f)
+{
+ return 1./sqrtf(f);
+}
+#endif
+#endif
+
+
diff --git a/xs/src/igl/SolverStatus.h b/xs/src/igl/SolverStatus.h
new file mode 100644
index 000000000..d9151f5c0
--- /dev/null
+++ b/xs/src/igl/SolverStatus.h
@@ -0,0 +1,23 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SOLVER_STATUS_H
+#define IGL_SOLVER_STATUS_H
+namespace igl
+{
+ enum SolverStatus
+ {
+ // Good
+ SOLVER_STATUS_CONVERGED = 0,
+ // OK
+ SOLVER_STATUS_MAX_ITER = 1,
+ // Bad
+ SOLVER_STATUS_ERROR = 2,
+ NUM_SOLVER_STATUSES = 3,
+ };
+};
+#endif
diff --git a/xs/src/igl/SortableRow.h b/xs/src/igl/SortableRow.h
new file mode 100644
index 000000000..5f172987b
--- /dev/null
+++ b/xs/src/igl/SortableRow.h
@@ -0,0 +1,70 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SORTABLE_ROW_H
+#define IGL_SORTABLE_ROW_H
+
+// Simple class to contain a rowvector which allows rowwise sorting and
+// reordering
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Templates:
+ // T should be a matrix that implements .size(), and operator(int i)
+ template <typename T>
+ class SortableRow
+ {
+ public:
+ T data;
+ public:
+ SortableRow():data(){};
+ SortableRow(const T & data):data(data){};
+ bool operator<(const SortableRow & that) const
+ {
+ // Get reference so that I can use parenthesis
+ const SortableRow<T> & THIS = *this;
+ // Lexicographical
+ int minc = (THIS.data.size() < that.data.size()?
+ THIS.data.size() : that.data.size());
+ // loop over columns
+ for(int i = 0;i<minc;i++)
+ {
+ if(THIS.data(i) == that.data(i))
+ {
+ continue;
+ }
+ return THIS.data(i) < that.data(i);
+ }
+ // All characters the same, comes done to length
+ return THIS.data.size()<that.data.size();
+ };
+ bool operator==(const SortableRow & that) const
+ {
+ // Get reference so that I can use parenthesis
+ const SortableRow<T> & THIS = *this;
+ if(THIS.data.size() != that.data.size())
+ {
+ return false;
+ }
+ for(int i = 0;i<THIS.data.size();i++)
+ {
+ if(THIS.data(i) != that.data(i))
+ {
+ return false;
+ }
+ }
+ return true;
+ };
+ bool operator!=(const SortableRow & that) const
+ {
+ return !(*this == that);
+ };
+ };
+}
+
+#endif
diff --git a/xs/src/igl/Timer.h b/xs/src/igl/Timer.h
new file mode 100644
index 000000000..ac9e55e6b
--- /dev/null
+++ b/xs/src/igl/Timer.h
@@ -0,0 +1,179 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+// High Resolution Timer.
+//
+// Resolution on Mac (clock tick)
+// Resolution on Linux (1 us not tested)
+// Resolution on Windows (clock tick not tested)
+
+#ifndef IGL_TIMER_H
+#define IGL_TIMER_H
+
+#ifdef WIN32 // Windows system specific
+#include <windows.h>
+#elif __APPLE__ // Unix based system specific
+#include <mach/mach_time.h> // for mach_absolute_time
+#else
+#include <sys/time.h>
+#endif
+#include <cstddef>
+
+namespace igl
+{
+ class Timer
+ {
+ public:
+ // default constructor
+ Timer():
+ stopped(0),
+#ifdef WIN32
+ frequency(),
+ startCount(),
+ endCount()
+#elif __APPLE__
+ startCount(0),
+ endCount(0)
+#else
+ startCount(),
+ endCount()
+#endif
+ {
+#ifdef WIN32
+ QueryPerformanceFrequency(&frequency);
+ startCount.QuadPart = 0;
+ endCount.QuadPart = 0;
+#elif __APPLE__
+ startCount = 0;
+ endCount = 0;
+#else
+ startCount.tv_sec = startCount.tv_usec = 0;
+ endCount.tv_sec = endCount.tv_usec = 0;
+#endif
+
+ stopped = 0;
+ }
+ // default destructor
+ ~Timer()
+ {
+
+ }
+
+#ifdef __APPLE__
+ //Raw mach_absolute_times going in, difference in seconds out
+ double subtractTimes( uint64_t endTime, uint64_t startTime )
+ {
+ uint64_t difference = endTime - startTime;
+ static double conversion = 0.0;
+
+ if( conversion == 0.0 )
+ {
+ mach_timebase_info_data_t info;
+ kern_return_t err = mach_timebase_info( &info );
+
+ //Convert the timebase into seconds
+ if( err == 0 )
+ conversion = 1e-9 * (double) info.numer / (double) info.denom;
+ }
+
+ return conversion * (double) difference;
+ }
+#endif
+
+ // start timer
+ void start()
+ {
+ stopped = 0; // reset stop flag
+#ifdef WIN32
+ QueryPerformanceCounter(&startCount);
+#elif __APPLE__
+ startCount = mach_absolute_time();
+#else
+ gettimeofday(&startCount, NULL);
+#endif
+
+ }
+
+ // stop the timer
+ void stop()
+ {
+ stopped = 1; // set timer stopped flag
+
+#ifdef WIN32
+ QueryPerformanceCounter(&endCount);
+#elif __APPLE__
+ endCount = mach_absolute_time();
+#else
+ gettimeofday(&endCount, NULL);
+#endif
+
+ }
+ // get elapsed time in second
+ double getElapsedTime()
+ {
+ return this->getElapsedTimeInSec();
+ }
+ // get elapsed time in second (same as getElapsedTime)
+ double getElapsedTimeInSec()
+ {
+ return this->getElapsedTimeInMicroSec() * 0.000001;
+ }
+
+ // get elapsed time in milli-second
+ double getElapsedTimeInMilliSec()
+ {
+ return this->getElapsedTimeInMicroSec() * 0.001;
+ }
+ // get elapsed time in micro-second
+ double getElapsedTimeInMicroSec()
+ {
+ double startTimeInMicroSec = 0;
+ double endTimeInMicroSec = 0;
+
+#ifdef WIN32
+ if(!stopped)
+ QueryPerformanceCounter(&endCount);
+
+ startTimeInMicroSec =
+ startCount.QuadPart * (1000000.0 / frequency.QuadPart);
+ endTimeInMicroSec = endCount.QuadPart * (1000000.0 / frequency.QuadPart);
+#elif __APPLE__
+ if (!stopped)
+ endCount = mach_absolute_time();
+
+ return subtractTimes(endCount,startCount)/1e-6;
+#else
+ if(!stopped)
+ gettimeofday(&endCount, NULL);
+
+ startTimeInMicroSec =
+ (startCount.tv_sec * 1000000.0) + startCount.tv_usec;
+ endTimeInMicroSec = (endCount.tv_sec * 1000000.0) + endCount.tv_usec;
+#endif
+
+ return endTimeInMicroSec - startTimeInMicroSec;
+ }
+
+ private:
+ // stop flag
+ int stopped;
+#ifdef WIN32
+ // ticks per second
+ LARGE_INTEGER frequency;
+ LARGE_INTEGER startCount;
+ LARGE_INTEGER endCount;
+#elif __APPLE__
+ uint64_t startCount;
+ uint64_t endCount;
+#else
+ timeval startCount;
+ timeval endCount;
+#endif
+ };
+}
+#endif // TIMER_H_DEF
+
diff --git a/xs/src/igl/Viewport.h b/xs/src/igl/Viewport.h
new file mode 100644
index 000000000..717d3f97b
--- /dev/null
+++ b/xs/src/igl/Viewport.h
@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VIEWPORT_H
+#define IGL_VIEWPORT_H
+
+namespace igl
+{
+ // Simple Viewport class for an opengl context. Handles reshaping and mouse.
+ struct Viewport
+ {
+ int x,y,width,height;
+ // Constructors
+ Viewport(
+ const int x=0,
+ const int y=0,
+ const int width=0,
+ const int height=0):
+ x(x),
+ y(y),
+ width(width),
+ height(height)
+ {
+ };
+ virtual ~Viewport(){}
+ void reshape(
+ const int x,
+ const int y,
+ const int width,
+ const int height)
+ {
+ this->x = x;
+ this->y = y;
+ this->width = width;
+ this->height = height;
+ };
+ // Given mouse_x,mouse_y on the entire window return mouse_x, mouse_y in
+ // this viewport.
+ //
+ // Inputs:
+ // my mouse y-coordinate
+ // wh window height
+ // Returns y-coordinate in viewport
+ int mouse_y(const int my,const int wh)
+ {
+ return my - (wh - height - y);
+ }
+ // Inputs:
+ // mx mouse x-coordinate
+ // Returns x-coordinate in viewport
+ int mouse_x(const int mx)
+ {
+ return mx - x;
+ }
+ // Returns whether point (mx,my) is in extend of Viewport
+ bool inside(const int mx, const int my) const
+ {
+ return
+ mx >= x && my >= y &&
+ mx < x+width && my < y+height;
+ }
+ };
+}
+
+#endif
diff --git a/xs/src/igl/WindingNumberAABB.h b/xs/src/igl/WindingNumberAABB.h
new file mode 100644
index 000000000..478026989
--- /dev/null
+++ b/xs/src/igl/WindingNumberAABB.h
@@ -0,0 +1,377 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+// # MUTUAL DEPENDENCY ISSUE FOR HEADER ONLY VERSION
+// MUST INCLUDE winding_number.h first before guard:
+#include "winding_number.h"
+
+#ifndef IGL_WINDINGNUMBERAABB_H
+#define IGL_WINDINGNUMBERAABB_H
+#include "WindingNumberTree.h"
+
+namespace igl
+{
+ template <
+ typename Point,
+ typename DerivedV,
+ typename DerivedF >
+ class WindingNumberAABB : public WindingNumberTree<Point,DerivedV,DerivedF>
+ {
+ protected:
+ Point min_corner;
+ Point max_corner;
+ typename DerivedV::Scalar total_positive_area;
+ public:
+ enum SplitMethod
+ {
+ CENTER_ON_LONGEST_AXIS = 0,
+ MEDIAN_ON_LONGEST_AXIS = 1,
+ NUM_SPLIT_METHODS = 2
+ } split_method;
+ public:
+ inline WindingNumberAABB():
+ total_positive_area(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
+ split_method(MEDIAN_ON_LONGEST_AXIS)
+ {}
+ 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
+ inline void set_mesh(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F);
+ inline void init();
+ inline bool inside(const Point & p) const;
+ inline virtual void grow();
+ // Compute min and max corners
+ inline void compute_min_max_corners();
+ inline typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
+ inline typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
+ };
+}
+
+// Implementation
+
+#include "winding_number.h"
+
+#include "barycenter.h"
+#include "median.h"
+#include "doublearea.h"
+#include "per_face_normals.h"
+
+#include <limits>
+#include <vector>
+#include <iostream>
+
+// Minimum number of faces in a hierarchy element (this is probably dependent
+// on speed of machine and compiler optimization)
+#ifndef WindingNumberAABB_MIN_F
+# define WindingNumberAABB_MIN_F 100
+#endif
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::set_mesh(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F)
+{
+ igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(V,F);
+ init();
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::init()
+{
+ using namespace Eigen;
+ assert(max_corner.size() == 3);
+ assert(min_corner.size() == 3);
+ compute_min_max_corners();
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,1> dblA;
+ doublearea(this->getV(),this->getF(),dblA);
+ total_positive_area = dblA.sum()/2.0;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F):
+ WindingNumberTree<Point,DerivedV,DerivedF>(V,F),
+ min_corner(),
+ max_corner(),
+ total_positive_area(
+ std::numeric_limits<typename DerivedV::Scalar>::infinity()),
+ split_method(MEDIAN_ON_LONGEST_AXIS)
+{
+ init();
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline igl::WindingNumberAABB<Point,DerivedV,DerivedF>::WindingNumberAABB(
+ const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
+ const Eigen::MatrixBase<DerivedF> & F):
+ WindingNumberTree<Point,DerivedV,DerivedF>(parent,F),
+ min_corner(),
+ max_corner(),
+ total_positive_area(
+ std::numeric_limits<typename DerivedV::Scalar>::infinity()),
+ split_method(MEDIAN_ON_LONGEST_AXIS)
+{
+ init();
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::grow()
+{
+ using namespace std;
+ using namespace Eigen;
+ // Clear anything that already exists
+ this->delete_children();
+
+ //cout<<"cap.rows(): "<<this->getcap().rows()<<endl;
+ //cout<<"F.rows(): "<<this->getF().rows()<<endl;
+
+ // Base cases
+ if(
+ this->getF().rows() <= (WindingNumberAABB_MIN_F>0?WindingNumberAABB_MIN_F:0) ||
+ (this->getcap().rows() - 2) >= this->getF().rows())
+ {
+ // Don't grow
+ return;
+ }
+
+ // Compute longest direction
+ int max_d = -1;
+ typename DerivedV::Scalar max_len =
+ -numeric_limits<typename DerivedV::Scalar>::infinity();
+ for(int d = 0;d<min_corner.size();d++)
+ {
+ if( (max_corner[d] - min_corner[d]) > max_len )
+ {
+ max_len = (max_corner[d] - min_corner[d]);
+ max_d = d;
+ }
+ }
+ // Compute facet barycenters
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic> BC;
+ barycenter(this->getV(),this->getF(),BC);
+
+
+ // Blerg, why is selecting rows so difficult
+
+ typename DerivedV::Scalar split_value;
+ // Split in longest direction
+ switch(split_method)
+ {
+ case MEDIAN_ON_LONGEST_AXIS:
+ // Determine median
+ median(BC.col(max_d),split_value);
+ break;
+ default:
+ assert(false);
+ case CENTER_ON_LONGEST_AXIS:
+ split_value = 0.5*(max_corner[max_d] + min_corner[max_d]);
+ break;
+ }
+ //cout<<"c: "<<0.5*(max_corner[max_d] + min_corner[max_d])<<" "<<
+ // "m: "<<split_value<<endl;;
+
+ vector<int> id( this->getF().rows());
+ for(int i = 0;i<this->getF().rows();i++)
+ {
+ if(BC(i,max_d) <= split_value)
+ {
+ id[i] = 0; //left
+ }else
+ {
+ id[i] = 1; //right
+ }
+ }
+
+ const int lefts = (int) count(id.begin(),id.end(),0);
+ const int rights = (int) count(id.begin(),id.end(),1);
+ if(lefts == 0 || rights == 0)
+ {
+ // badly balanced base case (could try to recut)
+ return;
+ }
+ assert(lefts+rights == this->getF().rows());
+ DerivedF leftF(lefts, this->getF().cols());
+ DerivedF rightF(rights,this->getF().cols());
+ int left_i = 0;
+ int right_i = 0;
+ for(int i = 0;i<this->getF().rows();i++)
+ {
+ if(id[i] == 0)
+ {
+ leftF.row(left_i++) = this->getF().row(i);
+ }else if(id[i] == 1)
+ {
+ rightF.row(right_i++) = this->getF().row(i);
+ }else
+ {
+ assert(false);
+ }
+ }
+ assert(right_i == rightF.rows());
+ assert(left_i == leftF.rows());
+ // Finally actually grow children and Recursively grow
+ WindingNumberAABB<Point,DerivedV,DerivedF> * leftWindingNumberAABB =
+ new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,leftF);
+ leftWindingNumberAABB->grow();
+ this->children.push_back(leftWindingNumberAABB);
+ WindingNumberAABB<Point,DerivedV,DerivedF> * rightWindingNumberAABB =
+ new WindingNumberAABB<Point,DerivedV,DerivedF>(*this,rightF);
+ rightWindingNumberAABB->grow();
+ this->children.push_back(rightWindingNumberAABB);
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline bool igl::WindingNumberAABB<Point,DerivedV,DerivedF>::inside(const Point & p) const
+{
+ assert(p.size() == max_corner.size());
+ assert(p.size() == min_corner.size());
+ for(int i = 0;i<p.size();i++)
+ {
+ //// Perfect matching is **not** robust
+ //if( p(i) < min_corner(i) || p(i) >= max_corner(i))
+ // **MUST** be conservative
+ if( p(i) < min_corner(i) || p(i) > max_corner(i))
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberAABB<Point,DerivedV,DerivedF>::compute_min_max_corners()
+{
+ using namespace std;
+ // initialize corners
+ for(int d = 0;d<min_corner.size();d++)
+ {
+ min_corner[d] = numeric_limits<typename Point::Scalar>::infinity();
+ max_corner[d] = -numeric_limits<typename Point::Scalar>::infinity();
+ }
+
+ this->center = Point(0,0,0);
+ // Loop over facets
+ for(int i = 0;i<this->getF().rows();i++)
+ {
+ for(int j = 0;j<this->getF().cols();j++)
+ {
+ for(int d = 0;d<min_corner.size();d++)
+ {
+ min_corner[d] =
+ this->getV()(this->getF()(i,j),d) < min_corner[d] ?
+ this->getV()(this->getF()(i,j),d) : min_corner[d];
+ max_corner[d] =
+ this->getV()(this->getF()(i,j),d) > max_corner[d] ?
+ this->getV()(this->getF()(i,j),d) : max_corner[d];
+ }
+ // This is biased toward vertices incident on more than one face, but
+ // perhaps that's good
+ this->center += this->getV().row(this->getF()(i,j));
+ }
+ }
+ // Average
+ this->center.array() /= this->getF().size();
+
+ //cout<<"min_corner: "<<this->min_corner.transpose()<<endl;
+ //cout<<"Center: "<<this->center.transpose()<<endl;
+ //cout<<"max_corner: "<<this->max_corner.transpose()<<endl;
+ //cout<<"Diag center: "<<((this->max_corner + this->min_corner)*0.5).transpose()<<endl;
+ //cout<<endl;
+
+ this->radius = (max_corner-min_corner).norm()/2.0;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & p) const
+{
+ using namespace std;
+ // Only valid if not inside
+ if(inside(p))
+ {
+ return numeric_limits<typename DerivedV::Scalar>::infinity();
+ }
+ // Q: we know the total positive area so what's the most this could project
+ // to? Remember it could be layered in the same direction.
+ return numeric_limits<typename DerivedV::Scalar>::infinity();
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+ igl::WindingNumberAABB<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
+ const Point & p) const
+{
+ using namespace std;
+ using namespace Eigen;
+ // Only valid if not inside
+ if(inside(p))
+ {
+ return numeric_limits<typename DerivedV::Scalar>::infinity();
+ }
+ // Max simple is the same as sum of positive winding number contributions of
+ // bounding box
+
+ // begin precomputation
+ //MatrixXd BV((int)pow(2,3),3);
+ typedef
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
+ MatrixXS;
+ typedef
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
+ MatrixXF;
+ MatrixXS BV((int)(1<<3),3);
+ BV <<
+ min_corner[0],min_corner[1],min_corner[2],
+ min_corner[0],min_corner[1],max_corner[2],
+ min_corner[0],max_corner[1],min_corner[2],
+ min_corner[0],max_corner[1],max_corner[2],
+ max_corner[0],min_corner[1],min_corner[2],
+ max_corner[0],min_corner[1],max_corner[2],
+ max_corner[0],max_corner[1],min_corner[2],
+ max_corner[0],max_corner[1],max_corner[2];
+ MatrixXF BF(2*2*3,3);
+ BF <<
+ 0,6,4,
+ 0,2,6,
+ 0,3,2,
+ 0,1,3,
+ 2,7,6,
+ 2,3,7,
+ 4,6,7,
+ 4,7,5,
+ 0,4,5,
+ 0,5,1,
+ 1,5,7,
+ 1,7,3;
+ MatrixXS BFN;
+ per_face_normals(BV,BF,BFN);
+ // end of precomputation
+
+ // Only keep those with positive dot products
+ MatrixXF PBF(BF.rows(),BF.cols());
+ int pbfi = 0;
+ Point p2c = 0.5*(min_corner+max_corner)-p;
+ for(int i = 0;i<BFN.rows();i++)
+ {
+ if(p2c.dot(BFN.row(i)) > 0)
+ {
+ PBF.row(pbfi++) = BF.row(i);
+ }
+ }
+ PBF.conservativeResize(pbfi,PBF.cols());
+ return igl::winding_number(BV,PBF,p);
+}
+
+#endif
diff --git a/xs/src/igl/WindingNumberMethod.h b/xs/src/igl/WindingNumberMethod.h
new file mode 100644
index 000000000..3bb9062b1
--- /dev/null
+++ b/xs/src/igl/WindingNumberMethod.h
@@ -0,0 +1,23 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WINDINGNUMBERMETHOD_H
+#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_WINDING_NUMBER_METHOD = 0,
+ APPROX_SIMPLE_WINDING_NUMBER_METHOD = 1,
+ APPROX_CACHE_WINDING_NUMBER_METHOD = 2,
+ NUM_WINDING_NUMBER_METHODS = 3
+ };
+}
+#endif
diff --git a/xs/src/igl/WindingNumberTree.h b/xs/src/igl/WindingNumberTree.h
new file mode 100644
index 000000000..317ad9442
--- /dev/null
+++ b/xs/src/igl/WindingNumberTree.h
@@ -0,0 +1,503 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WINDINGNUMBERTREE_H
+#define IGL_WINDINGNUMBERTREE_H
+#include <list>
+#include <map>
+#include <Eigen/Dense>
+#include "WindingNumberMethod.h"
+
+namespace igl
+{
+ // Space partitioning tree for computing winding number hierarchically.
+ //
+ // Templates:
+ // Point type for points in space, e.g. Eigen::Vector3d
+ template <
+ typename Point,
+ typename DerivedV,
+ typename DerivedF >
+ class WindingNumberTree
+ {
+ public:
+ // Method to use (see enum above)
+ //static double min_max_w;
+ static std::map<
+ std::pair<const WindingNumberTree*,const WindingNumberTree*>,
+ typename DerivedV::Scalar>
+ cached;
+ // This is only need to fill in references, it should never actually be touched
+ // and shouldn't cause race conditions. (This is a hack, but I think it's "safe")
+ static DerivedV dummyV;
+ protected:
+ WindingNumberMethod method;
+ const WindingNumberTree * parent;
+ std::list<WindingNumberTree * > children;
+ typedef
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic>
+ MatrixXS;
+ typedef
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
+ MatrixXF;
+ //// List of boundary edges (recall edges are vertices in 2d)
+ //const Eigen::MatrixXi boundary;
+ // Base mesh vertices
+ DerivedV & V;
+ // Base mesh vertices with duplicates removed
+ MatrixXS SV;
+ // Facets in this bounding volume
+ MatrixXF F;
+ // Tessellated boundary curve
+ MatrixXF cap;
+ // Upper Bound on radius of enclosing ball
+ typename DerivedV::Scalar radius;
+ // (Approximate) center (of mass)
+ Point center;
+ public:
+ inline WindingNumberTree();
+ // For root
+ inline WindingNumberTree(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F);
+ // For chilluns
+ inline WindingNumberTree(
+ const WindingNumberTree<Point,DerivedV,DerivedF> & parent,
+ const Eigen::MatrixBase<DerivedF> & F);
+ inline virtual ~WindingNumberTree();
+ inline void delete_children();
+ inline virtual void set_mesh(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F);
+ // Set method
+ inline void set_method( const WindingNumberMethod & m);
+ public:
+ inline const DerivedV & getV() const;
+ inline const MatrixXF & getF() const;
+ inline const MatrixXF & getcap() const;
+ // Grow the Tree recursively
+ inline virtual void grow();
+ // Determine whether a given point is inside the bounding
+ //
+ // Inputs:
+ // p query point
+ // Returns true if the point p is inside this bounding volume
+ inline virtual bool inside(const Point & p) const;
+ // Compute the (partial) winding number of a given point p
+ // According to method
+ //
+ // Inputs:
+ // p query point
+ // Returns winding number
+ inline typename DerivedV::Scalar winding_number(const Point & p) const;
+ // Same as above, but always computes winding number using exact method
+ // (sum over every facet)
+ inline typename DerivedV::Scalar winding_number_all(const Point & p) const;
+ // Same as above, but always computes using sum over tessllated boundary
+ inline typename DerivedV::Scalar winding_number_boundary(const Point & p) const;
+ //// Same as winding_number above, but if max_simple_abs_winding_number is
+ //// less than some threshold min_max_w just return 0 (colloquially the "fast
+ //// multipole method)
+ ////
+ ////
+ //// Inputs:
+ //// p query point
+ //// min_max_w minimum max simple w to be processed
+ //// Returns approximate winding number
+ //double winding_number_approx_simple(
+ // const Point & p,
+ // const double min_max_w);
+ // Print contents of Tree
+ //
+ // Optional input:
+ // tab tab to show depth
+ inline void print(const char * tab="");
+ // Determine max absolute winding number
+ //
+ // Inputs:
+ // p query point
+ // Returns max winding number of
+ inline virtual typename DerivedV::Scalar max_abs_winding_number(const Point & p) const;
+ // Same as above, but stronger assumptions on (V,F). Assumes (V,F) is a
+ // simple polyhedron
+ inline virtual typename DerivedV::Scalar max_simple_abs_winding_number(const Point & p) const;
+ // Compute or read cached winding number for point p with respect to mesh
+ // in bounding box, recursing according to approximation criteria
+ //
+ // Inputs:
+ // p query point
+ // that WindingNumberTree containing mesh w.r.t. which we're computing w.n.
+ // Returns cached winding number
+ inline virtual typename DerivedV::Scalar cached_winding_number(const WindingNumberTree & that, const Point & p) const;
+ };
+}
+
+// Implementation
+
+#include "WindingNumberTree.h"
+#include "winding_number.h"
+#include "triangle_fan.h"
+#include "exterior_edges.h"
+
+#include <igl/PI.h>
+#include <igl/remove_duplicate_vertices.h>
+
+#include <iostream>
+#include <limits>
+
+//template <typename Point, typename DerivedV, typename DerivedF>
+//WindingNumberMethod WindingNumberTree<Point,DerivedV,DerivedF>::method = EXACT_WINDING_NUMBER_METHOD;
+//template <typename Point, typename DerivedV, typename DerivedF>
+//double WindingNumberTree<Point,DerivedV,DerivedF>::min_max_w = 0;
+template <typename Point, typename DerivedV, typename DerivedF>
+std::map< std::pair<const igl::WindingNumberTree<Point,DerivedV,DerivedF>*,const igl::WindingNumberTree<Point,DerivedV,DerivedF>*>, typename DerivedV::Scalar>
+ igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached;
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree():
+ method(EXACT_WINDING_NUMBER_METHOD),
+ parent(NULL),
+ V(dummyV),
+ SV(),
+ F(),
+ //boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
+ cap(),
+ radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
+ center(0,0,0)
+{
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
+ const Eigen::MatrixBase<DerivedV> & _V,
+ const Eigen::MatrixBase<DerivedF> & _F):
+ method(EXACT_WINDING_NUMBER_METHOD),
+ parent(NULL),
+ V(dummyV),
+ SV(),
+ F(),
+ //boundary(igl::boundary_facets<Eigen::MatrixXi,Eigen::MatrixXi>(F))
+ cap(),
+ radius(std::numeric_limits<typename DerivedV::Scalar>::infinity()),
+ center(0,0,0)
+{
+ set_mesh(_V,_F);
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_mesh(
+ const Eigen::MatrixBase<DerivedV> & _V,
+ const Eigen::MatrixBase<DerivedF> & _F)
+{
+ using namespace std;
+ // Remove any exactly duplicate vertices
+ // Q: Can this ever increase the complexity of the boundary?
+ // Q: Would we gain even more by remove almost exactly duplicate vertices?
+ MatrixXF SF,SVI,SVJ;
+ igl::remove_duplicate_vertices(_V,_F,0.0,SV,SVI,SVJ,F);
+ triangle_fan(igl::exterior_edges(F),cap);
+ V = SV;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::WindingNumberTree(
+ const igl::WindingNumberTree<Point,DerivedV,DerivedF> & parent,
+ const Eigen::MatrixBase<DerivedF> & _F):
+ method(parent.method),
+ parent(&parent),
+ V(parent.V),
+ SV(),
+ F(_F),
+ cap(triangle_fan(igl::exterior_edges(_F)))
+{
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline igl::WindingNumberTree<Point,DerivedV,DerivedF>::~WindingNumberTree()
+{
+ delete_children();
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::delete_children()
+{
+ using namespace std;
+ // Delete children
+ typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
+ while(cit != children.end())
+ {
+ // clear the memory of this item
+ delete (* cit);
+ // erase from list, returns next element in iterator
+ cit = children.erase(cit);
+ }
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::set_method(const WindingNumberMethod & m)
+{
+ this->method = m;
+ for(auto child : children)
+ {
+ child->set_method(m);
+ }
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline const DerivedV & igl::WindingNumberTree<Point,DerivedV,DerivedF>::getV() const
+{
+ return V;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
+ igl::WindingNumberTree<Point,DerivedV,DerivedF>::getF() const
+{
+ return F;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline const typename igl::WindingNumberTree<Point,DerivedV,DerivedF>::MatrixXF&
+ igl::WindingNumberTree<Point,DerivedV,DerivedF>::getcap() const
+{
+ return cap;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::grow()
+{
+ // Don't grow
+ return;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline bool igl::WindingNumberTree<Point,DerivedV,DerivedF>::inside(const Point & /*p*/) const
+{
+ return true;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number(const Point & p) const
+{
+ using namespace std;
+ //cout<<"+"<<boundary.rows();
+ // If inside then we need to be careful
+ if(inside(p))
+ {
+ // If not a leaf then recurse
+ if(children.size()>0)
+ {
+ // Recurse on each child and accumulate
+ typename DerivedV::Scalar sum = 0;
+ for(
+ typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
+ cit != children.end();
+ cit++)
+ {
+ switch(method)
+ {
+ case EXACT_WINDING_NUMBER_METHOD:
+ sum += (*cit)->winding_number(p);
+ break;
+ case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
+ case APPROX_CACHE_WINDING_NUMBER_METHOD:
+ //if((*cit)->max_simple_abs_winding_number(p) > min_max_w)
+ //{
+ sum += (*cit)->winding_number(p);
+ //}
+ break;
+ default:
+ assert(false);
+ break;
+ }
+ }
+ return sum;
+ }else
+ {
+ return winding_number_all(p);
+ }
+ }else{
+ // Otherwise we can just consider boundary
+ // Q: If we using the "multipole" method should we also subdivide the
+ // boundary case?
+ if((cap.rows() - 2) < F.rows())
+ {
+ switch(method)
+ {
+ case EXACT_WINDING_NUMBER_METHOD:
+ return winding_number_boundary(p);
+ case APPROX_SIMPLE_WINDING_NUMBER_METHOD:
+ {
+ typename DerivedV::Scalar dist = (p-center).norm();
+ // Radius is already an overestimate of inside
+ if(dist>1.0*radius)
+ {
+ return 0;
+ }else
+ {
+ return winding_number_boundary(p);
+ }
+ }
+ case APPROX_CACHE_WINDING_NUMBER_METHOD:
+ {
+ return parent->cached_winding_number(*this,p);
+ }
+ default: assert(false);break;
+ }
+ }else
+ {
+ // doesn't pay off to use boundary
+ return winding_number_all(p);
+ }
+ }
+ return 0;
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+ igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_all(const Point & p) const
+{
+ return igl::winding_number(V,F,p);
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_boundary(const Point & p) const
+{
+ using namespace Eigen;
+ using namespace std;
+ return igl::winding_number(V,cap,p);
+}
+
+//template <typename Point, typename DerivedV, typename DerivedF>
+//inline double igl::WindingNumberTree<Point,DerivedV,DerivedF>::winding_number_approx_simple(
+// const Point & p,
+// const double min_max_w)
+//{
+// using namespace std;
+// if(max_simple_abs_winding_number(p) > min_max_w)
+// {
+// return winding_number(p);
+// }else
+// {
+// cout<<"Skipped! "<<max_simple_abs_winding_number(p)<<"<"<<min_max_w<<endl;
+// return 0;
+// }
+//}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline void igl::WindingNumberTree<Point,DerivedV,DerivedF>::print(const char * tab)
+{
+ using namespace std;
+ // Print all facets
+ cout<<tab<<"["<<endl<<F<<endl<<"]";
+ // Print children
+ for(
+ typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::iterator cit = children.begin();
+ cit != children.end();
+ cit++)
+ {
+ cout<<","<<endl;
+ (*cit)->print((string(tab)+"").c_str());
+ }
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_abs_winding_number(const Point & /*p*/) const
+{
+ return std::numeric_limits<typename DerivedV::Scalar>::infinity();
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+igl::WindingNumberTree<Point,DerivedV,DerivedF>::max_simple_abs_winding_number(
+ const Point & /*p*/) const
+{
+ using namespace std;
+ return numeric_limits<typename DerivedV::Scalar>::infinity();
+}
+
+template <typename Point, typename DerivedV, typename DerivedF>
+inline typename DerivedV::Scalar
+igl::WindingNumberTree<Point,DerivedV,DerivedF>::cached_winding_number(
+ const igl::WindingNumberTree<Point,DerivedV,DerivedF> & that,
+ const Point & p) const
+{
+ using namespace std;
+ // Simple metric for `is_far`
+ //
+ // this that
+ // --------
+ // ----- / | \ .
+ // / r \ / R \ .
+ // | p ! | | ! |
+ // \_____/ \ /
+ // \________/
+ //
+ //
+ // a = angle formed by trapazoid formed by raising sides with lengths r and R
+ // at respective centers.
+ //
+ // a = atan2(R-r,d), where d is the distance between centers
+
+ // That should be bigger (what about parent? what about sister?)
+ bool is_far = this->radius<that.radius;
+ if(is_far)
+ {
+ typename DerivedV::Scalar a = atan2(
+ that.radius - this->radius,
+ (that.center - this->center).norm());
+ assert(a>0);
+ is_far = (a<PI/8.0);
+ }
+
+ if(is_far)
+ {
+ // Not implemented yet
+ pair<const WindingNumberTree*,const WindingNumberTree*> this_that(this,&that);
+ // Need to compute it for first time?
+ if(cached.count(this_that)==0)
+ {
+ cached[this_that] =
+ that.winding_number_boundary(this->center);
+ }
+ return cached[this_that];
+ }else if(children.size() == 0)
+ {
+ // not far and hierarchy ended too soon: can't use cache
+ return that.winding_number_boundary(p);
+ }else
+ {
+ for(
+ typename list<WindingNumberTree<Point,DerivedV,DerivedF>* >::const_iterator cit = children.begin();
+ cit != children.end();
+ cit++)
+ {
+ if((*cit)->inside(p))
+ {
+ return (*cit)->cached_winding_number(that,p);
+ }
+ }
+ // Not inside any children? This can totally happen because bounding boxes
+ // are set to bound contained facets. So sibilings may overlap and their
+ // union may not contain their parent (though, their union is certainly a
+ // subset of their parent).
+ assert(false);
+ }
+ return 0;
+}
+
+// Explicit instantiation of static variable
+template <
+ typename Point,
+ typename DerivedV,
+ typename DerivedF >
+DerivedV igl::WindingNumberTree<Point,DerivedV,DerivedF>::dummyV;
+
+#endif
diff --git a/xs/src/igl/ZERO.h b/xs/src/igl/ZERO.h
new file mode 100644
index 000000000..bd2829905
--- /dev/null
+++ b/xs/src/igl/ZERO.h
@@ -0,0 +1,21 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ZERO_H
+#define IGL_ZERO_H
+namespace igl
+{
+ // Often one needs a reference to a dummy variable containing zero as its
+ // value, for example when using AntTweakBar's
+ // TwSetParam( "3D View", "opened", TW_PARAM_INT32, 1, &INT_ZERO);
+ const char CHAR_ZERO = 0;
+ const int INT_ZERO = 0;
+ const unsigned int UNSIGNED_INT_ZERO = 0;
+ const double DOUBLE_ZERO = 0;
+ const float FLOAT_ZERO = 0;
+}
+#endif
diff --git a/xs/src/igl/active_set.cpp b/xs/src/igl/active_set.cpp
new file mode 100755
index 000000000..fd5dfba88
--- /dev/null
+++ b/xs/src/igl/active_set.cpp
@@ -0,0 +1,370 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "active_set.h"
+#include "min_quad_with_fixed.h"
+#include "slice.h"
+#include "slice_into.h"
+#include "cat.h"
+//#include "matlab_format.h"
+
+#include <iostream>
+#include <limits>
+#include <algorithm>
+
+template <
+ typename AT,
+ typename DerivedB,
+ typename Derivedknown,
+ typename DerivedY,
+ typename AeqT,
+ typename DerivedBeq,
+ typename AieqT,
+ typename DerivedBieq,
+ typename Derivedlx,
+ typename Derivedux,
+ typename DerivedZ
+ >
+IGL_INLINE igl::SolverStatus igl::active_set(
+ const Eigen::SparseMatrix<AT>& A,
+ const Eigen::PlainObjectBase<DerivedB> & B,
+ const Eigen::PlainObjectBase<Derivedknown> & known,
+ const Eigen::PlainObjectBase<DerivedY> & Y,
+ const Eigen::SparseMatrix<AeqT>& Aeq,
+ const Eigen::PlainObjectBase<DerivedBeq> & Beq,
+ const Eigen::SparseMatrix<AieqT>& Aieq,
+ const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
+ const Eigen::PlainObjectBase<Derivedlx> & p_lx,
+ const Eigen::PlainObjectBase<Derivedux> & p_ux,
+ const igl::active_set_params & params,
+ Eigen::PlainObjectBase<DerivedZ> & Z
+ )
+{
+//#define ACTIVE_SET_CPP_DEBUG
+#if defined(ACTIVE_SET_CPP_DEBUG) && !defined(_MSC_VER)
+# warning "ACTIVE_SET_CPP_DEBUG"
+#endif
+ using namespace Eigen;
+ using namespace std;
+ SolverStatus ret = SOLVER_STATUS_ERROR;
+ const int n = A.rows();
+ assert(n == A.cols() && "A must be square");
+ // Discard const qualifiers
+ //if(B.size() == 0)
+ //{
+ // B = DerivedB::Zero(n,1);
+ //}
+ assert(n == B.rows() && "B.rows() must match A.rows()");
+ assert(B.cols() == 1 && "B must be a column vector");
+ assert(Y.cols() == 1 && "Y must be a column vector");
+ assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.cols() == n);
+ assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.rows() == Beq.rows());
+ assert((Aeq.size() == 0 && Beq.size() == 0) || Beq.cols() == 1);
+ assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.cols() == n);
+ assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.rows() == Bieq.rows());
+ assert((Aieq.size() == 0 && Bieq.size() == 0) || Bieq.cols() == 1);
+ Eigen::Matrix<typename Derivedlx::Scalar,Eigen::Dynamic,1> lx;
+ Eigen::Matrix<typename Derivedux::Scalar,Eigen::Dynamic,1> ux;
+ if(p_lx.size() == 0)
+ {
+ lx = Derivedlx::Constant(
+ n,1,-numeric_limits<typename Derivedlx::Scalar>::max());
+ }else
+ {
+ lx = p_lx;
+ }
+ if(p_ux.size() == 0)
+ {
+ ux = Derivedux::Constant(
+ n,1,numeric_limits<typename Derivedux::Scalar>::max());
+ }else
+ {
+ ux = p_ux;
+ }
+ assert(lx.rows() == n && "lx must have n rows");
+ assert(ux.rows() == n && "ux must have n rows");
+ assert(ux.cols() == 1 && "lx must be a column vector");
+ assert(lx.cols() == 1 && "ux must be a column vector");
+ assert((ux.array()-lx.array()).minCoeff() > 0 && "ux(i) must be > lx(i)");
+ if(Z.size() != 0)
+ {
+ // Initial guess should have correct size
+ assert(Z.rows() == n && "Z must have n rows");
+ assert(Z.cols() == 1 && "Z must be a column vector");
+ }
+ assert(known.cols() == 1 && "known must be a column vector");
+ // Number of knowns
+ const int nk = known.size();
+
+ // Initialize active sets
+ typedef int BOOL;
+#define TRUE 1
+#define FALSE 0
+ Matrix<BOOL,Dynamic,1> as_lx = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
+ Matrix<BOOL,Dynamic,1> as_ux = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
+ Matrix<BOOL,Dynamic,1> as_ieq = Matrix<BOOL,Dynamic,1>::Constant(Aieq.rows(),1,FALSE);
+
+ // Keep track of previous Z for comparison
+ DerivedZ old_Z;
+ old_Z = DerivedZ::Constant(
+ n,1,numeric_limits<typename DerivedZ::Scalar>::max());
+
+ int iter = 0;
+ while(true)
+ {
+#ifdef ACTIVE_SET_CPP_DEBUG
+ cout<<"Iteration: "<<iter<<":"<<endl;
+ cout<<" pre"<<endl;
+#endif
+ // FIND BREACHES OF CONSTRAINTS
+ int new_as_lx = 0;
+ int new_as_ux = 0;
+ int new_as_ieq = 0;
+ if(Z.size() > 0)
+ {
+ for(int z = 0;z < n;z++)
+ {
+ if(Z(z) < lx(z))
+ {
+ new_as_lx += (as_lx(z)?0:1);
+ //new_as_lx++;
+ as_lx(z) = TRUE;
+ }
+ if(Z(z) > ux(z))
+ {
+ new_as_ux += (as_ux(z)?0:1);
+ //new_as_ux++;
+ as_ux(z) = TRUE;
+ }
+ }
+ if(Aieq.rows() > 0)
+ {
+ DerivedZ AieqZ;
+ AieqZ = Aieq*Z;
+ for(int a = 0;a<Aieq.rows();a++)
+ {
+ if(AieqZ(a) > Bieq(a))
+ {
+ new_as_ieq += (as_ieq(a)?0:1);
+ as_ieq(a) = TRUE;
+ }
+ }
+ }
+#ifdef ACTIVE_SET_CPP_DEBUG
+ cout<<" new_as_lx: "<<new_as_lx<<endl;
+ cout<<" new_as_ux: "<<new_as_ux<<endl;
+#endif
+ const double diff = (Z-old_Z).squaredNorm();
+#ifdef ACTIVE_SET_CPP_DEBUG
+ cout<<"diff: "<<diff<<endl;
+#endif
+ if(diff < params.solution_diff_threshold)
+ {
+ ret = SOLVER_STATUS_CONVERGED;
+ break;
+ }
+ old_Z = Z;
+ }
+
+ const int as_lx_count = std::count(as_lx.data(),as_lx.data()+n,TRUE);
+ const int as_ux_count = std::count(as_ux.data(),as_ux.data()+n,TRUE);
+ const int as_ieq_count =
+ std::count(as_ieq.data(),as_ieq.data()+as_ieq.size(),TRUE);
+#ifndef NDEBUG
+ {
+ int count = 0;
+ for(int a = 0;a<as_ieq.size();a++)
+ {
+ if(as_ieq(a))
+ {
+ assert(as_ieq(a) == TRUE);
+ count++;
+ }
+ }
+ assert(as_ieq_count == count);
+ }
+#endif
+
+ // PREPARE FIXED VALUES
+ Derivedknown known_i;
+ known_i.resize(nk + as_lx_count + as_ux_count,1);
+ DerivedY Y_i;
+ Y_i.resize(nk + as_lx_count + as_ux_count,1);
+ {
+ known_i.block(0,0,known.rows(),known.cols()) = known;
+ Y_i.block(0,0,Y.rows(),Y.cols()) = Y;
+ int k = nk;
+ // Then all lx
+ for(int z = 0;z < n;z++)
+ {
+ if(as_lx(z))
+ {
+ known_i(k) = z;
+ Y_i(k) = lx(z);
+ k++;
+ }
+ }
+ // Finally all ux
+ for(int z = 0;z < n;z++)
+ {
+ if(as_ux(z))
+ {
+ known_i(k) = z;
+ Y_i(k) = ux(z);
+ k++;
+ }
+ }
+ assert(k==Y_i.size());
+ assert(k==known_i.size());
+ }
+ //cout<<matlab_format((known_i.array()+1).eval(),"known_i")<<endl;
+ // PREPARE EQUALITY CONSTRAINTS
+ VectorXi as_ieq_list(as_ieq_count,1);
+ // Gather active constraints and resp. rhss
+ DerivedBeq Beq_i;
+ Beq_i.resize(Beq.rows()+as_ieq_count,1);
+ Beq_i.head(Beq.rows()) = Beq;
+ {
+ int k =0;
+ for(int a=0;a<as_ieq.size();a++)
+ {
+ if(as_ieq(a))
+ {
+ assert(k<as_ieq_list.size());
+ as_ieq_list(k)=a;
+ Beq_i(Beq.rows()+k,0) = Bieq(k,0);
+ k++;
+ }
+ }
+ assert(k == as_ieq_count);
+ }
+ // extract active constraint rows
+ SparseMatrix<AeqT> Aeq_i,Aieq_i;
+ slice(Aieq,as_ieq_list,1,Aieq_i);
+ // Append to equality constraints
+ cat(1,Aeq,Aieq_i,Aeq_i);
+
+
+ min_quad_with_fixed_data<AT> data;
+#ifndef NDEBUG
+ {
+ // NO DUPES!
+ Matrix<BOOL,Dynamic,1> fixed = Matrix<BOOL,Dynamic,1>::Constant(n,1,FALSE);
+ for(int k = 0;k<known_i.size();k++)
+ {
+ assert(!fixed[known_i(k)]);
+ fixed[known_i(k)] = TRUE;
+ }
+ }
+#endif
+
+ DerivedZ sol;
+ if(known_i.size() == A.rows())
+ {
+ // Everything's fixed?
+#ifdef ACTIVE_SET_CPP_DEBUG
+ cout<<" everything's fixed."<<endl;
+#endif
+ Z.resize(A.rows(),Y_i.cols());
+ slice_into(Y_i,known_i,1,Z);
+ sol.resize(0,Y_i.cols());
+ assert(Aeq_i.rows() == 0 && "All fixed but linearly constrained");
+ }else
+ {
+#ifdef ACTIVE_SET_CPP_DEBUG
+ cout<<" min_quad_with_fixed_precompute"<<endl;
+#endif
+ if(!min_quad_with_fixed_precompute(A,known_i,Aeq_i,params.Auu_pd,data))
+ {
+ cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
+ if(iter > 0 && Aeq_i.rows() > Aeq.rows())
+ {
+ cerr<<" *Are you sure rows of [Aeq;Aieq] are linearly independent?*"<<
+ endl;
+ }
+ ret = SOLVER_STATUS_ERROR;
+ break;
+ }
+#ifdef ACTIVE_SET_CPP_DEBUG
+ cout<<" min_quad_with_fixed_solve"<<endl;
+#endif
+ if(!min_quad_with_fixed_solve(data,B,Y_i,Beq_i,Z,sol))
+ {
+ cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
+ ret = SOLVER_STATUS_ERROR;
+ break;
+ }
+ //cout<<matlab_format((Aeq*Z-Beq).eval(),"cr")<<endl;
+ //cout<<matlab_format(Z,"Z")<<endl;
+#ifdef ACTIVE_SET_CPP_DEBUG
+ cout<<" post"<<endl;
+#endif
+ // Computing Lagrange multipliers needs to be adjusted slightly if A is not symmetric
+ assert(data.Auu_sym);
+ }
+
+ // Compute Lagrange multiplier values for known_i
+ SparseMatrix<AT> Ak;
+ // Slow
+ slice(A,known_i,1,Ak);
+ DerivedB Bk;
+ slice(B,known_i,Bk);
+ MatrixXd Lambda_known_i = -(0.5*Ak*Z + 0.5*Bk);
+ // reverse the lambda values for lx
+ Lambda_known_i.block(nk,0,as_lx_count,1) =
+ (-1*Lambda_known_i.block(nk,0,as_lx_count,1)).eval();
+
+ // Extract Lagrange multipliers for Aieq_i (always at back of sol)
+ VectorXd Lambda_Aieq_i(Aieq_i.rows(),1);
+ for(int l = 0;l<Aieq_i.rows();l++)
+ {
+ Lambda_Aieq_i(Aieq_i.rows()-1-l) = sol(sol.rows()-1-l);
+ }
+
+ // Remove from active set
+ for(int l = 0;l<as_lx_count;l++)
+ {
+ if(Lambda_known_i(nk + l) < params.inactive_threshold)
+ {
+ as_lx(known_i(nk + l)) = FALSE;
+ }
+ }
+ for(int u = 0;u<as_ux_count;u++)
+ {
+ if(Lambda_known_i(nk + as_lx_count + u) <
+ params.inactive_threshold)
+ {
+ as_ux(known_i(nk + as_lx_count + u)) = FALSE;
+ }
+ }
+ for(int a = 0;a<as_ieq_count;a++)
+ {
+ if(Lambda_Aieq_i(a) < params.inactive_threshold)
+ {
+ as_ieq(as_ieq_list(a)) = FALSE;
+ }
+ }
+
+ iter++;
+ //cout<<iter<<endl;
+ if(params.max_iter>0 && iter>=params.max_iter)
+ {
+ ret = SOLVER_STATUS_MAX_ITER;
+ break;
+ }
+
+ }
+
+ return ret;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/active_set.h b/xs/src/igl/active_set.h
new file mode 100644
index 000000000..b82d0e52b
--- /dev/null
+++ b/xs/src/igl/active_set.h
@@ -0,0 +1,111 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ACTIVE_SET_H
+#define IGL_ACTIVE_SET_H
+
+#include "igl_inline.h"
+#include "SolverStatus.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ struct active_set_params;
+ // Known Bugs: rows of [Aeq;Aieq] **must** be linearly independent. Should be
+ // using QR decomposition otherwise:
+ // http://www.okstate.edu/sas/v8/sashtml/ormp/chap5/sect32.htm
+ //
+ // ACTIVE_SET Minimize quadratic energy
+ //
+ // 0.5*Z'*A*Z + Z'*B + C with constraints
+ //
+ // that Z(known) = Y, optionally also subject to the constraints Aeq*Z = Beq,
+ // and further optionally subject to the linear inequality constraints that
+ // Aieq*Z <= Bieq and constant inequality constraints lx <= x <= ux
+ //
+ // Inputs:
+ // A n by n matrix of quadratic coefficients
+ // B n by 1 column of linear coefficients
+ // known list of indices to known rows in Z
+ // Y list of fixed values corresponding to known rows in Z
+ // Aeq meq by n list of linear equality constraint coefficients
+ // Beq meq by 1 list of linear equality constraint constant values
+ // Aieq mieq by n list of linear inequality constraint coefficients
+ // Bieq mieq by 1 list of linear inequality constraint constant values
+ // lx n by 1 list of lower bounds [] implies -Inf
+ // ux n by 1 list of upper bounds [] implies Inf
+ // params struct of additional parameters (see below)
+ // Z if not empty, is taken to be an n by 1 list of initial guess values
+ // (see output)
+ // Outputs:
+ // Z n by 1 list of solution values
+ // Returns true on success, false on error
+ //
+ // Benchmark: For a harmonic solve on a mesh with 325K facets, matlab 2.2
+ // secs, igl/min_quad_with_fixed.h 7.1 secs
+ //
+ template <
+ typename AT,
+ typename DerivedB,
+ typename Derivedknown,
+ typename DerivedY,
+ typename AeqT,
+ typename DerivedBeq,
+ typename AieqT,
+ typename DerivedBieq,
+ typename Derivedlx,
+ typename Derivedux,
+ typename DerivedZ
+ >
+ IGL_INLINE igl::SolverStatus active_set(
+ const Eigen::SparseMatrix<AT>& A,
+ const Eigen::PlainObjectBase<DerivedB> & B,
+ const Eigen::PlainObjectBase<Derivedknown> & known,
+ const Eigen::PlainObjectBase<DerivedY> & Y,
+ const Eigen::SparseMatrix<AeqT>& Aeq,
+ const Eigen::PlainObjectBase<DerivedBeq> & Beq,
+ const Eigen::SparseMatrix<AieqT>& Aieq,
+ const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
+ const Eigen::PlainObjectBase<Derivedlx> & lx,
+ const Eigen::PlainObjectBase<Derivedux> & ux,
+ const igl::active_set_params & params,
+ Eigen::PlainObjectBase<DerivedZ> & Z
+ );
+};
+
+#include "EPS.h"
+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}
+ bool Auu_pd;
+ int max_iter;
+ double inactive_threshold;
+ double constraint_threshold;
+ double solution_diff_threshold;
+ active_set_params():
+ Auu_pd(false),
+ max_iter(100),
+ inactive_threshold(igl::DOUBLE_EPS),
+ constraint_threshold(igl::DOUBLE_EPS),
+ solution_diff_threshold(igl::DOUBLE_EPS)
+ {};
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "active_set.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/adjacency_list.cpp b/xs/src/igl/adjacency_list.cpp
new file mode 100644
index 000000000..1fb61ebf1
--- /dev/null
+++ b/xs/src/igl/adjacency_list.cpp
@@ -0,0 +1,168 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "adjacency_list.h"
+
+#include "verbose.h"
+#include <algorithm>
+
+template <typename Index, typename IndexVector>
+IGL_INLINE void igl::adjacency_list(
+ const Eigen::PlainObjectBase<Index> & F,
+ std::vector<std::vector<IndexVector> >& A,
+ bool sorted)
+{
+ A.clear();
+ A.resize(F.maxCoeff()+1);
+
+ // Loop over faces
+ for(int i = 0;i<F.rows();i++)
+ {
+ // Loop over this face
+ for(int j = 0;j<F.cols();j++)
+ {
+ // Get indices of edge: s --> d
+ int s = F(i,j);
+ int d = F(i,(j+1)%F.cols());
+ A.at(s).push_back(d);
+ A.at(d).push_back(s);
+ }
+ }
+
+ // Remove duplicates
+ for(int i=0; i<(int)A.size();++i)
+ {
+ std::sort(A[i].begin(), A[i].end());
+ A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end());
+ }
+
+ // If needed, sort every VV
+ if (sorted)
+ {
+ // Loop over faces
+
+ // for every vertex v store a set of ordered edges not incident to v that belongs to triangle incident on v.
+ std::vector<std::vector<std::vector<int> > > SR;
+ SR.resize(A.size());
+
+ for(int i = 0;i<F.rows();i++)
+ {
+ // Loop over this face
+ for(int j = 0;j<F.cols();j++)
+ {
+ // Get indices of edge: s --> d
+ int s = F(i,j);
+ int d = F(i,(j+1)%F.cols());
+ // Get index of opposing vertex v
+ int v = F(i,(j+2)%F.cols());
+
+ std::vector<int> e(2);
+ e[0] = d;
+ e[1] = v;
+ SR[s].push_back(e);
+ }
+ }
+
+ for(int v=0; v<(int)SR.size();++v)
+ {
+ std::vector<IndexVector>& vv = A.at(v);
+ std::vector<std::vector<int> >& sr = SR[v];
+
+ std::vector<std::vector<int> > pn = sr;
+
+ // Compute previous/next for every element in sr
+ for(int i=0;i<(int)sr.size();++i)
+ {
+ int a = sr[i][0];
+ int b = sr[i][1];
+
+ // search for previous
+ int p = -1;
+ for(int j=0;j<(int)sr.size();++j)
+ if(sr[j][1] == a)
+ p = j;
+ pn[i][0] = p;
+
+ // search for next
+ int n = -1;
+ for(int j=0;j<(int)sr.size();++j)
+ if(sr[j][0] == b)
+ n = j;
+ pn[i][1] = n;
+
+ }
+
+ // assume manifoldness (look for beginning of a single chain)
+ int c = 0;
+ for(int j=0; j<=(int)sr.size();++j)
+ if (pn[c][0] != -1)
+ c = pn[c][0];
+
+ if (pn[c][0] == -1) // border case
+ {
+ // finally produce the new vv relation
+ for(int j=0; j<(int)sr.size();++j)
+ {
+ vv[j] = sr[c][0];
+ if (pn[c][1] != -1)
+ c = pn[c][1];
+ }
+ vv.back() = sr[c][1];
+ }
+ else
+ {
+ // finally produce the new vv relation
+ for(int j=0; j<(int)sr.size();++j)
+ {
+ vv[j] = sr[c][0];
+
+ c = pn[c][1];
+ }
+ }
+ }
+ }
+}
+
+template <typename Index>
+IGL_INLINE void igl::adjacency_list(
+ const std::vector<std::vector<Index> > & F,
+ std::vector<std::vector<Index> >& A)
+{
+ A.clear();
+ A.resize(F.maxCoeff()+1);
+
+ // Loop over faces
+ for(int i = 0;i<F.size();i++)
+ {
+ // Loop over this face
+ for(int j = 0;j<F[i].size();j++)
+ {
+ // Get indices of edge: s --> d
+ int s = F(i,j);
+ int d = F(i,(j+1)%F[i].size());
+ A.at(s).push_back(d);
+ A.at(d).push_back(s);
+ }
+ }
+
+ // Remove duplicates
+ for(int i=0; i<(int)A.size();++i)
+ {
+ std::sort(A[i].begin(), A[i].end());
+ A[i].erase(std::unique(A[i].begin(), A[i].end()), A[i].end());
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::adjacency_list<Eigen::Matrix<int, -1, 2, 0, -1, 2>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
+// generated by autoexplicit.sh
+template void igl::adjacency_list<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
+template void igl::adjacency_list<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, bool);
+#endif
diff --git a/xs/src/igl/adjacency_list.h b/xs/src/igl/adjacency_list.h
new file mode 100644
index 000000000..7438cde42
--- /dev/null
+++ b/xs/src/igl/adjacency_list.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ADJACENCY_LIST_H
+#define IGL_ADJACENCY_LIST_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+#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
+ template <typename Index, typename IndexVector>
+ IGL_INLINE void adjacency_list(
+ const Eigen::PlainObjectBase<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.
+ template <typename Index>
+ IGL_INLINE void adjacency_list(
+ const std::vector<std::vector<Index> > & F,
+ std::vector<std::vector<Index> >& A);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "adjacency_list.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/adjacency_matrix.cpp b/xs/src/igl/adjacency_matrix.cpp
new file mode 100644
index 000000000..f6db955c2
--- /dev/null
+++ b/xs/src/igl/adjacency_matrix.cpp
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "adjacency_matrix.h"
+
+#include "verbose.h"
+
+#include <vector>
+
+template <typename DerivedF, typename T>
+IGL_INLINE void igl::adjacency_matrix(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<T>& A)
+{
+ using namespace std;
+ using namespace Eigen;
+ typedef typename DerivedF::Scalar Index;
+
+ typedef Triplet<T> IJV;
+ vector<IJV > ijv;
+ ijv.reserve(F.size()*2);
+ // Loop over **simplex** (i.e., **not quad**)
+ for(int i = 0;i<F.rows();i++)
+ {
+ // Loop over this **simplex**
+ for(int j = 0;j<F.cols();j++)
+ for(int k = j+1;k<F.cols();k++)
+ {
+ // Get indices of edge: s --> d
+ Index s = F(i,j);
+ Index d = F(i,k);
+ ijv.push_back(IJV(s,d,1));
+ ijv.push_back(IJV(d,s,1));
+ }
+ }
+
+ const Index n = F.maxCoeff()+1;
+ A.resize(n,n);
+ switch(F.cols())
+ {
+ case 3:
+ A.reserve(6*(F.maxCoeff()+1));
+ break;
+ case 4:
+ A.reserve(26*(F.maxCoeff()+1));
+ break;
+ }
+ A.setFromTriplets(ijv.begin(),ijv.end());
+
+ // Force all non-zeros to be one
+
+ // Iterate over outside
+ for(int k=0; k<A.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<T>::InnerIterator it (A,k); it; ++it)
+ {
+ assert(it.value() != 0);
+ A.coeffRef(it.row(),it.col()) = 1;
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<bool, 0, int>&);
+template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::adjacency_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<int, 0, int>&);
+#endif
diff --git a/xs/src/igl/adjacency_matrix.h b/xs/src/igl/adjacency_matrix.h
new file mode 100644
index 000000000..b117bccf7
--- /dev/null
+++ b/xs/src/igl/adjacency_matrix.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ADJACENCY_MATRIX_H
+#define IGL_ADJACENCY_MATRIX_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Constructs the graph adjacency matrix of a given mesh (V,F)
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // F #F by dim list of mesh simplices
+ // Outputs:
+ // A max(F) by max(F) cotangent matrix, each row i corresponding to V(i,:)
+ //
+ // Example:
+ // // Mesh in (V,F)
+ // Eigen::SparseMatrix<double> A;
+ // adjacency_matrix(F,A);
+ // // sum each row
+ // SparseVector<double> Asum;
+ // sum(A,1,Asum);
+ // // Convert row sums into diagonal of sparse matrix
+ // SparseMatrix<double> Adiag;
+ // diag(Asum,Adiag);
+ // // Build uniform laplacian
+ // SparseMatrix<double> U;
+ // U = A-Adiag;
+ //
+ // See also: edges, cotmatrix, diag
+ template <typename DerivedF, typename T>
+ IGL_INLINE void adjacency_matrix(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<T>& A);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "adjacency_matrix.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/all.cpp b/xs/src/igl/all.cpp
new file mode 100644
index 000000000..35245eacb
--- /dev/null
+++ b/xs/src/igl/all.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "all.h"
+#include "redux.h"
+
+
+template <typename AType, typename DerivedB>
+IGL_INLINE void igl::all(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB>& B)
+{
+ typedef typename DerivedB::Scalar Scalar;
+ igl::redux(A,dim,[](Scalar a, Scalar b){ return a && b!=0;},B);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
+
+
diff --git a/xs/src/igl/all.h b/xs/src/igl/all.h
new file mode 100644
index 000000000..6e84fdd52
--- /dev/null
+++ b/xs/src/igl/all.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ALL_H
+#define IGL_ALL_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#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)
+ //
+ template <typename AType, typename DerivedB>
+ IGL_INLINE void all(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB>& B);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "all.cpp"
+#endif
+#endif
+
+
diff --git a/xs/src/igl/all_edges.cpp b/xs/src/igl/all_edges.cpp
new file mode 100644
index 000000000..eabad3038
--- /dev/null
+++ b/xs/src/igl/all_edges.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "all_edges.h"
+#include "oriented_facets.h"
+
+template <typename DerivedF, typename DerivedE>
+IGL_INLINE void igl::all_edges(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E)
+{
+ return oriented_facets(F,E);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::all_edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::all_edges<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::all_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+#endif
diff --git a/xs/src/igl/all_edges.h b/xs/src/igl/all_edges.h
new file mode 100644
index 000000000..d5fe13a9a
--- /dev/null
+++ b/xs/src/igl/all_edges.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ALL_EDGES_H
+#define IGL_ALL_EDGES_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Deprecated: call oriented_facets instead.
+ //
+ // ALL_EDGES Determines all "directed edges" of a given set of simplices. For
+ // a manifold mesh, this computes all of the half-edges
+ //
+ // Inputs:
+ // F #F by simplex_size list of "faces"
+ // Outputs:
+ // E #E by simplex_size-1 list of edges
+ //
+ // Note: this is not the same as igl::edges because this includes every
+ // directed edge including repeats (meaning interior edges on a surface will
+ // show up once for each direction and non-manifold edges may appear more than
+ // once for each direction).
+ template <typename DerivedF, typename DerivedE>
+ IGL_INLINE void all_edges(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "all_edges.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/all_pairs_distances.cpp b/xs/src/igl/all_pairs_distances.cpp
new file mode 100644
index 000000000..608cf9b85
--- /dev/null
+++ b/xs/src/igl/all_pairs_distances.cpp
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "all_pairs_distances.h"
+#include <Eigen/Dense>
+
+template <typename Mat>
+IGL_INLINE void igl::all_pairs_distances(
+ const Mat & V,
+ const Mat & U,
+ const bool squared,
+ Mat & D)
+{
+ // dimension should be the same
+ assert(V.cols() == U.cols());
+ // resize output
+ D.resize(V.rows(),U.rows());
+ for(int i = 0;i<V.rows();i++)
+ {
+ for(int j=0;j<U.rows();j++)
+ {
+ D(i,j) = (V.row(i)-U.row(j)).squaredNorm();
+ if(!squared)
+ {
+ D(i,j) = sqrt(D(i,j));
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::all_pairs_distances<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, bool, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+#endif
diff --git a/xs/src/igl/all_pairs_distances.h b/xs/src/igl/all_pairs_distances.h
new file mode 100644
index 000000000..9acc1b730
--- /dev/null
+++ b/xs/src/igl/all_pairs_distances.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ALL_PAIRS_DISTANCES_H
+#define IGL_ALL_PAIRS_DISTANCES_H
+#include "igl_inline.h"
+
+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,:)
+ //
+ template <typename Mat>
+ IGL_INLINE void all_pairs_distances(
+ const Mat & V,
+ const Mat & U,
+ const bool squared,
+ Mat & D);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "all_pairs_distances.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/ambient_occlusion.cpp b/xs/src/igl/ambient_occlusion.cpp
new file mode 100644
index 000000000..343f8ae8a
--- /dev/null
+++ b/xs/src/igl/ambient_occlusion.cpp
@@ -0,0 +1,137 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ambient_occlusion.h"
+#include "random_dir.h"
+#include "ray_mesh_intersect.h"
+#include "EPS.h"
+#include "Hit.h"
+#include "parallel_for.h"
+#include <functional>
+#include <vector>
+#include <algorithm>
+
+template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::ambient_occlusion(
+ const std::function<
+ bool(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&)
+ > & shoot_ray,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ using namespace Eigen;
+ const int n = P.rows();
+ // Resize output
+ S.resize(n,1);
+ // Embree seems to be parallel when constructing but not when tracing rays
+ const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
+
+ const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
+ {
+ const Vector3f origin = P.row(p).template cast<float>();
+ const Vector3f normal = N.row(p).template cast<float>();
+ int num_hits = 0;
+ for(int s = 0;s<num_samples;s++)
+ {
+ Vector3f d = D.row(s);
+ if(d.dot(normal) < 0)
+ {
+ // reverse ray
+ d *= -1;
+ }
+ if(shoot_ray(origin,d))
+ {
+ num_hits++;
+ }
+ }
+ S(p) = (double)num_hits/(double)num_samples;
+ };
+ parallel_for(n,inner,1000);
+}
+
+template <
+ typename DerivedV,
+ int DIM,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::ambient_occlusion(
+ const igl::AABB<DerivedV,DIM> & aabb,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ const auto & shoot_ray = [&aabb,&V,&F](
+ const Eigen::Vector3f& _s,
+ const Eigen::Vector3f& dir)->bool
+ {
+ Eigen::Vector3f s = _s+1e-4*dir;
+ igl::Hit hit;
+ return aabb.intersect_ray(
+ V,
+ F,
+ s .cast<typename DerivedV::Scalar>().eval(),
+ dir.cast<typename DerivedV::Scalar>().eval(),
+ hit);
+ };
+ return ambient_occlusion(shoot_ray,P,N,num_samples,S);
+
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::ambient_occlusion(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ if(F.rows() < 100)
+ {
+ // Super naive
+ const auto & shoot_ray = [&V,&F](
+ const Eigen::Vector3f& _s,
+ const Eigen::Vector3f& dir)->bool
+ {
+ Eigen::Vector3f s = _s+1e-4*dir;
+ igl::Hit hit;
+ return ray_mesh_intersect(s,dir,V,F,hit);
+ };
+ return ambient_occlusion(shoot_ray,P,N,num_samples,S);
+ }
+ AABB<DerivedV,3> aabb;
+ aabb.init(V,F);
+ return ambient_occlusion(aabb,V,F,P,N,num_samples,S);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<bool (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/ambient_occlusion.h b/xs/src/igl/ambient_occlusion.h
new file mode 100644
index 000000000..1c173121e
--- /dev/null
+++ b/xs/src/igl/ambient_occlusion.h
@@ -0,0 +1,80 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_AMBIENT_OCCLUSION_H
+#define IGL_AMBIENT_OCCLUSION_H
+#include "igl_inline.h"
+#include "AABB.h"
+#include <Eigen/Core>
+#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)
+ //
+ template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void ambient_occlusion(
+ const std::function<
+ bool(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&)
+ > & shoot_ray,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ // Inputs:
+ // AABB axis-aligned bounding box hierarchy around (V,F)
+ template <
+ typename DerivedV,
+ int DIM,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void ambient_occlusion(
+ const igl::AABB<DerivedV,DIM> & aabb,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const 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
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void ambient_occlusion(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "ambient_occlusion.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/angular_distance.cpp b/xs/src/igl/angular_distance.cpp
new file mode 100644
index 000000000..803c290c9
--- /dev/null
+++ b/xs/src/igl/angular_distance.cpp
@@ -0,0 +1,20 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "angular_distance.h"
+#include <igl/EPS.h>
+#include <igl/PI.h>
+IGL_INLINE double igl::angular_distance(
+ const Eigen::Quaterniond & A,
+ const Eigen::Quaterniond & B)
+{
+ assert(fabs(A.norm()-1)<FLOAT_EPS && "A should be unit norm");
+ assert(fabs(B.norm()-1)<FLOAT_EPS && "B should be unit norm");
+ //// acos is always in [0,2*pi)
+ //return acos(fabs(A.dot(B)));
+ return fmod(2.*acos(A.dot(B)),2.*PI);
+}
diff --git a/xs/src/igl/angular_distance.h b/xs/src/igl/angular_distance.h
new file mode 100644
index 000000000..35b100ace
--- /dev/null
+++ b/xs/src/igl/angular_distance.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ANGULAR_DISTANCE_H
+#define IGL_ANGULAR_DISTANCE_H
+#include "igl_inline.h"
+#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
+ IGL_INLINE double angular_distance(
+ const Eigen::Quaterniond & A,
+ const Eigen::Quaterniond & B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "angular_distance.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/anttweakbar/ReAntTweakBar.cpp b/xs/src/igl/anttweakbar/ReAntTweakBar.cpp
new file mode 100644
index 000000000..3664c6bce
--- /dev/null
+++ b/xs/src/igl/anttweakbar/ReAntTweakBar.cpp
@@ -0,0 +1,934 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ReAntTweakBar.h"
+
+#include <cstdio>
+#include <cstring>
+#include <sstream>
+#include <iostream>
+#include <iomanip>
+#include <map>
+
+// GLOBAL WRAPPERS
+namespace
+{
+ std::map<
+ TwType,std::pair<const char *,std::vector<TwEnumVal> >
+ > ReTw_custom_types;
+}
+
+IGL_INLINE TwType igl::anttweakbar::ReTwDefineEnum(
+ const char *name,
+ const TwEnumVal *enumValues,
+ unsigned int nbValues)
+{
+ using namespace std;
+ // copy enum valus into vector
+ std::vector<TwEnumVal> enum_vals;
+ enum_vals.resize(nbValues);
+ for(unsigned int j = 0; j<nbValues;j++)
+ {
+ enum_vals[j] = enumValues[j];
+ }
+ TwType type = TwDefineEnum(name,enumValues,nbValues);
+
+ ReTw_custom_types[type] =
+ std::pair<const char *,std::vector<TwEnumVal> >(name,enum_vals);
+
+ return type;
+}
+
+IGL_INLINE TwType igl::anttweakbar::ReTwDefineEnumFromString(
+ const char * _Name,
+ const char * _EnumString)
+{
+ // Taken directly from TwMgr.cpp, just replace TwDefineEnum with
+ // ReTwDefineEnum
+ using namespace std;
+ {
+ if (_EnumString == NULL)
+ return ReTwDefineEnum(_Name, NULL, 0);
+
+ // split enumString
+ stringstream EnumStream(_EnumString);
+ string Label;
+ vector<string> Labels;
+ while( getline(EnumStream, Label, ',') ) {
+ // trim Label
+ size_t Start = Label.find_first_not_of(" \n\r\t");
+ size_t End = Label.find_last_not_of(" \n\r\t");
+ if( Start==string::npos || End==string::npos )
+ Label = "";
+ else
+ Label = Label.substr(Start, (End-Start)+1);
+ // store Label
+ Labels.push_back(Label);
+ }
+ // create TwEnumVal array
+ vector<TwEnumVal> Vals(Labels.size());
+ for( int i=0; i<(int)Labels.size(); i++ )
+ {
+ Vals[i].Value = i;
+ // Wrong:
+ //Vals[i].Label = Labels[i].c_str();
+ // Allocate char on heap
+ // http://stackoverflow.com/a/10050258/148668
+ char * c_label = new char[Labels[i].length()+1];
+ std::strcpy(c_label, Labels[i].c_str());
+ Vals[i].Label = c_label;
+ }
+
+ const TwType type =
+ ReTwDefineEnum(_Name, Vals.empty() ?
+ NULL :
+ &(Vals[0]), (unsigned int)Vals.size());
+ return type;
+ }
+}
+
+namespace
+{
+ struct ReTwTypeString
+ {
+ TwType type;
+ const char * type_str;
+ };
+
+ #define RETW_NUM_DEFAULT_TYPE_STRINGS 23
+ ReTwTypeString ReTwDefaultTypeStrings[RETW_NUM_DEFAULT_TYPE_STRINGS] =
+ {
+ {TW_TYPE_UNDEF,"TW_TYPE_UNDEF"},
+ {TW_TYPE_BOOLCPP,"TW_TYPE_BOOLCPP"},
+ {TW_TYPE_BOOL8,"TW_TYPE_BOOL8"},
+ {TW_TYPE_BOOL16,"TW_TYPE_BOOL16"},
+ {TW_TYPE_BOOL32,"TW_TYPE_BOOL32"},
+ {TW_TYPE_CHAR,"TW_TYPE_CHAR"},
+ {TW_TYPE_INT8,"TW_TYPE_INT8"},
+ {TW_TYPE_UINT8,"TW_TYPE_UINT8"},
+ {TW_TYPE_INT16,"TW_TYPE_INT16"},
+ {TW_TYPE_UINT16,"TW_TYPE_UINT16"},
+ {TW_TYPE_INT32,"TW_TYPE_INT32"},
+ {TW_TYPE_UINT32,"TW_TYPE_UINT32"},
+ {TW_TYPE_FLOAT,"TW_TYPE_FLOAT"},
+ {TW_TYPE_DOUBLE,"TW_TYPE_DOUBLE"},
+ {TW_TYPE_COLOR32,"TW_TYPE_COLOR32"},
+ {TW_TYPE_COLOR3F,"TW_TYPE_COLOR3F"},
+ {TW_TYPE_COLOR4F,"TW_TYPE_COLOR4F"},
+ {TW_TYPE_CDSTRING,"TW_TYPE_CDSTRING"},
+ {TW_TYPE_STDSTRING,"TW_TYPE_STDSTRING"},
+ {TW_TYPE_QUAT4F,"TW_TYPE_QUAT4F"},
+ {TW_TYPE_QUAT4D,"TW_TYPE_QUAT4D"},
+ {TW_TYPE_DIR3F,"TW_TYPE_DIR3F"},
+ {TW_TYPE_DIR3D,"TW_TYPE_DIR3D"}
+ };
+}
+
+IGL_INLINE igl::anttweakbar::ReTwBar::ReTwBar():
+ bar(NULL),
+ name(),
+ rw_items(),cb_items()
+{
+}
+
+IGL_INLINE igl::anttweakbar::ReTwBar::ReTwBar(
+ const igl::anttweakbar::ReTwBar & that):
+ bar(that.bar),
+ name(that.name),
+ rw_items(that.rw_items),
+ cb_items(that.cb_items)
+{
+}
+
+IGL_INLINE igl::anttweakbar::ReTwBar &
+igl::anttweakbar::ReTwBar::operator=(const igl::anttweakbar::ReTwBar & that)
+{
+ // check for self assignment
+ if(this != &that)
+ {
+ bar = that.bar;
+ rw_items = that.rw_items;
+ cb_items = that.cb_items;
+ }
+ return *this;
+}
+
+
+// BAR WRAPPERS
+IGL_INLINE void igl::anttweakbar::ReTwBar::TwNewBar(const char * _name)
+{
+ this->bar = ::TwNewBar(_name);
+ // Alec: This causes trouble (not sure why) in multiple applications
+ // (medit, puppet) Probably there is some sort of memory corrpution.
+ // this->name = _name;
+ // Suspiciously this also fails:
+ //this->name = "foobar";
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarRW(
+ const char *name,
+ TwType type,
+ void *var,
+ const char *def,
+ const bool record)
+{
+ int ret = ::TwAddVarRW(this->bar,name,type,var,def);
+ if(ret && record)
+ {
+ rw_items.push_back(ReTwRWItem(name,type,var));
+ }
+ return ret;
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarCB(
+ const char *name,
+ TwType type,
+ TwSetVarCallback setCallback,
+ TwGetVarCallback getCallback,
+ void *clientData,
+ const char *def,
+ const bool record)
+{
+ int ret =
+ ::TwAddVarCB(this->bar,name,type,setCallback,getCallback,clientData,def);
+ if(ret && record)
+ {
+ cb_items.push_back(ReTwCBItem(name,type,setCallback,getCallback,clientData));
+ }
+ return ret;
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddVarRO(
+ const char *name,
+ TwType type,
+ void *var,
+ const char *def)
+{
+ int ret = ::TwAddVarRO(this->bar,name,type,var,def);
+ // Read only variables are not recorded
+ //if(ret)
+ //{
+ // rw_items.push_back(ReTwRWItem(name,type,var));
+ //}
+ return ret;
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwAddButton(
+ const char *name,
+ TwButtonCallback buttonCallback,
+ void *clientData,
+ const char *def)
+{
+ int ret =
+ ::TwAddButton(this->bar,name,buttonCallback,clientData,def);
+ // buttons are not recorded
+ //if(ret)
+ //{
+ // cb_items.push_back(ReTwCBItem(name,type,setCallback,getCallback,clientData));
+ //}
+ return ret;
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwSetParam(
+ const char *varName,
+ const char *paramName,
+ TwParamValueType paramValueType,
+ unsigned int inValueCount,
+ const void *inValues)
+{
+ // For now just pass these along
+ return
+ ::TwSetParam(
+ this->bar,
+ varName,
+ paramName,
+ paramValueType,
+ inValueCount,
+ inValues);
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwGetParam(
+ const char *varName,
+ const char *paramName,
+ TwParamValueType paramValueType,
+ unsigned int outValueMaxCount,
+ void *outValues)
+{
+ return
+ ::TwGetParam(
+ this->bar,
+ varName,
+ paramName,
+ paramValueType,
+ outValueMaxCount,
+ outValues);
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwRefreshBar()
+{
+ return ::TwRefreshBar(this->bar);
+}
+
+IGL_INLINE int igl::anttweakbar::ReTwBar::TwTerminate()
+{
+ //std::cout<<"TwTerminate"<<std::endl;
+ int r = ::TwTerminate();
+ //std::cout<<" "<<r<<std::endl;
+ return r;
+}
+
+IGL_INLINE bool igl::anttweakbar::ReTwBar::save(const char *file_name)
+{
+ FILE * fp;
+ if(file_name == NULL)
+ {
+ fp = stdout;
+ }else
+ {
+ fp = fopen(file_name,"w");
+ }
+
+ if(fp == NULL)
+ {
+ printf("ERROR: not able to open %s for writing...\n",file_name);
+ return false;
+ }
+
+ // Print all RW variables
+ for(
+ std::vector<ReTwRWItem>::iterator it = rw_items.begin();
+ it != rw_items.end();
+ it++)
+ {
+ std::string s = (*it).name;
+ const char * name = s.c_str();
+ TwType type = (*it).type;
+ void * var = (*it).var;
+ fprintf(fp,"%s: %s\n",
+ name,
+ get_value_as_string(var,type).c_str());
+ }
+
+ char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
+ // Print all CB variables
+ for(
+ std::vector<ReTwCBItem>::iterator it = cb_items.begin();
+ it != cb_items.end();
+ it++)
+ {
+ const char * name = it->name.c_str();
+ TwType type = it->type;
+ //TwSetVarCallback setCallback = it->setCallback;
+ TwGetVarCallback getCallback = it->getCallback;
+ void * clientData = it->clientData;
+ // I'm not sure how to do what I want to do. getCallback needs to be sure
+ // that it can write to var. So var needs to point to a valid and big
+ // enough chunk of memory
+ getCallback(var,clientData);
+ fprintf(fp,"%s: %s\n",
+ name,
+ get_value_as_string(var,type).c_str());
+ }
+
+ fprintf(fp,"\n");
+
+ if(file_name != NULL)
+ {
+ fclose(fp);
+ }
+ // everything succeeded
+ return true;
+}
+
+IGL_INLINE std::string igl::anttweakbar::ReTwBar::get_value_as_string(
+ void * var,
+ TwType type)
+{
+ std::stringstream sstr;
+ switch(type)
+ {
+ case TW_TYPE_BOOLCPP:
+ {
+ sstr << "TW_TYPE_BOOLCPP" << " ";
+ sstr << *(static_cast<bool*>(var));
+ break;
+ }
+ case TW_TYPE_QUAT4D:
+ {
+ sstr << "TW_TYPE_QUAT4D" << " ";
+ // Q: Why does casting to double* work? shouldn't I have to cast to
+ // double**?
+ double * q = static_cast<double*>(var);
+ sstr << std::setprecision(15) << q[0] << " " << q[1] << " " << q[2] << " " << q[3];
+ break;
+ }
+ case TW_TYPE_QUAT4F:
+ {
+ sstr << "TW_TYPE_QUAT4F" << " ";
+ // Q: Why does casting to float* work? shouldn't I have to cast to
+ // float**?
+ float * q = static_cast<float*>(var);
+ sstr << q[0] << " " << q[1] << " " << q[2] << " " << q[3];
+ break;
+ }
+ case TW_TYPE_COLOR4F:
+ {
+ sstr << "TW_TYPE_COLOR4F" << " ";
+ float * c = static_cast<float*>(var);
+ sstr << c[0] << " " << c[1] << " " << c[2] << " " << c[3];
+ break;
+ }
+ case TW_TYPE_COLOR3F:
+ {
+ sstr << "TW_TYPE_COLOR3F" << " ";
+ float * c = static_cast<float*>(var);
+ sstr << c[0] << " " << c[1] << " " << c[2];
+ break;
+ }
+ case TW_TYPE_DIR3D:
+ {
+ sstr << "TW_TYPE_DIR3D" << " ";
+ double * d = static_cast<double*>(var);
+ sstr << std::setprecision(15) << d[0] << " " << d[1] << " " << d[2];
+ break;
+ }
+ case TW_TYPE_DIR3F:
+ {
+ sstr << "TW_TYPE_DIR3F" << " ";
+ float * d = static_cast<float*>(var);
+ sstr << d[0] << " " << d[1] << " " << d[2];
+ break;
+ }
+ case TW_TYPE_BOOL32:
+ {
+ sstr << "TW_TYPE_BOOL32" << " ";
+ sstr << *(static_cast<int*>(var));
+ break;
+ }
+ case TW_TYPE_UINT8:
+ {
+ sstr << "TW_TYPE_UINT8" << " ";
+ // Cast to int so that it's human readable
+ sstr << (int)*(static_cast<unsigned char*>(var));
+ break;
+ }
+ case TW_TYPE_INT32:
+ {
+ sstr << "TW_TYPE_INT32" << " ";
+ sstr << *(static_cast<int*>(var));
+ break;
+ }
+ case TW_TYPE_UINT32:
+ {
+ sstr << "TW_TYPE_UINT32" << " ";
+ sstr << *(static_cast<unsigned int*>(var));
+ break;
+ }
+ case TW_TYPE_FLOAT:
+ {
+ sstr << "TW_TYPE_FLOAT" << " ";
+ sstr << *(static_cast<float*>(var));
+ break;
+ }
+ case TW_TYPE_DOUBLE:
+ {
+ sstr << "TW_TYPE_DOUBLE" << " ";
+ sstr << std::setprecision(15) << *(static_cast<double*>(var));
+ break;
+ }
+ case TW_TYPE_STDSTRING:
+ {
+ sstr << "TW_TYPE_STDSTRING" << " ";
+ std::string *destPtr = static_cast<std::string *>(var);
+ sstr << destPtr->c_str();
+ break;
+ }
+ default:
+ {
+ using namespace std;
+ std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::const_iterator iter =
+ ReTw_custom_types.find(type);
+ if(iter != ReTw_custom_types.end())
+ {
+ sstr << (*iter).second.first << " ";
+ int enum_val = *(static_cast<int*>(var));
+ // try find display name for enum value
+ std::vector<TwEnumVal>::const_iterator eit = (*iter).second.second.begin();
+ bool found = false;
+ for(;eit<(*iter).second.second.end();eit++)
+ {
+ if(enum_val == eit->Value)
+ {
+ sstr << eit->Label;
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ sstr << "ERROR_ENUM_VALUE_NOT_DEFINED";
+ }
+ }else
+ {
+ sstr << "ERROR_TYPE_NOT_SUPPORTED";
+ }
+ break;
+ }
+ }
+ return sstr.str();
+}
+
+IGL_INLINE bool igl::anttweakbar::ReTwBar::load(const char *file_name)
+{
+ FILE * fp;
+ fp = fopen(file_name,"r");
+
+ if(fp == NULL)
+ {
+ printf("ERROR: not able to open %s for reading...\n",file_name);
+ return false;
+ }
+
+ // go through file line by line
+ char line[REANTTWEAKBAR_MAX_LINE];
+ bool still_comments;
+ char name[REANTTWEAKBAR_MAX_WORD];
+ char type_str[REANTTWEAKBAR_MAX_WORD];
+ char value_str[REANTTWEAKBAR_MAX_WORD];
+
+
+ // line number
+ int j = 0;
+ bool finished = false;
+ while(true)
+ {
+ // Eat comments
+ still_comments = true;
+ while(still_comments)
+ {
+ if(fgets(line,REANTTWEAKBAR_MAX_LINE,fp) == NULL)
+ {
+ finished = true;
+ break;
+ }
+ // Blank lines and lines that begin with # are comments
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ j++;
+ }
+ if(finished)
+ {
+ break;
+ }
+
+ sscanf(line,"%[^:]: %s %[^\n]",name,type_str,value_str);
+ //printf("%s: %s %s\n",name, type_str,value_str);
+
+ TwType type;
+ if(!type_from_string(type_str,type))
+ {
+ printf("ERROR: %s type not found... Skipping...\n",type_str);
+ continue;
+ }
+ set_value_from_string(name,type,value_str);
+
+ }
+
+ fclose(fp);
+
+ // everything succeeded
+ return true;
+}
+
+IGL_INLINE bool igl::anttweakbar::ReTwBar::type_from_string(
+ const char *type_str, TwType & type)
+{
+ // first check default types
+ for(int j = 0; j < RETW_NUM_DEFAULT_TYPE_STRINGS; j++)
+ {
+ if(strcmp(type_str,ReTwDefaultTypeStrings[j].type_str) == 0)
+ {
+ type = ReTwDefaultTypeStrings[j].type;
+ return true;
+ break;
+ }
+ }
+
+ // then check custom types
+ std::map<
+ TwType,std::pair<const char *,std::vector<TwEnumVal> >
+ >::const_iterator iter =
+ ReTw_custom_types.begin();
+ for(;iter != ReTw_custom_types.end(); iter++)
+ {
+ if(strcmp((*iter).second.first,type_str)==0)
+ {
+ type = (*iter).first;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool igl::anttweakbar::ReTwBar::set_value_from_string(
+ const char * name,
+ TwType type,
+ const char * value_str)
+{
+ void * value = NULL;
+ // possible value slots
+ int i;
+ float v;
+ double dv;
+ float f[4];
+ double d[4];
+ bool b;
+ unsigned int u;
+ unsigned char uc;
+ std::string s;
+
+ // First try to get value from default types
+ switch(type)
+ {
+ case TW_TYPE_BOOLCPP:
+ {
+ int ib;
+ if(sscanf(value_str," %d",&ib) == 1)
+ {
+ b = ib!=0;
+ value = &b;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_QUAT4D:
+ //case TW_TYPE_COLOR4D:
+ {
+ if(sscanf(value_str," %lf %lf %lf %lf",&d[0],&d[1],&d[2],&d[3]) == 4)
+ {
+ value = &d;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_QUAT4F:
+ case TW_TYPE_COLOR4F:
+ {
+ if(sscanf(value_str," %f %f %f %f",&f[0],&f[1],&f[2],&f[3]) == 4)
+ {
+ value = &f;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ //case TW_TYPE_COLOR3D:
+ case TW_TYPE_DIR3D:
+ {
+ if(sscanf(value_str," %lf %lf %lf",&d[0],&d[1],&d[2]) == 3)
+ {
+ value = &d;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_COLOR3F:
+ case TW_TYPE_DIR3F:
+ {
+ if(sscanf(value_str," %f %f %f",&f[0],&f[1],&f[2]) == 3)
+ {
+ value = &f;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_UINT8:
+ {
+ if(sscanf(value_str," %d",&i) == 1)
+ {
+ // Cast to unsigned char
+ uc = (unsigned char) i;
+ value = &uc;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_BOOL32:
+ case TW_TYPE_INT32:
+ {
+ if(sscanf(value_str," %d",&i) == 1)
+ {
+ value = &i;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_UINT32:
+ {
+ if(sscanf(value_str," %u",&u) == 1)
+ {
+ value = &u;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_FLOAT:
+ {
+ if(sscanf(value_str," %f",&v) == 1)
+ {
+ value = &v;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_DOUBLE:
+ {
+ if(sscanf(value_str," %lf",&dv) == 1)
+ {
+ value = &dv;
+ }else
+ {
+ printf("ERROR: Bad value format...\n");
+ return false;
+ }
+ break;
+ }
+ case TW_TYPE_STDSTRING:
+ {
+ s = value_str;
+ value = &s;
+ break;
+ }
+ default:
+ // Try to find type in custom enum types
+ std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::const_iterator iter =
+ ReTw_custom_types.find(type);
+ if(iter != ReTw_custom_types.end())
+ {
+ std::vector<TwEnumVal>::const_iterator eit = (*iter).second.second.begin();
+ bool found = false;
+ for(;eit<(*iter).second.second.end();eit++)
+ {
+ if(strcmp(value_str,eit->Label) == 0)
+ {
+ i = eit->Value;
+ value = &i;
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ printf("ERROR_ENUM_VALUE_NOT_DEFINED");
+ }
+ }else
+ {
+ printf("ERROR_TYPE_NOT_SUPPORTED\n");
+ }
+
+ break;
+ }
+
+
+ // Find variable based on name
+ // First look in RW items
+ bool item_found = false;
+ for(
+ std::vector<ReTwRWItem>::iterator it = rw_items.begin();
+ it != rw_items.end();
+ it++)
+ {
+ if(it->name == name)
+ {
+ void * var = it->var;
+ switch(type)
+ {
+ case TW_TYPE_BOOLCPP:
+ {
+ bool * bvar = static_cast<bool*>(var);
+ bool * bvalue = static_cast<bool*>(value);
+ *bvar = *bvalue;
+ break;
+ }
+ case TW_TYPE_QUAT4D:
+ //case TW_TYPE_COLOR4D:
+ {
+ double * dvar = static_cast<double*>(var);
+ double * dvalue = static_cast<double*>(value);
+ dvar[0] = dvalue[0];
+ dvar[1] = dvalue[1];
+ dvar[2] = dvalue[2];
+ dvar[3] = dvalue[3];
+ break;
+ }
+ case TW_TYPE_QUAT4F:
+ case TW_TYPE_COLOR4F:
+ {
+ float * fvar = static_cast<float*>(var);
+ float * fvalue = static_cast<float*>(value);
+ fvar[0] = fvalue[0];
+ fvar[1] = fvalue[1];
+ fvar[2] = fvalue[2];
+ fvar[3] = fvalue[3];
+ break;
+ }
+ //case TW_TYPE_COLOR3D:
+ case TW_TYPE_DIR3D:
+ {
+ double * dvar = static_cast<double*>(var);
+ double * dvalue = static_cast<double*>(value);
+ dvar[0] = dvalue[0];
+ dvar[1] = dvalue[1];
+ dvar[2] = dvalue[2];
+ break;
+ }
+ case TW_TYPE_COLOR3F:
+ case TW_TYPE_DIR3F:
+ {
+ float * fvar = static_cast<float*>(var);
+ float * fvalue = static_cast<float*>(value);
+ fvar[0] = fvalue[0];
+ fvar[1] = fvalue[1];
+ fvar[2] = fvalue[2];
+ break;
+ }
+ case TW_TYPE_UINT8:
+ {
+ unsigned char * ucvar = static_cast<unsigned char*>(var);
+ unsigned char * ucvalue = static_cast<unsigned char*>(value);
+ *ucvar = *ucvalue;
+ break;
+ }
+ case TW_TYPE_BOOL32:
+ case TW_TYPE_INT32:
+ {
+ int * ivar = static_cast<int*>(var);
+ int * ivalue = static_cast<int*>(value);
+ *ivar = *ivalue;
+ break;
+ }
+ case TW_TYPE_UINT32:
+ {
+ unsigned int * uvar = static_cast<unsigned int*>(var);
+ unsigned int * uvalue = static_cast<unsigned int*>(value);
+ *uvar = *uvalue;
+ break;
+ }
+ case TW_TYPE_FLOAT:
+ {
+ float * fvar = static_cast<float*>(var);
+ float * fvalue = static_cast<float*>(value);
+ *fvar = *fvalue;
+ break;
+ }
+ case TW_TYPE_DOUBLE:
+ {
+ double * dvar = static_cast<double*>(var);
+ double * fvalue = static_cast<double*>(value);
+ *dvar = *fvalue;
+ break;
+ }
+ case TW_TYPE_STDSTRING:
+ {
+ std::string * svar = static_cast<std::string*>(var);
+ std::string * svalue = static_cast<std::string*>(value);
+ *svar = *svalue;
+ break;
+ }
+ default:
+ // Try to find type in custom enum types
+ std::map<TwType,std::pair<const char *,std::vector<TwEnumVal> > >::iterator iter =
+ ReTw_custom_types.find(type);
+ if(iter != ReTw_custom_types.end())
+ {
+ int * ivar = static_cast<int*>(var);
+ std::vector<TwEnumVal>::iterator eit = (*iter).second.second.begin();
+ bool found = false;
+ for(;eit<(*iter).second.second.end();eit++)
+ {
+ if(strcmp(value_str,eit->Label) == 0)
+ {
+ *ivar = eit->Value;
+ found = true;
+ break;
+ }
+ }
+ if(!found)
+ {
+ printf("ERROR_ENUM_VALUE_NOT_DEFINED");
+ }
+ }else
+ {
+ printf("ERROR_TYPE_NOT_SUPPORTED\n");
+ }
+ break;
+ }
+ item_found = true;
+ break;
+ }
+ }
+
+ // Try looking in CB items
+ if(!item_found)
+ {
+ for(
+ std::vector<ReTwCBItem>::iterator it = cb_items.begin();
+ it != cb_items.end();
+ it++)
+ {
+ if(it->name==name)
+ {
+ it->setCallback(value,it->clientData);
+ item_found = true;
+ break;
+ }
+ }
+ }
+
+ if(!item_found)
+ {
+ printf("ERROR: item '%s' not found\n",name);
+ }
+ return true;
+}
+
+IGL_INLINE const std::vector<igl::anttweakbar::ReTwRWItem> &
+ igl::anttweakbar::ReTwBar::get_rw_items()
+{
+ return rw_items;
+}
+
+IGL_INLINE const std::vector<igl::anttweakbar::ReTwCBItem> &
+ igl::anttweakbar::ReTwBar::get_cb_items()
+{
+ return cb_items;
+}
diff --git a/xs/src/igl/anttweakbar/ReAntTweakBar.h b/xs/src/igl/anttweakbar/ReAntTweakBar.h
new file mode 100644
index 000000000..d1dede927
--- /dev/null
+++ b/xs/src/igl/anttweakbar/ReAntTweakBar.h
@@ -0,0 +1,286 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
+#define IGL_ANTTWEAKBAR_REANTTWEAKBAR_H
+#include "../igl_inline.h"
+// ReAntTweakBar is a minimal wrapper for the AntTweakBar library that allows
+// "bars" to be saved and load from disk. Changing your existing app that uses
+// AntTweakBar to use ReAntTweakBar is trivial.
+//
+// Many (but not all) variable types are supported. I'll try to keep track them
+// here:
+// TW_TYPE_BOOLCPP
+// TW_TYPE_QUAT4F
+// TW_TYPE_QUAT4D
+// TW_TYPE_COLOR4F
+// TW_TYPE_COLOR4D
+// TW_TYPE_COLOR3F
+// TW_TYPE_DIR3F
+// TW_TYPE_DIR3D
+// TW_TYPE_BOOL32
+// TW_TYPE_INT32
+// TW_TYPE_UINT32
+// TW_TYPE_FLOAT
+// TW_TYPE_DOUBLE
+// TW_TYPE_UINT8
+// and
+// custom TwTypes made with TwDefineEnum
+//
+// I'm working on adding the rest on an as-needed basis. Adding a new type only
+// requires changes in a few places...
+//
+//
+//
+
+// This allows the user to have a non-global, static installation of
+// AntTweakBar
+#include <AntTweakBar.h>
+// Instead of including AntTweakBar.h, just define the necessary types
+// Types used:
+// - TwType
+// - TwEnumVal
+// - TwSetVarCallback
+// - TwGetVarCallback
+// - TwBar
+// - TwButtonCallback
+
+
+#include <vector>
+#include <string>
+
+#define REANTTWEAKBAR_MAX_CB_VAR_SIZE 1000
+// Max line size for reading files
+#define REANTTWEAKBAR_MAX_LINE 1000
+#define REANTTWEAKBAR_MAX_WORD 100
+
+namespace igl
+{
+ namespace anttweakbar
+ {
+ TwType ReTwDefineEnum(
+ const char *name,
+ const TwEnumVal *enumValues,
+ unsigned int nbValues);
+ TwType ReTwDefineEnumFromString(const char * name,const char * enumString);
+
+ struct ReTwRWItem
+ {
+ //const char * name;
+ std::string name;
+ TwType type;
+ void * var;
+ // Default constructor
+ IGL_INLINE ReTwRWItem(
+ const std::string _name,
+ TwType _type,
+ void *_var):
+ name(_name),
+ type(_type),
+ var(_var)
+ {
+ }
+ // Shallow copy constructor
+ // I solemnly swear it's OK to copy var this way
+ // Q: Is it really?
+ IGL_INLINE ReTwRWItem(const ReTwRWItem & that):
+ name(that.name),
+ type(that.type),
+ var(that.var)
+ {
+ }
+ // Shallow assignment
+ // I solemnly swear it's OK to copy var this way
+ IGL_INLINE ReTwRWItem & operator=(const ReTwRWItem & that)
+ {
+ if(this != &that)
+ {
+ this->name = that.name;
+ this->type = that.type;
+ this->var = that.var;
+ }
+ return *this;
+ }
+ };
+
+ struct ReTwCBItem
+ {
+ //const char * name;
+ std::string name;
+ TwType type;
+ TwSetVarCallback setCallback;
+ TwGetVarCallback getCallback;
+ void * clientData;
+ // Default constructor
+ IGL_INLINE ReTwCBItem(
+ const std::string _name,
+ TwType _type,
+ TwSetVarCallback _setCallback,
+ TwGetVarCallback _getCallback,
+ void * _clientData):
+ name(_name),
+ type(_type),
+ setCallback(_setCallback),
+ getCallback(_getCallback),
+ clientData(_clientData)
+ {
+ }
+ // Shallow copy
+ // I solemnly swear it's OK to copy clientData this way
+ IGL_INLINE ReTwCBItem(const ReTwCBItem & that):
+ name(that.name),
+ type(that.type),
+ setCallback(that.setCallback),
+ getCallback(that.getCallback),
+ clientData(that.clientData)
+ {
+ }
+ // Shallow assignment
+ // I solemnly swear it's OK to copy clientData this way
+ IGL_INLINE ReTwCBItem & operator=(const ReTwCBItem & that)
+ {
+ if(this != &that)
+ {
+ name = that.name;
+ type = that.type;
+ setCallback = that.setCallback;
+ getCallback = that.getCallback;
+ clientData = that.clientData;
+ }
+ return *this;
+ }
+
+ };
+
+ class ReTwBar
+ {
+ // VARIABLES
+ // Should be private, but seeing as I'm not going to implement all of the
+ // AntTweakBar public functions right away, I'll expose this so that at
+ // anytime AntTweakBar functions can be called directly on the bar
+ public:
+ TwBar * bar;
+ std::string name;
+ protected:
+ std::vector<ReTwRWItem> rw_items;
+ std::vector<ReTwCBItem> cb_items;
+ public:
+ // Default constructor with explicit initialization
+ IGL_INLINE ReTwBar();
+ private:
+ // Copy constructor does shallow copy
+ IGL_INLINE ReTwBar(const ReTwBar & that);
+ // Assignment operator does shallow assignment
+ IGL_INLINE ReTwBar &operator=(const ReTwBar & that);
+
+ // WRAPPERS FOR ANTTWEAKBAR FUNCTIONS
+ public:
+ IGL_INLINE void TwNewBar(const char *_name);
+ IGL_INLINE int TwAddVarRW(
+ const char *name,
+ TwType type,
+ void *var,
+ const char *def,
+ const bool record=true);
+ IGL_INLINE int TwAddVarCB(
+ const char *name,
+ TwType type,
+ TwSetVarCallback setCallback,
+ TwGetVarCallback getCallback,
+ void *clientData,
+ const char *def,
+ const bool record=true);
+ // Wrappers for convenience (not recorded, just passed on)
+ IGL_INLINE int TwAddVarRO(const char *name, TwType type, void *var, const char *def);
+ IGL_INLINE int TwAddButton(
+ const char *name,
+ TwButtonCallback buttonCallback,
+ void *clientData,
+ const char *def);
+ IGL_INLINE int TwSetParam(
+ const char *varName,
+ const char *paramName,
+ TwParamValueType paramValueType,
+ unsigned int inValueCount,
+ const void *inValues);
+ IGL_INLINE int TwGetParam(
+ const char *varName,
+ const char *paramName,
+ TwParamValueType paramValueType,
+ unsigned int outValueMaxCount,
+ void *outValues);
+ IGL_INLINE int TwRefreshBar();
+ IGL_INLINE int TwTerminate();
+
+
+ // IO FUNCTIONS
+ public:
+ // Save current items to file
+ // Input:
+ // file_name name of file to save data to, can be null which means print
+ // to stdout
+ // Return:
+ // true only if there were no (fatal) errors
+ IGL_INLINE bool save(const char *file_name);
+ std::string get_value_as_string(
+ void * var,
+ TwType type);
+ // Load into current items from file
+ // Input:
+ // file_name name of input file to load
+ // Return:
+ // true only if there were no (fatal) errors
+ IGL_INLINE bool load(const char *file_name);
+ // Get TwType from string
+ // Input
+ // type_str string of type
+ // Output
+ // type TwType converted from string
+ // Returns
+ // true only if string matched a valid type
+ IGL_INLINE bool type_from_string(const char *type_str, TwType & type);
+ // I realize that I mix std::string and const char * all over the place.
+ // What can you do...
+ IGL_INLINE bool set_value_from_string(
+ const char * name,
+ TwType type,
+ const char * value_str);
+ IGL_INLINE const std::vector<ReTwRWItem> & get_rw_items();
+ IGL_INLINE const std::vector<ReTwCBItem> & get_cb_items();
+ };
+ }
+}
+
+// List of TwBar functions
+//TW_API TwBar * TW_CALL TwNewBar(const char *barName);
+//TW_API int TW_CALL TwDeleteBar(TwBar *bar);
+//TW_API int TW_CALL TwDeleteAllBars();
+//TW_API int TW_CALL TwSetTopBar(const TwBar *bar);
+//TW_API TwBar * TW_CALL TwGetTopBar();
+//TW_API int TW_CALL TwSetBottomBar(const TwBar *bar);
+//TW_API TwBar * TW_CALL TwGetBottomBar();
+//TW_API const char * TW_CALL TwGetBarName(TwBar *bar);
+//TW_API int TW_CALL TwGetBarCount();
+//TW_API TwBar * TW_CALL TwGetBarByIndex(int barIndex);
+//TW_API TwBar * TW_CALL TwGetBarByName(const char *barName);
+//TW_API int TW_CALL TwRefreshBar(TwBar *bar);
+//TW_API int TW_CALL TwTerminate();
+//
+//TW_API int TW_CALL TwAddVarRW(TwBar *bar, const char *name, TwType type, void *var, const char *def);
+//TW_API int TW_CALL TwAddVarRO(TwBar *bar, const char *name, TwType type, const void *var, const char *def);
+//TW_API int TW_CALL TwAddVarCB(TwBar *bar, const char *name, TwType type, TwSetVarCallback setCallback, TwGetVarCallback getCallback, void *clientData, const char *def);
+//TW_API int TW_CALL TwAddButton(TwBar *bar, const char *name, TwButtonCallback callback, void *clientData, const char *def);
+//TW_API int TW_CALL TwAddSeparator(TwBar *bar, const char *name, const char *def);
+//TW_API int TW_CALL TwRemoveVar(TwBar *bar, const char *name);
+//TW_API int TW_CALL TwRemoveAllVars(TwBar *bar);
+
+// Until AntTweakBar dependency folder exists, this is header-only
+#ifndef IGL_STATIC_LIBRARY
+# include "ReAntTweakBar.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.cpp b/xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.cpp
new file mode 100644
index 000000000..bcd6e2be5
--- /dev/null
+++ b/xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.cpp
@@ -0,0 +1,81 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cocoa_key_to_anttweakbar_key.h"
+
+#include <AntTweakBar.h>
+
+IGL_INLINE int igl::anttweakbar::cocoa_key_to_anttweakbar_key(int key)
+{
+ // I've left commented the AntTweakBar key codes that correspond to keys I
+ // don't have on my keyboard. Please fill this in if you have those keys
+ switch(key)
+ {
+ case 127:
+ return TW_KEY_BACKSPACE;
+ case 9:
+ return TW_KEY_TAB;
+ //TW_KEY_CLEAR = 0x0c,
+ case 3://ENTER
+ case 13:
+ return TW_KEY_RETURN;
+ case 27:
+ return TW_KEY_ESCAPE;
+ case 32:
+ return TW_KEY_SPACE;
+ // IN A GLUT APP 40 is (
+ //case 40:
+ case 63272:
+ return TW_KEY_DELETE;
+ case 63232:
+ return TW_KEY_UP;
+ case 63233:
+ return TW_KEY_DOWN;
+ case 63235:
+ return TW_KEY_RIGHT;
+ case 63234:
+ return TW_KEY_LEFT;
+ //TW_KEY_INSERT,
+ //TW_KEY_HOME,
+ //TW_KEY_END,
+ //TW_KEY_PAGE_UP,
+ //TW_KEY_PAGE_DOWN,
+ case 63236:
+ return TW_KEY_F1;
+ case 63237:
+ return TW_KEY_F2;
+ case 63238:
+ return TW_KEY_F3;
+ case 63239:
+ return TW_KEY_F4;
+ case 63240:
+ return TW_KEY_F5;
+ case 63241:
+ return TW_KEY_F6;
+ case 63242:
+ return TW_KEY_F7;
+ case 63243:
+ return TW_KEY_F8;
+ case 63244:
+ return TW_KEY_F9;
+ case 63245:
+ return TW_KEY_F10;
+ case 63246:
+ return TW_KEY_F11;
+ case 63247:
+ return TW_KEY_F12;
+ case 63248:
+ return TW_KEY_F13;
+ case 63249:
+ return TW_KEY_F14;
+ case 63250:
+ return TW_KEY_F15;
+ default:
+ break;
+ }
+ return key;
+}
diff --git a/xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.h b/xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.h
new file mode 100644
index 000000000..fdf3d3bea
--- /dev/null
+++ b/xs/src/igl/anttweakbar/cocoa_key_to_anttweakbar_key.h
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
+#define IGL_ANTTWEAKBAR_COCOA_KEY_TO_ANTTWEAKBAR_KEY_H
+#include "../igl_inline.h"
+
+
+namespace igl
+{
+ namespace anttweakbar
+ {
+ // Convert an unsigned char (like that from Cocoa apps) to AntTweakBar key
+ // code.
+ // See also: TranslateKey() in TwMgr.cpp in AntTweakBar source
+ // Inputs:
+ // key unsigned char key from keyboard
+ // Returns int of new key code
+ IGL_INLINE int cocoa_key_to_anttweakbar_key(int key);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cocoa_key_to_anttweakbar_key.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/any.cpp b/xs/src/igl/any.cpp
new file mode 100644
index 000000000..0488c8ffb
--- /dev/null
+++ b/xs/src/igl/any.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "any.h"
+#include "redux.h"
+
+
+template <typename AType, typename DerivedB>
+IGL_INLINE void igl::any(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB>& B)
+{
+ typedef typename DerivedB::Scalar Scalar;
+ igl::redux(A,dim,[](Scalar a, Scalar b){ return a || b!=0;},B);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::any<bool, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/any.h b/xs/src/igl/any.h
new file mode 100644
index 000000000..08a80e4cb
--- /dev/null
+++ b/xs/src/igl/any.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ANY_H
+#define IGL_ANY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#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)
+ //
+ template <typename AType, typename DerivedB>
+ IGL_INLINE void any(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB>& B);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "any.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/any_of.cpp b/xs/src/igl/any_of.cpp
new file mode 100644
index 000000000..9defd0339
--- /dev/null
+++ b/xs/src/igl/any_of.cpp
@@ -0,0 +1,20 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "any_of.h"
+#include <Eigen/Core>
+template <typename Mat>
+IGL_INLINE bool igl::any_of(const Mat & S)
+{
+ return std::any_of(S.data(),S.data()+S.size(),[](bool s){return s;});
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::any_of<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+#endif
+
diff --git a/xs/src/igl/any_of.h b/xs/src/igl/any_of.h
new file mode 100644
index 000000000..95ec1d373
--- /dev/null
+++ b/xs/src/igl/any_of.h
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ANY_OF_H
+#define IGL_ANY_OF_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Wrapper for STL `any_of` for matrix types
+ //
+ // Inputs:
+ // S matrix
+ // Returns whether any entries are true
+ //
+ // Seems that Eigen (now) implements this for `Eigen::Array`
+ template <typename Mat>
+ IGL_INLINE bool any_of(const Mat & S);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "any_of.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/arap.cpp b/xs/src/igl/arap.cpp
new file mode 100644
index 000000000..dc5af4cf6
--- /dev/null
+++ b/xs/src/igl/arap.cpp
@@ -0,0 +1,312 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "arap.h"
+#include "colon.h"
+#include "cotmatrix.h"
+#include "massmatrix.h"
+#include "group_sum_matrix.h"
+#include "covariance_scatter_matrix.h"
+#include "speye.h"
+#include "mode.h"
+#include "project_isometrically_to_plane.h"
+#include "slice.h"
+#include "arap_rhs.h"
+#include "repdiag.h"
+#include "columnize.h"
+#include "fit_rotations.h"
+#include <cassert>
+#include <iostream>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb>
+IGL_INLINE bool igl::arap_precomputation(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const int dim,
+ const Eigen::PlainObjectBase<Derivedb> & b,
+ ARAPData & data)
+{
+ using namespace std;
+ using namespace Eigen;
+ typedef typename DerivedV::Scalar Scalar;
+ // number of vertices
+ const int n = V.rows();
+ data.n = n;
+ assert((b.size() == 0 || b.maxCoeff() < n) && "b out of bounds");
+ assert((b.size() == 0 || b.minCoeff() >=0) && "b out of bounds");
+ // remember b
+ data.b = b;
+ //assert(F.cols() == 3 && "For now only triangles");
+ // dimension
+ //const int dim = V.cols();
+ assert((dim == 3 || dim ==2) && "dim should be 2 or 3");
+ data.dim = dim;
+ //assert(dim == 3 && "Only 3d supported");
+ // Defaults
+ data.f_ext = MatrixXd::Zero(n,data.dim);
+
+ assert(data.dim <= V.cols() && "solve dim should be <= embedding");
+ bool flat = (V.cols() - data.dim)==1;
+
+ DerivedV plane_V;
+ DerivedF plane_F;
+ typedef SparseMatrix<Scalar> SparseMatrixS;
+ SparseMatrixS ref_map,ref_map_dim;
+ if(flat)
+ {
+ project_isometrically_to_plane(V,F,plane_V,plane_F,ref_map);
+ repdiag(ref_map,dim,ref_map_dim);
+ }
+ const PlainObjectBase<DerivedV>& ref_V = (flat?plane_V:V);
+ const PlainObjectBase<DerivedF>& ref_F = (flat?plane_F:F);
+ SparseMatrixS L;
+ cotmatrix(V,F,L);
+
+ ARAPEnergyType eff_energy = data.energy;
+ if(eff_energy == ARAP_ENERGY_TYPE_DEFAULT)
+ {
+ switch(F.cols())
+ {
+ case 3:
+ if(data.dim == 3)
+ {
+ eff_energy = ARAP_ENERGY_TYPE_SPOKES_AND_RIMS;
+ }else
+ {
+ eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
+ }
+ break;
+ case 4:
+ eff_energy = ARAP_ENERGY_TYPE_ELEMENTS;
+ break;
+ default:
+ assert(false);
+ }
+ }
+
+
+ // Get covariance scatter matrix, when applied collects the covariance
+ // matrices used to fit rotations to during optimization
+ covariance_scatter_matrix(ref_V,ref_F,eff_energy,data.CSM);
+ if(flat)
+ {
+ data.CSM = (data.CSM * ref_map_dim.transpose()).eval();
+ }
+ assert(data.CSM.cols() == V.rows()*data.dim);
+
+ // Get group sum scatter matrix, when applied sums all entries of the same
+ // group according to G
+ SparseMatrix<double> G_sum;
+ if(data.G.size() == 0)
+ {
+ if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
+ {
+ speye(F.rows(),G_sum);
+ }else
+ {
+ speye(n,G_sum);
+ }
+ }else
+ {
+ // groups are defined per vertex, convert to per face using mode
+ if(eff_energy == ARAP_ENERGY_TYPE_ELEMENTS)
+ {
+ Eigen::Matrix<int,Eigen::Dynamic,1> GG;
+ MatrixXi GF(F.rows(),F.cols());
+ for(int j = 0;j<F.cols();j++)
+ {
+ Matrix<int,Eigen::Dynamic,1> GFj;
+ slice(data.G,F.col(j),GFj);
+ GF.col(j) = GFj;
+ }
+ mode<int>(GF,2,GG);
+ data.G=GG;
+ }
+ //printf("group_sum_matrix()\n");
+ group_sum_matrix(data.G,G_sum);
+ }
+ SparseMatrix<double> G_sum_dim;
+ repdiag(G_sum,data.dim,G_sum_dim);
+ assert(G_sum_dim.cols() == data.CSM.rows());
+ data.CSM = (G_sum_dim * data.CSM).eval();
+
+
+ arap_rhs(ref_V,ref_F,data.dim,eff_energy,data.K);
+ if(flat)
+ {
+ data.K = (ref_map_dim * data.K).eval();
+ }
+ assert(data.K.rows() == data.n*data.dim);
+
+ SparseMatrix<double> Q = (-L).eval();
+
+ if(data.with_dynamics)
+ {
+ const double h = data.h;
+ assert(h != 0);
+ SparseMatrix<double> M;
+ massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,data.M);
+ const double dw = (1./data.ym)*(h*h);
+ SparseMatrix<double> DQ = dw * 1./(h*h)*data.M;
+ Q += DQ;
+ // Dummy external forces
+ data.f_ext = MatrixXd::Zero(n,data.dim);
+ data.vel = MatrixXd::Zero(n,data.dim);
+ }
+
+ return min_quad_with_fixed_precompute(
+ Q,b,SparseMatrix<double>(),true,data.solver_data);
+}
+
+template <
+ typename Derivedbc,
+ typename DerivedU>
+IGL_INLINE bool igl::arap_solve(
+ const Eigen::PlainObjectBase<Derivedbc> & bc,
+ ARAPData & data,
+ Eigen::PlainObjectBase<DerivedU> & U)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(data.b.size() == bc.rows());
+ if(bc.size() > 0)
+ {
+ assert(bc.cols() == data.dim && "bc.cols() match data.dim");
+ }
+ const int n = data.n;
+ int iter = 0;
+ if(U.size() == 0)
+ {
+ // terrible initial guess.. should at least copy input mesh
+#ifndef NDEBUG
+ cerr<<"arap_solve: Using terrible initial guess for U. Try U = V."<<endl;
+#endif
+ U = MatrixXd::Zero(data.n,data.dim);
+ }else
+ {
+ assert(U.cols() == data.dim && "U.cols() match data.dim");
+ }
+ // changes each arap iteration
+ MatrixXd U_prev = U;
+ // doesn't change for fixed with_dynamics timestep
+ MatrixXd U0;
+ if(data.with_dynamics)
+ {
+ U0 = U_prev;
+ }
+ while(iter < data.max_iter)
+ {
+ U_prev = U;
+ // enforce boundary conditions exactly
+ for(int bi = 0;bi<bc.rows();bi++)
+ {
+ U.row(data.b(bi)) = bc.row(bi);
+ }
+
+ const auto & Udim = U.replicate(data.dim,1);
+ assert(U.cols() == data.dim);
+ // As if U.col(2) was 0
+ MatrixXd S = data.CSM * Udim;
+ // THIS NORMALIZATION IS IMPORTANT TO GET SINGLE PRECISION SVD CODE TO WORK
+ // CORRECTLY.
+ S /= S.array().abs().maxCoeff();
+
+ const int Rdim = data.dim;
+ MatrixXd R(Rdim,data.CSM.rows());
+ if(R.rows() == 2)
+ {
+ fit_rotations_planar(S,R);
+ }else
+ {
+ fit_rotations(S,true,R);
+//#ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
+// fit_rotations_SSE(S,R);
+//#else
+// fit_rotations(S,true,R);
+//#endif
+ }
+ //for(int k = 0;k<(data.CSM.rows()/dim);k++)
+ //{
+ // R.block(0,dim*k,dim,dim) = MatrixXd::Identity(dim,dim);
+ //}
+
+
+ // Number of rotations: #vertices or #elements
+ int num_rots = data.K.cols()/Rdim/Rdim;
+ // distribute group rotations to vertices in each group
+ MatrixXd eff_R;
+ if(data.G.size() == 0)
+ {
+ // copy...
+ eff_R = R;
+ }else
+ {
+ eff_R.resize(Rdim,num_rots*Rdim);
+ for(int r = 0;r<num_rots;r++)
+ {
+ eff_R.block(0,Rdim*r,Rdim,Rdim) =
+ R.block(0,Rdim*data.G(r),Rdim,Rdim);
+ }
+ }
+
+ MatrixXd Dl;
+ if(data.with_dynamics)
+ {
+ assert(data.M.rows() == n &&
+ "No mass matrix. Call arap_precomputation if changing with_dynamics");
+ const double h = data.h;
+ assert(h != 0);
+ //Dl = 1./(h*h*h)*M*(-2.*V0 + Vm1) - fext;
+ // data.vel = (V0-Vm1)/h
+ // h*data.vel = (V0-Vm1)
+ // -h*data.vel = -V0+Vm1)
+ // -V0-h*data.vel = -2V0+Vm1
+ const double dw = (1./data.ym)*(h*h);
+ Dl = dw * (1./(h*h)*data.M*(-U0 - h*data.vel) - data.f_ext);
+ }
+
+ VectorXd Rcol;
+ columnize(eff_R,num_rots,2,Rcol);
+ VectorXd Bcol = -data.K * Rcol;
+ assert(Bcol.size() == data.n*data.dim);
+ for(int c = 0;c<data.dim;c++)
+ {
+ VectorXd Uc,Bc,bcc,Beq;
+ Bc = Bcol.block(c*n,0,n,1);
+ if(data.with_dynamics)
+ {
+ Bc += Dl.col(c);
+ }
+ if(bc.size()>0)
+ {
+ bcc = bc.col(c);
+ }
+ min_quad_with_fixed_solve(
+ data.solver_data,
+ Bc,bcc,Beq,
+ Uc);
+ U.col(c) = Uc;
+ }
+
+ iter++;
+ }
+ if(data.with_dynamics)
+ {
+ // Keep track of velocity for next time
+ data.vel = (U-U0)/data.h;
+ }
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::arap_solve<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::ARAPData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::arap_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, igl::ARAPData&);
+#endif
diff --git a/xs/src/igl/arap.h b/xs/src/igl/arap.h
new file mode 100644
index 000000000..b2210e64f
--- /dev/null
+++ b/xs/src/igl/arap.h
@@ -0,0 +1,104 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ARAP_H
+#define IGL_ARAP_H
+#include "igl_inline.h"
+#include "min_quad_with_fixed.h"
+#include "ARAPEnergyType.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ 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
+ int n;
+ Eigen::VectorXi G;
+ ARAPEnergyType energy;
+ bool with_dynamics;
+ Eigen::MatrixXd f_ext,vel;
+ double h;
+ double ym;
+ int max_iter;
+ Eigen::SparseMatrix<double> K,M;
+ Eigen::SparseMatrix<double> CSM;
+ min_quad_with_fixed_data<double> solver_data;
+ Eigen::VectorXi b;
+ int dim;
+ ARAPData():
+ n(0),
+ G(),
+ energy(ARAP_ENERGY_TYPE_DEFAULT),
+ with_dynamics(false),
+ f_ext(),
+ h(1),
+ ym(1),
+ max_iter(10),
+ K(),
+ CSM(),
+ solver_data(),
+ b(),
+ dim(-1) // force this to be set by _precomputation
+ {
+ };
+ };
+
+ // 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
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb>
+ IGL_INLINE bool arap_precomputation(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const int dim,
+ const Eigen::PlainObjectBase<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
+ template <
+ typename Derivedbc,
+ typename DerivedU>
+ IGL_INLINE bool arap_solve(
+ const Eigen::PlainObjectBase<Derivedbc> & bc,
+ ARAPData & data,
+ Eigen::PlainObjectBase<DerivedU> & U);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+#include "arap.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/arap_dof.cpp b/xs/src/igl/arap_dof.cpp
new file mode 100644
index 000000000..033d1deb3
--- /dev/null
+++ b/xs/src/igl/arap_dof.cpp
@@ -0,0 +1,884 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "arap_dof.h"
+
+#include "cotmatrix.h"
+#include "massmatrix.h"
+#include "speye.h"
+#include "repdiag.h"
+#include "repmat.h"
+#include "slice.h"
+#include "colon.h"
+#include "is_sparse.h"
+#include "mode.h"
+#include "is_symmetric.h"
+#include "group_sum_matrix.h"
+#include "arap_rhs.h"
+#include "covariance_scatter_matrix.h"
+#include "fit_rotations.h"
+
+#include "verbose.h"
+#include "print_ijv.h"
+
+#include "get_seconds_hires.h"
+//#include "MKLEigenInterface.h"
+#include "min_quad_dense.h"
+#include "get_seconds.h"
+#include "columnize.h"
+
+// defined if no early exit is supported, i.e., always take a fixed number of iterations
+#define IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
+
+// A careful derivation of this implementation is given in the corresponding
+// matlab function arap_dof.m
+template <typename LbsMatrixType, typename SSCALAR>
+IGL_INLINE bool igl::arap_dof_precomputation(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const LbsMatrixType & M,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
+ ArapDOFData<LbsMatrixType, SSCALAR> & data)
+{
+ using namespace Eigen;
+ typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
+ // number of mesh (domain) vertices
+ int n = V.rows();
+ // cache problem size
+ data.n = n;
+ // dimension of mesh
+ data.dim = V.cols();
+ assert(data.dim == M.rows()/n);
+ assert(data.dim*n == M.rows());
+ if(data.dim == 3)
+ {
+ // Check if z-coordinate is all zeros
+ if(V.col(2).minCoeff() == 0 && V.col(2).maxCoeff() == 0)
+ {
+ data.effective_dim = 2;
+ }
+ }else
+ {
+ data.effective_dim = data.dim;
+ }
+ // Number of handles
+ data.m = M.cols()/data.dim/(data.dim+1);
+ assert(data.m*data.dim*(data.dim+1) == M.cols());
+ //assert(m == C.rows());
+
+ //printf("n=%d; dim=%d; m=%d;\n",n,data.dim,data.m);
+
+ // Build cotangent laplacian
+ SparseMatrix<double> Lcot;
+ //printf("cotmatrix()\n");
+ cotmatrix(V,F,Lcot);
+ // Discrete laplacian (should be minus matlab version)
+ SparseMatrix<double> Lapl = -2.0*Lcot;
+#ifdef EXTREME_VERBOSE
+ cout<<"LaplIJV=["<<endl;print_ijv(Lapl,1);cout<<endl<<"];"<<
+ endl<<"Lapl=sparse(LaplIJV(:,1),LaplIJV(:,2),LaplIJV(:,3),"<<
+ Lapl.rows()<<","<<Lapl.cols()<<");"<<endl;
+#endif
+
+ // Get group sum scatter matrix, when applied sums all entries of the same
+ // group according to G
+ SparseMatrix<double> G_sum;
+ if(G.size() == 0)
+ {
+ speye(n,G_sum);
+ }else
+ {
+ // groups are defined per vertex, convert to per face using mode
+ Eigen::Matrix<int,Eigen::Dynamic,1> GG;
+ if(data.energy == ARAP_ENERGY_TYPE_ELEMENTS)
+ {
+ MatrixXi GF(F.rows(),F.cols());
+ for(int j = 0;j<F.cols();j++)
+ {
+ Matrix<int,Eigen::Dynamic,1> GFj;
+ slice(G,F.col(j),GFj);
+ GF.col(j) = GFj;
+ }
+ mode<int>(GF,2,GG);
+ }else
+ {
+ GG=G;
+ }
+ //printf("group_sum_matrix()\n");
+ group_sum_matrix(GG,G_sum);
+ }
+
+#ifdef EXTREME_VERBOSE
+ cout<<"G_sumIJV=["<<endl;print_ijv(G_sum,1);cout<<endl<<"];"<<
+ endl<<"G_sum=sparse(G_sumIJV(:,1),G_sumIJV(:,2),G_sumIJV(:,3),"<<
+ G_sum.rows()<<","<<G_sum.cols()<<");"<<endl;
+#endif
+
+ // Get covariance scatter matrix, when applied collects the covariance matrices
+ // used to fit rotations to during optimization
+ SparseMatrix<double> CSM;
+ //printf("covariance_scatter_matrix()\n");
+ covariance_scatter_matrix(V,F,data.energy,CSM);
+#ifdef EXTREME_VERBOSE
+ cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
+ endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
+ CSM.rows()<<","<<CSM.cols()<<");"<<endl;
+#endif
+
+
+ // Build the covariance matrix "constructor". This is a set of *scatter*
+ // matrices that when multiplied on the right by column of the transformation
+ // matrix entries (the degrees of freedom) L, we get a stack of dim by 1
+ // covariance matrix column, with a column in the stack for each rotation
+ // *group*. The output is a list of matrices because we construct each column
+ // in the stack of covariance matrices with an independent matrix-vector
+ // multiplication.
+ //
+ // We want to build S which is a stack of dim by dim covariance matrices.
+ // Thus S is dim*g by dim, where dim is the number of dimensions and g is the
+ // number of groups. We can precompute dim matrices CSM_M such that column i
+ // in S is computed as S(:,i) = CSM_M{i} * L, where L is a column of the
+ // skinning transformation matrix values. To be clear, the covariance matrix
+ // for group k is then given as the dim by dim matrix pulled from the stack:
+ // S((k-1)*dim + 1:dim,:)
+
+ // Apply group sum to each dimension's block of covariance scatter matrix
+ SparseMatrix<double> G_sum_dim;
+ repdiag(G_sum,data.dim,G_sum_dim);
+ CSM = (G_sum_dim * CSM).eval();
+#ifdef EXTREME_VERBOSE
+ cout<<"CSMIJV=["<<endl;print_ijv(CSM,1);cout<<endl<<"];"<<
+ endl<<"CSM=sparse(CSMIJV(:,1),CSMIJV(:,2),CSMIJV(:,3),"<<
+ CSM.rows()<<","<<CSM.cols()<<");"<<endl;
+#endif
+
+ //printf("CSM_M()\n");
+ // Precompute CSM times M for each dimension
+ data.CSM_M.resize(data.dim);
+#ifdef EXTREME_VERBOSE
+ cout<<"data.CSM_M = cell("<<data.dim<<",1);"<<endl;
+#endif
+ // span of integers from 0 to n-1
+ Eigen::Matrix<int,Eigen::Dynamic,1> span_n(n);
+ for(int i = 0;i<n;i++)
+ {
+ span_n(i) = i;
+ }
+
+ // span of integers from 0 to M.cols()-1
+ Eigen::Matrix<int,Eigen::Dynamic,1> span_mlbs_cols(M.cols());
+ for(int i = 0;i<M.cols();i++)
+ {
+ span_mlbs_cols(i) = i;
+ }
+
+ // number of groups
+ int k = CSM.rows()/data.dim;
+ for(int i = 0;i<data.dim;i++)
+ {
+ //printf("CSM_M(): Mi\n");
+ LbsMatrixType M_i;
+ //printf("CSM_M(): slice\n");
+ slice(M,(span_n.array()+i*n).matrix().eval(),span_mlbs_cols,M_i);
+ LbsMatrixType M_i_dim;
+ data.CSM_M[i].resize(k*data.dim,data.m*data.dim*(data.dim+1));
+ assert(data.CSM_M[i].cols() == M.cols());
+ for(int j = 0;j<data.dim;j++)
+ {
+ SparseMatrix<double> CSMj;
+ //printf("CSM_M(): slice\n");
+ slice(
+ CSM,
+ colon<int>(j*k,(j+1)*k-1),
+ colon<int>(j*n,(j+1)*n-1),
+ CSMj);
+ assert(CSMj.rows() == k);
+ assert(CSMj.cols() == n);
+ LbsMatrixType CSMjM_i = CSMj * M_i;
+ if(is_sparse(CSMjM_i))
+ {
+ // Convert to full
+ //printf("CSM_M(): full\n");
+ MatrixXd CSMjM_ifull(CSMjM_i);
+// printf("CSM_M[%d]: %d %d\n",i,data.CSM_M[i].rows(),data.CSM_M[i].cols());
+// printf("CSM_M[%d].block(%d*%d=%d,0,%d,%d): %d %d\n",i,j,k,CSMjM_i.rows(),CSMjM_i.cols(),
+// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).rows(),
+// data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()).cols());
+// printf("CSM_MjMi: %d %d\n",i,CSMjM_i.rows(),CSMjM_i.cols());
+// printf("CSM_MjM_ifull: %d %d\n",i,CSMjM_ifull.rows(),CSMjM_ifull.cols());
+ data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_ifull;
+ }else
+ {
+ data.CSM_M[i].block(j*k,0,CSMjM_i.rows(),CSMjM_i.cols()) = CSMjM_i;
+ }
+ }
+#ifdef EXTREME_VERBOSE
+ cout<<"CSM_Mi=["<<endl<<data.CSM_M[i]<<endl<<"];"<<endl;
+#endif
+ }
+
+ // precompute arap_rhs matrix
+ //printf("arap_rhs()\n");
+ SparseMatrix<double> K;
+ arap_rhs(V,F,V.cols(),data.energy,K);
+//#ifdef EXTREME_VERBOSE
+// cout<<"KIJV=["<<endl;print_ijv(K,1);cout<<endl<<"];"<<
+// endl<<"K=sparse(KIJV(:,1),KIJV(:,2),KIJV(:,3),"<<
+// K.rows()<<","<<K.cols()<<");"<<endl;
+//#endif
+ // Precompute left muliplication by M and right multiplication by G_sum
+ SparseMatrix<double> G_sumT = G_sum.transpose();
+ SparseMatrix<double> G_sumT_dim_dim;
+ repdiag(G_sumT,data.dim*data.dim,G_sumT_dim_dim);
+ LbsMatrixType MT = M.transpose();
+ // If this is a bottle neck then consider reordering matrix multiplication
+ data.M_KG = -4.0 * (MT * (K * G_sumT_dim_dim));
+//#ifdef EXTREME_VERBOSE
+// cout<<"data.M_KGIJV=["<<endl;print_ijv(data.M_KG,1);cout<<endl<<"];"<<
+// endl<<"data.M_KG=sparse(data.M_KGIJV(:,1),data.M_KGIJV(:,2),data.M_KGIJV(:,3),"<<
+// data.M_KG.rows()<<","<<data.M_KG.cols()<<");"<<endl;
+//#endif
+
+ // Precompute system matrix
+ //printf("A()\n");
+ SparseMatrix<double> A;
+ repdiag(Lapl,data.dim,A);
+ data.Q = MT * (A * M);
+//#ifdef EXTREME_VERBOSE
+// cout<<"QIJV=["<<endl;print_ijv(data.Q,1);cout<<endl<<"];"<<
+// endl<<"Q=sparse(QIJV(:,1),QIJV(:,2),QIJV(:,3),"<<
+// data.Q.rows()<<","<<data.Q.cols()<<");"<<endl;
+//#endif
+
+ // Always do dynamics precomputation so we can hot-switch
+ //if(data.with_dynamics)
+ //{
+ // Build cotangent laplacian
+ SparseMatrix<double> Mass;
+ //printf("massmatrix()\n");
+ massmatrix(V,F,(F.cols()>3?MASSMATRIX_TYPE_BARYCENTRIC:MASSMATRIX_TYPE_VORONOI),Mass);
+ //cout<<"MIJV=["<<endl;print_ijv(Mass,1);cout<<endl<<"];"<<
+ // endl<<"M=sparse(MIJV(:,1),MIJV(:,2),MIJV(:,3),"<<
+ // Mass.rows()<<","<<Mass.cols()<<");"<<endl;
+ //speye(data.n,Mass);
+ SparseMatrix<double> Mass_rep;
+ repdiag(Mass,data.dim,Mass_rep);
+
+ // Multiply either side by weights matrix (should be dense)
+ data.Mass_tilde = MT * Mass_rep * M;
+ MatrixXd ones(data.dim*data.n,data.dim);
+ for(int i = 0;i<data.n;i++)
+ {
+ for(int d = 0;d<data.dim;d++)
+ {
+ ones(i+d*data.n,d) = 1;
+ }
+ }
+ data.fgrav = MT * (Mass_rep * ones);
+ data.fext = MatrixXS::Zero(MT.rows(),1);
+ //data.fgrav = MT * (ones);
+ //}
+
+
+ // This may/should be superfluous
+ //printf("is_symmetric()\n");
+ if(!is_symmetric(data.Q))
+ {
+ //printf("Fixing symmetry...\n");
+ // "Fix" symmetry
+ LbsMatrixType QT = data.Q.transpose();
+ LbsMatrixType Q_copy = data.Q;
+ data.Q = 0.5*(Q_copy+QT);
+ // Check that ^^^ this really worked. It doesn't always
+ //assert(is_symmetric(*Q));
+ }
+
+ //printf("arap_dof_precomputation() succeeded... so far...\n");
+ verbose("Number of handles: %i\n", data.m);
+ return true;
+}
+
+/////////////////////////////////////////////////////////////////////////
+//
+// STATIC FUNCTIONS (These should be removed or properly defined)
+//
+/////////////////////////////////////////////////////////////////////////
+namespace igl
+{
+ // returns maximal difference of 'blok' from scalar times 3x3 identity:
+ template <typename SSCALAR>
+ inline static SSCALAR maxBlokErr(const Eigen::Matrix3f &blok)
+ {
+ SSCALAR mD;
+ SSCALAR value = blok(0,0);
+ SSCALAR diff1 = fabs(blok(1,1) - value);
+ SSCALAR diff2 = fabs(blok(2,2) - value);
+ if (diff1 > diff2) mD = diff1;
+ else mD = diff2;
+
+ for (int v=0; v<3; v++)
+ {
+ for (int w=0; w<3; w++)
+ {
+ if (v == w)
+ {
+ continue;
+ }
+ if (mD < fabs(blok(v, w)))
+ {
+ mD = fabs(blok(v, w));
+ }
+ }
+ }
+
+ return mD;
+ }
+
+ // converts CSM_M_SSCALAR[0], CSM_M_SSCALAR[1], CSM_M_SSCALAR[2] into one
+ // "condensed" matrix CSM while checking we're not losing any information by
+ // this process; specifically, returns maximal difference from scaled 3x3
+ // identity blocks, which should be pretty small number
+ template <typename MatrixXS>
+ static typename MatrixXS::Scalar condense_CSM(
+ const std::vector<MatrixXS> &CSM_M_SSCALAR,
+ int numBones,
+ int dim,
+ MatrixXS &CSM)
+ {
+ const int numRows = CSM_M_SSCALAR[0].rows();
+ assert(CSM_M_SSCALAR[0].cols() == dim*(dim+1)*numBones);
+ assert(CSM_M_SSCALAR[1].cols() == dim*(dim+1)*numBones);
+ assert(CSM_M_SSCALAR[2].cols() == dim*(dim+1)*numBones);
+ assert(CSM_M_SSCALAR[1].rows() == numRows);
+ assert(CSM_M_SSCALAR[2].rows() == numRows);
+
+ const int numCols = (dim + 1)*numBones;
+ CSM.resize(numRows, numCols);
+
+ typedef typename MatrixXS::Scalar SSCALAR;
+ SSCALAR maxDiff = 0.0f;
+
+ for (int r=0; r<numRows; r++)
+ {
+ for (int coord=0; coord<dim+1; coord++)
+ {
+ for (int b=0; b<numBones; b++)
+ {
+ // this is just a test if we really have a multiple of 3x3 identity
+ Eigen::Matrix3f blok;
+ for (int v=0; v<3; v++)
+ {
+ for (int w=0; w<3; w++)
+ {
+ blok(v,w) = CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + w*numBones);
+ }
+ }
+
+ //SSCALAR value[3];
+ //for (int v=0; v<3; v++)
+ // CSM_M_SSCALAR[v](r, coord*(numBones*dim) + b + v*numBones);
+
+ SSCALAR mD = maxBlokErr<SSCALAR>(blok);
+ if (mD > maxDiff) maxDiff = mD;
+
+ // use the first value:
+ CSM(r, coord*numBones + b) = blok(0,0);
+ }
+ }
+ }
+
+ return maxDiff;
+ }
+
+ // splits x_0, ... , x_dim coordinates in column vector 'L' into a numBones*(dimp1) x dim matrix 'Lsep';
+ // assumes 'Lsep' has already been preallocated
+ //
+ // is this the same as uncolumnize? no.
+ template <typename MatL, typename MatLsep>
+ static void splitColumns(
+ const MatL &L,
+ int numBones,
+ int dim,
+ int dimp1,
+ MatLsep &Lsep)
+ {
+ assert(L.cols() == 1);
+ assert(L.rows() == dim*(dimp1)*numBones);
+
+ assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
+
+ for (int b=0; b<numBones; b++)
+ {
+ for (int coord=0; coord<dimp1; coord++)
+ {
+ for (int c=0; c<dim; c++)
+ {
+ Lsep(coord*numBones + b, c) = L(coord*numBones*dim + c*numBones + b, 0);
+ }
+ }
+ }
+ }
+
+
+ // the inverse of splitColumns, i.e., takes numBones*(dimp1) x dim matrix 'Lsep' and merges the dimensions
+ // into columns vector 'L' (which is assumed to be already allocated):
+ //
+ // is this the same as columnize? no.
+ template <typename MatrixXS>
+ static void mergeColumns(const MatrixXS &Lsep, int numBones, int dim, int dimp1, MatrixXS &L)
+ {
+ assert(L.cols() == 1);
+ assert(L.rows() == dim*(dimp1)*numBones);
+
+ assert(Lsep.rows() == (dimp1)*numBones && Lsep.cols() == dim);
+
+ for (int b=0; b<numBones; b++)
+ {
+ for (int coord=0; coord<dimp1; coord++)
+ {
+ for (int c=0; c<dim; c++)
+ {
+ L(coord*numBones*dim + c*numBones + b, 0) = Lsep(coord*numBones + b, c);
+ }
+ }
+ }
+ }
+
+ // converts "Solve1" the "rotations" part of FullSolve matrix (the first part)
+ // into one "condensed" matrix CSolve1 while checking we're not losing any
+ // information by this process; specifically, returns maximal difference from
+ // scaled 3x3 identity blocks, which should be pretty small number
+ template <typename MatrixXS>
+ static typename MatrixXS::Scalar condense_Solve1(MatrixXS &Solve1, int numBones, int numGroups, int dim, MatrixXS &CSolve1)
+ {
+ assert(Solve1.rows() == dim*(dim + 1)*numBones);
+ assert(Solve1.cols() == dim*dim*numGroups);
+
+ typedef typename MatrixXS::Scalar SSCALAR;
+ SSCALAR maxDiff = 0.0f;
+
+ CSolve1.resize((dim + 1)*numBones, dim*numGroups);
+ for (int rowCoord=0; rowCoord<dim+1; rowCoord++)
+ {
+ for (int b=0; b<numBones; b++)
+ {
+ for (int colCoord=0; colCoord<dim; colCoord++)
+ {
+ for (int g=0; g<numGroups; g++)
+ {
+ Eigen::Matrix3f blok;
+ for (int r=0; r<3; r++)
+ {
+ for (int c=0; c<3; c++)
+ {
+ blok(r, c) = Solve1(rowCoord*numBones*dim + r*numBones + b, colCoord*numGroups*dim + c*numGroups + g);
+ }
+ }
+
+ SSCALAR mD = maxBlokErr<SSCALAR>(blok);
+ if (mD > maxDiff) maxDiff = mD;
+
+ CSolve1(rowCoord*numBones + b, colCoord*numGroups + g) = blok(0,0);
+ }
+ }
+ }
+ }
+
+ return maxDiff;
+ }
+}
+
+template <typename LbsMatrixType, typename SSCALAR>
+IGL_INLINE bool igl::arap_dof_recomputation(
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & fixed_dim,
+ const Eigen::SparseMatrix<double> & A_eq,
+ ArapDOFData<LbsMatrixType, SSCALAR> & data)
+{
+ using namespace Eigen;
+ typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
+
+ LbsMatrixType * Q;
+ LbsMatrixType Qdyn;
+ if(data.with_dynamics)
+ {
+ // multiply by 1/timestep and to quadratic coefficients matrix
+ // Might be missing a 0.5 here
+ LbsMatrixType Q_copy = data.Q;
+ Qdyn = Q_copy + (1.0/(data.h*data.h))*data.Mass_tilde;
+ Q = &Qdyn;
+
+ // This may/should be superfluous
+ //printf("is_symmetric()\n");
+ if(!is_symmetric(*Q))
+ {
+ //printf("Fixing symmetry...\n");
+ // "Fix" symmetry
+ LbsMatrixType QT = (*Q).transpose();
+ LbsMatrixType Q_copy = *Q;
+ *Q = 0.5*(Q_copy+QT);
+ // Check that ^^^ this really worked. It doesn't always
+ //assert(is_symmetric(*Q));
+ }
+ }else
+ {
+ Q = &data.Q;
+ }
+
+ assert((int)data.CSM_M.size() == data.dim);
+ assert(A_eq.cols() == data.m*data.dim*(data.dim+1));
+ data.fixed_dim = fixed_dim;
+
+ if(fixed_dim.size() > 0)
+ {
+ assert(fixed_dim.maxCoeff() < data.m*data.dim*(data.dim+1));
+ assert(fixed_dim.minCoeff() >= 0);
+ }
+
+#ifdef EXTREME_VERBOSE
+ cout<<"data.fixed_dim=["<<endl<<data.fixed_dim<<endl<<"]+1;"<<endl;
+#endif
+
+ // Compute dense solve matrix (alternative of matrix factorization)
+ //printf("min_quad_dense_precompute()\n");
+ MatrixXd Qfull(*Q);
+ MatrixXd A_eqfull(A_eq);
+ MatrixXd M_Solve;
+
+ double timer0_start = get_seconds_hires();
+ bool use_lu = data.effective_dim != 2;
+ //use_lu = false;
+ //printf("use_lu: %s\n",(use_lu?"TRUE":"FALSE"));
+ min_quad_dense_precompute(Qfull, A_eqfull, use_lu,M_Solve);
+ double timer0_end = get_seconds_hires();
+ verbose("Bob timing: %.20f\n", (timer0_end - timer0_start)*1000.0);
+
+ // Precompute full solve matrix:
+ const int fsRows = data.m * data.dim * (data.dim + 1); // 12 * number_of_bones
+ const int fsCols1 = data.M_KG.cols(); // 9 * number_of_posConstraints
+ const int fsCols2 = A_eq.rows(); // number_of_posConstraints
+ data.M_FullSolve.resize(fsRows, fsCols1 + fsCols2);
+ // note the magical multiplicative constant "-0.5", I've no idea why it has
+ // to be there :)
+ data.M_FullSolve <<
+ (-0.5 * M_Solve.block(0, 0, fsRows, fsRows) * data.M_KG).template cast<SSCALAR>(),
+ M_Solve.block(0, fsRows, fsRows, fsCols2).template cast<SSCALAR>();
+
+ if(data.with_dynamics)
+ {
+ printf(
+ "---------------------------------------------------------------------\n"
+ "\n\n\nWITH DYNAMICS recomputation\n\n\n"
+ "---------------------------------------------------------------------\n"
+ );
+ // Also need to save Π1 before it gets multiplied by Ktilde (aka M_KG)
+ data.Pi_1 = M_Solve.block(0, 0, fsRows, fsRows).template cast<SSCALAR>();
+ }
+
+ // Precompute condensed matrices,
+ // first CSM:
+ std::vector<MatrixXS> CSM_M_SSCALAR;
+ CSM_M_SSCALAR.resize(data.dim);
+ for (int i=0; i<data.dim; i++) CSM_M_SSCALAR[i] = data.CSM_M[i].template cast<SSCALAR>();
+ SSCALAR maxErr1 = condense_CSM(CSM_M_SSCALAR, data.m, data.dim, data.CSM);
+ verbose("condense_CSM maxErr = %.15f (this should be close to zero)\n", maxErr1);
+ assert(fabs(maxErr1) < 1e-5);
+
+ // and then solveBlock1:
+ // number of groups
+ const int k = data.CSM_M[0].rows()/data.dim;
+ MatrixXS SolveBlock1 = data.M_FullSolve.block(0, 0, data.M_FullSolve.rows(), data.dim * data.dim * k);
+ SSCALAR maxErr2 = condense_Solve1(SolveBlock1, data.m, k, data.dim, data.CSolveBlock1);
+ verbose("condense_Solve1 maxErr = %.15f (this should be close to zero)\n", maxErr2);
+ assert(fabs(maxErr2) < 1e-5);
+
+ return true;
+}
+
+template <typename LbsMatrixType, typename SSCALAR>
+IGL_INLINE bool igl::arap_dof_update(
+ const ArapDOFData<LbsMatrixType, SSCALAR> & data,
+ const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
+ const Eigen::MatrixXd & L0,
+ const int max_iters,
+ const double
+#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
+ tol,
+#else
+ /*tol*/,
+#endif
+ Eigen::MatrixXd & L
+ )
+{
+ using namespace Eigen;
+ typedef Matrix<SSCALAR, Dynamic, Dynamic> MatrixXS;
+#ifdef ARAP_GLOBAL_TIMING
+ double timer_start = get_seconds_hires();
+#endif
+
+ // number of dimensions
+ assert((int)data.CSM_M.size() == data.dim);
+ assert((int)L0.size() == (data.m)*data.dim*(data.dim+1));
+ assert(max_iters >= 0);
+ assert(tol >= 0);
+
+ // timing variables
+ double
+ sec_start,
+ sec_covGather,
+ sec_fitRotations,
+ //sec_rhs,
+ sec_prepMult,
+ sec_solve, sec_end;
+
+ assert(L0.cols() == 1);
+#ifdef EXTREME_VERBOSE
+ cout<<"dim="<<data.dim<<";"<<endl;
+ cout<<"m="<<data.m<<";"<<endl;
+#endif
+
+ // number of groups
+ const int k = data.CSM_M[0].rows()/data.dim;
+ for(int i = 0;i<data.dim;i++)
+ {
+ assert(data.CSM_M[i].rows()/data.dim == k);
+ }
+#ifdef EXTREME_VERBOSE
+ cout<<"k="<<k<<";"<<endl;
+#endif
+
+ // resize output and initialize with initial guess
+ L = L0;
+#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
+ // Keep track of last solution
+ MatrixXS L_prev;
+#endif
+ // We will be iterating on L_SSCALAR, only at the end we convert back to double
+ MatrixXS L_SSCALAR = L.cast<SSCALAR>();
+
+ int iters = 0;
+#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
+ double max_diff = tol+1;
+#endif
+
+ MatrixXS S(k*data.dim,data.dim);
+ MatrixXS R(data.dim,data.dim*k);
+ Eigen::Matrix<SSCALAR,Eigen::Dynamic,1> Rcol(data.dim * data.dim * k);
+ Matrix<SSCALAR,Dynamic,1> B_eq_SSCALAR = B_eq.cast<SSCALAR>();
+ Matrix<SSCALAR,Dynamic,1> B_eq_fix_SSCALAR;
+ Matrix<SSCALAR,Dynamic,1> L0SSCALAR = L0.cast<SSCALAR>();
+ slice(L0SSCALAR, data.fixed_dim, B_eq_fix_SSCALAR);
+ //MatrixXS rhsFull(Rcol.rows() + B_eq.rows() + B_eq_fix_SSCALAR.rows(), 1);
+
+ MatrixXS Lsep(data.m*(data.dim + 1), 3);
+ const MatrixXS L_part2 =
+ data.M_FullSolve.block(0, Rcol.rows(), data.M_FullSolve.rows(), B_eq_SSCALAR.rows()) * B_eq_SSCALAR;
+ const MatrixXS L_part3 =
+ data.M_FullSolve.block(0, Rcol.rows() + B_eq_SSCALAR.rows(), data.M_FullSolve.rows(), B_eq_fix_SSCALAR.rows()) * B_eq_fix_SSCALAR;
+ MatrixXS L_part2and3 = L_part2 + L_part3;
+
+ // preallocate workspace variables:
+ MatrixXS Rxyz(k*data.dim, data.dim);
+ MatrixXS L_part1xyz((data.dim + 1) * data.m, data.dim);
+ MatrixXS L_part1(data.dim * (data.dim + 1) * data.m, 1);
+
+#ifdef ARAP_GLOBAL_TIMING
+ double timer_prepFinished = get_seconds_hires();
+#endif
+
+#ifdef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
+ while(iters < max_iters)
+#else
+ while(iters < max_iters && max_diff > tol)
+#endif
+ {
+ if(data.print_timings)
+ {
+ sec_start = get_seconds_hires();
+ }
+
+#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
+ L_prev = L_SSCALAR;
+#endif
+ ///////////////////////////////////////////////////////////////////////////
+ // Local step: Fix positions, fit rotations
+ ///////////////////////////////////////////////////////////////////////////
+
+ // Gather covariance matrices
+
+ splitColumns(L_SSCALAR, data.m, data.dim, data.dim + 1, Lsep);
+
+ S = data.CSM * Lsep;
+ // interestingly, this doesn't seem to be so slow, but
+ //MKL is still 2x faster (probably due to AVX)
+ //#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
+ // MKL_matMatMult_double(S, data.CSM, Lsep);
+ //#else
+ // MKL_matMatMult_single(S, data.CSM, Lsep);
+ //#endif
+
+ if(data.print_timings)
+ {
+ sec_covGather = get_seconds_hires();
+ }
+
+#ifdef EXTREME_VERBOSE
+ cout<<"S=["<<endl<<S<<endl<<"];"<<endl;
+#endif
+ // Fit rotations to covariance matrices
+ if(data.effective_dim == 2)
+ {
+ fit_rotations_planar(S,R);
+ }else
+ {
+#ifdef __SSE__ // fit_rotations_SSE will convert to float if necessary
+ fit_rotations_SSE(S,R);
+#else
+ fit_rotations(S,false,R);
+#endif
+ }
+
+#ifdef EXTREME_VERBOSE
+ cout<<"R=["<<endl<<R<<endl<<"];"<<endl;
+#endif
+
+ if(data.print_timings)
+ {
+ sec_fitRotations = get_seconds_hires();
+ }
+
+ ///////////////////////////////////////////////////////////////////////////
+ // "Global" step: fix rotations per mesh vertex, solve for
+ // linear transformations at handles
+ ///////////////////////////////////////////////////////////////////////////
+
+ // all this shuffling is retarded and not completely negligible time-wise;
+ // TODO: change fit_rotations_XXX so it returns R in the format ready for
+ // CSolveBlock1 multiplication
+ columnize(R, k, 2, Rcol);
+#ifdef EXTREME_VERBOSE
+ cout<<"Rcol=["<<endl<<Rcol<<endl<<"];"<<endl;
+#endif
+ splitColumns(Rcol, k, data.dim, data.dim, Rxyz);
+
+ if(data.print_timings)
+ {
+ sec_prepMult = get_seconds_hires();
+ }
+
+ L_part1xyz = data.CSolveBlock1 * Rxyz;
+ //#ifdef IGL_ARAP_DOF_DOUBLE_PRECISION_SOLVE
+ // MKL_matMatMult_double(L_part1xyz, data.CSolveBlock1, Rxyz);
+ //#else
+ // MKL_matMatMult_single(L_part1xyz, data.CSolveBlock1, Rxyz);
+ //#endif
+ mergeColumns(L_part1xyz, data.m, data.dim, data.dim + 1, L_part1);
+
+ if(data.with_dynamics)
+ {
+ // Consider reordering or precomputing matrix multiplications
+ MatrixXS L_part1_dyn(data.dim * (data.dim + 1) * data.m, 1);
+ // Eigen can't parse this:
+ //L_part1_dyn =
+ // -(2.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.L0 +
+ // (1.0/(data.h*data.h)) * data.Pi_1 * data.Mass_tilde * data.Lm1;
+ // -1.0 because we've moved these linear terms to the right hand side
+ //MatrixXS temp = -1.0 *
+ // ((-2.0/(data.h*data.h)) * data.L0.array() +
+ // (1.0/(data.h*data.h)) * data.Lm1.array()).matrix();
+ //MatrixXS temp = -1.0 *
+ // ( (-1.0/(data.h*data.h)) * data.L0.array() +
+ // (1.0/(data.h*data.h)) * data.Lm1.array()
+ // (-1.0/(data.h*data.h)) * data.L0.array() +
+ // ).matrix();
+ //Lvel0 = (1.0/(data.h)) * data.Lm1.array() - data.L0.array();
+ MatrixXS temp = -1.0 *
+ ( (-1.0/(data.h*data.h)) * data.L0.array() +
+ (1.0/(data.h)) * data.Lvel0.array()
+ ).matrix();
+ MatrixXd temp_d = temp.template cast<double>();
+
+ MatrixXd temp_g = data.fgrav*(data.grav_mag*data.grav_dir);
+
+ assert(data.fext.rows() == temp_g.rows());
+ assert(data.fext.cols() == temp_g.cols());
+ MatrixXd temp2 = data.Mass_tilde * temp_d + temp_g + data.fext.template cast<double>();
+ MatrixXS temp2_f = temp2.template cast<SSCALAR>();
+ L_part1_dyn = data.Pi_1 * temp2_f;
+ L_part1.array() = L_part1.array() + L_part1_dyn.array();
+ }
+
+ //L_SSCALAR = L_part1 + L_part2and3;
+ assert(L_SSCALAR.rows() == L_part1.rows() && L_SSCALAR.rows() == L_part2and3.rows());
+ for (int i=0; i<L_SSCALAR.rows(); i++)
+ {
+ L_SSCALAR(i, 0) = L_part1(i, 0) + L_part2and3(i, 0);
+ }
+
+#ifdef EXTREME_VERBOSE
+ cout<<"L=["<<endl<<L<<endl<<"];"<<endl;
+#endif
+
+ if(data.print_timings)
+ {
+ sec_solve = get_seconds_hires();
+ }
+
+#ifndef IGL_ARAP_DOF_FIXED_ITERATIONS_COUNT
+ // Compute maximum absolute difference with last iteration's solution
+ max_diff = (L_SSCALAR-L_prev).eval().array().abs().matrix().maxCoeff();
+#endif
+ iters++;
+
+ if(data.print_timings)
+ {
+ sec_end = get_seconds_hires();
+#ifndef WIN32
+ // trick to get sec_* variables to compile without warning on mac
+ if(false)
+#endif
+ printf(
+ "\ntotal iteration time = %f "
+ "[local: covGather = %f, "
+ "fitRotations = %f, "
+ "global: prep = %f, "
+ "solve = %f, "
+ "error = %f [ms]]\n",
+ (sec_end - sec_start)*1000.0,
+ (sec_covGather - sec_start)*1000.0,
+ (sec_fitRotations - sec_covGather)*1000.0,
+ (sec_prepMult - sec_fitRotations)*1000.0,
+ (sec_solve - sec_prepMult)*1000.0,
+ (sec_end - sec_solve)*1000.0 );
+ }
+ }
+
+
+ L = L_SSCALAR.template cast<double>();
+ assert(L.cols() == 1);
+
+#ifdef ARAP_GLOBAL_TIMING
+ double timer_finito = get_seconds_hires();
+ printf(
+ "ARAP preparation = %f, "
+ "all %i iterations = %f [ms]\n",
+ (timer_prepFinished - timer_start)*1000.0,
+ max_iters,
+ (timer_finito - timer_prepFinished)*1000.0);
+#endif
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
+template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, double>&);
+template bool igl::arap_dof_update<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template bool igl::arap_dof_recomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
+template bool igl::arap_dof_precomputation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, igl::ArapDOFData<Eigen::Matrix<double, -1, -1, 0, -1, -1>, float>&);
+#endif
diff --git a/xs/src/igl/arap_dof.h b/xs/src/igl/arap_dof.h
new file mode 100644
index 000000000..f3647a3a1
--- /dev/null
+++ b/xs/src/igl/arap_dof.h
@@ -0,0 +1,244 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ARAP_ENERGY_TYPE_DOF_H
+#define IGL_ARAP_ENERGY_TYPE_DOF_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+#include "ARAPEnergyType.h"
+#include <vector>
+
+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
+ template <typename LbsMatrixType, typename SSCALAR>
+ IGL_INLINE bool arap_dof_precomputation(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const LbsMatrixType & M,
+ 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
+ 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
+ template <typename LbsMatrixType, typename SSCALAR>
+ IGL_INLINE bool arap_dof_update(
+ const ArapDOFData<LbsMatrixType,SSCALAR> & data,
+ const Eigen::Matrix<double,Eigen::Dynamic,1> & B_eq,
+ const Eigen::MatrixXd & L0,
+ const int max_iters,
+ const double tol,
+ Eigen::MatrixXd & L
+ );
+
+ // Structure that contains fields for all precomputed data or data that needs
+ // to be remembered at update
+ template <typename LbsMatrixType, typename SSCALAR>
+ struct ArapDOFData
+ {
+ typedef Eigen::Matrix<SSCALAR, Eigen::Dynamic, Eigen::Dynamic> MatrixXS;
+ // 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
+ 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;
+ std::vector<Eigen::MatrixXd> CSM_M;
+ LbsMatrixType M_KG;
+ // Number of mesh vertices
+ int n;
+ // Number of weight functions
+ int m;
+ // Number of dimensions
+ int dim;
+ // Effective dimensions
+ int effective_dim;
+ // List of indices into C of positional constraints
+ Eigen::Matrix<int,Eigen::Dynamic,1> interpolated;
+ std::vector<bool> free_mask;
+ // 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
+ MatrixXS M_FullSolve;
+
+ // Precomputed condensed matrices (3x3 commutators folded to 1x1):
+ MatrixXS CSM;
+ MatrixXS CSolveBlock1;
+
+ // Print timings at each update
+ bool print_timings;
+
+ // 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
+ double h;
+
+ // L0 #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"
+ MatrixXS Lvel0;
+
+ // #V by dim matrix of external forces
+ // fext
+ MatrixXS fext;
+
+ // Mass_tilde: MT * Mass * M
+ LbsMatrixType Mass_tilde;
+
+ // Force due to gravity (premultiplier)
+ Eigen::MatrixXd fgrav;
+ // Direction of gravity
+ Eigen::Vector3d grav_dir;
+ // Magnitude of gravity
+ double grav_mag;
+
+ // Π1 from the paper
+ MatrixXS Pi_1;
+
+ // Default values
+ ArapDOFData():
+ energy(igl::ARAP_ENERGY_TYPE_SPOKES),
+ with_dynamics(false),
+ h(1),
+ grav_dir(0,-1,0),
+ grav_mag(0)
+ {
+ }
+ };
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "arap_dof.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/arap_linear_block.cpp b/xs/src/igl/arap_linear_block.cpp
new file mode 100644
index 000000000..14886b2bc
--- /dev/null
+++ b/xs/src/igl/arap_linear_block.cpp
@@ -0,0 +1,253 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "arap_linear_block.h"
+#include "verbose.h"
+#include "cotmatrix_entries.h"
+#include <Eigen/Dense>
+
+template <typename MatV, typename MatF, typename Scalar>
+IGL_INLINE void igl::arap_linear_block(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ const igl::ARAPEnergyType energy,
+ Eigen::SparseMatrix<Scalar> & Kd)
+{
+ switch(energy)
+ {
+ case ARAP_ENERGY_TYPE_SPOKES:
+ return igl::arap_linear_block_spokes(V,F,d,Kd);
+ break;
+ case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
+ return igl::arap_linear_block_spokes_and_rims(V,F,d,Kd);
+ break;
+ case ARAP_ENERGY_TYPE_ELEMENTS:
+ return igl::arap_linear_block_elements(V,F,d,Kd);
+ break;
+ default:
+ verbose("Unsupported energy type: %d\n",energy);
+ assert(false);
+ }
+}
+
+
+template <typename MatV, typename MatF, typename Scalar>
+IGL_INLINE void igl::arap_linear_block_spokes(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ Eigen::SparseMatrix<Scalar> & Kd)
+{
+ using namespace std;
+ using namespace Eigen;
+ // simplex size (3: triangles, 4: tetrahedra)
+ int simplex_size = F.cols();
+ // Number of elements
+ int m = F.rows();
+ // Temporary output
+ Matrix<int,Dynamic,2> edges;
+ Kd.resize(V.rows(), V.rows());
+ vector<Triplet<Scalar> > Kd_IJV;
+ if(simplex_size == 3)
+ {
+ // triangles
+ Kd.reserve(7*V.rows());
+ Kd_IJV.reserve(7*V.rows());
+ edges.resize(3,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1;
+ }else if(simplex_size == 4)
+ {
+ // tets
+ Kd.reserve(17*V.rows());
+ Kd_IJV.reserve(17*V.rows());
+ edges.resize(6,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1,
+ 3,0,
+ 3,1,
+ 3,2;
+ }
+ // gather cotangent weights
+ Matrix<Scalar,Dynamic,Dynamic> C;
+ cotmatrix_entries(V,F,C);
+ // should have weights for each edge
+ assert(C.cols() == edges.rows());
+ // loop over elements
+ for(int i = 0;i<m;i++)
+ {
+ // loop over edges of element
+ for(int e = 0;e<edges.rows();e++)
+ {
+ int source = F(i,edges(e,0));
+ int dest = F(i,edges(e,1));
+ double v = 0.5*C(i,e)*(V(source,d)-V(dest,d));
+ Kd_IJV.push_back(Triplet<Scalar>(source,dest,v));
+ Kd_IJV.push_back(Triplet<Scalar>(dest,source,-v));
+ Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
+ Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
+ }
+ }
+ Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
+ Kd.makeCompressed();
+}
+
+template <typename MatV, typename MatF, typename Scalar>
+IGL_INLINE void igl::arap_linear_block_spokes_and_rims(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ Eigen::SparseMatrix<Scalar> & Kd)
+{
+ using namespace std;
+ using namespace Eigen;
+ // simplex size (3: triangles, 4: tetrahedra)
+ int simplex_size = F.cols();
+ // Number of elements
+ int m = F.rows();
+ // Temporary output
+ Kd.resize(V.rows(), V.rows());
+ vector<Triplet<Scalar> > Kd_IJV;
+ Matrix<int,Dynamic,2> edges;
+ if(simplex_size == 3)
+ {
+ // triangles
+ Kd.reserve(7*V.rows());
+ Kd_IJV.reserve(7*V.rows());
+ edges.resize(3,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1;
+ }else if(simplex_size == 4)
+ {
+ // tets
+ Kd.reserve(17*V.rows());
+ Kd_IJV.reserve(17*V.rows());
+ edges.resize(6,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1,
+ 3,0,
+ 3,1,
+ 3,2;
+ // Not implemented yet for tets
+ assert(false);
+ }
+ // gather cotangent weights
+ Matrix<Scalar,Dynamic,Dynamic> C;
+ cotmatrix_entries(V,F,C);
+ // should have weights for each edge
+ assert(C.cols() == edges.rows());
+ // loop over elements
+ for(int i = 0;i<m;i++)
+ {
+ // loop over edges of element
+ for(int e = 0;e<edges.rows();e++)
+ {
+ int source = F(i,edges(e,0));
+ int dest = F(i,edges(e,1));
+ double v = C(i,e)*(V(source,d)-V(dest,d))/3.0;
+ // loop over edges again
+ for(int f = 0;f<edges.rows();f++)
+ {
+ int Rs = F(i,edges(f,0));
+ int Rd = F(i,edges(f,1));
+ if(Rs == source && Rd == dest)
+ {
+ Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,v));
+ Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,-v));
+ }else if(Rd == source)
+ {
+ Kd_IJV.push_back(Triplet<Scalar>(Rd,Rs,v));
+ }else if(Rs == dest)
+ {
+ Kd_IJV.push_back(Triplet<Scalar>(Rs,Rd,-v));
+ }
+ }
+ Kd_IJV.push_back(Triplet<Scalar>(source,source,v));
+ Kd_IJV.push_back(Triplet<Scalar>(dest,dest,-v));
+ }
+ }
+ Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
+ Kd.makeCompressed();
+}
+
+template <typename MatV, typename MatF, typename Scalar>
+IGL_INLINE void igl::arap_linear_block_elements(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ Eigen::SparseMatrix<Scalar> & Kd)
+{
+ using namespace std;
+ using namespace Eigen;
+ // simplex size (3: triangles, 4: tetrahedra)
+ int simplex_size = F.cols();
+ // Number of elements
+ int m = F.rows();
+ // Temporary output
+ Kd.resize(V.rows(), F.rows());
+ vector<Triplet<Scalar> > Kd_IJV;
+ Matrix<int,Dynamic,2> edges;
+ if(simplex_size == 3)
+ {
+ // triangles
+ Kd.reserve(7*V.rows());
+ Kd_IJV.reserve(7*V.rows());
+ edges.resize(3,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1;
+ }else if(simplex_size == 4)
+ {
+ // tets
+ Kd.reserve(17*V.rows());
+ Kd_IJV.reserve(17*V.rows());
+ edges.resize(6,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1,
+ 3,0,
+ 3,1,
+ 3,2;
+ }
+ // gather cotangent weights
+ Matrix<Scalar,Dynamic,Dynamic> C;
+ cotmatrix_entries(V,F,C);
+ // should have weights for each edge
+ assert(C.cols() == edges.rows());
+ // loop over elements
+ for(int i = 0;i<m;i++)
+ {
+ // loop over edges of element
+ for(int e = 0;e<edges.rows();e++)
+ {
+ int source = F(i,edges(e,0));
+ int dest = F(i,edges(e,1));
+ double v = C(i,e)*(V(source,d)-V(dest,d));
+ Kd_IJV.push_back(Triplet<Scalar>(source,i,v));
+ Kd_IJV.push_back(Triplet<Scalar>(dest,i,-v));
+ }
+ }
+ Kd.setFromTriplets(Kd_IJV.begin(),Kd_IJV.end());
+ Kd.makeCompressed();
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template IGL_INLINE void igl::arap_linear_block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, igl::ARAPEnergyType, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/arap_linear_block.h b/xs/src/igl/arap_linear_block.h
new file mode 100644
index 000000000..8dfb744f6
--- /dev/null
+++ b/xs/src/igl/arap_linear_block.h
@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ARAP_LINEAR_BLOCK_H
+#define IGL_ARAP_LINEAR_BLOCK_H
+#include "igl_inline.h"
+
+#include <Eigen/Sparse>
+#include <igl/ARAPEnergyType.h>
+
+namespace igl
+{
+ // ARAP_LINEAR_BLOCK constructs a block of the matrix which constructs the
+ // linear terms of a given arap energy. When treating rotations as knowns
+ // (arranged in a column) then this constructs Kd of K such that the linear
+ // portion of the energy is as a column:
+ // K * R = [Kx Z ... Ky Z ...
+ // Z Kx ... Z Ky ...
+ // ... ]
+ // These blocks are also used to build the "covariance scatter matrices".
+ // Here we want to build a scatter matrix that multiplies against positions
+ // (treated as known) producing covariance matrices to fit each rotation.
+ // Notice that in the case of the RHS of the poisson solve the rotations are
+ // known and the positions unknown, and vice versa for rotation fitting.
+ // These linear block just relate the rotations to the positions, linearly in
+ // each.
+ //
+ // Templates:
+ // MatV vertex position matrix, e.g. Eigen::MatrixXd
+ // MatF face index matrix, e.g. Eigen::MatrixXd
+ // Scalar e.g. double
+ // Inputs:
+ // V #V by dim list of initial domain positions
+ // F #F by #simplex size list of triangle indices into V
+ // d coordinate of linear constructor to build
+ // energy ARAPEnergyType enum value defining which energy is being used.
+ // See ARAPEnergyType.h for valid options and explanations.
+ // Outputs:
+ // Kd #V by #V/#F block of the linear constructor matrix corresponding to
+ // coordinate d
+ //
+ template <typename MatV, typename MatF, typename Scalar>
+ IGL_INLINE void arap_linear_block(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ const igl::ARAPEnergyType energy,
+ Eigen::SparseMatrix<Scalar> & Kd);
+ // Helper functions for each energy type
+ template <typename MatV, typename MatF, typename Scalar>
+ IGL_INLINE void arap_linear_block_spokes(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ Eigen::SparseMatrix<Scalar> & Kd);
+ template <typename MatV, typename MatF, typename Scalar>
+ IGL_INLINE void arap_linear_block_spokes_and_rims(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ Eigen::SparseMatrix<Scalar> & Kd);
+ template <typename MatV, typename MatF, typename Scalar>
+ IGL_INLINE void arap_linear_block_elements(
+ const MatV & V,
+ const MatF & F,
+ const int d,
+ Eigen::SparseMatrix<Scalar> & Kd);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "arap_linear_block.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/arap_rhs.cpp b/xs/src/igl/arap_rhs.cpp
new file mode 100644
index 000000000..b46462168
--- /dev/null
+++ b/xs/src/igl/arap_rhs.cpp
@@ -0,0 +1,89 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "arap_rhs.h"
+#include "arap_linear_block.h"
+#include "verbose.h"
+#include "repdiag.h"
+#include "cat.h"
+#include <iostream>
+
+IGL_INLINE void igl::arap_rhs(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const int dim,
+ const igl::ARAPEnergyType energy,
+ Eigen::SparseMatrix<double>& K)
+{
+ using namespace std;
+ using namespace Eigen;
+ // Number of dimensions
+ int Vdim = V.cols();
+ //// Number of mesh vertices
+ //int n = V.rows();
+ //// Number of mesh elements
+ //int m = F.rows();
+ //// number of rotations
+ //int nr;
+ switch(energy)
+ {
+ case ARAP_ENERGY_TYPE_SPOKES:
+ //nr = n;
+ break;
+ case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
+ //nr = n;
+ break;
+ case ARAP_ENERGY_TYPE_ELEMENTS:
+ //nr = m;
+ break;
+ default:
+ fprintf(
+ stderr,
+ "arap_rhs.h: Error: Unsupported arap energy %d\n",
+ energy);
+ return;
+ }
+
+ SparseMatrix<double> KX,KY,KZ;
+ arap_linear_block(V,F,0,energy,KX);
+ arap_linear_block(V,F,1,energy,KY);
+ if(Vdim == 2)
+ {
+ K = cat(2,repdiag(KX,dim),repdiag(KY,dim));
+ }else if(Vdim == 3)
+ {
+ arap_linear_block(V,F,2,energy,KZ);
+ if(dim == 3)
+ {
+ K = cat(2,cat(2,repdiag(KX,dim),repdiag(KY,dim)),repdiag(KZ,dim));
+ }else if(dim ==2)
+ {
+ SparseMatrix<double> ZZ(KX.rows()*2,KX.cols());
+ K = cat(2,cat(2,
+ cat(2,repdiag(KX,dim),ZZ),
+ cat(2,repdiag(KY,dim),ZZ)),
+ cat(2,repdiag(KZ,dim),ZZ));
+ }else
+ {
+ assert(false);
+ fprintf(
+ stderr,
+ "arap_rhs.h: Error: Unsupported dimension %d\n",
+ dim);
+ }
+ }else
+ {
+ assert(false);
+ fprintf(
+ stderr,
+ "arap_rhs.h: Error: Unsupported dimension %d\n",
+ Vdim);
+ return;
+ }
+
+}
+
diff --git a/xs/src/igl/arap_rhs.h b/xs/src/igl/arap_rhs.h
new file mode 100644
index 000000000..5a1c370c1
--- /dev/null
+++ b/xs/src/igl/arap_rhs.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ARAP_RHS_H
+#define IGL_ARAP_RHS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+#include <igl/ARAPEnergyType.h>
+
+namespace igl
+{
+ // ARAP_RHS build right-hand side constructor of global poisson solve for
+ // various Arap energies
+ // Inputs:
+ // V #V by Vdim list of initial domain positions
+ // F #F by 3 list of triangle indices into V
+ // dim dimension being used at solve time. For deformation usually dim =
+ // V.cols(), for surface parameterization V.cols() = 3 and dim = 2
+ // energy igl::ARAPEnergyType enum value defining which energy is being
+ // used. See igl::ARAPEnergyType.h for valid options and explanations.
+ // Outputs:
+ // K #V*dim by #(F|V)*dim*dim matrix such that:
+ // b = K * reshape(permute(R,[3 1 2]),size(V|F,1)*size(V,2)*size(V,2),1);
+ //
+ // See also: arap_linear_block
+ IGL_INLINE void arap_rhs(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const int dim,
+ const igl::ARAPEnergyType energy,
+ Eigen::SparseMatrix<double>& K);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "arap_rhs.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/average_onto_faces.cpp b/xs/src/igl/average_onto_faces.cpp
new file mode 100644
index 000000000..b5cec91ad
--- /dev/null
+++ b/xs/src/igl/average_onto_faces.cpp
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "average_onto_faces.h"
+
+template <typename T, typename I>
+IGL_INLINE void igl::average_onto_faces(const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
+ const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
+ const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
+ Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF)
+{
+
+ SF = Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>::Zero(F.rows(),S.cols());
+
+ for (int i = 0; i <F.rows(); ++i)
+ for (int j = 0; j<F.cols(); ++j)
+ SF.row(i) += S.row(F(i,j));
+
+ SF.array() /= F.cols();
+
+};
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/average_onto_faces.h b/xs/src/igl/average_onto_faces.h
new file mode 100644
index 000000000..1afa919e9
--- /dev/null
+++ b/xs/src/igl/average_onto_faces.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_AVERAGE_ONTO_FACES_H
+#define IGL_AVERAGE_ONTO_FACES_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+namespace igl
+{
+ // average_onto_vertices
+ // Move a scalar field defined on faces to vertices by averaging
+ //
+ // Input:
+ // V,F: mesh
+ // S: scalar field defined on vertices, Vx1
+ //
+ // Output:
+ // SV: scalar field defined on faces
+ template <typename T, typename I>
+ IGL_INLINE void average_onto_faces(
+ const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
+ const Eigen::Matrix<I, Eigen::Dynamic, Eigen::Dynamic> &F,
+ const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &S,
+ Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &SF);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "average_onto_faces.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/average_onto_vertices.cpp b/xs/src/igl/average_onto_vertices.cpp
new file mode 100644
index 000000000..a30854edb
--- /dev/null
+++ b/xs/src/igl/average_onto_vertices.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "average_onto_vertices.h"
+
+template<typename DerivedV,typename DerivedF,typename DerivedS>
+IGL_INLINE void igl::average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ const Eigen::MatrixBase<DerivedS> &S,
+ Eigen::MatrixBase<DerivedS> &SV)
+{
+ SV = DerivedS::Zero(V.rows(),S.cols());
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> COUNT(V.rows());
+ COUNT.setZero();
+ for (int i = 0; i <F.rows(); ++i)
+ {
+ for (int j = 0; j<F.cols(); ++j)
+ {
+ SV.row(F(i,j)) += S.row(i);
+ COUNT[F(i,j)] ++;
+ }
+ }
+ for (int i = 0; i <V.rows(); ++i)
+ SV.row(i) /= COUNT[i];
+};
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/average_onto_vertices.h b/xs/src/igl/average_onto_vertices.h
new file mode 100644
index 000000000..e7fca6238
--- /dev/null
+++ b/xs/src/igl/average_onto_vertices.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_AVERAGE_ONTO_VERTICES_H
+#define IGL_AVERAGE_ONTO_VERTICES_H
+#include "igl_inline.h"
+
+#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
+ template<typename DerivedV,typename DerivedF,typename DerivedS>
+ IGL_INLINE void average_onto_vertices(const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ const Eigen::MatrixBase<DerivedS> &S,
+ Eigen::MatrixBase<DerivedS> &SV);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "average_onto_vertices.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/avg_edge_length.cpp b/xs/src/igl/avg_edge_length.cpp
new file mode 100644
index 000000000..b813d484a
--- /dev/null
+++ b/xs/src/igl/avg_edge_length.cpp
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "avg_edge_length.h"
+
+#include <vector>
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE double igl::avg_edge_length(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F)
+{
+ double avg = 0;
+ long int count = 0;
+
+ // Augh. Technically this is double counting interior edges...
+ for (unsigned i=0;i<F.rows();++i)
+ {
+ for (unsigned j=0;j<F.cols();++j)
+ {
+ ++count;
+ avg += (V.row(F(i,j)) - V.row(F(i,(j+1)%F.cols()))).norm();
+ }
+ }
+
+ return avg / (double) count;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template double igl::avg_edge_length<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template double igl::avg_edge_length<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+// generated by autoexplicit.sh
+#endif
diff --git a/xs/src/igl/avg_edge_length.h b/xs/src/igl/avg_edge_length.h
new file mode 100644
index 000000000..613f8f5da
--- /dev/null
+++ b/xs/src/igl/avg_edge_length.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_AVERAGEEDGELENGTH_H
+#define IGL_AVERAGEEDGELENGTH_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+#include <vector>
+
+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
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE double avg_edge_length(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "avg_edge_length.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/axis_angle_to_quat.cpp b/xs/src/igl/axis_angle_to_quat.cpp
new file mode 100644
index 000000000..009d0522c
--- /dev/null
+++ b/xs/src/igl/axis_angle_to_quat.cpp
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "axis_angle_to_quat.h"
+#include "EPS.h"
+#include <cmath>
+
+// http://www.antisphere.com/Wiki/tools:anttweakbar
+template <typename Q_type>
+IGL_INLINE void igl::axis_angle_to_quat(
+ const Q_type *axis,
+ const Q_type angle,
+ Q_type *out)
+{
+ Q_type n = axis[0]*axis[0] + axis[1]*axis[1] + axis[2]*axis[2];
+ if( fabs(n)>igl::EPS<Q_type>())
+ {
+ Q_type f = 0.5*angle;
+ out[3] = cos(f);
+ f = sin(f)/sqrt(n);
+ out[0] = axis[0]*f;
+ out[1] = axis[1]*f;
+ out[2] = axis[2]*f;
+ }
+ else
+ {
+ out[3] = 1.0;
+ out[0] = out[1] = out[2] = 0.0;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::axis_angle_to_quat<double>(double const*, double, double*);
+// generated by autoexplicit.sh
+template void igl::axis_angle_to_quat<float>(float const*, float, float*);
+#endif
diff --git a/xs/src/igl/axis_angle_to_quat.h b/xs/src/igl/axis_angle_to_quat.h
new file mode 100644
index 000000000..6533b1bec
--- /dev/null
+++ b/xs/src/igl/axis_angle_to_quat.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_AXIS_ANGLE_TO_QUAT_H
+#define IGL_AXIS_ANGLE_TO_QUAT_H
+#include "igl_inline.h"
+
+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
+ template <typename Q_type>
+ IGL_INLINE void axis_angle_to_quat(
+ const Q_type *axis,
+ const Q_type angle,
+ Q_type *out);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "axis_angle_to_quat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/barycenter.cpp b/xs/src/igl/barycenter.cpp
new file mode 100644
index 000000000..065f82aab
--- /dev/null
+++ b/xs/src/igl/barycenter.cpp
@@ -0,0 +1,57 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "barycenter.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedBC>
+IGL_INLINE void igl::barycenter(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedBC> & BC)
+{
+ BC.setZero(F.rows(),V.cols());
+ // Loop over faces
+ for(int i = 0;i<F.rows();i++)
+ {
+ // loop around face
+ for(int j = 0;j<F.cols();j++)
+ {
+ // Accumulate
+ BC.row(i) += V.row(F(i,j));
+ }
+ // average
+ BC.row(i) /= double(F.cols());
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::barycenter<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::barycenter<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+#endif
diff --git a/xs/src/igl/barycenter.h b/xs/src/igl/barycenter.h
new file mode 100644
index 000000000..ef78e94a6
--- /dev/null
+++ b/xs/src/igl/barycenter.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BARYCENTER_H
+#define IGL_BARYCENTER_H
+#include "igl_inline.h"
+#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
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedBC>
+ IGL_INLINE void barycenter(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedBC> & BC);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "barycenter.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/barycentric_coordinates.cpp b/xs/src/igl/barycentric_coordinates.cpp
new file mode 100644
index 000000000..998a737bf
--- /dev/null
+++ b/xs/src/igl/barycentric_coordinates.cpp
@@ -0,0 +1,113 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "barycentric_coordinates.h"
+#include "volume.h"
+
+template <
+ typename DerivedP,
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedD,
+ typename DerivedL>
+IGL_INLINE void igl::barycentric_coordinates(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ const Eigen::MatrixBase<DerivedD> & D,
+ Eigen::PlainObjectBase<DerivedL> & L)
+{
+ using namespace Eigen;
+ assert(P.cols() == 3 && "query must be in 3d");
+ assert(A.cols() == 3 && "corners must be in 3d");
+ assert(B.cols() == 3 && "corners must be in 3d");
+ assert(C.cols() == 3 && "corners must be in 3d");
+ assert(D.cols() == 3 && "corners must be in 3d");
+ assert(P.rows() == A.rows() && "Must have same number of queries as corners");
+ assert(A.rows() == B.rows() && "Corners must be same size");
+ assert(A.rows() == C.rows() && "Corners must be same size");
+ assert(A.rows() == D.rows() && "Corners must be same size");
+ typedef Matrix<typename DerivedL::Scalar,DerivedL::RowsAtCompileTime,1>
+ VectorXS;
+ // Total volume
+ VectorXS vol,LA,LB,LC,LD;
+ volume(B,D,C,P,LA);
+ volume(A,C,D,P,LB);
+ volume(A,D,B,P,LC);
+ volume(A,B,C,P,LD);
+ volume(A,B,C,D,vol);
+ L.resize(P.rows(),4);
+ L<<LA,LB,LC,LD;
+ L.array().colwise() /= vol.array();
+}
+
+template <
+ typename DerivedP,
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedL>
+IGL_INLINE void igl::barycentric_coordinates(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedL> & L)
+{
+ using namespace Eigen;
+#ifndef NDEBUG
+ const int DIM = P.cols();
+ assert(A.cols() == DIM && "corners must be in same dimension as query");
+ assert(B.cols() == DIM && "corners must be in same dimension as query");
+ assert(C.cols() == DIM && "corners must be in same dimension as query");
+ assert(P.rows() == A.rows() && "Must have same number of queries as corners");
+ assert(A.rows() == B.rows() && "Corners must be same size");
+ assert(A.rows() == C.rows() && "Corners must be same size");
+#endif
+
+ // http://gamedev.stackexchange.com/a/23745
+ typedef
+ Eigen::Array<
+ typename DerivedP::Scalar,
+ DerivedP::RowsAtCompileTime,
+ DerivedP::ColsAtCompileTime>
+ ArrayS;
+ typedef
+ Eigen::Array<
+ typename DerivedP::Scalar,
+ DerivedP::RowsAtCompileTime,
+ 1>
+ VectorS;
+
+ const ArrayS v0 = B.array() - A.array();
+ const ArrayS v1 = C.array() - A.array();
+ const ArrayS v2 = P.array() - A.array();
+ VectorS d00 = (v0*v0).rowwise().sum();
+ VectorS d01 = (v0*v1).rowwise().sum();
+ VectorS d11 = (v1*v1).rowwise().sum();
+ VectorS d20 = (v2*v0).rowwise().sum();
+ VectorS d21 = (v2*v1).rowwise().sum();
+ VectorS denom = d00 * d11 - d01 * d01;
+ L.resize(P.rows(),3);
+ L.col(1) = (d11 * d20 - d01 * d21) / denom;
+ L.col(2) = (d00 * d21 - d01 * d20) / denom;
+ L.col(0) = 1.0f -(L.col(1) + L.col(2)).array();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::barycentric_coordinates<Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::barycentric_coordinates<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+template void igl::barycentric_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::barycentric_coordinates<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::barycentric_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/barycentric_coordinates.h b/xs/src/igl/barycentric_coordinates.h
new file mode 100644
index 000000000..ec08669f2
--- /dev/null
+++ b/xs/src/igl/barycentric_coordinates.h
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BARYCENTRIC_COORDINATES_H
+#define IGL_BARYCENTRIC_COORDINATES_H
+#include "igl_inline.h"
+#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
+ //
+ template <
+ typename DerivedP,
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedD,
+ typename DerivedL>
+ IGL_INLINE void barycentric_coordinates(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ 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
+ //
+ template <
+ typename DerivedP,
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedL>
+ IGL_INLINE void barycentric_coordinates(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedL> & L);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "barycentric_coordinates.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/barycentric_to_global.cpp b/xs/src/igl/barycentric_to_global.cpp
new file mode 100755
index 000000000..e2656ad70
--- /dev/null
+++ b/xs/src/igl/barycentric_to_global.cpp
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "barycentric_to_global.h"
+
+// For error printing
+#include <cstdio>
+#include <vector>
+
+namespace igl
+{
+ template <typename Scalar, typename Index>
+ IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> barycentric_to_global(
+ const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
+ const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
+ const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc)
+ {
+ Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> R;
+ R.resize(bc.rows(),3);
+
+ for (unsigned i=0; i<R.rows(); ++i)
+ {
+ unsigned id = round(bc(i,0));
+ double u = bc(i,1);
+ double v = bc(i,2);
+
+ if (id != -1)
+ R.row(i) = V.row(F(id,0)) +
+ ((V.row(F(id,1)) - V.row(F(id,0))) * u +
+ (V.row(F(id,2)) - V.row(F(id,0))) * v );
+ else
+ R.row(i) << 0,0,0;
+ }
+ return R;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::barycentric_to_global<double, int>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&);
+#endif
diff --git a/xs/src/igl/barycentric_to_global.h b/xs/src/igl/barycentric_to_global.h
new file mode 100755
index 000000000..466187173
--- /dev/null
+++ b/xs/src/igl/barycentric_to_global.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BARYCENTRIC2GLOBAL_H
+#define IGL_BARYCENTRIC2GLOBAL_H
+#include <igl/igl_inline.h>
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Converts barycentric coordinates in the embree form to 3D coordinates
+ // Embree stores barycentric coordinates as triples: fid, bc1, bc2
+ // fid is the id of a face, bc1 is the displacement of the point wrt the
+ // first vertex v0 and the edge v1-v0. Similarly, bc2 is the displacement
+ // wrt v2-v0.
+ //
+ // Input:
+ // V: #Vx3 Vertices of the mesh
+ // F: #Fxe Faces of the mesh
+ // bc: #Xx3 Barycentric coordinates, one row per point
+ //
+ // Output:
+ // #X: #Xx3 3D coordinates of all points in bc
+ template <typename Scalar, typename Index>
+ IGL_INLINE Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>
+ barycentric_to_global(
+ const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V,
+ const Eigen::Matrix<Index,Eigen::Dynamic,Eigen::Dynamic> & F,
+ const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & bc);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "barycentric_to_global.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/basename.cpp b/xs/src/igl/basename.cpp
new file mode 100644
index 000000000..ae4fb118e
--- /dev/null
+++ b/xs/src/igl/basename.cpp
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "basename.h"
+
+#include <algorithm>
+
+IGL_INLINE std::string igl::basename(const std::string & path)
+{
+ if(path == "")
+ {
+ return std::string("");
+ }
+ // http://stackoverflow.com/questions/5077693/dirnamephp-similar-function-in-c
+ std::string::const_reverse_iterator last_slash =
+ std::find(
+ path.rbegin(),
+ path.rend(), '/');
+ if( last_slash == path.rend() )
+ {
+ // No slashes found
+ return path;
+ }else if(1 == (last_slash.base() - path.begin()))
+ {
+ // Slash is first char
+ return std::string(path.begin()+1,path.end());
+ }else if(path.end() == last_slash.base() )
+ {
+ // Slash is last char
+ std::string redo = std::string(path.begin(),path.end()-1);
+ return igl::basename(redo);
+ }
+ return std::string(last_slash.base(),path.end());
+}
diff --git a/xs/src/igl/basename.h b/xs/src/igl/basename.h
new file mode 100644
index 000000000..fb333b5c4
--- /dev/null
+++ b/xs/src/igl/basename.h
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BASENAME_H
+#define IGL_BASENAME_H
+#include "igl_inline.h"
+
+#include <string>
+
+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
+ IGL_INLINE std::string basename(const std::string & path);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "basename.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/bbw.cpp b/xs/src/igl/bbw.cpp
new file mode 100644
index 000000000..c7df7dd3b
--- /dev/null
+++ b/xs/src/igl/bbw.cpp
@@ -0,0 +1,143 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bbw.h"
+#include "min_quad_with_fixed.h"
+#include "harmonic.h"
+#include "parallel_for.h"
+#include <Eigen/Sparse>
+#include <iostream>
+#include <mutex>
+#include <cstdio>
+
+igl::BBWData::BBWData():
+ partition_unity(false),
+ W0(),
+ active_set_params(),
+ verbosity(0)
+{
+ // We know that the Bilaplacian is positive semi-definite
+ active_set_params.Auu_pd = true;
+}
+
+void igl::BBWData::print()
+{
+ using namespace std;
+ cout<<"partition_unity: "<<partition_unity<<endl;
+ cout<<"W0=["<<endl<<W0<<endl<<"];"<<endl;
+}
+
+
+template <
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+IGL_INLINE bool igl::bbw(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedEle> & Ele,
+ const Eigen::PlainObjectBase<Derivedb> & b,
+ const Eigen::PlainObjectBase<Derivedbc> & bc,
+ igl::BBWData & data,
+ Eigen::PlainObjectBase<DerivedW> & W
+ )
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(!data.partition_unity && "partition_unity not implemented yet");
+ // number of domain vertices
+ int n = V.rows();
+ // number of handles
+ int m = bc.cols();
+ // Build biharmonic operator
+ Eigen::SparseMatrix<typename DerivedV::Scalar> Q;
+ harmonic(V,Ele,2,Q);
+ W.derived().resize(n,m);
+ // No linear terms
+ VectorXd c = VectorXd::Zero(n);
+ // No linear constraints
+ SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n);
+ VectorXd Beq(0,1),Bieq(0,1);
+ // Upper and lower box constraints (Constant bounds)
+ VectorXd ux = VectorXd::Ones(n);
+ VectorXd lx = VectorXd::Zero(n);
+ active_set_params eff_params = data.active_set_params;
+ if(data.verbosity >= 1)
+ {
+ cout<<"BBW: max_iter: "<<data.active_set_params.max_iter<<endl;
+ cout<<"BBW: eff_max_iter: "<<eff_params.max_iter<<endl;
+ }
+ if(data.verbosity >= 1)
+ {
+ cout<<"BBW: Computing initial weights for "<<m<<" handle"<<
+ (m!=1?"s":"")<<"."<<endl;
+ }
+ min_quad_with_fixed_data<typename DerivedW::Scalar > mqwf;
+ min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf);
+ min_quad_with_fixed_solve(mqwf,c,bc,Beq,W);
+ // decrement
+ eff_params.max_iter--;
+ bool error = false;
+ // Loop over handles
+ std::mutex critical;
+ const auto & optimize_weight = [&](const int i)
+ {
+ // Quicker exit for paralle_for
+ if(error)
+ {
+ return;
+ }
+ if(data.verbosity >= 1)
+ {
+ std::lock_guard<std::mutex> lock(critical);
+ cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
+ "."<<endl;
+ }
+ VectorXd bci = bc.col(i);
+ VectorXd Wi;
+ // use initial guess
+ Wi = W.col(i);
+ SolverStatus ret = active_set(
+ Q,c,b,bci,Aeq,Beq,Aieq,Bieq,lx,ux,eff_params,Wi);
+ switch(ret)
+ {
+ case SOLVER_STATUS_CONVERGED:
+ break;
+ case SOLVER_STATUS_MAX_ITER:
+ cerr<<"active_set: max iter without convergence."<<endl;
+ break;
+ case SOLVER_STATUS_ERROR:
+ default:
+ cerr<<"active_set error."<<endl;
+ error = true;
+ }
+ W.col(i) = Wi;
+ };
+ parallel_for(m,optimize_weight,2);
+ if(error)
+ {
+ return false;
+ }
+
+#ifndef NDEBUG
+ const double min_rowsum = W.rowwise().sum().array().abs().minCoeff();
+ if(min_rowsum < 0.1)
+ {
+ cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
+ "active set iterations or enforcing partition of unity."<<endl;
+ }
+#endif
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::bbw<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
+
diff --git a/xs/src/igl/bbw.h b/xs/src/igl/bbw.h
new file mode 100644
index 000000000..bec20bb98
--- /dev/null
+++ b/xs/src/igl/bbw.h
@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BBW_H
+#define IGL_BBW_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <igl/active_set.h>
+
+namespace igl
+{
+ // Container for BBW computation related data and flags
+ class BBWData
+ {
+ public:
+ // Enforce partition of unity during optimization (optimize all weight
+ // simultaneously)
+ bool partition_unity;
+ // Initial guess
+ Eigen::MatrixXd W0;
+ igl::active_set_params active_set_params;
+ // Verbosity level
+ // 0: quiet
+ // 1: loud
+ // 2: louder
+ int verbosity;
+ public:
+ IGL_INLINE BBWData();
+ // 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
+ template <
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+ IGL_INLINE bool bbw(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedEle> & Ele,
+ const Eigen::PlainObjectBase<Derivedb> & b,
+ const Eigen::PlainObjectBase<Derivedbc> & bc,
+ BBWData & data,
+ Eigen::PlainObjectBase<DerivedW> & W);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "bbw.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/bfs.cpp b/xs/src/igl/bfs.cpp
new file mode 100644
index 000000000..8ff51c050
--- /dev/null
+++ b/xs/src/igl/bfs.cpp
@@ -0,0 +1,93 @@
+#include "bfs.h"
+#include "list_to_matrix.h"
+#include <vector>
+#include <queue>
+
+template <
+ typename AType,
+ typename DerivedD,
+ typename DerivedP>
+IGL_INLINE void igl::bfs(
+ const AType & A,
+ const size_t s,
+ Eigen::PlainObjectBase<DerivedD> & D,
+ Eigen::PlainObjectBase<DerivedP> & P)
+{
+ std::vector<typename DerivedD::Scalar> vD;
+ std::vector<typename DerivedP::Scalar> vP;
+ bfs(A,s,vD,vP);
+ list_to_matrix(vD,D);
+ list_to_matrix(vP,P);
+}
+
+template <
+ typename AType,
+ typename DType,
+ typename PType>
+IGL_INLINE void igl::bfs(
+ const std::vector<std::vector<AType> > & A,
+ const size_t s,
+ std::vector<DType> & D,
+ std::vector<PType> & P)
+{
+ // number of nodes
+ int N = s+1;
+ for(const auto & Ai : A) for(const auto & a : Ai) N = std::max(N,a+1);
+ std::vector<bool> seen(N,false);
+ P.resize(N,-1);
+ std::queue<std::pair<int,int> > Q;
+ Q.push({s,-1});
+ while(!Q.empty())
+ {
+ const int f = Q.front().first;
+ const int p = Q.front().second;
+ Q.pop();
+ if(seen[f])
+ {
+ continue;
+ }
+ D.push_back(f);
+ P[f] = p;
+ seen[f] = true;
+ for(const auto & n : A[f]) Q.push({n,f});
+ }
+}
+
+
+template <
+ typename AType,
+ typename DType,
+ typename PType>
+IGL_INLINE void igl::bfs(
+ const Eigen::SparseMatrix<AType> & A,
+ const size_t s,
+ std::vector<DType> & D,
+ std::vector<PType> & P)
+{
+ // number of nodes
+ int N = A.rows();
+ assert(A.rows() == A.cols());
+ std::vector<bool> seen(N,false);
+ P.resize(N,-1);
+ std::queue<std::pair<int,int> > Q;
+ Q.push({s,-1});
+ while(!Q.empty())
+ {
+ const int f = Q.front().first;
+ const int p = Q.front().second;
+ Q.pop();
+ if(seen[f])
+ {
+ continue;
+ }
+ D.push_back(f);
+ P[f] = p;
+ seen[f] = true;
+ for(typename Eigen::SparseMatrix<AType>::InnerIterator it (A,f); it; ++it)
+ {
+ if(it.value()) Q.push({it.index(),f});
+ }
+ }
+
+}
+
diff --git a/xs/src/igl/bfs.h b/xs/src/igl/bfs.h
new file mode 100644
index 000000000..6f49e93eb
--- /dev/null
+++ b/xs/src/igl/bfs.h
@@ -0,0 +1,54 @@
+#ifndef IGL_BFS_H
+#define IGL_BFS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#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.
+ template <
+ typename AType,
+ typename DerivedD,
+ typename DerivedP>
+ IGL_INLINE void bfs(
+ const AType & A,
+ const size_t s,
+ Eigen::PlainObjectBase<DerivedD> & D,
+ Eigen::PlainObjectBase<DerivedP> & P);
+
+ template <
+ typename AType,
+ typename DType,
+ typename PType>
+ IGL_INLINE void bfs(
+ const std::vector<std::vector<AType> > & A,
+ const size_t s,
+ std::vector<DType> & D,
+ std::vector<PType> & P);
+ template <
+ typename AType,
+ typename DType,
+ typename PType>
+ IGL_INLINE void bfs(
+ const Eigen::SparseMatrix<AType> & A,
+ const size_t s,
+ std::vector<DType> & D,
+ std::vector<PType> & P);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "bfs.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/bfs_orient.cpp b/xs/src/igl/bfs_orient.cpp
new file mode 100644
index 000000000..23dd93a49
--- /dev/null
+++ b/xs/src/igl/bfs_orient.cpp
@@ -0,0 +1,100 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bfs_orient.h"
+#include "orientable_patches.h"
+#include <Eigen/Sparse>
+#include <queue>
+
+template <typename DerivedF, typename DerivedFF, typename DerivedC>
+IGL_INLINE void igl::bfs_orient(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ using namespace Eigen;
+ using namespace std;
+ SparseMatrix<int> A;
+ orientable_patches(F,C,A);
+
+ // number of faces
+ const int m = F.rows();
+ // number of patches
+ const int num_cc = C.maxCoeff()+1;
+ VectorXi seen = VectorXi::Zero(m);
+
+ // Edge sets
+ const int ES[3][2] = {{1,2},{2,0},{0,1}};
+
+ if(&FF != &F)
+ {
+ FF = F;
+ }
+ // loop over patches
+#pragma omp parallel for
+ for(int c = 0;c<num_cc;c++)
+ {
+ queue<int> Q;
+ // find first member of patch c
+ for(int f = 0;f<FF.rows();f++)
+ {
+ if(C(f) == c)
+ {
+ Q.push(f);
+ break;
+ }
+ }
+ assert(!Q.empty());
+ while(!Q.empty())
+ {
+ const int f = Q.front();
+ Q.pop();
+ if(seen(f) > 0)
+ {
+ continue;
+ }
+ seen(f)++;
+ // loop over neighbors of f
+ for(typename SparseMatrix<int>::InnerIterator it (A,f); it; ++it)
+ {
+ // might be some lingering zeros, and skip self-adjacency
+ if(it.value() != 0 && it.row() != f)
+ {
+ const int n = it.row();
+ assert(n != f);
+ // loop over edges of f
+ for(int efi = 0;efi<3;efi++)
+ {
+ // efi'th edge of face f
+ Vector2i ef(FF(f,ES[efi][0]),FF(f,ES[efi][1]));
+ // loop over edges of n
+ for(int eni = 0;eni<3;eni++)
+ {
+ // eni'th edge of face n
+ Vector2i en(FF(n,ES[eni][0]),FF(n,ES[eni][1]));
+ // Match (half-edges go same direction)
+ if(ef(0) == en(0) && ef(1) == en(1))
+ {
+ // flip face n
+ FF.row(n) = FF.row(n).reverse().eval();
+ }
+ }
+ }
+ // add neighbor to queue
+ Q.push(n);
+ }
+ }
+ }
+ }
+
+ // make sure flip is OK if &FF = &F
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::bfs_orient<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/bfs_orient.h b/xs/src/igl/bfs_orient.h
new file mode 100644
index 000000000..b37f397d8
--- /dev/null
+++ b/xs/src/igl/bfs_orient.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BFS_ORIENT_H
+#define IGL_BFS_ORIENT_H
+#include <Eigen/Core>
+#include <igl/igl_inline.h>
+
+namespace igl
+{
+ // Consistently orient faces in orientable patches using BFS
+ //
+ // F = bfs_orient(F,V);
+ //
+ // Inputs:
+ // F #F by 3 list of faces
+ // Outputs:
+ // FF #F by 3 list of faces (OK if same as F)
+ // C #F list of component ids
+ //
+ //
+ template <typename DerivedF, typename DerivedFF, typename DerivedC>
+ IGL_INLINE void bfs_orient(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedC> & C);
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "bfs_orient.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/biharmonic_coordinates.cpp b/xs/src/igl/biharmonic_coordinates.cpp
new file mode 100644
index 000000000..686ecd5e4
--- /dev/null
+++ b/xs/src/igl/biharmonic_coordinates.cpp
@@ -0,0 +1,203 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "biharmonic_coordinates.h"
+#include "cotmatrix.h"
+#include "sum.h"
+#include "massmatrix.h"
+#include "min_quad_with_fixed.h"
+#include "crouzeix_raviart_massmatrix.h"
+#include "crouzeix_raviart_cotmatrix.h"
+#include "normal_derivative.h"
+#include "on_boundary.h"
+#include <Eigen/Sparse>
+
+template <
+ typename DerivedV,
+ typename DerivedT,
+ typename SType,
+ typename DerivedW>
+IGL_INLINE bool igl::biharmonic_coordinates(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const std::vector<std::vector<SType> > & S,
+ Eigen::PlainObjectBase<DerivedW> & W)
+{
+ return biharmonic_coordinates(V,T,S,2,W);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedT,
+ typename SType,
+ typename DerivedW>
+IGL_INLINE bool igl::biharmonic_coordinates(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const std::vector<std::vector<SType> > & S,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W)
+{
+ using namespace Eigen;
+ using namespace std;
+ // This is not the most efficient way to build A, but follows "Linear
+ // Subspace Design for Real-Time Shape Deformation" [Wang et al. 2015].
+ SparseMatrix<double> A;
+ {
+ DiagonalMatrix<double,Dynamic> Minv;
+ SparseMatrix<double> L,K;
+ Array<bool,Dynamic,Dynamic> C;
+ {
+ Array<bool,Dynamic,1> I;
+ on_boundary(T,I,C);
+ }
+#ifdef false
+ // Version described in paper is "wrong"
+ // http://www.cs.toronto.edu/~jacobson/images/error-in-linear-subspace-design-for-real-time-shape-deformation-2017-wang-et-al.pdf
+ SparseMatrix<double> N,Z,M;
+ normal_derivative(V,T,N);
+ {
+ std::vector<Triplet<double> >ZIJV;
+ for(int t =0;t<T.rows();t++)
+ {
+ for(int f =0;f<T.cols();f++)
+ {
+ if(C(t,f))
+ {
+ const int i = t+f*T.rows();
+ for(int c = 1;c<T.cols();c++)
+ {
+ ZIJV.emplace_back(T(t,(f+c)%T.cols()),i,1);
+ }
+ }
+ }
+ }
+ Z.resize(V.rows(),N.rows());
+ Z.setFromTriplets(ZIJV.begin(),ZIJV.end());
+ N = (Z*N).eval();
+ }
+ cotmatrix(V,T,L);
+ K = N+L;
+ massmatrix(V,T,MASSMATRIX_TYPE_DEFAULT,M);
+ // normalize
+ M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
+ Minv =
+ ((VectorXd)M.diagonal().array().inverse()).asDiagonal();
+#else
+ Eigen::SparseMatrix<double> M;
+ Eigen::MatrixXi E;
+ Eigen::VectorXi EMAP;
+ crouzeix_raviart_massmatrix(V,T,M,E,EMAP);
+ crouzeix_raviart_cotmatrix(V,T,E,EMAP,L);
+ // Ad #E by #V facet-vertex incidence matrix
+ Eigen::SparseMatrix<double> Ad(E.rows(),V.rows());
+ {
+ std::vector<Eigen::Triplet<double> > AIJV(E.size());
+ for(int e = 0;e<E.rows();e++)
+ {
+ for(int c = 0;c<E.cols();c++)
+ {
+ AIJV[e+c*E.rows()] = Eigen::Triplet<double>(e,E(e,c),1);
+ }
+ }
+ Ad.setFromTriplets(AIJV.begin(),AIJV.end());
+ }
+ // Degrees
+ Eigen::VectorXd De;
+ sum(Ad,2,De);
+ Eigen::DiagonalMatrix<double,Eigen::Dynamic> De_diag =
+ De.array().inverse().matrix().asDiagonal();
+ K = L*(De_diag*Ad);
+ // normalize
+ M /= ((VectorXd)M.diagonal()).array().abs().maxCoeff();
+ Minv = ((VectorXd)M.diagonal().array().inverse()).asDiagonal();
+ // kill boundary edges
+ for(int f = 0;f<T.rows();f++)
+ {
+ for(int c = 0;c<T.cols();c++)
+ {
+ if(C(f,c))
+ {
+ const int e = EMAP(f+T.rows()*c);
+ Minv.diagonal()(e) = 0;
+ }
+ }
+ }
+
+#endif
+ switch(k)
+ {
+ default:
+ assert(false && "unsupported");
+ case 2:
+ // For C1 smoothness in 2D, one should use bi-harmonic
+ A = K.transpose() * (Minv * K);
+ break;
+ case 3:
+ // For C1 smoothness in 3D, one should use tri-harmonic
+ A = K.transpose() * (Minv * (-L * (Minv * K)));
+ break;
+ }
+ }
+ // Vertices in point handles
+ const size_t mp =
+ count_if(S.begin(),S.end(),[](const vector<int> & h){return h.size()==1;});
+ // number of region handles
+ const size_t r = S.size()-mp;
+ // Vertices in region handles
+ size_t mr = 0;
+ for(const auto & h : S)
+ {
+ if(h.size() > 1)
+ {
+ mr += h.size();
+ }
+ }
+ const size_t dim = T.cols()-1;
+ // Might as well be dense... I think...
+ MatrixXd J = MatrixXd::Zero(mp+mr,mp+r*(dim+1));
+ VectorXi b(mp+mr);
+ MatrixXd H(mp+r*(dim+1),dim);
+ {
+ int v = 0;
+ 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);
+ J(v,c++) = 1;
+ b(v) = S[h][0];
+ v++;
+ }else
+ {
+ assert(S[h].size() >= dim+1);
+ for(int p = 0;p<S[h].size();p++)
+ {
+ for(int d = 0;d<dim;d++)
+ {
+ J(v,c+d) = V(S[h][p],d);
+ }
+ J(v,c+dim) = 1;
+ b(v) = S[h][p];
+ v++;
+ }
+ H.block(c,0,dim+1,dim).setIdentity();
+ c+=dim+1;
+ }
+ }
+ }
+ // minimize ½ W' A W'
+ // subject to W(b,:) = J
+ return min_quad_with_fixed(
+ A,VectorXd::Zero(A.rows()).eval(),b,J,SparseMatrix<double>(),VectorXd(),true,W);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::biharmonic_coordinates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/biharmonic_coordinates.h b/xs/src/igl/biharmonic_coordinates.h
new file mode 100644
index 000000000..26f67329a
--- /dev/null
+++ b/xs/src/igl/biharmonic_coordinates.h
@@ -0,0 +1,90 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BIHARMONIC_COORDINATES_H
+#define IGL_BIHARMONIC_COORDINATES_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+#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 );
+ template <
+ typename DerivedV,
+ typename DerivedT,
+ typename SType,
+ typename DerivedW>
+ IGL_INLINE bool biharmonic_coordinates(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const std::vector<std::vector<SType> > & S,
+ Eigen::PlainObjectBase<DerivedW> & W);
+ // k 2-->biharmonic, 3-->triharmonic
+ template <
+ typename DerivedV,
+ typename DerivedT,
+ typename SType,
+ typename DerivedW>
+ IGL_INLINE bool biharmonic_coordinates(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const std::vector<std::vector<SType> > & S,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W);
+
+};
+# ifndef IGL_STATIC_LIBRARY
+# include "biharmonic_coordinates.cpp"
+# endif
+#endif
diff --git a/xs/src/igl/bijective_composite_harmonic_mapping.cpp b/xs/src/igl/bijective_composite_harmonic_mapping.cpp
new file mode 100644
index 000000000..517109c04
--- /dev/null
+++ b/xs/src/igl/bijective_composite_harmonic_mapping.cpp
@@ -0,0 +1,115 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bijective_composite_harmonic_mapping.h"
+
+#include "slice.h"
+#include "doublearea.h"
+#include "harmonic.h"
+//#include "matlab/MatlabWorkspace.h"
+#include <iostream>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedU>
+IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ Eigen::PlainObjectBase<DerivedU> & U)
+{
+ return bijective_composite_harmonic_mapping(V,F,b,bc,1,200,20,true,U);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedU>
+IGL_INLINE bool igl::bijective_composite_harmonic_mapping(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int min_steps,
+ const int max_steps,
+ const int num_inner_iters,
+ const bool test_for_flips,
+ Eigen::PlainObjectBase<DerivedU> & U)
+{
+ typedef typename Derivedbc::Scalar Scalar;
+ assert(V.cols() == 2 && bc.cols() == 2 && "Input should be 2D");
+ assert(F.cols() == 3 && "F should contain triangles");
+ int tries = 0;
+ int nsteps = min_steps;
+ Derivedbc bc0;
+ slice(V,b,1,bc0);
+
+ // It's difficult to check for flips "robustly" in the sense that the input
+ // mesh might not have positive/consistent sign to begin with.
+
+ while(nsteps<=max_steps)
+ {
+ U = V;
+ int flipped = 0;
+ int nans = 0;
+ int step = 0;
+ for(;step<=nsteps;step++)
+ {
+ const Scalar t = ((Scalar)step)/((Scalar)nsteps);
+ // linearly interpolate boundary conditions
+ // TODO: replace this with something that guarantees a homotopic "morph"
+ // of the boundary conditions. Something like "Homotopic Morphing of
+ // Planar Curves" [Dym et al. 2015] but also handling multiple connected
+ // components.
+ Derivedbc bct = bc0 + t*(bc - bc0);
+ // Compute dsicrete harmonic map using metric of previous step
+ for(int iter = 0;iter<num_inner_iters;iter++)
+ {
+ //std::cout<<nsteps<<" t: "<<t<<" iter: "<<iter;
+ //igl::matlab::MatlabWorkspace mw;
+ //mw.save(U,"U");
+ //mw.save_index(F,"F");
+ //mw.save_index(b,"b");
+ //mw.save(bct,"bct");
+ //mw.write("numerical.mat");
+ harmonic(DerivedU(U),F,b,bct,1,U);
+ igl::slice(U,b,1,bct);
+ nans = (U.array() != U.array()).count();
+ if(test_for_flips)
+ {
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1> A;
+ doublearea(U,F,A);
+ flipped = (A.array() < 0 ).count();
+ //std::cout<<" "<<flipped<<" nan? "<<(U.array() != U.array()).any()<<std::endl;
+ if(flipped == 0 && nans == 0) break;
+ }
+ }
+ if(flipped > 0 || nans>0) break;
+ }
+ if(flipped == 0 && nans == 0)
+ {
+ return step == nsteps+1;
+ }
+ nsteps *= 2;
+ }
+ //std::cout<<"failed to finish in "<<nsteps<<"..."<<std::endl;
+ return false;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::bijective_composite_harmonic_mapping<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::bijective_composite_harmonic_mapping<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/bijective_composite_harmonic_mapping.h b/xs/src/igl/bijective_composite_harmonic_mapping.h
new file mode 100644
index 000000000..f055e5293
--- /dev/null
+++ b/xs/src/igl/bijective_composite_harmonic_mapping.h
@@ -0,0 +1,79 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BIJECTIVE_COMPOSITE_HARMONIC_MAPPING_H
+#define IGL_BIJECTIVE_COMPOSITE_HARMONIC_MAPPING_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+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
+ //
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedU>
+ IGL_INLINE bool bijective_composite_harmonic_mapping(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ 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
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedU>
+ IGL_INLINE bool bijective_composite_harmonic_mapping(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int min_steps,
+ const int max_steps,
+ const int num_inner_iters,
+ const bool test_for_flips,
+ Eigen::PlainObjectBase<DerivedU> & U);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "bijective_composite_harmonic_mapping.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/bone_parents.cpp b/xs/src/igl/bone_parents.cpp
new file mode 100644
index 000000000..d5cd6ddfa
--- /dev/null
+++ b/xs/src/igl/bone_parents.cpp
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bone_parents.h"
+
+template <typename DerivedBE, typename DerivedP>
+IGL_INLINE void igl::bone_parents(
+ const Eigen::PlainObjectBase<DerivedBE>& BE,
+ Eigen::PlainObjectBase<DerivedP>& P)
+{
+ P.resize(BE.rows(),1);
+ // Stupid O(n²) version
+ for(int e = 0;e<BE.rows();e++)
+ {
+ P(e) = -1;
+ for(int f = 0;f<BE.rows();f++)
+ {
+ if(BE(e,0) == BE(f,1))
+ {
+ P(e) = f;
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::bone_parents<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/bone_parents.h b/xs/src/igl/bone_parents.h
new file mode 100644
index 000000000..e0091cdfc
--- /dev/null
+++ b/xs/src/igl/bone_parents.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BONE_PARENTS_H
+#define IGL_BONE_PARENTS_H
+#include "igl_inline.h"
+#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.
+ //
+ template <typename DerivedBE, typename DerivedP>
+ IGL_INLINE void bone_parents(
+ const Eigen::PlainObjectBase<DerivedBE>& BE,
+ Eigen::PlainObjectBase<DerivedP>& P);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "bone_parents.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/boundary_conditions.cpp b/xs/src/igl/boundary_conditions.cpp
new file mode 100644
index 000000000..f7146cd70
--- /dev/null
+++ b/xs/src/igl/boundary_conditions.cpp
@@ -0,0 +1,192 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "boundary_conditions.h"
+
+#include "verbose.h"
+#include "EPS.h"
+#include "project_to_line.h"
+
+#include <vector>
+#include <map>
+#include <iostream>
+
+IGL_INLINE bool igl::boundary_conditions(
+ const Eigen::MatrixXd & V ,
+ const Eigen::MatrixXi & /*Ele*/,
+ const Eigen::MatrixXd & C ,
+ const Eigen::VectorXi & P ,
+ const Eigen::MatrixXi & BE ,
+ const Eigen::MatrixXi & CE ,
+ Eigen::VectorXi & b ,
+ Eigen::MatrixXd & bc )
+{
+ using namespace Eigen;
+ using namespace std;
+
+ if(P.size()+BE.rows() == 0)
+ {
+ verbose("^%s: Error: no handles found\n",__FUNCTION__);
+ return false;
+ }
+
+ vector<int> bci;
+ vector<int> bcj;
+ vector<double> bcv;
+
+ // loop over points
+ for(int p = 0;p<P.size();p++)
+ {
+ VectorXd pos = C.row(P(p));
+ // loop over domain vertices
+ for(int i = 0;i<V.rows();i++)
+ {
+ // Find samples just on pos
+ //Vec3 vi(V(i,0),V(i,1),V(i,2));
+ // EIGEN GOTCHA:
+ // double sqrd = (V.row(i)-pos).array().pow(2).sum();
+ // Must first store in temporary
+ VectorXd vi = V.row(i);
+ double sqrd = (vi-pos).squaredNorm();
+ if(sqrd <= FLOAT_EPS)
+ {
+ //cout<<"sum((["<<
+ // V(i,0)<<" "<<
+ // V(i,1)<<" "<<
+ // V(i,2)<<"] - ["<<
+ // pos(0)<<" "<<
+ // pos(1)<<" "<<
+ // pos(2)<<"]).^2) = "<<sqrd<<endl;
+ bci.push_back(i);
+ bcj.push_back(p);
+ bcv.push_back(1.0);
+ }
+ }
+ }
+
+ // loop over bone edges
+ for(int e = 0;e<BE.rows();e++)
+ {
+ // loop over domain vertices
+ for(int i = 0;i<V.rows();i++)
+ {
+ // Find samples from tip up to tail
+ VectorXd tip = C.row(BE(e,0));
+ VectorXd tail = C.row(BE(e,1));
+ // Compute parameter along bone and squared distance
+ double t,sqrd;
+ project_to_line(
+ V(i,0),V(i,1),V(i,2),
+ tip(0),tip(1),tip(2),
+ tail(0),tail(1),tail(2),
+ t,sqrd);
+ if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
+ {
+ bci.push_back(i);
+ bcj.push_back(P.size()+e);
+ bcv.push_back(1.0);
+ }
+ }
+ }
+
+ // loop over cage edges
+ for(int e = 0;e<CE.rows();e++)
+ {
+ // loop over domain vertices
+ for(int i = 0;i<V.rows();i++)
+ {
+ // Find samples from tip up to tail
+ VectorXd tip = C.row(P(CE(e,0)));
+ VectorXd tail = C.row(P(CE(e,1)));
+ // Compute parameter along bone and squared distance
+ double t,sqrd;
+ project_to_line(
+ V(i,0),V(i,1),V(i,2),
+ tip(0),tip(1),tip(2),
+ tail(0),tail(1),tail(2),
+ t,sqrd);
+ if(t>=-FLOAT_EPS && t<=(1.0f+FLOAT_EPS) && sqrd<=FLOAT_EPS)
+ {
+ bci.push_back(i);
+ bcj.push_back(CE(e,0));
+ bcv.push_back(1.0-t);
+ bci.push_back(i);
+ bcj.push_back(CE(e,1));
+ bcv.push_back(t);
+ }
+ }
+ }
+
+ // find unique boundary indices
+ vector<int> vb = bci;
+ sort(vb.begin(),vb.end());
+ vb.erase(unique(vb.begin(), vb.end()), vb.end());
+
+ b.resize(vb.size());
+ bc = MatrixXd::Zero(vb.size(),P.size()+BE.rows());
+ // Map from boundary index to index in boundary
+ map<int,int> bim;
+ int i = 0;
+ // Also fill in b
+ for(vector<int>::iterator bit = vb.begin();bit != vb.end();bit++)
+ {
+ b(i) = *bit;
+ bim[*bit] = i;
+ i++;
+ }
+
+ // Build BC
+ for(i = 0;i < (int)bci.size();i++)
+ {
+ assert(bim.find(bci[i]) != bim.end());
+ bc(bim[bci[i]],bcj[i]) = bcv[i];
+ }
+
+ // Normalize across rows so that conditions sum to one
+ for(i = 0;i<bc.rows();i++)
+ {
+ double sum = bc.row(i).sum();
+ assert(sum != 0 && "Some boundary vertex getting all zero BCs");
+ bc.row(i).array() /= sum;
+ }
+
+ if(bc.size() == 0)
+ {
+ verbose("^%s: Error: boundary conditions are empty.\n",__FUNCTION__);
+ return false;
+ }
+
+ // If there's only a single boundary condition, the following tests
+ // are overzealous.
+ if(bc.cols() == 1)
+ {
+ // If there is only one weight function,
+ // then we expect that there is only one handle.
+ assert(P.rows() + BE.rows() == 1);
+ return true;
+ }
+
+ // Check that every Weight function has at least one boundary value of 1 and
+ // one value of 0
+ for(i = 0;i<bc.cols();i++)
+ {
+ double min_abs_c = bc.col(i).array().abs().minCoeff();
+ double max_c = bc.col(i).maxCoeff();
+ if(min_abs_c > FLOAT_EPS)
+ {
+ verbose("^%s: Error: handle %d does not receive 0 weight\n",__FUNCTION__,i);
+ return false;
+ }
+ if(max_c< (1-FLOAT_EPS))
+ {
+ verbose("^%s: Error: handle %d does not receive 1 weight\n",__FUNCTION__,i);
+ return false;
+ }
+ }
+
+ return true;
+}
diff --git a/xs/src/igl/boundary_conditions.h b/xs/src/igl/boundary_conditions.h
new file mode 100644
index 000000000..643dbe7c1
--- /dev/null
+++ b/xs/src/igl/boundary_conditions.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BOUNDARY_CONDITIONS_H
+#define IGL_BOUNDARY_CONDITIONS_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+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)
+ IGL_INLINE bool boundary_conditions(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & Ele,
+ const Eigen::MatrixXd & C,
+ const Eigen::VectorXi & P,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXi & CE,
+ Eigen::VectorXi & b,
+ Eigen::MatrixXd & bc);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "boundary_conditions.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/boundary_facets.cpp b/xs/src/igl/boundary_facets.cpp
new file mode 100644
index 000000000..67e74db4f
--- /dev/null
+++ b/xs/src/igl/boundary_facets.cpp
@@ -0,0 +1,141 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "boundary_facets.h"
+#include "face_occurrences.h"
+
+// IGL includes
+#include "sort.h"
+
+// STL includes
+#include <map>
+#include <iostream>
+
+template <typename IntegerT, typename IntegerF>
+IGL_INLINE void igl::boundary_facets(
+ const std::vector<std::vector<IntegerT> > & T,
+ std::vector<std::vector<IntegerF> > & F)
+{
+ using namespace std;
+
+ if(T.size() == 0)
+ {
+ F.clear();
+ return;
+ }
+
+ int simplex_size = T[0].size();
+ // Get a list of all faces
+ vector<vector<IntegerF> > allF(
+ T.size()*simplex_size,
+ vector<IntegerF>(simplex_size-1));
+
+ // Gather faces, loop over tets
+ for(int i = 0; i< (int)T.size();i++)
+ {
+ assert((int)T[i].size() == simplex_size);
+ switch(simplex_size)
+ {
+ case 4:
+ // get face in correct order
+ allF[i*simplex_size+0][0] = T[i][1];
+ allF[i*simplex_size+0][1] = T[i][3];
+ allF[i*simplex_size+0][2] = T[i][2];
+ // get face in correct order
+ allF[i*simplex_size+1][0] = T[i][0];
+ allF[i*simplex_size+1][1] = T[i][2];
+ allF[i*simplex_size+1][2] = T[i][3];
+ // get face in correct order
+ allF[i*simplex_size+2][0] = T[i][0];
+ allF[i*simplex_size+2][1] = T[i][3];
+ allF[i*simplex_size+2][2] = T[i][1];
+ // get face in correct order
+ allF[i*simplex_size+3][0] = T[i][0];
+ allF[i*simplex_size+3][1] = T[i][1];
+ allF[i*simplex_size+3][2] = T[i][2];
+ break;
+ case 3:
+ allF[i*simplex_size+0][0] = T[i][1];
+ allF[i*simplex_size+0][1] = T[i][2];
+ allF[i*simplex_size+1][0] = T[i][2];
+ allF[i*simplex_size+1][1] = T[i][0];
+ allF[i*simplex_size+2][0] = T[i][0];
+ allF[i*simplex_size+2][1] = T[i][1];
+ break;
+ }
+ }
+
+ // Counts
+ vector<int> C;
+ face_occurrences(allF,C);
+
+ // Q: Why not just count the number of ones?
+ // A: because we are including non-manifold edges as boundary edges
+ int twos = (int) count(C.begin(),C.end(),2);
+ //int ones = (int) count(C.begin(),C.end(),1);
+ // Resize output to fit number of ones
+ F.resize(allF.size() - twos);
+ //F.resize(ones);
+ int k = 0;
+ for(int i = 0;i< (int)allF.size();i++)
+ {
+ if(C[i] != 2)
+ {
+ assert(k<(int)F.size());
+ F[k] = allF[i];
+ k++;
+ }
+ }
+ assert(k==(int)F.size());
+ //if(k != F.size())
+ //{
+ // printf("%d =? %d\n",k,F.size());
+ //}
+
+}
+
+#include "list_to_matrix.h"
+#include "matrix_to_list.h"
+
+template <typename DerivedT, typename DerivedF>
+IGL_INLINE void igl::boundary_facets(
+ const Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ assert(T.cols() == 0 || T.cols() == 4 || T.cols() == 3);
+ using namespace std;
+ using namespace Eigen;
+ // Cop out: use vector of vectors version
+ vector<vector<typename DerivedT::Scalar> > vT;
+ matrix_to_list(T,vT);
+ vector<vector<typename DerivedF::Scalar> > vF;
+ boundary_facets(vT,vF);
+ list_to_matrix(vF,F);
+}
+
+template <typename DerivedT, typename Ret>
+Ret igl::boundary_facets(
+ const Eigen::PlainObjectBase<DerivedT>& T)
+{
+ Ret F;
+ igl::boundary_facets(T,F);
+ return F;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::boundary_facets<int, int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+//template Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > igl::boundary_facets(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template void igl::boundary_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/boundary_facets.h b/xs/src/igl/boundary_facets.h
new file mode 100644
index 000000000..74ac032a1
--- /dev/null
+++ b/xs/src/igl/boundary_facets.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BOUNDARY_FACETS_H
+#define IGL_BOUNDARY_FACETS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+#include <vector>
+
+namespace igl
+{
+ // BOUNDARY_FACETS Determine boundary faces (edges) of tetrahedra (triangles)
+ // stored in T (analogous to qptoolbox's `outline` and `boundary_faces`).
+ //
+ // Templates:
+ // IntegerT integer-value: e.g. int
+ // IntegerF integer-value: e.g. int
+ // 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
+ //
+ //
+ template <typename IntegerT, typename IntegerF>
+ IGL_INLINE void boundary_facets(
+ const std::vector<std::vector<IntegerT> > & T,
+ std::vector<std::vector<IntegerF> > & F);
+
+ // Templates:
+ // DerivedT integer-value: i.e. from MatrixXi
+ // DerivedF integer-value: i.e. from MatrixXi
+ template <typename DerivedT, typename DerivedF>
+ IGL_INLINE void boundary_facets(
+ const Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ // Same as above but returns F
+ template <typename DerivedT, typename Ret>
+ Ret boundary_facets(
+ const Eigen::PlainObjectBase<DerivedT>& T);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "boundary_facets.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/boundary_loop.cpp b/xs/src/igl/boundary_loop.cpp
new file mode 100755
index 000000000..9a3ec625e
--- /dev/null
+++ b/xs/src/igl/boundary_loop.cpp
@@ -0,0 +1,153 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "boundary_loop.h"
+#include "slice.h"
+#include "triangle_triangle_adjacency.h"
+#include "vertex_triangle_adjacency.h"
+#include "is_border_vertex.h"
+#include <set>
+
+template <typename DerivedF, typename Index>
+IGL_INLINE void igl::boundary_loop(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ std::vector<std::vector<Index> >& L)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ if(F.rows() == 0)
+ return;
+
+ VectorXd Vdummy(F.maxCoeff()+1,1);
+ DerivedF TT,TTi;
+ vector<std::vector<int> > VF, VFi;
+ triangle_triangle_adjacency(F,TT,TTi);
+ vertex_triangle_adjacency(Vdummy,F,VF,VFi);
+
+ vector<bool> unvisited = is_border_vertex(Vdummy,F);
+ set<int> unseen;
+ for (size_t i = 0; i < unvisited.size(); ++i)
+ {
+ if (unvisited[i])
+ unseen.insert(unseen.end(),i);
+ }
+
+ while (!unseen.empty())
+ {
+ vector<Index> l;
+
+ // Get first vertex of loop
+ int start = *unseen.begin();
+ unseen.erase(unseen.begin());
+ unvisited[start] = false;
+ l.push_back(start);
+
+ bool done = false;
+ while (!done)
+ {
+ // Find next vertex
+ bool newBndEdge = false;
+ int v = l[l.size()-1];
+ int next;
+ for (int i = 0; i < (int)VF[v].size() && !newBndEdge; i++)
+ {
+ int fid = VF[v][i];
+
+ if (TT.row(fid).minCoeff() < 0.) // Face contains boundary edge
+ {
+ int vLoc = -1;
+ if (F(fid,0) == v) vLoc = 0;
+ if (F(fid,1) == v) vLoc = 1;
+ if (F(fid,2) == v) vLoc = 2;
+
+ int vNext = F(fid,(vLoc + 1) % F.cols());
+
+ newBndEdge = false;
+ if (unvisited[vNext] && TT(fid,vLoc) < 0)
+ {
+ next = vNext;
+ newBndEdge = true;
+ }
+ }
+ }
+
+ if (newBndEdge)
+ {
+ l.push_back(next);
+ unseen.erase(next);
+ unvisited[next] = false;
+ }
+ else
+ done = true;
+ }
+ L.push_back(l);
+ }
+}
+
+template <typename DerivedF, typename Index>
+IGL_INLINE void igl::boundary_loop(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ std::vector<Index>& L)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ if(F.rows() == 0)
+ return;
+
+ vector<vector<int> > Lall;
+ boundary_loop(F,Lall);
+
+ int idxMax = -1;
+ size_t maxLen = 0;
+ for (size_t i = 0; i < Lall.size(); ++i)
+ {
+ if (Lall[i].size() > maxLen)
+ {
+ maxLen = Lall[i].size();
+ idxMax = i;
+ }
+ }
+
+ //Check for meshes without boundary
+ if (idxMax == -1)
+ {
+ L.clear();
+ return;
+ }
+
+ L.resize(Lall[idxMax].size());
+ for (size_t i = 0; i < Lall[idxMax].size(); ++i)
+ {
+ L[i] = Lall[idxMax][i];
+ }
+}
+
+template <typename DerivedF, typename DerivedL>
+IGL_INLINE void igl::boundary_loop(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedL>& L)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ if(F.rows() == 0)
+ return;
+
+ vector<int> Lvec;
+ boundary_loop(F,Lvec);
+
+ L.resize(Lvec.size());
+ for (size_t i = 0; i < Lvec.size(); ++i)
+ L(i) = Lvec[i];
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::boundary_loop<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/boundary_loop.h b/xs/src/igl/boundary_loop.h
new file mode 100755
index 000000000..ebb5072a5
--- /dev/null
+++ b/xs/src/igl/boundary_loop.h
@@ -0,0 +1,66 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BOUNDARY_LOOP_H
+#define IGL_BOUNDARY_LOOP_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <vector>
+
+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
+ //
+ template <typename DerivedF, typename Index>
+ IGL_INLINE void boundary_loop(
+ const Eigen::PlainObjectBase<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
+ //
+ template <typename DerivedF, typename Index>
+ IGL_INLINE void boundary_loop(
+ const Eigen::PlainObjectBase<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
+ //
+ template <typename DerivedF, typename DerivedL>
+ IGL_INLINE void boundary_loop(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedL>& L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "boundary_loop.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/bounding_box.cpp b/xs/src/igl/bounding_box.cpp
new file mode 100644
index 000000000..e740b058f
--- /dev/null
+++ b/xs/src/igl/bounding_box.cpp
@@ -0,0 +1,103 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bounding_box.h"
+#include <iostream>
+
+template <typename DerivedV, typename DerivedBV, typename DerivedBF>
+IGL_INLINE void igl::bounding_box(
+ const Eigen::MatrixBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedBV>& BV,
+ Eigen::PlainObjectBase<DerivedBF>& BF)
+{
+ return bounding_box(V,0.,BV,BF);
+}
+
+template <typename DerivedV, typename DerivedBV, typename DerivedBF>
+IGL_INLINE void igl::bounding_box(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const typename DerivedV::Scalar pad,
+ Eigen::PlainObjectBase<DerivedBV>& BV,
+ Eigen::PlainObjectBase<DerivedBF>& BF)
+{
+ using namespace std;
+
+ const int dim = V.cols();
+ const auto & minV = V.colwise().minCoeff().array()-pad;
+ const auto & maxV = V.colwise().maxCoeff().array()+pad;
+ // 2^n vertices
+ BV.resize((1<<dim),dim);
+
+ // Recursive lambda to generate all 2^n combinations
+ const std::function<void(const int,const int,int*,int)> combos =
+ [&BV,&minV,&maxV,&combos](
+ const int dim,
+ const int i,
+ int * X,
+ const int pre_index)
+ {
+ for(X[i] = 0;X[i]<2;X[i]++)
+ {
+ int index = pre_index*2+X[i];
+ if((i+1)<dim)
+ {
+ combos(dim,i+1,X,index);
+ }else
+ {
+ for(int d = 0;d<dim;d++)
+ {
+ BV(index,d) = (X[d]?minV[d]:maxV[d]);
+ }
+ }
+ }
+ };
+
+ Eigen::VectorXi X(dim);
+ combos(dim,0,X.data(),0);
+ switch(dim)
+ {
+ case 2:
+ BF.resize(4,2);
+ BF<<
+ 3,1,
+ 1,0,
+ 0,2,
+ 2,3;
+ break;
+ case 3:
+ BF.resize(12,3);
+ BF<<
+ 2,0,6,
+ 0,4,6,
+ 5,4,0,
+ 5,0,1,
+ 6,4,5,
+ 5,7,6,
+ 3,0,2,
+ 1,0,3,
+ 3,2,6,
+ 6,7,3,
+ 5,1,3,
+ 3,7,5;
+ break;
+ default:
+ assert(false && "Unsupported dimension.");
+ break;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 1, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::bounding_box<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::bounding_box<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/bounding_box.h b/xs/src/igl/bounding_box.h
new file mode 100644
index 000000000..7e053d2cc
--- /dev/null
+++ b/xs/src/igl/bounding_box.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BOUNDING_BOX_H
+#define IGL_BOUNDING_BOX_H
+#include "igl_inline.h"
+#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
+ 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);
+ template <typename DerivedV, typename DerivedBV, typename DerivedBF>
+ IGL_INLINE void bounding_box(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const typename DerivedV::Scalar pad,
+ Eigen::PlainObjectBase<DerivedBV>& BV,
+ Eigen::PlainObjectBase<DerivedBF>& BF);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "bounding_box.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/bounding_box_diagonal.cpp b/xs/src/igl/bounding_box_diagonal.cpp
new file mode 100644
index 000000000..1023abb50
--- /dev/null
+++ b/xs/src/igl/bounding_box_diagonal.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bounding_box_diagonal.h"
+#include "mat_max.h"
+#include "mat_min.h"
+#include <cmath>
+
+IGL_INLINE double igl::bounding_box_diagonal(
+ const Eigen::MatrixXd & V)
+{
+ using namespace Eigen;
+ VectorXd maxV,minV;
+ VectorXi maxVI,minVI;
+ mat_max(V,1,maxV,maxVI);
+ mat_min(V,1,minV,minVI);
+ return sqrt((maxV-minV).array().square().sum());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/bounding_box_diagonal.h b/xs/src/igl/bounding_box_diagonal.h
new file mode 100644
index 000000000..d89025bd5
--- /dev/null
+++ b/xs/src/igl/bounding_box_diagonal.h
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_BOUNDING_BOX_DIAGONAL_H
+#define IGL_BOUNDING_BOX_DIAGONAL_H
+#include "igl_inline.h"
+#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 positions
+ // F #F by 3 list of triangle indices into V
+ // Returns length of bounding box diagonal
+ IGL_INLINE double bounding_box_diagonal( const Eigen::MatrixXd & V);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "bounding_box_diagonal.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/canonical_quaternions.cpp b/xs/src/igl/canonical_quaternions.cpp
new file mode 100644
index 000000000..55d68da86
--- /dev/null
+++ b/xs/src/igl/canonical_quaternions.cpp
@@ -0,0 +1,21 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "canonical_quaternions.h"
+
+template <> IGL_INLINE float igl::CANONICAL_VIEW_QUAT<float>(int i, int j)
+{
+ return (float)igl::CANONICAL_VIEW_QUAT_F[i][j];
+}
+template <> IGL_INLINE double igl::CANONICAL_VIEW_QUAT<double>(int i, int j)
+{
+ return (double)igl::CANONICAL_VIEW_QUAT_D[i][j];
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/canonical_quaternions.h b/xs/src/igl/canonical_quaternions.h
new file mode 100644
index 000000000..86d90112d
--- /dev/null
+++ b/xs/src/igl/canonical_quaternions.h
@@ -0,0 +1,129 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_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
+namespace igl
+{
+ // Float versions
+#define SQRT_2_OVER_2 0.707106781f
+ // Identity
+ 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
+ const float XY_PLANE_QUAT_F[4] = {0,0,0,1};
+ // X points right, Y points *in* and Z points up
+ const float XZ_PLANE_QUAT_F[4] = {-SQRT_2_OVER_2,0,0,SQRT_2_OVER_2};
+ // X points out, Y points right, and Z points up
+ const float YZ_PLANE_QUAT_F[4] = {-0.5,-0.5,-0.5,0.5};
+ const float CANONICAL_VIEW_QUAT_F[][4] =
+ {
+ { 0, 0, 0, 1}, // 0
+ { 0, 0, SQRT_2_OVER_2, SQRT_2_OVER_2}, // 1
+ { 0, 0, 1, 0}, // 2
+ { 0, 0, SQRT_2_OVER_2,-SQRT_2_OVER_2}, // 3
+
+ { 0, -1, 0, 0}, // 4
+ {-SQRT_2_OVER_2, SQRT_2_OVER_2, 0, 0}, // 5
+ { -1, 0, 0, 0}, // 6
+ {-SQRT_2_OVER_2,-SQRT_2_OVER_2, 0, 0}, // 7
+
+ { -0.5, -0.5, -0.5, 0.5}, // 8
+ { 0,-SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, // 9
+ { 0.5, -0.5, 0.5, 0.5}, // 10
+ { SQRT_2_OVER_2, 0, SQRT_2_OVER_2, 0}, // 11
+
+ { SQRT_2_OVER_2, 0,-SQRT_2_OVER_2, 0}, // 12
+ { 0.5, 0.5, -0.5, 0.5}, // 13
+ { 0, SQRT_2_OVER_2, 0, SQRT_2_OVER_2}, // 14
+ { -0.5, 0.5, 0.5, 0.5}, // 15
+
+ { 0, SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, // 16
+ { -0.5, 0.5, 0.5, -0.5}, // 17
+ {-SQRT_2_OVER_2, 0, 0,-SQRT_2_OVER_2}, // 18
+ { -0.5, -0.5, -0.5, -0.5}, // 19
+
+ {-SQRT_2_OVER_2, 0, 0, SQRT_2_OVER_2}, // 20
+ { -0.5, -0.5, 0.5, 0.5}, // 21
+ { 0,-SQRT_2_OVER_2, SQRT_2_OVER_2, 0}, // 22
+ { 0.5, -0.5, 0.5, -0.5} // 23
+ };
+#undef SQRT_2_OVER_2
+ // Double versions
+#define SQRT_2_OVER_2 0.70710678118654757
+ // Identity
+ const double IDENTITY_QUAT_D[4] = {0,0,0,1};
+ // The following match the Matlab canonical views
+ // X point right, Y pointing up and Z point out
+ const double XY_PLANE_QUAT_D[4] = {0,0,0,1};
+ // X points right, Y points *in* and Z points up
+ const double XZ_PLANE_QUAT_D[4] = {-SQRT_2_OVER_2,0,0,SQRT_2_OVER_2};
+ // X points out, Y points right, and Z points up
+ const double YZ_PLANE_QUAT_D[4] = {-0.5,-0.5,-0.5,0.5};
+ const double CANONICAL_VIEW_QUAT_D[][4] =
+ {
+ { 0, 0, 0, 1},
+ { 0, 0, SQRT_2_OVER_2, SQRT_2_OVER_2},
+ { 0, 0, 1, 0},
+ { 0, 0, SQRT_2_OVER_2,-SQRT_2_OVER_2},
+
+ { 0, -1, 0, 0},
+ {-SQRT_2_OVER_2, SQRT_2_OVER_2, 0, 0},
+ { -1, 0, 0, 0},
+ {-SQRT_2_OVER_2,-SQRT_2_OVER_2, 0, 0},
+
+ { -0.5, -0.5, -0.5, 0.5},
+ { 0,-SQRT_2_OVER_2, 0, SQRT_2_OVER_2},
+ { 0.5, -0.5, 0.5, 0.5},
+ { SQRT_2_OVER_2, 0, SQRT_2_OVER_2, 0},
+
+ { SQRT_2_OVER_2, 0,-SQRT_2_OVER_2, 0},
+ { 0.5, 0.5, -0.5, 0.5},
+ { 0, SQRT_2_OVER_2, 0, SQRT_2_OVER_2},
+ { -0.5, 0.5, 0.5, 0.5},
+
+ { 0, SQRT_2_OVER_2, SQRT_2_OVER_2, 0},
+ { -0.5, 0.5, 0.5, -0.5},
+ {-SQRT_2_OVER_2, 0, 0,-SQRT_2_OVER_2},
+ { -0.5, -0.5, -0.5, -0.5},
+
+ {-SQRT_2_OVER_2, 0, 0, SQRT_2_OVER_2},
+ { -0.5, -0.5, 0.5, 0.5},
+ { 0,-SQRT_2_OVER_2, SQRT_2_OVER_2, 0},
+ { 0.5, -0.5, 0.5, -0.5}
+ };
+#undef SQRT_2_OVER_2
+#define NUM_CANONICAL_VIEW_QUAT 24
+
+ // NOTE: I want to rather be able to return a Q_type[][] but C++ is not
+ // making it easy. So instead I've written a per-element accessor
+
+ // Return element [i][j] of the corresponding CANONICAL_VIEW_QUAT_* of the
+ // given templated type
+ // Inputs:
+ // i index of quaternion
+ // j index of coordinate in quaternion i
+ // Returns values of CANONICAL_VIEW_QUAT_*[i][j]
+ template <typename Q_type>
+ IGL_INLINE Q_type CANONICAL_VIEW_QUAT(int i, int j);
+ // Template specializations for float and double
+ template <>
+ IGL_INLINE float CANONICAL_VIEW_QUAT<float>(int i, int j);
+ template <>
+ IGL_INLINE double CANONICAL_VIEW_QUAT<double>(int i, int j);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "canonical_quaternions.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/cat.cpp b/xs/src/igl/cat.cpp
new file mode 100644
index 000000000..f297fc135
--- /dev/null
+++ b/xs/src/igl/cat.cpp
@@ -0,0 +1,267 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cat.h"
+
+#include <cstdio>
+
+// Bug in unsupported/Eigen/SparseExtra needs iostream first
+#include <iostream>
+#include <unsupported/Eigen/SparseExtra>
+
+
+// Sparse matrices need to be handled carefully. Because C++ does not
+// Template:
+// Scalar sparse matrix scalar type, e.g. double
+template <typename Scalar>
+IGL_INLINE void igl::cat(
+ const int dim,
+ const Eigen::SparseMatrix<Scalar> & A,
+ const Eigen::SparseMatrix<Scalar> & B,
+ Eigen::SparseMatrix<Scalar> & C)
+{
+
+ assert(dim == 1 || dim == 2);
+ using namespace Eigen;
+ // Special case if B or A is empty
+ if(A.size() == 0)
+ {
+ C = B;
+ return;
+ }
+ if(B.size() == 0)
+ {
+ C = A;
+ return;
+ }
+
+#if false
+ // This **must** be DynamicSparseMatrix, otherwise this implementation is
+ // insanely slow
+ DynamicSparseMatrix<Scalar, RowMajor> dyn_C;
+ if(dim == 1)
+ {
+ assert(A.cols() == B.cols());
+ dyn_C.resize(A.rows()+B.rows(),A.cols());
+ }else if(dim == 2)
+ {
+ assert(A.rows() == B.rows());
+ dyn_C.resize(A.rows(),A.cols()+B.cols());
+ }else
+ {
+ fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim);
+ }
+
+ dyn_C.reserve(A.nonZeros()+B.nonZeros());
+
+ // Iterate over outside of A
+ for(int k=0; k<A.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ dyn_C.coeffRef(it.row(),it.col()) += it.value();
+ }
+ }
+
+ // Iterate over outside of B
+ for(int k=0; k<B.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
+ {
+ int r = (dim == 1 ? A.rows()+it.row() : it.row());
+ int c = (dim == 2 ? A.cols()+it.col() : it.col());
+ dyn_C.coeffRef(r,c) += it.value();
+ }
+ }
+
+ C = SparseMatrix<Scalar>(dyn_C);
+#elif false
+ std::vector<Triplet<Scalar> > CIJV;
+ CIJV.reserve(A.nonZeros() + B.nonZeros());
+ {
+ // Iterate over outside of A
+ for(int k=0; k<A.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ CIJV.emplace_back(it.row(),it.col(),it.value());
+ }
+ }
+ // Iterate over outside of B
+ for(int k=0; k<B.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
+ {
+ int r = (dim == 1 ? A.rows()+it.row() : it.row());
+ int c = (dim == 2 ? A.cols()+it.col() : it.col());
+ CIJV.emplace_back(r,c,it.value());
+ }
+ }
+
+ }
+
+ C = SparseMatrix<Scalar>(
+ dim == 1 ? A.rows()+B.rows() : A.rows(),
+ dim == 1 ? A.cols() : A.cols()+B.cols());
+ C.reserve(A.nonZeros() + B.nonZeros());
+ C.setFromTriplets(CIJV.begin(),CIJV.end());
+#else
+ C = SparseMatrix<Scalar>(
+ dim == 1 ? A.rows()+B.rows() : A.rows(),
+ dim == 1 ? A.cols() : A.cols()+B.cols());
+ Eigen::VectorXi per_col = Eigen::VectorXi::Zero(C.cols());
+ if(dim == 1)
+ {
+ assert(A.outerSize() == B.outerSize());
+ for(int k = 0;k<A.outerSize();++k)
+ {
+ for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ per_col(k)++;
+ }
+ for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
+ {
+ per_col(k)++;
+ }
+ }
+ }else
+ {
+ for(int k = 0;k<A.outerSize();++k)
+ {
+ for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ per_col(k)++;
+ }
+ }
+ for(int k = 0;k<B.outerSize();++k)
+ {
+ for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
+ {
+ per_col(A.cols() + k)++;
+ }
+ }
+ }
+ C.reserve(per_col);
+ if(dim == 1)
+ {
+ for(int k = 0;k<A.outerSize();++k)
+ {
+ for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ C.insert(it.row(),k) = it.value();
+ }
+ for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
+ {
+ C.insert(A.rows()+it.row(),k) = it.value();
+ }
+ }
+ }else
+ {
+ for(int k = 0;k<A.outerSize();++k)
+ {
+ for(typename SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ C.insert(it.row(),k) = it.value();
+ }
+ }
+ for(int k = 0;k<B.outerSize();++k)
+ {
+ for(typename SparseMatrix<Scalar>::InnerIterator it (B,k); it; ++it)
+ {
+ C.insert(it.row(),A.cols()+k) = it.value();
+ }
+ }
+ }
+ C.makeCompressed();
+
+#endif
+
+}
+
+template <typename Derived, class MatC>
+IGL_INLINE void igl::cat(
+ const int dim,
+ const Eigen::MatrixBase<Derived> & A,
+ const Eigen::MatrixBase<Derived> & B,
+ MatC & C)
+{
+ assert(dim == 1 || dim == 2);
+ // Special case if B or A is empty
+ if(A.size() == 0)
+ {
+ C = B;
+ return;
+ }
+ if(B.size() == 0)
+ {
+ C = A;
+ return;
+ }
+
+ if(dim == 1)
+ {
+ assert(A.cols() == B.cols());
+ C.resize(A.rows()+B.rows(),A.cols());
+ C << A,B;
+ }else if(dim == 2)
+ {
+ assert(A.rows() == B.rows());
+ C.resize(A.rows(),A.cols()+B.cols());
+ C << A,B;
+ }else
+ {
+ fprintf(stderr,"cat.h: Error: Unsupported dimension %d\n",dim);
+ }
+}
+
+template <class Mat>
+IGL_INLINE Mat igl::cat(const int dim, const Mat & A, const Mat & B)
+{
+ assert(dim == 1 || dim == 2);
+ Mat C;
+ igl::cat(dim,A,B,C);
+ return C;
+}
+
+template <class Mat>
+IGL_INLINE void igl::cat(const std::vector<std::vector< Mat > > & A, Mat & C)
+{
+ using namespace std;
+ // Start with empty matrix
+ C.resize(0,0);
+ for(const auto & row_vec : A)
+ {
+ // Concatenate each row horizontally
+ // Start with empty matrix
+ Mat row(0,0);
+ for(const auto & element : row_vec)
+ {
+ row = cat(2,row,element);
+ }
+ // Concatenate rows vertically
+ C = cat(1,C,row);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::cat<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&);
+// generated by autoexplicit.sh
+template Eigen::SparseMatrix<double, 0, int> igl::cat<Eigen::SparseMatrix<double, 0, int> >(int, Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int> const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&);
+template void igl::cat<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(int, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::cat<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::cat<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(int, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&);
+template void igl::cat<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(int, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template void igl::cat<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
+#endif
diff --git a/xs/src/igl/cat.h b/xs/src/igl/cat.h
new file mode 100644
index 000000000..615bda130
--- /dev/null
+++ b/xs/src/igl/cat.h
@@ -0,0 +1,71 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CAT_H
+#define IGL_CAT_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Sparse>
+#include <Eigen/Dense>
+
+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
+ //
+ template <typename Scalar>
+ IGL_INLINE void cat(
+ const int dim,
+ const Eigen::SparseMatrix<Scalar> & A,
+ const Eigen::SparseMatrix<Scalar> & B,
+ Eigen::SparseMatrix<Scalar> & C);
+ 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
+ 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
+ template <class Mat>
+ IGL_INLINE void cat(const std::vector<std::vector< Mat > > & A, Mat & C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/ceil.cpp b/xs/src/igl/ceil.cpp
new file mode 100644
index 000000000..278269ab2
--- /dev/null
+++ b/xs/src/igl/ceil.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ceil.h"
+#include <cmath>
+
+template < typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::ceil(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedY>& Y)
+{
+ using namespace std;
+ //Y = DerivedY::Zero(m,n);
+//#pragma omp parallel for
+ //for(int i = 0;i<m;i++)
+ //{
+ // for(int j = 0;j<n;j++)
+ // {
+ // Y(i,j) = std::ceil(X(i,j));
+ // }
+ //}
+ typedef typename DerivedX::Scalar Scalar;
+ Y = X.unaryExpr([](const Scalar &x)->Scalar{return std::ceil(x);}).template cast<typename DerivedY::Scalar >();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::ceil<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/ceil.h b/xs/src/igl/ceil.h
new file mode 100644
index 000000000..b6acee904
--- /dev/null
+++ b/xs/src/igl/ceil.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CEIL_H
+#define IGL_CEIL_H
+#include "igl_inline.h"
+#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
+ template < typename DerivedX, typename DerivedY>
+ IGL_INLINE void ceil(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedY>& Y);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "ceil.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/centroid.cpp b/xs/src/igl/centroid.cpp
new file mode 100644
index 000000000..a9ed25df2
--- /dev/null
+++ b/xs/src/igl/centroid.cpp
@@ -0,0 +1,67 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "centroid.h"
+#include <Eigen/Geometry>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedc,
+ typename Derivedvol>
+IGL_INLINE void igl::centroid(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<Derivedc>& cen,
+ Derivedvol & vol)
+{
+ using namespace Eigen;
+ assert(F.cols() == 3 && "F should contain triangles.");
+ assert(V.cols() == 3 && "V should contain 3d points.");
+ const int m = F.rows();
+ cen.setZero();
+ vol = 0;
+ // loop over faces
+ for(int f = 0;f<m;f++)
+ {
+ // "Calculating the volume and centroid of a polyhedron in 3d" [Nuernberg 2013]
+ // http://www2.imperial.ac.uk/~rn/centroid.pdf
+ // rename corners
+ typedef Eigen::Matrix<typename DerivedV::Scalar,1,3> RowVector3S;
+ const RowVector3S & a = V.row(F(f,0));
+ const RowVector3S & b = V.row(F(f,1));
+ const RowVector3S & c = V.row(F(f,2));
+ // un-normalized normal
+ const RowVector3S & n = (b-a).cross(c-a);
+ // total volume via divergence theorem: ∫ 1
+ vol += n.dot(a)/6.;
+ // centroid via divergence theorem and midpoint quadrature: ∫ x
+ cen.array() += (1./24.*n.array()*((a+b).array().square() + (b+c).array().square() +
+ (c+a).array().square()).array());
+ }
+ cen *= 1./(2.*vol);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedc>
+IGL_INLINE void igl::centroid(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<Derivedc>& c)
+{
+ typename Derivedc::Scalar vol;
+ return centroid(V,F,c,vol);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::centroid<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+template void igl::centroid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+#endif
diff --git a/xs/src/igl/centroid.h b/xs/src/igl/centroid.h
new file mode 100644
index 000000000..31fa7ae6b
--- /dev/null
+++ b/xs/src/igl/centroid.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CENTROID_H
+#define IGL_CENTROID_H
+#include "igl_inline.h"
+#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.
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedc,
+ typename Derivedvol>
+ IGL_INLINE void centroid(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<Derivedc>& c,
+ Derivedvol & vol);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedc>
+ IGL_INLINE void centroid(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<Derivedc>& c);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "centroid.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/circulation.cpp b/xs/src/igl/circulation.cpp
new file mode 100644
index 000000000..6f711b946
--- /dev/null
+++ b/xs/src/igl/circulation.cpp
@@ -0,0 +1,71 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "circulation.h"
+#include "list_to_matrix.h"
+
+IGL_INLINE std::vector<int> igl::circulation(
+ const int e,
+ const bool ccw,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI)
+{
+ // prepare output
+ std::vector<int> N;
+ N.reserve(6);
+ const int m = F.rows();
+ const auto & step = [&](
+ const int e,
+ const int ff,
+ int & ne,
+ int & nf)
+ {
+ assert((EF(e,1) == ff || EF(e,0) == ff) && "e should touch ff");
+ //const int fside = EF(e,1)==ff?1:0;
+ const int nside = EF(e,0)==ff?1:0;
+ const int nv = EI(e,nside);
+ // get next face
+ nf = EF(e,nside);
+ // get next edge
+ const int dir = ccw?-1:1;
+ ne = EMAP(nf+m*((nv+dir+3)%3));
+ };
+ // Always start with first face (ccw in step will be sure to turn right
+ // direction)
+ const int f0 = EF(e,0);
+ int fi = f0;
+ int ei = e;
+ while(true)
+ {
+ step(ei,fi,ei,fi);
+ N.push_back(fi);
+ // back to start?
+ if(fi == f0)
+ {
+ assert(ei == e);
+ break;
+ }
+ }
+ return N;
+}
+
+IGL_INLINE void igl::circulation(
+ const int e,
+ const bool ccw,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ Eigen::VectorXi & vN)
+{
+ std::vector<int> N = circulation(e,ccw,F,E,EMAP,EF,EI);
+ igl::list_to_matrix(N,vN);
+}
diff --git a/xs/src/igl/circulation.h b/xs/src/igl/circulation.h
new file mode 100644
index 000000000..d8d14c7ed
--- /dev/null
+++ b/xs/src/igl/circulation.h
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CIRCULATION_H
+#define IGL_CIRCULATION_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+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))
+ // F #F by 3 list of face indices
+ // E #E by 2 list of edge indices
+ // 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).
+ //
+ IGL_INLINE std::vector<int> circulation(
+ const int e,
+ const bool ccw,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI);
+ // Wrapper with VectorXi output.
+ IGL_INLINE void circulation(
+ const int e,
+ const bool ccw,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ Eigen::VectorXi & vN);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "circulation.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/circumradius.cpp b/xs/src/igl/circumradius.cpp
new file mode 100644
index 000000000..34424eae2
--- /dev/null
+++ b/xs/src/igl/circumradius.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "circumradius.h"
+#include "edge_lengths.h"
+#include "doublearea.h"
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedR>
+IGL_INLINE void igl::circumradius(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedR> & R)
+{
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> l;
+ igl::edge_lengths(V,F,l);
+ DerivedR A;
+ igl::doublearea(l,0.,A);
+ // use formula: R=abc/(4*area) to compute the circum radius
+ R = l.col(0).array() * l.col(1).array() * l.col(2).array() / (2.0*A.array());
+}
diff --git a/xs/src/igl/circumradius.h b/xs/src/igl/circumradius.h
new file mode 100644
index 000000000..12592ee3f
--- /dev/null
+++ b/xs/src/igl/circumradius.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CIRCUMRADIUS_H
+#define IGL_CIRCUMRADIUS_H
+#include "igl_inline.h"
+#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 circumradii
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedR>
+ IGL_INLINE void circumradius(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedR> & R);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "circumradius.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/collapse_edge.cpp b/xs/src/igl/collapse_edge.cpp
new file mode 100644
index 000000000..9f00b4323
--- /dev/null
+++ b/xs/src/igl/collapse_edge.cpp
@@ -0,0 +1,394 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "collapse_edge.h"
+#include "circulation.h"
+#include "edge_collapse_is_valid.h"
+#include <vector>
+
+IGL_INLINE bool igl::collapse_edge(
+ const int e,
+ const Eigen::RowVectorXd & p,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ int & a_e1,
+ int & a_e2,
+ int & a_f1,
+ int & a_f2)
+{
+ // Assign this to 0 rather than, say, -1 so that deleted elements will get
+ // draw as degenerate elements at vertex 0 (which should always exist and
+ // never get collapsed to anything else since it is the smallest index)
+ using namespace Eigen;
+ using namespace std;
+ const int eflip = E(e,0)>E(e,1);
+ // source and destination
+ const int s = eflip?E(e,1):E(e,0);
+ const int d = eflip?E(e,0):E(e,1);
+
+ if(!edge_collapse_is_valid(e,F,E,EMAP,EF,EI))
+ {
+ return false;
+ }
+
+ // Important to grab neighbors of d before monkeying with edges
+ const std::vector<int> nV2Fd = circulation(e,!eflip,F,E,EMAP,EF,EI);
+
+ // The following implementation strongly relies on s<d
+ assert(s<d && "s should be less than d");
+ // move source and destination to midpoint
+ V.row(s) = p;
+ V.row(d) = p;
+
+ // Helper function to replace edge and associate information with NULL
+ const auto & kill_edge = [&E,&EI,&EF](const int e)
+ {
+ E(e,0) = IGL_COLLAPSE_EDGE_NULL;
+ E(e,1) = IGL_COLLAPSE_EDGE_NULL;
+ EF(e,0) = IGL_COLLAPSE_EDGE_NULL;
+ EF(e,1) = IGL_COLLAPSE_EDGE_NULL;
+ EI(e,0) = IGL_COLLAPSE_EDGE_NULL;
+ EI(e,1) = IGL_COLLAPSE_EDGE_NULL;
+ };
+
+ // update edge info
+ // for each flap
+ const int m = F.rows();
+ for(int side = 0;side<2;side++)
+ {
+ const int f = EF(e,side);
+ const int v = EI(e,side);
+ const int sign = (eflip==0?1:-1)*(1-2*side);
+ // next edge emanating from d
+ const int e1 = EMAP(f+m*((v+sign*1+3)%3));
+ // prev edge pointing to s
+ const int e2 = EMAP(f+m*((v+sign*2+3)%3));
+ assert(E(e1,0) == d || E(e1,1) == d);
+ assert(E(e2,0) == s || E(e2,1) == s);
+ // face adjacent to f on e1, also incident on d
+ const bool flip1 = EF(e1,1)==f;
+ const int f1 = flip1 ? EF(e1,0) : EF(e1,1);
+ assert(f1!=f);
+ assert(F(f1,0)==d || F(f1,1)==d || F(f1,2) == d);
+ // across from which vertex of f1 does e1 appear?
+ const int v1 = flip1 ? EI(e1,0) : EI(e1,1);
+ // Kill e1
+ kill_edge(e1);
+ // Kill f
+ F(f,0) = IGL_COLLAPSE_EDGE_NULL;
+ F(f,1) = IGL_COLLAPSE_EDGE_NULL;
+ F(f,2) = IGL_COLLAPSE_EDGE_NULL;
+ // map f1's edge on e1 to e2
+ assert(EMAP(f1+m*v1) == e1);
+ EMAP(f1+m*v1) = e2;
+ // side opposite f2, the face adjacent to f on e2, also incident on s
+ const int opp2 = (EF(e2,0)==f?0:1);
+ assert(EF(e2,opp2) == f);
+ EF(e2,opp2) = f1;
+ EI(e2,opp2) = v1;
+ // remap e2 from d to s
+ E(e2,0) = E(e2,0)==d ? s : E(e2,0);
+ E(e2,1) = E(e2,1)==d ? s : E(e2,1);
+ if(side==0)
+ {
+ a_e1 = e1;
+ a_f1 = f;
+ }else
+ {
+ a_e2 = e1;
+ a_f2 = f;
+ }
+ }
+
+ // finally, reindex faces and edges incident on d. Do this last so asserts
+ // make sense.
+ //
+ // Could actually skip first and last, since those are always the two
+ // collpased faces.
+ for(auto f : nV2Fd)
+ {
+ for(int v = 0;v<3;v++)
+ {
+ if(F(f,v) == d)
+ {
+ const int flip1 = (EF(EMAP(f+m*((v+1)%3)),0)==f)?1:0;
+ const int flip2 = (EF(EMAP(f+m*((v+2)%3)),0)==f)?0:1;
+ assert(
+ E(EMAP(f+m*((v+1)%3)),flip1) == d ||
+ E(EMAP(f+m*((v+1)%3)),flip1) == s);
+ E(EMAP(f+m*((v+1)%3)),flip1) = s;
+ assert(
+ E(EMAP(f+m*((v+2)%3)),flip2) == d ||
+ E(EMAP(f+m*((v+2)%3)),flip2) == s);
+ E(EMAP(f+m*((v+2)%3)),flip2) = s;
+ F(f,v) = s;
+ break;
+ }
+ }
+ }
+ // Finally, "remove" this edge and its information
+ kill_edge(e);
+
+ return true;
+}
+
+IGL_INLINE bool igl::collapse_edge(
+ const int e,
+ const Eigen::RowVectorXd & p,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI)
+{
+ int e1,e2,f1,f2;
+ return collapse_edge(e,p,V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
+}
+
+IGL_INLINE bool igl::collapse_edge(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ std::set<std::pair<double,int> > & Q,
+ std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
+ Eigen::MatrixXd & C)
+{
+ int e,e1,e2,f1,f2;
+ const auto always_try = [](
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ ) -> bool { return true;};
+ const auto never_care = [](
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )-> void { };
+ return
+ collapse_edge(
+ cost_and_placement,always_try,never_care,
+ V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
+}
+
+IGL_INLINE bool igl::collapse_edge(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ std::set<std::pair<double,int> > & Q,
+ std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
+ Eigen::MatrixXd & C)
+{
+ int e,e1,e2,f1,f2;
+ return
+ collapse_edge(
+ cost_and_placement,pre_collapse,post_collapse,
+ V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
+}
+
+
+IGL_INLINE bool igl::collapse_edge(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ std::set<std::pair<double,int> > & Q,
+ std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
+ Eigen::MatrixXd & C,
+ int & e,
+ int & e1,
+ int & e2,
+ int & f1,
+ int & f2)
+{
+ using namespace Eigen;
+ if(Q.empty())
+ {
+ // no edges to collapse
+ return false;
+ }
+ std::pair<double,int> p = *(Q.begin());
+ if(p.first == std::numeric_limits<double>::infinity())
+ {
+ // min cost edge is infinite cost
+ return false;
+ }
+ Q.erase(Q.begin());
+ e = p.second;
+ Qit[e] = Q.end();
+ std::vector<int> N = circulation(e, true,F,E,EMAP,EF,EI);
+ std::vector<int> Nd = circulation(e,false,F,E,EMAP,EF,EI);
+ N.insert(N.begin(),Nd.begin(),Nd.end());
+ bool collapsed = true;
+ if(pre_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e))
+ {
+ collapsed = collapse_edge(e,C.row(e),V,F,E,EMAP,EF,EI,e1,e2,f1,f2);
+ }else
+ {
+ // Aborted by pre collapse callback
+ collapsed = false;
+ }
+ post_collapse(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2,collapsed);
+ if(collapsed)
+ {
+ // Erase the two, other collapsed edges
+ Q.erase(Qit[e1]);
+ Qit[e1] = Q.end();
+ Q.erase(Qit[e2]);
+ Qit[e2] = Q.end();
+ // update local neighbors
+ // loop over original face neighbors
+ for(auto n : N)
+ {
+ if(F(n,0) != IGL_COLLAPSE_EDGE_NULL ||
+ F(n,1) != IGL_COLLAPSE_EDGE_NULL ||
+ F(n,2) != IGL_COLLAPSE_EDGE_NULL)
+ {
+ for(int v = 0;v<3;v++)
+ {
+ // get edge id
+ const int ei = EMAP(v*F.rows()+n);
+ // erase old entry
+ Q.erase(Qit[ei]);
+ // compute cost and potential placement
+ double cost;
+ RowVectorXd place;
+ cost_and_placement(ei,V,F,E,EMAP,EF,EI,cost,place);
+ // Replace in queue
+ Qit[ei] = Q.insert(std::pair<double,int>(cost,ei)).first;
+ C.row(ei) = place;
+ }
+ }
+ }
+ }else
+ {
+ // reinsert with infinite weight (the provided cost function must **not**
+ // have given this un-collapsable edge inf cost already)
+ p.first = std::numeric_limits<double>::infinity();
+ Qit[e] = Q.insert(p).first;
+ }
+ return collapsed;
+}
diff --git a/xs/src/igl/collapse_edge.h b/xs/src/igl/collapse_edge.h
new file mode 100644
index 000000000..90e562556
--- /dev/null
+++ b/xs/src/igl/collapse_edge.h
@@ -0,0 +1,216 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COLLAPSE_EDGE_H
+#define IGL_COLLAPSE_EDGE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#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 left
+ // f1 index into E of edge collpased on left
+ // f2 index into E of edge collpased on left
+ // Returns true if edge was collapsed
+ #define IGL_COLLAPSE_EDGE_NULL 0
+ IGL_INLINE bool collapse_edge(
+ const int e,
+ const Eigen::RowVectorXd & p,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ int & e1,
+ int & e2,
+ int & f1,
+ int & f2);
+ IGL_INLINE bool collapse_edge(
+ const int e,
+ const Eigen::RowVectorXd & p,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ 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
+ // Qit list of iterators so that Qit[e] --> iterator of edge e in Q
+ // C #E by dim list of stored placements
+ IGL_INLINE bool collapse_edge(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ std::set<std::pair<double,int> > & Q,
+ std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
+ 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.
+ IGL_INLINE bool collapse_edge(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ std::set<std::pair<double,int> > & Q,
+ std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
+ Eigen::MatrixXd & C);
+
+ IGL_INLINE bool collapse_edge(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI,
+ std::set<std::pair<double,int> > & Q,
+ std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
+ Eigen::MatrixXd & C,
+ int & e,
+ int & e1,
+ int & e2,
+ int & f1,
+ int & f2);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "collapse_edge.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/collapse_small_triangles.cpp b/xs/src/igl/collapse_small_triangles.cpp
new file mode 100644
index 000000000..5177c584f
--- /dev/null
+++ b/xs/src/igl/collapse_small_triangles.cpp
@@ -0,0 +1,139 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "collapse_small_triangles.h"
+
+#include "bounding_box_diagonal.h"
+#include "doublearea.h"
+#include "edge_lengths.h"
+#include "colon.h"
+#include "faces_first.h"
+
+#include <limits>
+
+#include <iostream>
+
+void igl::collapse_small_triangles(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const double eps,
+ Eigen::MatrixXi & FF)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ // Compute bounding box diagonal length
+ double bbd = bounding_box_diagonal(V);
+ MatrixXd l;
+ edge_lengths(V,F,l);
+ VectorXd dblA;
+ doublearea(l,0.,dblA);
+
+ // Minimum area tolerance
+ const double min_dblarea = 2.0*eps*bbd*bbd;
+
+ Eigen::VectorXi FIM = colon<int>(0,V.rows()-1);
+ int num_edge_collapses = 0;
+ // Loop over triangles
+ for(int f = 0;f<F.rows();f++)
+ {
+ if(dblA(f) < min_dblarea)
+ {
+ double minl = 0;
+ int minli = -1;
+ // Find shortest edge
+ for(int e = 0;e<3;e++)
+ {
+ if(minli==-1 || l(f,e)<minl)
+ {
+ minli = e;
+ minl = l(f,e);
+ }
+ }
+ double maxl = 0;
+ int maxli = -1;
+ // Find longest edge
+ for(int e = 0;e<3;e++)
+ {
+ if(maxli==-1 || l(f,e)>maxl)
+ {
+ maxli = e;
+ maxl = l(f,e);
+ }
+ }
+ // Be sure that min and max aren't the same
+ maxli = (minli==maxli?(minli+1)%3:maxli);
+
+ // Collapse min edge maintaining max edge: i-->j
+ // Q: Why this direction?
+ int i = maxli;
+ int j = ((minli+1)%3 == maxli ? (minli+2)%3: (minli+1)%3);
+ assert(i != minli);
+ assert(j != minli);
+ assert(i != j);
+ FIM(F(f,i)) = FIM(F(f,j));
+ num_edge_collapses++;
+ }
+ }
+
+ // Reindex faces
+ MatrixXi rF = F;
+ // Loop over triangles
+ for(int f = 0;f<rF.rows();f++)
+ {
+ for(int i = 0;i<rF.cols();i++)
+ {
+ rF(f,i) = FIM(rF(f,i));
+ }
+ }
+
+ FF.resizeLike(rF);
+ int num_face_collapses=0;
+ // Only keep uncollapsed faces
+ {
+ int ff = 0;
+ // Loop over triangles
+ for(int f = 0;f<rF.rows();f++)
+ {
+ bool collapsed = false;
+ // Check if any indices are the same
+ for(int i = 0;i<rF.cols();i++)
+ {
+ for(int j = i+1;j<rF.cols();j++)
+ {
+ if(rF(f,i)==rF(f,j))
+ {
+ collapsed = true;
+ num_face_collapses++;
+ break;
+ }
+ }
+ }
+ if(!collapsed)
+ {
+ FF.row(ff++) = rF.row(f);
+ }
+ }
+ // Use conservative resize
+ FF.conservativeResize(ff,FF.cols());
+ }
+ //cout<<"num_edge_collapses: "<<num_edge_collapses<<endl;
+ //cout<<"num_face_collapses: "<<num_face_collapses<<endl;
+ if(num_edge_collapses == 0)
+ {
+ // There must have been a "collapsed edge" in the input
+ assert(num_face_collapses==0);
+ // Base case
+ return;
+ }
+
+ //// force base case
+ //return;
+
+ MatrixXi recFF = FF;
+ return collapse_small_triangles(V,recFF,eps,FF);
+}
diff --git a/xs/src/igl/collapse_small_triangles.h b/xs/src/igl/collapse_small_triangles.h
new file mode 100644
index 000000000..dacf86953
--- /dev/null
+++ b/xs/src/igl/collapse_small_triangles.h
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COLLAPSE_SMALL_TRIANGLES_H
+#define IGL_COLLAPSE_SMALL_TRIANGLES_H
+#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
+ //
+ //
+ void collapse_small_triangles(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const double eps,
+ Eigen::MatrixXi & FF);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "collapse_small_triangles.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/colon.cpp b/xs/src/igl/colon.cpp
new file mode 100644
index 000000000..a10c2982e
--- /dev/null
+++ b/xs/src/igl/colon.cpp
@@ -0,0 +1,66 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "colon.h"
+#include "LinSpaced.h"
+
+#include <cstdio>
+
+template <typename L,typename S,typename H,typename T>
+IGL_INLINE void igl::colon(
+ const L low,
+ const S step,
+ const H hi,
+ Eigen::Matrix<T,Eigen::Dynamic,1> & I)
+{
+ const int size = ((hi-low)/step)+1;
+ I = igl::LinSpaced<Eigen::Matrix<T,Eigen::Dynamic,1> >(size,low,low+step*(size-1));
+}
+
+template <typename L,typename H,typename T>
+IGL_INLINE void igl::colon(
+ const L low,
+ const H hi,
+ Eigen::Matrix<T,Eigen::Dynamic,1> & I)
+{
+ return igl::colon(low,(T)1,hi,I);
+}
+
+template <typename T,typename L,typename H>
+IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> igl::colon(
+ const L low,
+ const H hi)
+{
+ Eigen::Matrix<T,Eigen::Dynamic,1> I;
+ igl::colon(low,hi,I);
+ return I;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::Matrix<int,-1,1,0,-1,1> igl::colon<int,int,int>(int, int);
+template Eigen::Matrix<int,-1,1,0,-1,1> igl::colon<int,int,long>(int,long);
+template Eigen::Matrix<int,-1,1,0,-1,1> igl::colon<int,int,long long int>(int,long long int);
+template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::colon<double, double, double>(double, double);
+// generated by autoexplicit.sh
+template void igl::colon<int, long, int, int>(int, long, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, int, long, int>(int, int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, long, int>(int, long, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, int, int>(int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::colon<int,long long int,int>(int,long long int,Eigen::Matrix<int,-1,1,0,-1,1> &);
+template void igl::colon<int, int, int, int>(int, int, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, long, long>(int, long, Eigen::Matrix<long, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, double, double, double>(int, double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
+template void igl::colon<double, double, double>(double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
+template void igl::colon<double, double, double, double>(double, double, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
+template void igl::colon<int, int, long>(int, int, Eigen::Matrix<long, -1, 1, 0, -1, 1>&);
+#ifdef WIN32
+template void igl::colon<int, long long,long>(int, long long, class Eigen::Matrix<long,-1,1,0,-1,1> &);
+template void igl::colon<int, __int64, __int64>(int, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> &);
+#endif
+#endif
diff --git a/xs/src/igl/colon.h b/xs/src/igl/colon.h
new file mode 100644
index 000000000..1f2b9bf6f
--- /dev/null
+++ b/xs/src/igl/colon.h
@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COLON_H
+#define IGL_COLON_H
+#include "igl_inline.h"
+#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
+ 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
+ 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
+ template <typename T,typename L,typename H>
+ IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> colon(
+ const L low,
+ const H hi);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "colon.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/colormap.cpp b/xs/src/igl/colormap.cpp
new file mode 100644
index 000000000..560cbe6c0
--- /dev/null
+++ b/xs/src/igl/colormap.cpp
@@ -0,0 +1,1434 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Joe Graus <jgraus@gmu.edu>, Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "colormap.h"
+#include "jet.h"
+#include <algorithm>
+
+// One of the new matplotlib colormaps by Nathaniel J.Smith, Stefan van der Walt, and (in the case of viridis) Eric Firing.
+// Released under the CC0 license / public domain dedication
+
+namespace igl
+{
+static double inferno_cm[256][3] = {
+ { 0.001462, 0.000466, 0.013866 },
+ { 0.002267, 0.001270, 0.018570 },
+ { 0.003299, 0.002249, 0.024239 },
+ { 0.004547, 0.003392, 0.030909 },
+ { 0.006006, 0.004692, 0.038558 },
+ { 0.007676, 0.006136, 0.046836 },
+ { 0.009561, 0.007713, 0.055143 },
+ { 0.011663, 0.009417, 0.063460 },
+ { 0.013995, 0.011225, 0.071862 },
+ { 0.016561, 0.013136, 0.080282 },
+ { 0.019373, 0.015133, 0.088767 },
+ { 0.022447, 0.017199, 0.097327 },
+ { 0.025793, 0.019331, 0.105930 },
+ { 0.029432, 0.021503, 0.114621 },
+ { 0.033385, 0.023702, 0.123397 },
+ { 0.037668, 0.025921, 0.132232 },
+ { 0.042253, 0.028139, 0.141141 },
+ { 0.046915, 0.030324, 0.150164 },
+ { 0.051644, 0.032474, 0.159254 },
+ { 0.056449, 0.034569, 0.168414 },
+ { 0.061340, 0.036590, 0.177642 },
+ { 0.066331, 0.038504, 0.186962 },
+ { 0.071429, 0.040294, 0.196354 },
+ { 0.076637, 0.041905, 0.205799 },
+ { 0.081962, 0.043328, 0.215289 },
+ { 0.087411, 0.044556, 0.224813 },
+ { 0.092990, 0.045583, 0.234358 },
+ { 0.098702, 0.046402, 0.243904 },
+ { 0.104551, 0.047008, 0.253430 },
+ { 0.110536, 0.047399, 0.262912 },
+ { 0.116656, 0.047574, 0.272321 },
+ { 0.122908, 0.047536, 0.281624 },
+ { 0.129285, 0.047293, 0.290788 },
+ { 0.135778, 0.046856, 0.299776 },
+ { 0.142378, 0.046242, 0.308553 },
+ { 0.149073, 0.045468, 0.317085 },
+ { 0.155850, 0.044559, 0.325338 },
+ { 0.162689, 0.043554, 0.333277 },
+ { 0.169575, 0.042489, 0.340874 },
+ { 0.176493, 0.041402, 0.348111 },
+ { 0.183429, 0.040329, 0.354971 },
+ { 0.190367, 0.039309, 0.361447 },
+ { 0.197297, 0.038400, 0.367535 },
+ { 0.204209, 0.037632, 0.373238 },
+ { 0.211095, 0.037030, 0.378563 },
+ { 0.217949, 0.036615, 0.383522 },
+ { 0.224763, 0.036405, 0.388129 },
+ { 0.231538, 0.036405, 0.392400 },
+ { 0.238273, 0.036621, 0.396353 },
+ { 0.244967, 0.037055, 0.400007 },
+ { 0.251620, 0.037705, 0.403378 },
+ { 0.258234, 0.038571, 0.406485 },
+ { 0.264810, 0.039647, 0.409345 },
+ { 0.271347, 0.040922, 0.411976 },
+ { 0.277850, 0.042353, 0.414392 },
+ { 0.284321, 0.043933, 0.416608 },
+ { 0.290763, 0.045644, 0.418637 },
+ { 0.297178, 0.047470, 0.420491 },
+ { 0.303568, 0.049396, 0.422182 },
+ { 0.309935, 0.051407, 0.423721 },
+ { 0.316282, 0.053490, 0.425116 },
+ { 0.322610, 0.055634, 0.426377 },
+ { 0.328921, 0.057827, 0.427511 },
+ { 0.335217, 0.060060, 0.428524 },
+ { 0.341500, 0.062325, 0.429425 },
+ { 0.347771, 0.064616, 0.430217 },
+ { 0.354032, 0.066925, 0.430906 },
+ { 0.360284, 0.069247, 0.431497 },
+ { 0.366529, 0.071579, 0.431994 },
+ { 0.372768, 0.073915, 0.432400 },
+ { 0.379001, 0.076253, 0.432719 },
+ { 0.385228, 0.078591, 0.432955 },
+ { 0.391453, 0.080927, 0.433109 },
+ { 0.397674, 0.083257, 0.433183 },
+ { 0.403894, 0.085580, 0.433179 },
+ { 0.410113, 0.087896, 0.433098 },
+ { 0.416331, 0.090203, 0.432943 },
+ { 0.422549, 0.092501, 0.432714 },
+ { 0.428768, 0.094790, 0.432412 },
+ { 0.434987, 0.097069, 0.432039 },
+ { 0.441207, 0.099338, 0.431594 },
+ { 0.447428, 0.101597, 0.431080 },
+ { 0.453651, 0.103848, 0.430498 },
+ { 0.459875, 0.106089, 0.429846 },
+ { 0.466100, 0.108322, 0.429125 },
+ { 0.472328, 0.110547, 0.428334 },
+ { 0.478558, 0.112764, 0.427475 },
+ { 0.484789, 0.114974, 0.426548 },
+ { 0.491022, 0.117179, 0.425552 },
+ { 0.497257, 0.119379, 0.424488 },
+ { 0.503493, 0.121575, 0.423356 },
+ { 0.509730, 0.123769, 0.422156 },
+ { 0.515967, 0.125960, 0.420887 },
+ { 0.522206, 0.128150, 0.419549 },
+ { 0.528444, 0.130341, 0.418142 },
+ { 0.534683, 0.132534, 0.416667 },
+ { 0.540920, 0.134729, 0.415123 },
+ { 0.547157, 0.136929, 0.413511 },
+ { 0.553392, 0.139134, 0.411829 },
+ { 0.559624, 0.141346, 0.410078 },
+ { 0.565854, 0.143567, 0.408258 },
+ { 0.572081, 0.145797, 0.406369 },
+ { 0.578304, 0.148039, 0.404411 },
+ { 0.584521, 0.150294, 0.402385 },
+ { 0.590734, 0.152563, 0.400290 },
+ { 0.596940, 0.154848, 0.398125 },
+ { 0.603139, 0.157151, 0.395891 },
+ { 0.609330, 0.159474, 0.393589 },
+ { 0.615513, 0.161817, 0.391219 },
+ { 0.621685, 0.164184, 0.388781 },
+ { 0.627847, 0.166575, 0.386276 },
+ { 0.633998, 0.168992, 0.383704 },
+ { 0.640135, 0.171438, 0.381065 },
+ { 0.646260, 0.173914, 0.378359 },
+ { 0.652369, 0.176421, 0.375586 },
+ { 0.658463, 0.178962, 0.372748 },
+ { 0.664540, 0.181539, 0.369846 },
+ { 0.670599, 0.184153, 0.366879 },
+ { 0.676638, 0.186807, 0.363849 },
+ { 0.682656, 0.189501, 0.360757 },
+ { 0.688653, 0.192239, 0.357603 },
+ { 0.694627, 0.195021, 0.354388 },
+ { 0.700576, 0.197851, 0.351113 },
+ { 0.706500, 0.200728, 0.347777 },
+ { 0.712396, 0.203656, 0.344383 },
+ { 0.718264, 0.206636, 0.340931 },
+ { 0.724103, 0.209670, 0.337424 },
+ { 0.729909, 0.212759, 0.333861 },
+ { 0.735683, 0.215906, 0.330245 },
+ { 0.741423, 0.219112, 0.326576 },
+ { 0.747127, 0.222378, 0.322856 },
+ { 0.752794, 0.225706, 0.319085 },
+ { 0.758422, 0.229097, 0.315266 },
+ { 0.764010, 0.232554, 0.311399 },
+ { 0.769556, 0.236077, 0.307485 },
+ { 0.775059, 0.239667, 0.303526 },
+ { 0.780517, 0.243327, 0.299523 },
+ { 0.785929, 0.247056, 0.295477 },
+ { 0.791293, 0.250856, 0.291390 },
+ { 0.796607, 0.254728, 0.287264 },
+ { 0.801871, 0.258674, 0.283099 },
+ { 0.807082, 0.262692, 0.278898 },
+ { 0.812239, 0.266786, 0.274661 },
+ { 0.817341, 0.270954, 0.270390 },
+ { 0.822386, 0.275197, 0.266085 },
+ { 0.827372, 0.279517, 0.261750 },
+ { 0.832299, 0.283913, 0.257383 },
+ { 0.837165, 0.288385, 0.252988 },
+ { 0.841969, 0.292933, 0.248564 },
+ { 0.846709, 0.297559, 0.244113 },
+ { 0.851384, 0.302260, 0.239636 },
+ { 0.855992, 0.307038, 0.235133 },
+ { 0.860533, 0.311892, 0.230606 },
+ { 0.865006, 0.316822, 0.226055 },
+ { 0.869409, 0.321827, 0.221482 },
+ { 0.873741, 0.326906, 0.216886 },
+ { 0.878001, 0.332060, 0.212268 },
+ { 0.882188, 0.337287, 0.207628 },
+ { 0.886302, 0.342586, 0.202968 },
+ { 0.890341, 0.347957, 0.198286 },
+ { 0.894305, 0.353399, 0.193584 },
+ { 0.898192, 0.358911, 0.188860 },
+ { 0.902003, 0.364492, 0.184116 },
+ { 0.905735, 0.370140, 0.179350 },
+ { 0.909390, 0.375856, 0.174563 },
+ { 0.912966, 0.381636, 0.169755 },
+ { 0.916462, 0.387481, 0.164924 },
+ { 0.919879, 0.393389, 0.160070 },
+ { 0.923215, 0.399359, 0.155193 },
+ { 0.926470, 0.405389, 0.150292 },
+ { 0.929644, 0.411479, 0.145367 },
+ { 0.932737, 0.417627, 0.140417 },
+ { 0.935747, 0.423831, 0.135440 },
+ { 0.938675, 0.430091, 0.130438 },
+ { 0.941521, 0.436405, 0.125409 },
+ { 0.944285, 0.442772, 0.120354 },
+ { 0.946965, 0.449191, 0.115272 },
+ { 0.949562, 0.455660, 0.110164 },
+ { 0.952075, 0.462178, 0.105031 },
+ { 0.954506, 0.468744, 0.099874 },
+ { 0.956852, 0.475356, 0.094695 },
+ { 0.959114, 0.482014, 0.089499 },
+ { 0.961293, 0.488716, 0.084289 },
+ { 0.963387, 0.495462, 0.079073 },
+ { 0.965397, 0.502249, 0.073859 },
+ { 0.967322, 0.509078, 0.068659 },
+ { 0.969163, 0.515946, 0.063488 },
+ { 0.970919, 0.522853, 0.058367 },
+ { 0.972590, 0.529798, 0.053324 },
+ { 0.974176, 0.536780, 0.048392 },
+ { 0.975677, 0.543798, 0.043618 },
+ { 0.977092, 0.550850, 0.039050 },
+ { 0.978422, 0.557937, 0.034931 },
+ { 0.979666, 0.565057, 0.031409 },
+ { 0.980824, 0.572209, 0.028508 },
+ { 0.981895, 0.579392, 0.026250 },
+ { 0.982881, 0.586606, 0.024661 },
+ { 0.983779, 0.593849, 0.023770 },
+ { 0.984591, 0.601122, 0.023606 },
+ { 0.985315, 0.608422, 0.024202 },
+ { 0.985952, 0.615750, 0.025592 },
+ { 0.986502, 0.623105, 0.027814 },
+ { 0.986964, 0.630485, 0.030908 },
+ { 0.987337, 0.637890, 0.034916 },
+ { 0.987622, 0.645320, 0.039886 },
+ { 0.987819, 0.652773, 0.045581 },
+ { 0.987926, 0.660250, 0.051750 },
+ { 0.987945, 0.667748, 0.058329 },
+ { 0.987874, 0.675267, 0.065257 },
+ { 0.987714, 0.682807, 0.072489 },
+ { 0.987464, 0.690366, 0.079990 },
+ { 0.987124, 0.697944, 0.087731 },
+ { 0.986694, 0.705540, 0.095694 },
+ { 0.986175, 0.713153, 0.103863 },
+ { 0.985566, 0.720782, 0.112229 },
+ { 0.984865, 0.728427, 0.120785 },
+ { 0.984075, 0.736087, 0.129527 },
+ { 0.983196, 0.743758, 0.138453 },
+ { 0.982228, 0.751442, 0.147565 },
+ { 0.981173, 0.759135, 0.156863 },
+ { 0.980032, 0.766837, 0.166353 },
+ { 0.978806, 0.774545, 0.176037 },
+ { 0.977497, 0.782258, 0.185923 },
+ { 0.976108, 0.789974, 0.196018 },
+ { 0.974638, 0.797692, 0.206332 },
+ { 0.973088, 0.805409, 0.216877 },
+ { 0.971468, 0.813122, 0.227658 },
+ { 0.969783, 0.820825, 0.238686 },
+ { 0.968041, 0.828515, 0.249972 },
+ { 0.966243, 0.836191, 0.261534 },
+ { 0.964394, 0.843848, 0.273391 },
+ { 0.962517, 0.851476, 0.285546 },
+ { 0.960626, 0.859069, 0.298010 },
+ { 0.958720, 0.866624, 0.310820 },
+ { 0.956834, 0.874129, 0.323974 },
+ { 0.954997, 0.881569, 0.337475 },
+ { 0.953215, 0.888942, 0.351369 },
+ { 0.951546, 0.896226, 0.365627 },
+ { 0.950018, 0.903409, 0.380271 },
+ { 0.948683, 0.910473, 0.395289 },
+ { 0.947594, 0.917399, 0.410665 },
+ { 0.946809, 0.924168, 0.426373 },
+ { 0.946392, 0.930761, 0.442367 },
+ { 0.946403, 0.937159, 0.458592 },
+ { 0.946903, 0.943348, 0.474970 },
+ { 0.947937, 0.949318, 0.491426 },
+ { 0.949545, 0.955063, 0.507860 },
+ { 0.951740, 0.960587, 0.524203 },
+ { 0.954529, 0.965896, 0.540361 },
+ { 0.957896, 0.971003, 0.556275 },
+ { 0.961812, 0.975924, 0.571925 },
+ { 0.966249, 0.980678, 0.587206 },
+ { 0.971162, 0.985282, 0.602154 },
+ { 0.976511, 0.989753, 0.616760 },
+ { 0.982257, 0.994109, 0.631017 },
+ { 0.988362, 0.998364, 0.644924 }
+};
+
+static double magma_cm[256][3] = {
+ { 0.001462, 0.000466, 0.013866 },
+ { 0.002258, 0.001295, 0.018331 },
+ { 0.003279, 0.002305, 0.023708 },
+ { 0.004512, 0.003490, 0.029965 },
+ { 0.005950, 0.004843, 0.037130 },
+ { 0.007588, 0.006356, 0.044973 },
+ { 0.009426, 0.008022, 0.052844 },
+ { 0.011465, 0.009828, 0.060750 },
+ { 0.013708, 0.011771, 0.068667 },
+ { 0.016156, 0.013840, 0.076603 },
+ { 0.018815, 0.016026, 0.084584 },
+ { 0.021692, 0.018320, 0.092610 },
+ { 0.024792, 0.020715, 0.100676 },
+ { 0.028123, 0.023201, 0.108787 },
+ { 0.031696, 0.025765, 0.116965 },
+ { 0.035520, 0.028397, 0.125209 },
+ { 0.039608, 0.031090, 0.133515 },
+ { 0.043830, 0.033830, 0.141886 },
+ { 0.048062, 0.036607, 0.150327 },
+ { 0.052320, 0.039407, 0.158841 },
+ { 0.056615, 0.042160, 0.167446 },
+ { 0.060949, 0.044794, 0.176129 },
+ { 0.065330, 0.047318, 0.184892 },
+ { 0.069764, 0.049726, 0.193735 },
+ { 0.074257, 0.052017, 0.202660 },
+ { 0.078815, 0.054184, 0.211667 },
+ { 0.083446, 0.056225, 0.220755 },
+ { 0.088155, 0.058133, 0.229922 },
+ { 0.092949, 0.059904, 0.239164 },
+ { 0.097833, 0.061531, 0.248477 },
+ { 0.102815, 0.063010, 0.257854 },
+ { 0.107899, 0.064335, 0.267289 },
+ { 0.113094, 0.065492, 0.276784 },
+ { 0.118405, 0.066479, 0.286321 },
+ { 0.123833, 0.067295, 0.295879 },
+ { 0.129380, 0.067935, 0.305443 },
+ { 0.135053, 0.068391, 0.315000 },
+ { 0.140858, 0.068654, 0.324538 },
+ { 0.146785, 0.068738, 0.334011 },
+ { 0.152839, 0.068637, 0.343404 },
+ { 0.159018, 0.068354, 0.352688 },
+ { 0.165308, 0.067911, 0.361816 },
+ { 0.171713, 0.067305, 0.370771 },
+ { 0.178212, 0.066576, 0.379497 },
+ { 0.184801, 0.065732, 0.387973 },
+ { 0.191460, 0.064818, 0.396152 },
+ { 0.198177, 0.063862, 0.404009 },
+ { 0.204935, 0.062907, 0.411514 },
+ { 0.211718, 0.061992, 0.418647 },
+ { 0.218512, 0.061158, 0.425392 },
+ { 0.225302, 0.060445, 0.431742 },
+ { 0.232077, 0.059889, 0.437695 },
+ { 0.238826, 0.059517, 0.443256 },
+ { 0.245543, 0.059352, 0.448436 },
+ { 0.252220, 0.059415, 0.453248 },
+ { 0.258857, 0.059706, 0.457710 },
+ { 0.265447, 0.060237, 0.461840 },
+ { 0.271994, 0.060994, 0.465660 },
+ { 0.278493, 0.061978, 0.469190 },
+ { 0.284951, 0.063168, 0.472451 },
+ { 0.291366, 0.064553, 0.475462 },
+ { 0.297740, 0.066117, 0.478243 },
+ { 0.304081, 0.067835, 0.480812 },
+ { 0.310382, 0.069702, 0.483186 },
+ { 0.316654, 0.071690, 0.485380 },
+ { 0.322899, 0.073782, 0.487408 },
+ { 0.329114, 0.075972, 0.489287 },
+ { 0.335308, 0.078236, 0.491024 },
+ { 0.341482, 0.080564, 0.492631 },
+ { 0.347636, 0.082946, 0.494121 },
+ { 0.353773, 0.085373, 0.495501 },
+ { 0.359898, 0.087831, 0.496778 },
+ { 0.366012, 0.090314, 0.497960 },
+ { 0.372116, 0.092816, 0.499053 },
+ { 0.378211, 0.095332, 0.500067 },
+ { 0.384299, 0.097855, 0.501002 },
+ { 0.390384, 0.100379, 0.501864 },
+ { 0.396467, 0.102902, 0.502658 },
+ { 0.402548, 0.105420, 0.503386 },
+ { 0.408629, 0.107930, 0.504052 },
+ { 0.414709, 0.110431, 0.504662 },
+ { 0.420791, 0.112920, 0.505215 },
+ { 0.426877, 0.115395, 0.505714 },
+ { 0.432967, 0.117855, 0.506160 },
+ { 0.439062, 0.120298, 0.506555 },
+ { 0.445163, 0.122724, 0.506901 },
+ { 0.451271, 0.125132, 0.507198 },
+ { 0.457386, 0.127522, 0.507448 },
+ { 0.463508, 0.129893, 0.507652 },
+ { 0.469640, 0.132245, 0.507809 },
+ { 0.475780, 0.134577, 0.507921 },
+ { 0.481929, 0.136891, 0.507989 },
+ { 0.488088, 0.139186, 0.508011 },
+ { 0.494258, 0.141462, 0.507988 },
+ { 0.500438, 0.143719, 0.507920 },
+ { 0.506629, 0.145958, 0.507806 },
+ { 0.512831, 0.148179, 0.507648 },
+ { 0.519045, 0.150383, 0.507443 },
+ { 0.525270, 0.152569, 0.507192 },
+ { 0.531507, 0.154739, 0.506895 },
+ { 0.537755, 0.156894, 0.506551 },
+ { 0.544015, 0.159033, 0.506159 },
+ { 0.550287, 0.161158, 0.505719 },
+ { 0.556571, 0.163269, 0.505230 },
+ { 0.562866, 0.165368, 0.504692 },
+ { 0.569172, 0.167454, 0.504105 },
+ { 0.575490, 0.169530, 0.503466 },
+ { 0.581819, 0.171596, 0.502777 },
+ { 0.588158, 0.173652, 0.502035 },
+ { 0.594508, 0.175701, 0.501241 },
+ { 0.600868, 0.177743, 0.500394 },
+ { 0.607238, 0.179779, 0.499492 },
+ { 0.613617, 0.181811, 0.498536 },
+ { 0.620005, 0.183840, 0.497524 },
+ { 0.626401, 0.185867, 0.496456 },
+ { 0.632805, 0.187893, 0.495332 },
+ { 0.639216, 0.189921, 0.494150 },
+ { 0.645633, 0.191952, 0.492910 },
+ { 0.652056, 0.193986, 0.491611 },
+ { 0.658483, 0.196027, 0.490253 },
+ { 0.664915, 0.198075, 0.488836 },
+ { 0.671349, 0.200133, 0.487358 },
+ { 0.677786, 0.202203, 0.485819 },
+ { 0.684224, 0.204286, 0.484219 },
+ { 0.690661, 0.206384, 0.482558 },
+ { 0.697098, 0.208501, 0.480835 },
+ { 0.703532, 0.210638, 0.479049 },
+ { 0.709962, 0.212797, 0.477201 },
+ { 0.716387, 0.214982, 0.475290 },
+ { 0.722805, 0.217194, 0.473316 },
+ { 0.729216, 0.219437, 0.471279 },
+ { 0.735616, 0.221713, 0.469180 },
+ { 0.742004, 0.224025, 0.467018 },
+ { 0.748378, 0.226377, 0.464794 },
+ { 0.754737, 0.228772, 0.462509 },
+ { 0.761077, 0.231214, 0.460162 },
+ { 0.767398, 0.233705, 0.457755 },
+ { 0.773695, 0.236249, 0.455289 },
+ { 0.779968, 0.238851, 0.452765 },
+ { 0.786212, 0.241514, 0.450184 },
+ { 0.792427, 0.244242, 0.447543 },
+ { 0.798608, 0.247040, 0.444848 },
+ { 0.804752, 0.249911, 0.442102 },
+ { 0.810855, 0.252861, 0.439305 },
+ { 0.816914, 0.255895, 0.436461 },
+ { 0.822926, 0.259016, 0.433573 },
+ { 0.828886, 0.262229, 0.430644 },
+ { 0.834791, 0.265540, 0.427671 },
+ { 0.840636, 0.268953, 0.424666 },
+ { 0.846416, 0.272473, 0.421631 },
+ { 0.852126, 0.276106, 0.418573 },
+ { 0.857763, 0.279857, 0.415496 },
+ { 0.863320, 0.283729, 0.412403 },
+ { 0.868793, 0.287728, 0.409303 },
+ { 0.874176, 0.291859, 0.406205 },
+ { 0.879464, 0.296125, 0.403118 },
+ { 0.884651, 0.300530, 0.400047 },
+ { 0.889731, 0.305079, 0.397002 },
+ { 0.894700, 0.309773, 0.393995 },
+ { 0.899552, 0.314616, 0.391037 },
+ { 0.904281, 0.319610, 0.388137 },
+ { 0.908884, 0.324755, 0.385308 },
+ { 0.913354, 0.330052, 0.382563 },
+ { 0.917689, 0.335500, 0.379915 },
+ { 0.921884, 0.341098, 0.377376 },
+ { 0.925937, 0.346844, 0.374959 },
+ { 0.929845, 0.352734, 0.372677 },
+ { 0.933606, 0.358764, 0.370541 },
+ { 0.937221, 0.364929, 0.368567 },
+ { 0.940687, 0.371224, 0.366762 },
+ { 0.944006, 0.377643, 0.365136 },
+ { 0.947180, 0.384178, 0.363701 },
+ { 0.950210, 0.390820, 0.362468 },
+ { 0.953099, 0.397563, 0.361438 },
+ { 0.955849, 0.404400, 0.360619 },
+ { 0.958464, 0.411324, 0.360014 },
+ { 0.960949, 0.418323, 0.359630 },
+ { 0.963310, 0.425390, 0.359469 },
+ { 0.965549, 0.432519, 0.359529 },
+ { 0.967671, 0.439703, 0.359810 },
+ { 0.969680, 0.446936, 0.360311 },
+ { 0.971582, 0.454210, 0.361030 },
+ { 0.973381, 0.461520, 0.361965 },
+ { 0.975082, 0.468861, 0.363111 },
+ { 0.976690, 0.476226, 0.364466 },
+ { 0.978210, 0.483612, 0.366025 },
+ { 0.979645, 0.491014, 0.367783 },
+ { 0.981000, 0.498428, 0.369734 },
+ { 0.982279, 0.505851, 0.371874 },
+ { 0.983485, 0.513280, 0.374198 },
+ { 0.984622, 0.520713, 0.376698 },
+ { 0.985693, 0.528148, 0.379371 },
+ { 0.986700, 0.535582, 0.382210 },
+ { 0.987646, 0.543015, 0.385210 },
+ { 0.988533, 0.550446, 0.388365 },
+ { 0.989363, 0.557873, 0.391671 },
+ { 0.990138, 0.565296, 0.395122 },
+ { 0.990871, 0.572706, 0.398714 },
+ { 0.991558, 0.580107, 0.402441 },
+ { 0.992196, 0.587502, 0.406299 },
+ { 0.992785, 0.594891, 0.410283 },
+ { 0.993326, 0.602275, 0.414390 },
+ { 0.993834, 0.609644, 0.418613 },
+ { 0.994309, 0.616999, 0.422950 },
+ { 0.994738, 0.624350, 0.427397 },
+ { 0.995122, 0.631696, 0.431951 },
+ { 0.995480, 0.639027, 0.436607 },
+ { 0.995810, 0.646344, 0.441361 },
+ { 0.996096, 0.653659, 0.446213 },
+ { 0.996341, 0.660969, 0.451160 },
+ { 0.996580, 0.668256, 0.456192 },
+ { 0.996775, 0.675541, 0.461314 },
+ { 0.996925, 0.682828, 0.466526 },
+ { 0.997077, 0.690088, 0.471811 },
+ { 0.997186, 0.697349, 0.477182 },
+ { 0.997254, 0.704611, 0.482635 },
+ { 0.997325, 0.711848, 0.488154 },
+ { 0.997351, 0.719089, 0.493755 },
+ { 0.997351, 0.726324, 0.499428 },
+ { 0.997341, 0.733545, 0.505167 },
+ { 0.997285, 0.740772, 0.510983 },
+ { 0.997228, 0.747981, 0.516859 },
+ { 0.997138, 0.755190, 0.522806 },
+ { 0.997019, 0.762398, 0.528821 },
+ { 0.996898, 0.769591, 0.534892 },
+ { 0.996727, 0.776795, 0.541039 },
+ { 0.996571, 0.783977, 0.547233 },
+ { 0.996369, 0.791167, 0.553499 },
+ { 0.996162, 0.798348, 0.559820 },
+ { 0.995932, 0.805527, 0.566202 },
+ { 0.995680, 0.812706, 0.572645 },
+ { 0.995424, 0.819875, 0.579140 },
+ { 0.995131, 0.827052, 0.585701 },
+ { 0.994851, 0.834213, 0.592307 },
+ { 0.994524, 0.841387, 0.598983 },
+ { 0.994222, 0.848540, 0.605696 },
+ { 0.993866, 0.855711, 0.612482 },
+ { 0.993545, 0.862859, 0.619299 },
+ { 0.993170, 0.870024, 0.626189 },
+ { 0.992831, 0.877168, 0.633109 },
+ { 0.992440, 0.884330, 0.640099 },
+ { 0.992089, 0.891470, 0.647116 },
+ { 0.991688, 0.898627, 0.654202 },
+ { 0.991332, 0.905763, 0.661309 },
+ { 0.990930, 0.912915, 0.668481 },
+ { 0.990570, 0.920049, 0.675675 },
+ { 0.990175, 0.927196, 0.682926 },
+ { 0.989815, 0.934329, 0.690198 },
+ { 0.989434, 0.941470, 0.697519 },
+ { 0.989077, 0.948604, 0.704863 },
+ { 0.988717, 0.955742, 0.712242 },
+ { 0.988367, 0.962878, 0.719649 },
+ { 0.988033, 0.970012, 0.727077 },
+ { 0.987691, 0.977154, 0.734536 },
+ { 0.987387, 0.984288, 0.742002 },
+ { 0.987053, 0.991438, 0.749504 }
+};
+
+static double plasma_cm[256][3] = {
+ { 0.050383, 0.029803, 0.527975 },
+ { 0.063536, 0.028426, 0.533124 },
+ { 0.075353, 0.027206, 0.538007 },
+ { 0.086222, 0.026125, 0.542658 },
+ { 0.096379, 0.025165, 0.547103 },
+ { 0.105980, 0.024309, 0.551368 },
+ { 0.115124, 0.023556, 0.555468 },
+ { 0.123903, 0.022878, 0.559423 },
+ { 0.132381, 0.022258, 0.563250 },
+ { 0.140603, 0.021687, 0.566959 },
+ { 0.148607, 0.021154, 0.570562 },
+ { 0.156421, 0.020651, 0.574065 },
+ { 0.164070, 0.020171, 0.577478 },
+ { 0.171574, 0.019706, 0.580806 },
+ { 0.178950, 0.019252, 0.584054 },
+ { 0.186213, 0.018803, 0.587228 },
+ { 0.193374, 0.018354, 0.590330 },
+ { 0.200445, 0.017902, 0.593364 },
+ { 0.207435, 0.017442, 0.596333 },
+ { 0.214350, 0.016973, 0.599239 },
+ { 0.221197, 0.016497, 0.602083 },
+ { 0.227983, 0.016007, 0.604867 },
+ { 0.234715, 0.015502, 0.607592 },
+ { 0.241396, 0.014979, 0.610259 },
+ { 0.248032, 0.014439, 0.612868 },
+ { 0.254627, 0.013882, 0.615419 },
+ { 0.261183, 0.013308, 0.617911 },
+ { 0.267703, 0.012716, 0.620346 },
+ { 0.274191, 0.012109, 0.622722 },
+ { 0.280648, 0.011488, 0.625038 },
+ { 0.287076, 0.010855, 0.627295 },
+ { 0.293478, 0.010213, 0.629490 },
+ { 0.299855, 0.009561, 0.631624 },
+ { 0.306210, 0.008902, 0.633694 },
+ { 0.312543, 0.008239, 0.635700 },
+ { 0.318856, 0.007576, 0.637640 },
+ { 0.325150, 0.006915, 0.639512 },
+ { 0.331426, 0.006261, 0.641316 },
+ { 0.337683, 0.005618, 0.643049 },
+ { 0.343925, 0.004991, 0.644710 },
+ { 0.350150, 0.004382, 0.646298 },
+ { 0.356359, 0.003798, 0.647810 },
+ { 0.362553, 0.003243, 0.649245 },
+ { 0.368733, 0.002724, 0.650601 },
+ { 0.374897, 0.002245, 0.651876 },
+ { 0.381047, 0.001814, 0.653068 },
+ { 0.387183, 0.001434, 0.654177 },
+ { 0.393304, 0.001114, 0.655199 },
+ { 0.399411, 0.000859, 0.656133 },
+ { 0.405503, 0.000678, 0.656977 },
+ { 0.411580, 0.000577, 0.657730 },
+ { 0.417642, 0.000564, 0.658390 },
+ { 0.423689, 0.000646, 0.658956 },
+ { 0.429719, 0.000831, 0.659425 },
+ { 0.435734, 0.001127, 0.659797 },
+ { 0.441732, 0.001540, 0.660069 },
+ { 0.447714, 0.002080, 0.660240 },
+ { 0.453677, 0.002755, 0.660310 },
+ { 0.459623, 0.003574, 0.660277 },
+ { 0.465550, 0.004545, 0.660139 },
+ { 0.471457, 0.005678, 0.659897 },
+ { 0.477344, 0.006980, 0.659549 },
+ { 0.483210, 0.008460, 0.659095 },
+ { 0.489055, 0.010127, 0.658534 },
+ { 0.494877, 0.011990, 0.657865 },
+ { 0.500678, 0.014055, 0.657088 },
+ { 0.506454, 0.016333, 0.656202 },
+ { 0.512206, 0.018833, 0.655209 },
+ { 0.517933, 0.021563, 0.654109 },
+ { 0.523633, 0.024532, 0.652901 },
+ { 0.529306, 0.027747, 0.651586 },
+ { 0.534952, 0.031217, 0.650165 },
+ { 0.540570, 0.034950, 0.648640 },
+ { 0.546157, 0.038954, 0.647010 },
+ { 0.551715, 0.043136, 0.645277 },
+ { 0.557243, 0.047331, 0.643443 },
+ { 0.562738, 0.051545, 0.641509 },
+ { 0.568201, 0.055778, 0.639477 },
+ { 0.573632, 0.060028, 0.637349 },
+ { 0.579029, 0.064296, 0.635126 },
+ { 0.584391, 0.068579, 0.632812 },
+ { 0.589719, 0.072878, 0.630408 },
+ { 0.595011, 0.077190, 0.627917 },
+ { 0.600266, 0.081516, 0.625342 },
+ { 0.605485, 0.085854, 0.622686 },
+ { 0.610667, 0.090204, 0.619951 },
+ { 0.615812, 0.094564, 0.617140 },
+ { 0.620919, 0.098934, 0.614257 },
+ { 0.625987, 0.103312, 0.611305 },
+ { 0.631017, 0.107699, 0.608287 },
+ { 0.636008, 0.112092, 0.605205 },
+ { 0.640959, 0.116492, 0.602065 },
+ { 0.645872, 0.120898, 0.598867 },
+ { 0.650746, 0.125309, 0.595617 },
+ { 0.655580, 0.129725, 0.592317 },
+ { 0.660374, 0.134144, 0.588971 },
+ { 0.665129, 0.138566, 0.585582 },
+ { 0.669845, 0.142992, 0.582154 },
+ { 0.674522, 0.147419, 0.578688 },
+ { 0.679160, 0.151848, 0.575189 },
+ { 0.683758, 0.156278, 0.571660 },
+ { 0.688318, 0.160709, 0.568103 },
+ { 0.692840, 0.165141, 0.564522 },
+ { 0.697324, 0.169573, 0.560919 },
+ { 0.701769, 0.174005, 0.557296 },
+ { 0.706178, 0.178437, 0.553657 },
+ { 0.710549, 0.182868, 0.550004 },
+ { 0.714883, 0.187299, 0.546338 },
+ { 0.719181, 0.191729, 0.542663 },
+ { 0.723444, 0.196158, 0.538981 },
+ { 0.727670, 0.200586, 0.535293 },
+ { 0.731862, 0.205013, 0.531601 },
+ { 0.736019, 0.209439, 0.527908 },
+ { 0.740143, 0.213864, 0.524216 },
+ { 0.744232, 0.218288, 0.520524 },
+ { 0.748289, 0.222711, 0.516834 },
+ { 0.752312, 0.227133, 0.513149 },
+ { 0.756304, 0.231555, 0.509468 },
+ { 0.760264, 0.235976, 0.505794 },
+ { 0.764193, 0.240396, 0.502126 },
+ { 0.768090, 0.244817, 0.498465 },
+ { 0.771958, 0.249237, 0.494813 },
+ { 0.775796, 0.253658, 0.491171 },
+ { 0.779604, 0.258078, 0.487539 },
+ { 0.783383, 0.262500, 0.483918 },
+ { 0.787133, 0.266922, 0.480307 },
+ { 0.790855, 0.271345, 0.476706 },
+ { 0.794549, 0.275770, 0.473117 },
+ { 0.798216, 0.280197, 0.469538 },
+ { 0.801855, 0.284626, 0.465971 },
+ { 0.805467, 0.289057, 0.462415 },
+ { 0.809052, 0.293491, 0.458870 },
+ { 0.812612, 0.297928, 0.455338 },
+ { 0.816144, 0.302368, 0.451816 },
+ { 0.819651, 0.306812, 0.448306 },
+ { 0.823132, 0.311261, 0.444806 },
+ { 0.826588, 0.315714, 0.441316 },
+ { 0.830018, 0.320172, 0.437836 },
+ { 0.833422, 0.324635, 0.434366 },
+ { 0.836801, 0.329105, 0.430905 },
+ { 0.840155, 0.333580, 0.427455 },
+ { 0.843484, 0.338062, 0.424013 },
+ { 0.846788, 0.342551, 0.420579 },
+ { 0.850066, 0.347048, 0.417153 },
+ { 0.853319, 0.351553, 0.413734 },
+ { 0.856547, 0.356066, 0.410322 },
+ { 0.859750, 0.360588, 0.406917 },
+ { 0.862927, 0.365119, 0.403519 },
+ { 0.866078, 0.369660, 0.400126 },
+ { 0.869203, 0.374212, 0.396738 },
+ { 0.872303, 0.378774, 0.393355 },
+ { 0.875376, 0.383347, 0.389976 },
+ { 0.878423, 0.387932, 0.386600 },
+ { 0.881443, 0.392529, 0.383229 },
+ { 0.884436, 0.397139, 0.379860 },
+ { 0.887402, 0.401762, 0.376494 },
+ { 0.890340, 0.406398, 0.373130 },
+ { 0.893250, 0.411048, 0.369768 },
+ { 0.896131, 0.415712, 0.366407 },
+ { 0.898984, 0.420392, 0.363047 },
+ { 0.901807, 0.425087, 0.359688 },
+ { 0.904601, 0.429797, 0.356329 },
+ { 0.907365, 0.434524, 0.352970 },
+ { 0.910098, 0.439268, 0.349610 },
+ { 0.912800, 0.444029, 0.346251 },
+ { 0.915471, 0.448807, 0.342890 },
+ { 0.918109, 0.453603, 0.339529 },
+ { 0.920714, 0.458417, 0.336166 },
+ { 0.923287, 0.463251, 0.332801 },
+ { 0.925825, 0.468103, 0.329435 },
+ { 0.928329, 0.472975, 0.326067 },
+ { 0.930798, 0.477867, 0.322697 },
+ { 0.933232, 0.482780, 0.319325 },
+ { 0.935630, 0.487712, 0.315952 },
+ { 0.937990, 0.492667, 0.312575 },
+ { 0.940313, 0.497642, 0.309197 },
+ { 0.942598, 0.502639, 0.305816 },
+ { 0.944844, 0.507658, 0.302433 },
+ { 0.947051, 0.512699, 0.299049 },
+ { 0.949217, 0.517763, 0.295662 },
+ { 0.951344, 0.522850, 0.292275 },
+ { 0.953428, 0.527960, 0.288883 },
+ { 0.955470, 0.533093, 0.285490 },
+ { 0.957469, 0.538250, 0.282096 },
+ { 0.959424, 0.543431, 0.278701 },
+ { 0.961336, 0.548636, 0.275305 },
+ { 0.963203, 0.553865, 0.271909 },
+ { 0.965024, 0.559118, 0.268513 },
+ { 0.966798, 0.564396, 0.265118 },
+ { 0.968526, 0.569700, 0.261721 },
+ { 0.970205, 0.575028, 0.258325 },
+ { 0.971835, 0.580382, 0.254931 },
+ { 0.973416, 0.585761, 0.251540 },
+ { 0.974947, 0.591165, 0.248151 },
+ { 0.976428, 0.596595, 0.244767 },
+ { 0.977856, 0.602051, 0.241387 },
+ { 0.979233, 0.607532, 0.238013 },
+ { 0.980556, 0.613039, 0.234646 },
+ { 0.981826, 0.618572, 0.231287 },
+ { 0.983041, 0.624131, 0.227937 },
+ { 0.984199, 0.629718, 0.224595 },
+ { 0.985301, 0.635330, 0.221265 },
+ { 0.986345, 0.640969, 0.217948 },
+ { 0.987332, 0.646633, 0.214648 },
+ { 0.988260, 0.652325, 0.211364 },
+ { 0.989128, 0.658043, 0.208100 },
+ { 0.989935, 0.663787, 0.204859 },
+ { 0.990681, 0.669558, 0.201642 },
+ { 0.991365, 0.675355, 0.198453 },
+ { 0.991985, 0.681179, 0.195295 },
+ { 0.992541, 0.687030, 0.192170 },
+ { 0.993032, 0.692907, 0.189084 },
+ { 0.993456, 0.698810, 0.186041 },
+ { 0.993814, 0.704741, 0.183043 },
+ { 0.994103, 0.710698, 0.180097 },
+ { 0.994324, 0.716681, 0.177208 },
+ { 0.994474, 0.722691, 0.174381 },
+ { 0.994553, 0.728728, 0.171622 },
+ { 0.994561, 0.734791, 0.168938 },
+ { 0.994495, 0.740880, 0.166335 },
+ { 0.994355, 0.746995, 0.163821 },
+ { 0.994141, 0.753137, 0.161404 },
+ { 0.993851, 0.759304, 0.159092 },
+ { 0.993482, 0.765499, 0.156891 },
+ { 0.993033, 0.771720, 0.154808 },
+ { 0.992505, 0.777967, 0.152855 },
+ { 0.991897, 0.784239, 0.151042 },
+ { 0.991209, 0.790537, 0.149377 },
+ { 0.990439, 0.796859, 0.147870 },
+ { 0.989587, 0.803205, 0.146529 },
+ { 0.988648, 0.809579, 0.145357 },
+ { 0.987621, 0.815978, 0.144363 },
+ { 0.986509, 0.822401, 0.143557 },
+ { 0.985314, 0.828846, 0.142945 },
+ { 0.984031, 0.835315, 0.142528 },
+ { 0.982653, 0.841812, 0.142303 },
+ { 0.981190, 0.848329, 0.142279 },
+ { 0.979644, 0.854866, 0.142453 },
+ { 0.977995, 0.861432, 0.142808 },
+ { 0.976265, 0.868016, 0.143351 },
+ { 0.974443, 0.874622, 0.144061 },
+ { 0.972530, 0.881250, 0.144923 },
+ { 0.970533, 0.887896, 0.145919 },
+ { 0.968443, 0.894564, 0.147014 },
+ { 0.966271, 0.901249, 0.148180 },
+ { 0.964021, 0.907950, 0.149370 },
+ { 0.961681, 0.914672, 0.150520 },
+ { 0.959276, 0.921407, 0.151566 },
+ { 0.956808, 0.928152, 0.152409 },
+ { 0.954287, 0.934908, 0.152921 },
+ { 0.951726, 0.941671, 0.152925 },
+ { 0.949151, 0.948435, 0.152178 },
+ { 0.946602, 0.955190, 0.150328 },
+ { 0.944152, 0.961916, 0.146861 },
+ { 0.941896, 0.968590, 0.140956 },
+ { 0.940015, 0.975158, 0.131326 }
+};
+
+static double viridis_cm[256][3] = {
+ { 0.267004, 0.004874, 0.329415 },
+ { 0.268510, 0.009605, 0.335427 },
+ { 0.269944, 0.014625, 0.341379 },
+ { 0.271305, 0.019942, 0.347269 },
+ { 0.272594, 0.025563, 0.353093 },
+ { 0.273809, 0.031497, 0.358853 },
+ { 0.274952, 0.037752, 0.364543 },
+ { 0.276022, 0.044167, 0.370164 },
+ { 0.277018, 0.050344, 0.375715 },
+ { 0.277941, 0.056324, 0.381191 },
+ { 0.278791, 0.062145, 0.386592 },
+ { 0.279566, 0.067836, 0.391917 },
+ { 0.280267, 0.073417, 0.397163 },
+ { 0.280894, 0.078907, 0.402329 },
+ { 0.281446, 0.084320, 0.407414 },
+ { 0.281924, 0.089666, 0.412415 },
+ { 0.282327, 0.094955, 0.417331 },
+ { 0.282656, 0.100196, 0.422160 },
+ { 0.282910, 0.105393, 0.426902 },
+ { 0.283091, 0.110553, 0.431554 },
+ { 0.283197, 0.115680, 0.436115 },
+ { 0.283229, 0.120777, 0.440584 },
+ { 0.283187, 0.125848, 0.444960 },
+ { 0.283072, 0.130895, 0.449241 },
+ { 0.282884, 0.135920, 0.453427 },
+ { 0.282623, 0.140926, 0.457517 },
+ { 0.282290, 0.145912, 0.461510 },
+ { 0.281887, 0.150881, 0.465405 },
+ { 0.281412, 0.155834, 0.469201 },
+ { 0.280868, 0.160771, 0.472899 },
+ { 0.280255, 0.165693, 0.476498 },
+ { 0.279574, 0.170599, 0.479997 },
+ { 0.278826, 0.175490, 0.483397 },
+ { 0.278012, 0.180367, 0.486697 },
+ { 0.277134, 0.185228, 0.489898 },
+ { 0.276194, 0.190074, 0.493001 },
+ { 0.275191, 0.194905, 0.496005 },
+ { 0.274128, 0.199721, 0.498911 },
+ { 0.273006, 0.204520, 0.501721 },
+ { 0.271828, 0.209303, 0.504434 },
+ { 0.270595, 0.214069, 0.507052 },
+ { 0.269308, 0.218818, 0.509577 },
+ { 0.267968, 0.223549, 0.512008 },
+ { 0.266580, 0.228262, 0.514349 },
+ { 0.265145, 0.232956, 0.516599 },
+ { 0.263663, 0.237631, 0.518762 },
+ { 0.262138, 0.242286, 0.520837 },
+ { 0.260571, 0.246922, 0.522828 },
+ { 0.258965, 0.251537, 0.524736 },
+ { 0.257322, 0.256130, 0.526563 },
+ { 0.255645, 0.260703, 0.528312 },
+ { 0.253935, 0.265254, 0.529983 },
+ { 0.252194, 0.269783, 0.531579 },
+ { 0.250425, 0.274290, 0.533103 },
+ { 0.248629, 0.278775, 0.534556 },
+ { 0.246811, 0.283237, 0.535941 },
+ { 0.244972, 0.287675, 0.537260 },
+ { 0.243113, 0.292092, 0.538516 },
+ { 0.241237, 0.296485, 0.539709 },
+ { 0.239346, 0.300855, 0.540844 },
+ { 0.237441, 0.305202, 0.541921 },
+ { 0.235526, 0.309527, 0.542944 },
+ { 0.233603, 0.313828, 0.543914 },
+ { 0.231674, 0.318106, 0.544834 },
+ { 0.229739, 0.322361, 0.545706 },
+ { 0.227802, 0.326594, 0.546532 },
+ { 0.225863, 0.330805, 0.547314 },
+ { 0.223925, 0.334994, 0.548053 },
+ { 0.221989, 0.339161, 0.548752 },
+ { 0.220057, 0.343307, 0.549413 },
+ { 0.218130, 0.347432, 0.550038 },
+ { 0.216210, 0.351535, 0.550627 },
+ { 0.214298, 0.355619, 0.551184 },
+ { 0.212395, 0.359683, 0.551710 },
+ { 0.210503, 0.363727, 0.552206 },
+ { 0.208623, 0.367752, 0.552675 },
+ { 0.206756, 0.371758, 0.553117 },
+ { 0.204903, 0.375746, 0.553533 },
+ { 0.203063, 0.379716, 0.553925 },
+ { 0.201239, 0.383670, 0.554294 },
+ { 0.199430, 0.387607, 0.554642 },
+ { 0.197636, 0.391528, 0.554969 },
+ { 0.195860, 0.395433, 0.555276 },
+ { 0.194100, 0.399323, 0.555565 },
+ { 0.192357, 0.403199, 0.555836 },
+ { 0.190631, 0.407061, 0.556089 },
+ { 0.188923, 0.410910, 0.556326 },
+ { 0.187231, 0.414746, 0.556547 },
+ { 0.185556, 0.418570, 0.556753 },
+ { 0.183898, 0.422383, 0.556944 },
+ { 0.182256, 0.426184, 0.557120 },
+ { 0.180629, 0.429975, 0.557282 },
+ { 0.179019, 0.433756, 0.557430 },
+ { 0.177423, 0.437527, 0.557565 },
+ { 0.175841, 0.441290, 0.557685 },
+ { 0.174274, 0.445044, 0.557792 },
+ { 0.172719, 0.448791, 0.557885 },
+ { 0.171176, 0.452530, 0.557965 },
+ { 0.169646, 0.456262, 0.558030 },
+ { 0.168126, 0.459988, 0.558082 },
+ { 0.166617, 0.463708, 0.558119 },
+ { 0.165117, 0.467423, 0.558141 },
+ { 0.163625, 0.471133, 0.558148 },
+ { 0.162142, 0.474838, 0.558140 },
+ { 0.160665, 0.478540, 0.558115 },
+ { 0.159194, 0.482237, 0.558073 },
+ { 0.157729, 0.485932, 0.558013 },
+ { 0.156270, 0.489624, 0.557936 },
+ { 0.154815, 0.493313, 0.557840 },
+ { 0.153364, 0.497000, 0.557724 },
+ { 0.151918, 0.500685, 0.557587 },
+ { 0.150476, 0.504369, 0.557430 },
+ { 0.149039, 0.508051, 0.557250 },
+ { 0.147607, 0.511733, 0.557049 },
+ { 0.146180, 0.515413, 0.556823 },
+ { 0.144759, 0.519093, 0.556572 },
+ { 0.143343, 0.522773, 0.556295 },
+ { 0.141935, 0.526453, 0.555991 },
+ { 0.140536, 0.530132, 0.555659 },
+ { 0.139147, 0.533812, 0.555298 },
+ { 0.137770, 0.537492, 0.554906 },
+ { 0.136408, 0.541173, 0.554483 },
+ { 0.135066, 0.544853, 0.554029 },
+ { 0.133743, 0.548535, 0.553541 },
+ { 0.132444, 0.552216, 0.553018 },
+ { 0.131172, 0.555899, 0.552459 },
+ { 0.129933, 0.559582, 0.551864 },
+ { 0.128729, 0.563265, 0.551229 },
+ { 0.127568, 0.566949, 0.550556 },
+ { 0.126453, 0.570633, 0.549841 },
+ { 0.125394, 0.574318, 0.549086 },
+ { 0.124395, 0.578002, 0.548287 },
+ { 0.123463, 0.581687, 0.547445 },
+ { 0.122606, 0.585371, 0.546557 },
+ { 0.121831, 0.589055, 0.545623 },
+ { 0.121148, 0.592739, 0.544641 },
+ { 0.120565, 0.596422, 0.543611 },
+ { 0.120092, 0.600104, 0.542530 },
+ { 0.119738, 0.603785, 0.541400 },
+ { 0.119512, 0.607464, 0.540218 },
+ { 0.119423, 0.611141, 0.538982 },
+ { 0.119483, 0.614817, 0.537692 },
+ { 0.119699, 0.618490, 0.536347 },
+ { 0.120081, 0.622161, 0.534946 },
+ { 0.120638, 0.625828, 0.533488 },
+ { 0.121380, 0.629492, 0.531973 },
+ { 0.122312, 0.633153, 0.530398 },
+ { 0.123444, 0.636809, 0.528763 },
+ { 0.124780, 0.640461, 0.527068 },
+ { 0.126326, 0.644107, 0.525311 },
+ { 0.128087, 0.647749, 0.523491 },
+ { 0.130067, 0.651384, 0.521608 },
+ { 0.132268, 0.655014, 0.519661 },
+ { 0.134692, 0.658636, 0.517649 },
+ { 0.137339, 0.662252, 0.515571 },
+ { 0.140210, 0.665859, 0.513427 },
+ { 0.143303, 0.669459, 0.511215 },
+ { 0.146616, 0.673050, 0.508936 },
+ { 0.150148, 0.676631, 0.506589 },
+ { 0.153894, 0.680203, 0.504172 },
+ { 0.157851, 0.683765, 0.501686 },
+ { 0.162016, 0.687316, 0.499129 },
+ { 0.166383, 0.690856, 0.496502 },
+ { 0.170948, 0.694384, 0.493803 },
+ { 0.175707, 0.697900, 0.491033 },
+ { 0.180653, 0.701402, 0.488189 },
+ { 0.185783, 0.704891, 0.485273 },
+ { 0.191090, 0.708366, 0.482284 },
+ { 0.196571, 0.711827, 0.479221 },
+ { 0.202219, 0.715272, 0.476084 },
+ { 0.208030, 0.718701, 0.472873 },
+ { 0.214000, 0.722114, 0.469588 },
+ { 0.220124, 0.725509, 0.466226 },
+ { 0.226397, 0.728888, 0.462789 },
+ { 0.232815, 0.732247, 0.459277 },
+ { 0.239374, 0.735588, 0.455688 },
+ { 0.246070, 0.738910, 0.452024 },
+ { 0.252899, 0.742211, 0.448284 },
+ { 0.259857, 0.745492, 0.444467 },
+ { 0.266941, 0.748751, 0.440573 },
+ { 0.274149, 0.751988, 0.436601 },
+ { 0.281477, 0.755203, 0.432552 },
+ { 0.288921, 0.758394, 0.428426 },
+ { 0.296479, 0.761561, 0.424223 },
+ { 0.304148, 0.764704, 0.419943 },
+ { 0.311925, 0.767822, 0.415586 },
+ { 0.319809, 0.770914, 0.411152 },
+ { 0.327796, 0.773980, 0.406640 },
+ { 0.335885, 0.777018, 0.402049 },
+ { 0.344074, 0.780029, 0.397381 },
+ { 0.352360, 0.783011, 0.392636 },
+ { 0.360741, 0.785964, 0.387814 },
+ { 0.369214, 0.788888, 0.382914 },
+ { 0.377779, 0.791781, 0.377939 },
+ { 0.386433, 0.794644, 0.372886 },
+ { 0.395174, 0.797475, 0.367757 },
+ { 0.404001, 0.800275, 0.362552 },
+ { 0.412913, 0.803041, 0.357269 },
+ { 0.421908, 0.805774, 0.351910 },
+ { 0.430983, 0.808473, 0.346476 },
+ { 0.440137, 0.811138, 0.340967 },
+ { 0.449368, 0.813768, 0.335384 },
+ { 0.458674, 0.816363, 0.329727 },
+ { 0.468053, 0.818921, 0.323998 },
+ { 0.477504, 0.821444, 0.318195 },
+ { 0.487026, 0.823929, 0.312321 },
+ { 0.496615, 0.826376, 0.306377 },
+ { 0.506271, 0.828786, 0.300362 },
+ { 0.515992, 0.831158, 0.294279 },
+ { 0.525776, 0.833491, 0.288127 },
+ { 0.535621, 0.835785, 0.281908 },
+ { 0.545524, 0.838039, 0.275626 },
+ { 0.555484, 0.840254, 0.269281 },
+ { 0.565498, 0.842430, 0.262877 },
+ { 0.575563, 0.844566, 0.256415 },
+ { 0.585678, 0.846661, 0.249897 },
+ { 0.595839, 0.848717, 0.243329 },
+ { 0.606045, 0.850733, 0.236712 },
+ { 0.616293, 0.852709, 0.230052 },
+ { 0.626579, 0.854645, 0.223353 },
+ { 0.636902, 0.856542, 0.216620 },
+ { 0.647257, 0.858400, 0.209861 },
+ { 0.657642, 0.860219, 0.203082 },
+ { 0.668054, 0.861999, 0.196293 },
+ { 0.678489, 0.863742, 0.189503 },
+ { 0.688944, 0.865448, 0.182725 },
+ { 0.699415, 0.867117, 0.175971 },
+ { 0.709898, 0.868751, 0.169257 },
+ { 0.720391, 0.870350, 0.162603 },
+ { 0.730889, 0.871916, 0.156029 },
+ { 0.741388, 0.873449, 0.149561 },
+ { 0.751884, 0.874951, 0.143228 },
+ { 0.762373, 0.876424, 0.137064 },
+ { 0.772852, 0.877868, 0.131109 },
+ { 0.783315, 0.879285, 0.125405 },
+ { 0.793760, 0.880678, 0.120005 },
+ { 0.804182, 0.882046, 0.114965 },
+ { 0.814576, 0.883393, 0.110347 },
+ { 0.824940, 0.884720, 0.106217 },
+ { 0.835270, 0.886029, 0.102646 },
+ { 0.845561, 0.887322, 0.099702 },
+ { 0.855810, 0.888601, 0.097452 },
+ { 0.866013, 0.889868, 0.095953 },
+ { 0.876168, 0.891125, 0.095250 },
+ { 0.886271, 0.892374, 0.095374 },
+ { 0.896320, 0.893616, 0.096335 },
+ { 0.906311, 0.894855, 0.098125 },
+ { 0.916242, 0.896091, 0.100717 },
+ { 0.926106, 0.897330, 0.104071 },
+ { 0.935904, 0.898570, 0.108131 },
+ { 0.945636, 0.899815, 0.112838 },
+ { 0.955300, 0.901065, 0.118128 },
+ { 0.964894, 0.902323, 0.123941 },
+ { 0.974417, 0.903590, 0.130215 },
+ { 0.983868, 0.904867, 0.136897 },
+ { 0.993248, 0.906157, 0.143936 }
+};
+
+static double parula_cm[256][3] = {
+ { 0.2081, 0.1663, 0.5292 },
+ { 0.2091, 0.1721, 0.5411 },
+ { 0.2101, 0.1779, 0.553 },
+ { 0.2109, 0.1837, 0.565 },
+ { 0.2116, 0.1895, 0.5771 },
+ { 0.2121, 0.1954, 0.5892 },
+ { 0.2124, 0.2013, 0.6013 },
+ { 0.2125, 0.2072, 0.6135 },
+ { 0.2123, 0.2132, 0.6258 },
+ { 0.2118, 0.2192, 0.6381 },
+ { 0.2111, 0.2253, 0.6505 },
+ { 0.2099, 0.2315, 0.6629 },
+ { 0.2084, 0.2377, 0.6753 },
+ { 0.2063, 0.244, 0.6878 },
+ { 0.2038, 0.2503, 0.7003 },
+ { 0.2006, 0.2568, 0.7129 },
+ { 0.1968, 0.2632, 0.7255 },
+ { 0.1921, 0.2698, 0.7381 },
+ { 0.1867, 0.2764, 0.7507 },
+ { 0.1802, 0.2832, 0.7634 },
+ { 0.1728, 0.2902, 0.7762 },
+ { 0.1641, 0.2975, 0.789 },
+ { 0.1541, 0.3052, 0.8017 },
+ { 0.1427, 0.3132, 0.8145 },
+ { 0.1295, 0.3217, 0.8269 },
+ { 0.1147, 0.3306, 0.8387 },
+ { 0.0986, 0.3397, 0.8495 },
+ { 0.0816, 0.3486, 0.8588 },
+ { 0.0646, 0.3572, 0.8664 },
+ { 0.0482, 0.3651, 0.8722 },
+ { 0.0329, 0.3724, 0.8765 },
+ { 0.0213, 0.3792, 0.8796 },
+ { 0.0136, 0.3853, 0.8815 },
+ { 0.0086, 0.3911, 0.8827 },
+ { 0.006, 0.3965, 0.8833 },
+ { 0.0051, 0.4017, 0.8834 },
+ { 0.0054, 0.4066, 0.8831 },
+ { 0.0067, 0.4113, 0.8825 },
+ { 0.0089, 0.4159, 0.8816 },
+ { 0.0116, 0.4203, 0.8805 },
+ { 0.0148, 0.4246, 0.8793 },
+ { 0.0184, 0.4288, 0.8779 },
+ { 0.0223, 0.4329, 0.8763 },
+ { 0.0264, 0.437, 0.8747 },
+ { 0.0306, 0.441, 0.8729 },
+ { 0.0349, 0.4449, 0.8711 },
+ { 0.0394, 0.4488, 0.8692 },
+ { 0.0437, 0.4526, 0.8672 },
+ { 0.0477, 0.4564, 0.8652 },
+ { 0.0514, 0.4602, 0.8632 },
+ { 0.0549, 0.464, 0.8611 },
+ { 0.0582, 0.4677, 0.8589 },
+ { 0.0612, 0.4714, 0.8568 },
+ { 0.064, 0.4751, 0.8546 },
+ { 0.0666, 0.4788, 0.8525 },
+ { 0.0689, 0.4825, 0.8503 },
+ { 0.071, 0.4862, 0.8481 },
+ { 0.0729, 0.4899, 0.846 },
+ { 0.0746, 0.4937, 0.8439 },
+ { 0.0761, 0.4974, 0.8418 },
+ { 0.0773, 0.5012, 0.8398 },
+ { 0.0782, 0.5051, 0.8378 },
+ { 0.0789, 0.5089, 0.8359 },
+ { 0.0794, 0.5129, 0.8341 },
+ { 0.0795, 0.5169, 0.8324 },
+ { 0.0793, 0.521, 0.8308 },
+ { 0.0788, 0.5251, 0.8293 },
+ { 0.0778, 0.5295, 0.828 },
+ { 0.0764, 0.5339, 0.827 },
+ { 0.0746, 0.5384, 0.8261 },
+ { 0.0724, 0.5431, 0.8253 },
+ { 0.0698, 0.5479, 0.8247 },
+ { 0.0668, 0.5527, 0.8243 },
+ { 0.0636, 0.5577, 0.8239 },
+ { 0.06, 0.5627, 0.8237 },
+ { 0.0562, 0.5677, 0.8234 },
+ { 0.0523, 0.5727, 0.8231 },
+ { 0.0484, 0.5777, 0.8228 },
+ { 0.0445, 0.5826, 0.8223 },
+ { 0.0408, 0.5874, 0.8217 },
+ { 0.0372, 0.5922, 0.8209 },
+ { 0.0342, 0.5968, 0.8198 },
+ { 0.0317, 0.6012, 0.8186 },
+ { 0.0296, 0.6055, 0.8171 },
+ { 0.0279, 0.6097, 0.8154 },
+ { 0.0265, 0.6137, 0.8135 },
+ { 0.0255, 0.6176, 0.8114 },
+ { 0.0248, 0.6214, 0.8091 },
+ { 0.0243, 0.625, 0.8066 },
+ { 0.0239, 0.6285, 0.8039 },
+ { 0.0237, 0.6319, 0.801 },
+ { 0.0235, 0.6352, 0.798 },
+ { 0.0233, 0.6384, 0.7948 },
+ { 0.0231, 0.6415, 0.7916 },
+ { 0.023, 0.6445, 0.7881 },
+ { 0.0229, 0.6474, 0.7846 },
+ { 0.0227, 0.6503, 0.781, },
+ { 0.0227, 0.6531, 0.7773 },
+ { 0.0232, 0.6558, 0.7735 },
+ { 0.0238, 0.6585, 0.7696 },
+ { 0.0246, 0.6611, 0.7656 },
+ { 0.0263, 0.6637, 0.7615 },
+ { 0.0282, 0.6663, 0.7574 },
+ { 0.0306, 0.6688, 0.7532 },
+ { 0.0338, 0.6712, 0.749 },
+ { 0.0373, 0.6737, 0.7446 },
+ { 0.0418, 0.6761, 0.7402 },
+ { 0.0467, 0.6784, 0.7358 },
+ { 0.0516, 0.6808, 0.7313 },
+ { 0.0574, 0.6831, 0.7267 },
+ { 0.0629, 0.6854, 0.7221 },
+ { 0.0692, 0.6877, 0.7173 },
+ { 0.0755, 0.6899, 0.7126 },
+ { 0.082, 0.6921, 0.7078 },
+ { 0.0889, 0.6943, 0.7029 },
+ { 0.0956, 0.6965, 0.6979 },
+ { 0.1031, 0.6986, 0.6929 },
+ { 0.1104, 0.7007, 0.6878 },
+ { 0.118, 0.7028, 0.6827 },
+ { 0.1258, 0.7049, 0.6775 },
+ { 0.1335, 0.7069, 0.6723 },
+ { 0.1418, 0.7089, 0.6669 },
+ { 0.1499, 0.7109, 0.6616 },
+ { 0.1585, 0.7129, 0.6561 },
+ { 0.1671, 0.7148, 0.6507 },
+ { 0.1758, 0.7168, 0.6451 },
+ { 0.1849, 0.7186, 0.6395 },
+ { 0.1938, 0.7205, 0.6338 },
+ { 0.2033, 0.7223, 0.6281 },
+ { 0.2128, 0.7241, 0.6223 },
+ { 0.2224, 0.7259, 0.6165 },
+ { 0.2324, 0.7275, 0.6107 },
+ { 0.2423, 0.7292, 0.6048 },
+ { 0.2527, 0.7308, 0.5988 },
+ { 0.2631, 0.7324, 0.5929 },
+ { 0.2735, 0.7339, 0.5869 },
+ { 0.2845, 0.7354, 0.5809 },
+ { 0.2953, 0.7368, 0.5749 },
+ { 0.3064, 0.7381, 0.5689 },
+ { 0.3177, 0.7394, 0.563 },
+ { 0.3289, 0.7406, 0.557 },
+ { 0.3405, 0.7417, 0.5512 },
+ { 0.352, 0.7428, 0.5453 },
+ { 0.3635, 0.7438, 0.5396 },
+ { 0.3753, 0.7446, 0.5339 },
+ { 0.3869, 0.7454, 0.5283 },
+ { 0.3986, 0.7461, 0.5229 },
+ { 0.4103, 0.7467, 0.5175 },
+ { 0.4218, 0.7473, 0.5123 },
+ { 0.4334, 0.7477, 0.5072 },
+ { 0.4447, 0.7482, 0.5021 },
+ { 0.4561, 0.7485, 0.4972 },
+ { 0.4672, 0.7487, 0.4924 },
+ { 0.4783, 0.7489, 0.4877 },
+ { 0.4892, 0.7491, 0.4831 },
+ { 0.5, 0.7491, 0.4786 },
+ { 0.5106, 0.7492, 0.4741 },
+ { 0.5212, 0.7492, 0.4698 },
+ { 0.5315, 0.7491, 0.4655 },
+ { 0.5418, 0.749, 0.4613 },
+ { 0.5519, 0.7489, 0.4571 },
+ { 0.5619, 0.7487, 0.4531 },
+ { 0.5718, 0.7485, 0.449 },
+ { 0.5816, 0.7482, 0.4451 },
+ { 0.5913, 0.7479, 0.4412 },
+ { 0.6009, 0.7476, 0.4374 },
+ { 0.6103, 0.7473, 0.4335 },
+ { 0.6197, 0.7469, 0.4298 },
+ { 0.629, 0.7465, 0.4261 },
+ { 0.6382, 0.746, 0.4224 },
+ { 0.6473, 0.7456, 0.4188 },
+ { 0.6564, 0.7451, 0.4152 },
+ { 0.6653, 0.7446, 0.4116 },
+ { 0.6742, 0.7441, 0.4081 },
+ { 0.683, 0.7435, 0.4046 },
+ { 0.6918, 0.743, 0.4011 },
+ { 0.7004, 0.7424, 0.3976 },
+ { 0.7091, 0.7418, 0.3942 },
+ { 0.7176, 0.7412, 0.3908 },
+ { 0.7261, 0.7405, 0.3874 },
+ { 0.7346, 0.7399, 0.384 },
+ { 0.743, 0.7392, 0.3806 },
+ { 0.7513, 0.7385, 0.3773 },
+ { 0.7596, 0.7378, 0.3739 },
+ { 0.7679, 0.7372, 0.3706 },
+ { 0.7761, 0.7364, 0.3673 },
+ { 0.7843, 0.7357, 0.3639 },
+ { 0.7924, 0.735, 0.3606 },
+ { 0.8005, 0.7343, 0.3573 },
+ { 0.8085, 0.7336, 0.3539 },
+ { 0.8166, 0.7329, 0.3506 },
+ { 0.8246, 0.7322, 0.3472 },
+ { 0.8325, 0.7315, 0.3438 },
+ { 0.8405, 0.7308, 0.3404 },
+ { 0.8484, 0.7301, 0.337 },
+ { 0.8563, 0.7294, 0.3336 },
+ { 0.8642, 0.7288, 0.33 },
+ { 0.872, 0.7282, 0.3265 },
+ { 0.8798, 0.7276, 0.3229 },
+ { 0.8877, 0.7271, 0.3193 },
+ { 0.8954, 0.7266, 0.3156 },
+ { 0.9032, 0.7262, 0.3117 },
+ { 0.911, 0.7259, 0.3078 },
+ { 0.9187, 0.7256, 0.3038 },
+ { 0.9264, 0.7256, 0.2996 },
+ { 0.9341, 0.7256, 0.2953 },
+ { 0.9417, 0.7259, 0.2907 },
+ { 0.9493, 0.7264, 0.2859 },
+ { 0.9567, 0.7273, 0.2808 },
+ { 0.9639, 0.7285, 0.2754 },
+ { 0.9708, 0.7303, 0.2696 },
+ { 0.9773, 0.7326, 0.2634 },
+ { 0.9831, 0.7355, 0.257 },
+ { 0.9882, 0.739, 0.2504 },
+ { 0.9922, 0.7431, 0.2437 },
+ { 0.9952, 0.7476, 0.2373 },
+ { 0.9973, 0.7524, 0.231 },
+ { 0.9986, 0.7573, 0.2251 },
+ { 0.9991, 0.7624, 0.2195 },
+ { 0.999, 0.7675, 0.2141 },
+ { 0.9985, 0.7726, 0.209 },
+ { 0.9976, 0.7778, 0.2042 },
+ { 0.9964, 0.7829, 0.1995 },
+ { 0.995, 0.788, 0.1949 },
+ { 0.9933, 0.7931, 0.1905 },
+ { 0.9914, 0.7981, 0.1863 },
+ { 0.9894, 0.8032, 0.1821 },
+ { 0.9873, 0.8083, 0.178 },
+ { 0.9851, 0.8133, 0.174 },
+ { 0.9828, 0.8184, 0.17 },
+ { 0.9805, 0.8235, 0.1661 },
+ { 0.9782, 0.8286, 0.1622 },
+ { 0.9759, 0.8337, 0.1583 },
+ { 0.9736, 0.8389, 0.1544 },
+ { 0.9713, 0.8441, 0.1505 },
+ { 0.9692, 0.8494, 0.1465 },
+ { 0.9672, 0.8548, 0.1425 },
+ { 0.9654, 0.8603, 0.1385 },
+ { 0.9638, 0.8659, 0.1343 },
+ { 0.9623, 0.8716, 0.1301 },
+ { 0.9611, 0.8774, 0.1258 },
+ { 0.96, 0.8834, 0.1215 },
+ { 0.9593, 0.8895, 0.1171 },
+ { 0.9588, 0.8958, 0.1126 },
+ { 0.9586, 0.9022, 0.1082 },
+ { 0.9587, 0.9088, 0.1036 },
+ { 0.9591, 0.9155, 0.099 },
+ { 0.9599, 0.9225, 0.0944 },
+ { 0.961, 0.9296, 0.0897 },
+ { 0.9624, 0.9368, 0.085 },
+ { 0.9641, 0.9443, 0.0802 },
+ { 0.9662, 0.9518, 0.0753 },
+ { 0.9685, 0.9595, 0.0703 },
+ { 0.971, 0.9673, 0.0651 },
+ { 0.9736, 0.9752, 0.0597 },
+ { 0.9763, 0.9831, 0.0538 }
+};
+}
+
+template <typename T>
+IGL_INLINE void igl::colormap(const ColorMapType cm, const T x, T * rgb)
+{
+ return colormap(cm,x,rgb[0],rgb[1],rgb[2]);
+}
+
+template <typename T>
+IGL_INLINE void igl::colormap(
+ const ColorMapType cm, const T x_in, T & r, T & g, T & b)
+{
+ switch (cm)
+ {
+ case COLOR_MAP_TYPE_INFERNO:
+ colormap(inferno_cm, x_in, r, g, b);
+ break;
+ case COLOR_MAP_TYPE_JET:
+ jet(x_in, r, g, b);
+ break;
+ case COLOR_MAP_TYPE_MAGMA:
+ colormap(magma_cm, x_in, r, g, b);
+ break;
+ case COLOR_MAP_TYPE_PARULA:
+ colormap(parula_cm, x_in, r, g, b);
+ break;
+ case COLOR_MAP_TYPE_PLASMA:
+ colormap(plasma_cm, x_in, r, g, b);
+ break;
+ case COLOR_MAP_TYPE_VIRIDIS:
+ colormap(viridis_cm, x_in, r, g, b);
+ break;
+ default:
+ throw std::invalid_argument("igl::colormap(): Selected colormap is unsupported!");
+ break;
+ }
+}
+
+template <typename T>
+IGL_INLINE void igl::colormap(
+ const double palette[256][3], const T x_in, T & r, T & g, T & b)
+{
+ static const unsigned int pal = 256;
+ const T zero = 0.0;
+ const T one = 1.0;
+ T x_in_clamped = static_cast<T>(std::max(zero, std::min(one, x_in)));
+
+ // simple rgb lerp from palette
+ unsigned int least = std::floor(x_in_clamped * static_cast<T>(pal - 1));
+ unsigned int most = std::ceil(x_in_clamped * static_cast<T>(pal - 1));
+
+ T _r[2] = { static_cast<T>(palette[least][0]), static_cast<T>(palette[most][0]) };
+ T _g[2] = { static_cast<T>(palette[least][1]), static_cast<T>(palette[most][1]) };
+ T _b[2] = { static_cast<T>(palette[least][2]), static_cast<T>(palette[most][2]) };
+
+ T t = std::max(zero, std::min(one, static_cast<T>(fmod(x_in_clamped * static_cast<T>(pal), one))));
+
+ r = std::max(zero, std::min(one, (one - t) * _r[0] + t * _r[1]));
+ g = std::max(zero, std::min(one, (one - t) * _g[0] + t * _g[1]));
+ b = std::max(zero, std::min(one, (one - t) * _b[0] + t * _b[1]));
+}
+
+template <typename DerivedZ, typename DerivedC>
+IGL_INLINE void igl::colormap(
+ const ColorMapType cm,
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const bool normalize,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ const double min_z = normalize ? Z.minCoeff() : 0;
+ const double max_z = normalize ? Z.maxCoeff() : 1;
+ return colormap(cm, Z, min_z, max_z, C);
+}
+
+template <typename DerivedZ, typename DerivedC>
+IGL_INLINE void igl::colormap(
+ const ColorMapType cm,
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const double min_z,
+ const double max_z,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ C.resize(Z.rows(),3);
+ double denom = (max_z - min_z);
+ denom = (denom == 0) ? 1 : denom;
+ for(int r = 0; r < Z.rows(); ++r) {
+ colormap(
+ cm,
+ (typename DerivedC::Scalar)((-min_z + Z(r,0)) / denom),
+ C(r,0),
+ C(r,1),
+ C(r,2));
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::colormap<float>(igl::ColorMapType, float, float*);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Array<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Array<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<double>(igl::ColorMapType, double, double&, double&, double&);
+// generated by autoexplicit.sh
+template void igl::colormap<double>(igl::ColorMapType, double, double*);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::colormap<Eigen::Array<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Array<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+
+template void igl::colormap<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(igl::ColorMapType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/colormap.h b/xs/src/igl/colormap.h
new file mode 100644
index 000000000..1d93d73b1
--- /dev/null
+++ b/xs/src/igl/colormap.h
@@ -0,0 +1,76 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Joe Graus <jgraus@gmu.edu>, Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COLORMAP_H
+#define IGL_COLORMAP_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl {
+
+ enum ColorMapType
+ {
+ COLOR_MAP_TYPE_INFERNO = 0,
+ COLOR_MAP_TYPE_JET = 1,
+ COLOR_MAP_TYPE_MAGMA = 2,
+ COLOR_MAP_TYPE_PARULA = 3,
+ COLOR_MAP_TYPE_PLASMA = 4,
+ COLOR_MAP_TYPE_VIRIDIS = 5,
+ NUM_COLOR_MAP_TYPES = 6
+ };
+ // 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
+ 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
+ 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
+ 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
+ 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"
+ template <typename DerivedZ, typename DerivedC>
+ IGL_INLINE void colormap(
+ const ColorMapType cm,
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const double min_Z,
+ const double max_Z,
+ Eigen::PlainObjectBase<DerivedC> & C);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "colormap.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/column_to_quats.cpp b/xs/src/igl/column_to_quats.cpp
new file mode 100644
index 000000000..f87adab06
--- /dev/null
+++ b/xs/src/igl/column_to_quats.cpp
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "column_to_quats.h"
+IGL_INLINE bool igl::column_to_quats(
+ const Eigen::VectorXd & Q,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ)
+{
+ using namespace Eigen;
+ if(Q.size() % 4 != 0)
+ {
+ return false;
+ }
+ const int nQ = Q.size()/4;
+ vQ.resize(nQ);
+ for(int q=0;q<nQ;q++)
+ {
+ // Constructor uses wxyz
+ vQ[q] = Quaterniond( Q(q*4+3), Q(q*4+0), Q(q*4+1), Q(q*4+2));
+ }
+ return true;
+}
diff --git a/xs/src/igl/column_to_quats.h b/xs/src/igl/column_to_quats.h
new file mode 100644
index 000000000..0be12c250
--- /dev/null
+++ b/xs/src/igl/column_to_quats.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COLUMN_TO_QUATS_H
+#define IGL_COLUMN_TO_QUATS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#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
+ IGL_INLINE bool column_to_quats(
+ const Eigen::VectorXd & Q,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "column_to_quats.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/columnize.cpp b/xs/src/igl/columnize.cpp
new file mode 100644
index 000000000..29e91c669
--- /dev/null
+++ b/xs/src/igl/columnize.cpp
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "columnize.h"
+#include <cassert>
+
+template <typename DerivedA, typename DerivedB>
+IGL_INLINE void igl::columnize(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ const int k,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB> & B)
+{
+ // Eigen matrices must be 2d so dim must be only 1 or 2
+ assert(dim == 1 || dim == 2);
+
+ // block height, width, and number of blocks
+ int m,n;
+ if(dim == 1)
+ {
+ m = A.rows()/k;
+ assert(m*(int)k == (int)A.rows());
+ n = A.cols();
+ }else// dim == 2
+ {
+ m = A.rows();
+ n = A.cols()/k;
+ assert(n*(int)k == (int)A.cols());
+ }
+
+ // resize output
+ B.resize(A.rows()*A.cols(),1);
+
+ for(int b = 0;b<(int)k;b++)
+ {
+ for(int i = 0;i<m;i++)
+ {
+ for(int j = 0;j<n;j++)
+ {
+ if(dim == 1)
+ {
+ B(j*m*k+i*k+b) = A(i+b*m,j);
+ }else
+ {
+ B(j*m*k+i*k+b) = A(i,b*n+j);
+ }
+ }
+ }
+ }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::columnize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::columnize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+template void igl::columnize<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/columnize.h b/xs/src/igl/columnize.h
new file mode 100644
index 000000000..1bb453af1
--- /dev/null
+++ b/xs/src/igl/columnize.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COLUMNIZE_H
+#define IGL_COLUMNIZE_H
+#include "igl_inline.h"
+
+#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
+ template <typename DerivedA, typename DerivedB>
+ IGL_INLINE void columnize(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ const int k,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB> & B);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "columnize.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/comb_cross_field.cpp b/xs/src/igl/comb_cross_field.cpp
new file mode 100644
index 000000000..c277b056d
--- /dev/null
+++ b/xs/src/igl/comb_cross_field.cpp
@@ -0,0 +1,148 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "comb_cross_field.h"
+
+#include <vector>
+#include <deque>
+#include <Eigen/Geometry>
+#include "per_face_normals.h"
+#include "is_border_vertex.h"
+#include "rotation_matrix_from_directions.h"
+
+#include "triangle_triangle_adjacency.h"
+
+namespace igl {
+ template <typename DerivedV, typename DerivedF>
+ class Comb
+ {
+ public:
+
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ const Eigen::PlainObjectBase<DerivedV> &PD1;
+ const Eigen::PlainObjectBase<DerivedV> &PD2;
+ DerivedV N;
+
+ private:
+ // internal
+ DerivedF TT;
+ DerivedF TTi;
+
+
+ private:
+
+
+ static inline double Sign(double a){return (double)((a>0)?+1:-1);}
+
+
+ private:
+
+ // returns the 90 deg rotation of a (around n) most similar to target b
+ /// a and b should be in the same plane orthogonal to N
+ static inline Eigen::Matrix<typename DerivedV::Scalar, 3, 1> K_PI_new(const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& a,
+ const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& b,
+ const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& n)
+ {
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> c = (a.cross(n)).normalized();
+ typename DerivedV::Scalar scorea = a.dot(b);
+ typename DerivedV::Scalar scorec = c.dot(b);
+ if (fabs(scorea)>=fabs(scorec))
+ return a*Sign(scorea);
+ else
+ return c*Sign(scorec);
+ }
+
+
+
+ public:
+ inline Comb(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_PD1,
+ const Eigen::PlainObjectBase<DerivedV> &_PD2
+ ):
+ V(_V),
+ F(_F),
+ PD1(_PD1),
+ PD2(_PD2)
+ {
+ igl::per_face_normals(V,F,N);
+ igl::triangle_triangle_adjacency(F,TT,TTi);
+ }
+ inline void comb(Eigen::PlainObjectBase<DerivedV> &PD1out,
+ Eigen::PlainObjectBase<DerivedV> &PD2out)
+ {
+// PD1out = PD1;
+// PD2out = PD2;
+ PD1out.setZero(F.rows(),3);PD1out<<PD1;
+ PD2out.setZero(F.rows(),3);PD2out<<PD2;
+
+ Eigen::VectorXi mark = Eigen::VectorXi::Constant(F.rows(),false);
+
+ std::deque<int> d;
+
+ d.push_back(0);
+ mark(0) = true;
+
+ while (!d.empty())
+ {
+ int f0 = d.at(0);
+ d.pop_front();
+ for (int k=0; k<3; k++)
+ {
+ int f1 = TT(f0,k);
+ if (f1==-1) continue;
+ if (mark(f1)) continue;
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1out.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1out.row(f1);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
+
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0Rot = igl::rotation_matrix_from_directions(n0, n1)*dir0;
+ dir0Rot.normalize();
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> targD = K_PI_new(dir1,dir0Rot,n1);
+
+ PD1out.row(f1) = targD;
+ PD2out.row(f1) = n1.cross(targD).normalized();
+
+ mark(f1) = true;
+ d.push_back(f1);
+
+ }
+ }
+
+ // everything should be marked
+ for (int i=0; i<F.rows(); i++)
+ {
+ assert(mark(i));
+ }
+ }
+
+
+
+ };
+}
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::comb_cross_field(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const Eigen::PlainObjectBase<DerivedV> &PD2,
+ Eigen::PlainObjectBase<DerivedV> &PD1out,
+ Eigen::PlainObjectBase<DerivedV> &PD2out)
+{
+ igl::Comb<DerivedV, DerivedF> cmb(V, F, PD1, PD2);
+ cmb.comb(PD1out, PD2out);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::comb_cross_field<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::comb_cross_field<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/comb_cross_field.h b/xs/src/igl/comb_cross_field.h
new file mode 100644
index 000000000..fa3b57648
--- /dev/null
+++ b/xs/src/igl/comb_cross_field.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COMB_CROSS_FIELD_H
+#define IGL_COMB_CROSS_FIELD_H
+#include "igl_inline.h"
+#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
+ //
+
+
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void comb_cross_field(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1in,
+ const Eigen::PlainObjectBase<DerivedV> &PD2in,
+ Eigen::PlainObjectBase<DerivedV> &PD1out,
+ Eigen::PlainObjectBase<DerivedV> &PD2out);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "comb_cross_field.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/comb_frame_field.cpp b/xs/src/igl/comb_frame_field.cpp
new file mode 100644
index 000000000..f8afe56e9
--- /dev/null
+++ b/xs/src/igl/comb_frame_field.cpp
@@ -0,0 +1,82 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifdef WIN32
+ #define _USE_MATH_DEFINES
+#endif
+#include <cmath>
+
+#include "comb_frame_field.h"
+#include "local_basis.h"
+#include "PI.h"
+
+template <typename DerivedV, typename DerivedF, typename DerivedP>
+IGL_INLINE void igl::comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedP> &PD1,
+ const Eigen::PlainObjectBase<DerivedP> &PD2,
+ const Eigen::PlainObjectBase<DerivedP> &BIS1_combed,
+ const Eigen::PlainObjectBase<DerivedP> &BIS2_combed,
+ Eigen::PlainObjectBase<DerivedP> &PD1_combed,
+ Eigen::PlainObjectBase<DerivedP> &PD2_combed)
+{
+ DerivedV B1, B2, B3;
+ igl::local_basis(V,F,B1,B2,B3);
+
+ PD1_combed.resize(BIS1_combed.rows(),3);
+ PD2_combed.resize(BIS2_combed.rows(),3);
+
+ for (unsigned i=0; i<PD1.rows();++i)
+ {
+ Eigen::Matrix<typename DerivedP::Scalar,4,3> DIRs;
+ DIRs <<
+ PD1.row(i),
+ -PD1.row(i),
+ PD2.row(i),
+ -PD2.row(i);
+
+ std::vector<double> a(4);
+
+
+ double a_combed = atan2(B2.row(i).dot(BIS1_combed.row(i)),B1.row(i).dot(BIS1_combed.row(i)));
+
+ // center on the combed sector center
+ for (unsigned j=0;j<4;++j)
+ {
+ a[j] = atan2(B2.row(i).dot(DIRs.row(j)),B1.row(i).dot(DIRs.row(j))) - a_combed;
+ //make it positive by adding some multiple of 2pi
+ a[j] += std::ceil (std::max(0., -a[j]) / (igl::PI*2.)) * (igl::PI*2.);
+ //take modulo 2pi
+ a[j] = fmod(a[j], (igl::PI*2.));
+ }
+ // now the max is u and the min is v
+
+ int m = std::min_element(a.begin(),a.end())-a.begin();
+ int M = std::max_element(a.begin(),a.end())-a.begin();
+
+ assert(
+ ((m>=0 && m<=1) && (M>=2 && M<=3))
+ ||
+ ((m>=2 && m<=3) && (M>=0 && M<=1))
+ );
+
+ PD1_combed.row(i) = DIRs.row(m);
+ PD2_combed.row(i) = DIRs.row(M);
+
+ }
+
+
+ // PD1_combed = BIS1_combed;
+ // PD2_combed = BIS2_combed;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::comb_frame_field<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::comb_frame_field<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/comb_frame_field.h b/xs/src/igl/comb_frame_field.h
new file mode 100644
index 000000000..4691dc19d
--- /dev/null
+++ b/xs/src/igl/comb_frame_field.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COMB_FRAME_FIELD_H
+#define IGL_COMB_FRAME_FIELD_H
+#include "igl_inline.h"
+#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
+ //
+
+
+ template <typename DerivedV, typename DerivedF, typename DerivedP>
+ IGL_INLINE void comb_frame_field(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedP> &PD1,
+ const Eigen::PlainObjectBase<DerivedP> &PD2,
+ const Eigen::PlainObjectBase<DerivedP> &BIS1_combed,
+ const Eigen::PlainObjectBase<DerivedP> &BIS2_combed,
+ Eigen::PlainObjectBase<DerivedP> &PD1_combed,
+ Eigen::PlainObjectBase<DerivedP> &PD2_combed);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "comb_frame_field.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/comb_line_field.cpp b/xs/src/igl/comb_line_field.cpp
new file mode 100644
index 000000000..66899319a
--- /dev/null
+++ b/xs/src/igl/comb_line_field.cpp
@@ -0,0 +1,132 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Nico Pietroni <nico.pietroni@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "comb_line_field.h"
+
+#include <vector>
+#include <deque>
+#include "per_face_normals.h"
+#include "is_border_vertex.h"
+#include "rotation_matrix_from_directions.h"
+
+#include "triangle_triangle_adjacency.h"
+
+namespace igl {
+template <typename DerivedV, typename DerivedF>
+class CombLine
+{
+public:
+
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ const Eigen::PlainObjectBase<DerivedV> &PD1;
+ DerivedV N;
+
+private:
+ // internal
+ DerivedF TT;
+ DerivedF TTi;
+
+
+private:
+
+
+ static inline double Sign(double a){return (double)((a>0)?+1:-1);}
+
+
+private:
+
+ // returns the 180 deg rotation of a (around n) most similar to target b
+ // a and b should be in the same plane orthogonal to N
+ static inline Eigen::Matrix<typename DerivedV::Scalar, 3, 1> K_PI_line(const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& a,
+ const Eigen::Matrix<typename DerivedV::Scalar, 3, 1>& b)
+ {
+ typename DerivedV::Scalar scorea = a.dot(b);
+ if (scorea<0)
+ return -a;
+ else
+ return a;
+ }
+
+
+
+public:
+
+ inline CombLine(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_PD1):
+ V(_V),
+ F(_F),
+ PD1(_PD1)
+ {
+ igl::per_face_normals(V,F,N);
+ igl::triangle_triangle_adjacency(F,TT,TTi);
+ }
+
+ inline void comb(Eigen::PlainObjectBase<DerivedV> &PD1out)
+ {
+ PD1out.setZero(F.rows(),3);PD1out<<PD1;
+
+ Eigen::VectorXi mark = Eigen::VectorXi::Constant(F.rows(),false);
+
+ std::deque<int> d;
+
+ d.push_back(0);
+ mark(0) = true;
+
+ while (!d.empty())
+ {
+ int f0 = d.at(0);
+ d.pop_front();
+ for (int k=0; k<3; k++)
+ {
+ int f1 = TT(f0,k);
+ if (f1==-1) continue;
+ if (mark(f1)) continue;
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1out.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1out.row(f1);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0Rot = igl::rotation_matrix_from_directions(n0, n1)*dir0;
+ dir0Rot.normalize();
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> targD = K_PI_line(dir1,dir0Rot);
+
+ PD1out.row(f1) = targD;
+ //PD2out.row(f1) = n1.cross(targD).normalized();
+
+ mark(f1) = true;
+ d.push_back(f1);
+
+ }
+ }
+
+ // everything should be marked
+ for (int i=0; i<F.rows(); i++)
+ {
+ assert(mark(i));
+ }
+ }
+
+};
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::comb_line_field(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ Eigen::PlainObjectBase<DerivedV> &PD1out)
+{
+ igl::CombLine<DerivedV, DerivedF> cmb(V, F, PD1);
+ cmb.comb(PD1out);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/comb_line_field.h b/xs/src/igl/comb_line_field.h
new file mode 100644
index 000000000..e2f22b37f
--- /dev/null
+++ b/xs/src/igl/comb_line_field.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Nico Pietroni <nico.pietroni@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COMB_LINE_FIELD_H
+#define IGL_COMB_LINE_FIELD_H
+#include "igl_inline.h"
+#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
+ //
+
+
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void comb_line_field(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1in,
+ Eigen::PlainObjectBase<DerivedV> &PD1out);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "comb_line_field.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/combine.cpp b/xs/src/igl/combine.cpp
new file mode 100644
index 000000000..7e0af151a
--- /dev/null
+++ b/xs/src/igl/combine.cpp
@@ -0,0 +1,97 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "combine.h"
+#include <cassert>
+
+template <
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVsizes,
+ typename DerivedFsizes>
+IGL_INLINE void igl::combine(
+ const std::vector<DerivedVV> & VV,
+ const std::vector<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedVsizes> & Vsizes,
+ Eigen::PlainObjectBase<DerivedFsizes> & Fsizes)
+{
+ assert(VV.size() == FF.size() &&
+ "Lists of verex lists and face lists should be same size");
+ Vsizes.resize(VV.size());
+ Fsizes.resize(FF.size());
+ // Dimension of vertex positions
+ const int dim = VV.size() > 0 ? VV[0].cols() : 0;
+ // Simplex/element size
+ const int ss = FF.size() > 0 ? FF[0].cols() : 0;
+ int n = 0;
+ int m = 0;
+ for(int i = 0;i<VV.size();i++)
+ {
+ const auto & Vi = VV[i];
+ const auto & Fi = FF[i];
+ Vsizes(i) = Vi.rows();
+ n+=Vi.rows();
+ assert((Vi.size()==0 || dim == Vi.cols()) && "All vertex lists should have same #columns");
+ Fsizes(i) = Fi.rows();
+ m+=Fi.rows();
+ assert((Fi.size()==0 || ss == Fi.cols()) && "All face lists should have same #columns");
+ }
+ V.resize(n,dim);
+ F.resize(m,ss);
+ {
+ int kv = 0;
+ int kf = 0;
+ for(int i = 0;i<VV.size();i++)
+ {
+ const auto & Vi = VV[i];
+ const int ni = Vi.rows();
+ const auto & Fi = FF[i];
+ const int mi = Fi.rows();
+ if(Fi.size() >0)
+ {
+ F.block(kf,0,mi,ss) = Fi.array()+kv;
+ }
+ kf+=mi;
+ if(Vi.size() >0)
+ {
+ V.block(kv,0,ni,dim) = Vi;
+ }
+ kv+=ni;
+ }
+ assert(kv == V.rows());
+ assert(kf == F.rows());
+ }
+}
+
+template <
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE void igl::combine(
+ const std::vector<DerivedVV> & VV,
+ const std::vector<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F)
+{
+ Eigen::VectorXi Vsizes,Fsizes;
+ return igl::combine(VV,FF,V,F,Vsizes,Fsizes);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::combine<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&);
+template void igl::combine<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::vector<Eigen::Matrix<double, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<double, -1, 3, 1, -1, 3> > > const&, std::vector<Eigen::Matrix<int, -1, 3, 1, -1, 3>, std::allocator<Eigen::Matrix<int, -1, 3, 1, -1, 3> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+#ifdef WIN32
+template void igl::combine<Eigen::Matrix<double,-1,-1,0,-1,-1>, Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> >(class std::vector<Eigen::Matrix<double,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<double,-1,-1,0,-1,-1> > > const &,class std::vector<Eigen::Matrix<int,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<int,-1,-1,0,-1,-1> > > const &,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &);
+template void igl::combine<Eigen::Matrix<double,-1,-1,0,-1,-1>, Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1>,Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> >(class std::vector<Eigen::Matrix<double,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<double,-1,-1,0,-1,-1> > > const &,class std::vector<Eigen::Matrix<int,-1,-1,0,-1,-1>,class std::allocator<Eigen::Matrix<int,-1,-1,0,-1,-1> > > const &,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &,Eigen::PlainObjectBase<Eigen::Matrix<unsigned __int64,-1,1,0,-1,1> > &);
+#endif
+#endif
diff --git a/xs/src/igl/combine.h b/xs/src/igl/combine.h
new file mode 100644
index 000000000..ff5e1ae34
--- /dev/null
+++ b/xs/src/igl/combine.h
@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COMBINE_H
+#define IGL_COMBINE_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+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);
+ //
+ //
+ template <
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVsizes,
+ typename DerivedFsizes>
+ IGL_INLINE void combine(
+ const std::vector<DerivedVV> & VV,
+ const std::vector<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedVsizes> & Vsizes,
+ Eigen::PlainObjectBase<DerivedFsizes> & Fsizes);
+ template <
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE void combine(
+ const std::vector<DerivedVV> & VV,
+ const std::vector<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "combine.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/components.cpp b/xs/src/igl/components.cpp
new file mode 100644
index 000000000..253186889
--- /dev/null
+++ b/xs/src/igl/components.cpp
@@ -0,0 +1,98 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "components.h"
+#include "adjacency_matrix.h"
+#include <queue>
+#include <vector>
+
+template <typename AScalar, typename DerivedC, typename Derivedcounts>
+IGL_INLINE void igl::components(
+ const Eigen::SparseMatrix<AScalar> & A,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<Derivedcounts> & counts)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(A.rows() == A.cols() && "A should be square.");
+ const size_t n = A.rows();
+ Array<bool,Dynamic,1> seen = Array<bool,Dynamic,1>::Zero(n,1);
+ C.resize(n,1);
+ typename DerivedC::Scalar id = 0;
+ vector<typename Derivedcounts::Scalar> vcounts;
+ // breadth first search
+ for(int k=0; k<A.outerSize(); ++k)
+ {
+ if(seen(k))
+ {
+ continue;
+ }
+ queue<int> Q;
+ Q.push(k);
+ vcounts.push_back(0);
+ while(!Q.empty())
+ {
+ const int f = Q.front();
+ Q.pop();
+ if(seen(f))
+ {
+ continue;
+ }
+ seen(f) = true;
+ C(f,0) = id;
+ vcounts[id]++;
+ // Iterate over inside
+ for(typename SparseMatrix<AScalar>::InnerIterator it (A,f); it; ++it)
+ {
+ const int g = it.index();
+ if(!seen(g) && it.value())
+ {
+ Q.push(g);
+ }
+ }
+ }
+ id++;
+ }
+ assert((size_t) id == vcounts.size());
+ const size_t ncc = vcounts.size();
+ assert((size_t)C.maxCoeff()+1 == ncc);
+ counts.resize(ncc,1);
+ for(size_t i = 0;i<ncc;i++)
+ {
+ counts(i) = vcounts[i];
+ }
+}
+
+template <typename AScalar, typename DerivedC>
+IGL_INLINE void igl::components(
+ const Eigen::SparseMatrix<AScalar> & A,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ Eigen::VectorXi counts;
+ return components(A,C,counts);
+}
+
+template <typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::components(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ Eigen::SparseMatrix<typename DerivedC::Scalar> A;
+ adjacency_matrix(F,A);
+ return components(A,C);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::components<bool, Eigen::Array<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, Eigen::PlainObjectBase<Eigen::Array<int, -1, 1, 0, -1, 1> >&);
+template void igl::components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::components<int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<int, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::components<int, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<int, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::components<double, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/components.h b/xs/src/igl/components.h
new file mode 100644
index 000000000..d43a64c89
--- /dev/null
+++ b/xs/src/igl/components.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COMPONENTS_H
+#define IGL_COMPONENTS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Compute connected components of a graph represented by an adjacency
+ // matrix. This version is faster than the previous version using boost.
+ //
+ // Inputs:
+ // A n by n adjacency matrix
+ // Outputs:
+ // C n list of component ids (starting with 0)
+ // counts #components list of counts for each component
+ //
+ template <typename AScalar, typename DerivedC, typename Derivedcounts>
+ IGL_INLINE void components(
+ const Eigen::SparseMatrix<AScalar> & A,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<Derivedcounts> & counts);
+ template <typename AScalar, typename DerivedC>
+ IGL_INLINE void components(
+ const Eigen::SparseMatrix<AScalar> & A,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ // Ditto but for mesh faces as input. This computes connected components of
+ // **vertices** where **edges** establish connectivity.
+ //
+ // Inputs:
+ // F n by 3 list of triangle indices
+ // Outputs:
+ // C max(F) list of component ids
+ template <typename DerivedF, typename DerivedC>
+ IGL_INLINE void components(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "components.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/compute_frame_field_bisectors.cpp b/xs/src/igl/compute_frame_field_bisectors.cpp
new file mode 100644
index 000000000..e3c47c608
--- /dev/null
+++ b/xs/src/igl/compute_frame_field_bisectors.cpp
@@ -0,0 +1,85 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifdef WIN32
+ #define _USE_MATH_DEFINES
+#endif
+#include <cmath>
+
+#include "compute_frame_field_bisectors.h"
+#include "igl/local_basis.h"
+#include "PI.h"
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::compute_frame_field_bisectors(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedV>& B1,
+ const Eigen::PlainObjectBase<DerivedV>& B2,
+ const Eigen::PlainObjectBase<DerivedV>& PD1,
+ const Eigen::PlainObjectBase<DerivedV>& PD2,
+ Eigen::PlainObjectBase<DerivedV>& BIS1,
+ Eigen::PlainObjectBase<DerivedV>& BIS2)
+{
+ BIS1.resize(PD1.rows(),3);
+ BIS2.resize(PD1.rows(),3);
+
+ for (unsigned i=0; i<PD1.rows();++i)
+ {
+ // project onto the tangent plane and convert to angle
+ // Convert to angle
+ double a1 = atan2(B2.row(i).dot(PD1.row(i)),B1.row(i).dot(PD1.row(i)));
+ //make it positive by adding some multiple of 2pi
+ a1 += std::ceil (std::max(0., -a1) / (igl::PI*2.)) * (igl::PI*2.);
+ //take modulo 2pi
+ a1 = fmod(a1, (igl::PI*2.));
+ double a2 = atan2(B2.row(i).dot(PD2.row(i)),B1.row(i).dot(PD2.row(i)));
+ //make it positive by adding some multiple of 2pi
+ a2 += std::ceil (std::max(0., -a2) / (igl::PI*2.)) * (igl::PI*2.);
+ //take modulo 2pi
+ a2 = fmod(a2, (igl::PI*2.));
+
+ double b1 = (a1+a2)/2.0;
+ //make it positive by adding some multiple of 2pi
+ b1 += std::ceil (std::max(0., -b1) / (igl::PI*2.)) * (igl::PI*2.);
+ //take modulo 2pi
+ b1 = fmod(b1, (igl::PI*2.));
+
+ double b2 = b1+(igl::PI/2.);
+ //make it positive by adding some multiple of 2pi
+ b2 += std::ceil (std::max(0., -b2) / (igl::PI*2.)) * (igl::PI*2.);
+ //take modulo 2pi
+ b2 = fmod(b2, (igl::PI*2.));
+
+ BIS1.row(i) = cos(b1) * B1.row(i) + sin(b1) * B2.row(i);
+ BIS2.row(i) = cos(b2) * B1.row(i) + sin(b2) * B2.row(i);
+
+ }
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::compute_frame_field_bisectors(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedV>& PD1,
+ const Eigen::PlainObjectBase<DerivedV>& PD2,
+ Eigen::PlainObjectBase<DerivedV>& BIS1,
+ Eigen::PlainObjectBase<DerivedV>& BIS2)
+{
+ DerivedV B1, B2, B3;
+ igl::local_basis(V,F,B1,B2,B3);
+
+ compute_frame_field_bisectors( V, F, B1, B2, PD1, PD2, BIS1, BIS2);
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::compute_frame_field_bisectors<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::compute_frame_field_bisectors<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/compute_frame_field_bisectors.h b/xs/src/igl/compute_frame_field_bisectors.h
new file mode 100644
index 000000000..4c853febf
--- /dev/null
+++ b/xs/src/igl/compute_frame_field_bisectors.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COMPUTE_FRAME_FIELD_BISECTORS_H
+#define IGL_COMPUTE_FRAME_FIELD_BISECTORS_H
+#include "igl_inline.h"
+#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
+ //
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void compute_frame_field_bisectors(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedV>& B1,
+ const Eigen::PlainObjectBase<DerivedV>& B2,
+ const Eigen::PlainObjectBase<DerivedV>& PD1,
+ const Eigen::PlainObjectBase<DerivedV>& PD2,
+ Eigen::PlainObjectBase<DerivedV>& BIS1,
+ Eigen::PlainObjectBase<DerivedV>& BIS2);
+
+ // Wrapper without given basis vectors.
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void compute_frame_field_bisectors(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedV>& PD1,
+ const Eigen::PlainObjectBase<DerivedV>& PD2,
+ Eigen::PlainObjectBase<DerivedV>& BIS1,
+ Eigen::PlainObjectBase<DerivedV>& BIS2);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "compute_frame_field_bisectors.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/connect_boundary_to_infinity.cpp b/xs/src/igl/connect_boundary_to_infinity.cpp
new file mode 100644
index 000000000..627b0b9b6
--- /dev/null
+++ b/xs/src/igl/connect_boundary_to_infinity.cpp
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "connect_boundary_to_infinity.h"
+#include "boundary_facets.h"
+
+template <typename DerivedF, typename DerivedFO>
+IGL_INLINE void igl::connect_boundary_to_infinity(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFO> & FO)
+{
+ return connect_boundary_to_infinity(F,F.maxCoeff(),FO);
+}
+template <typename DerivedF, typename DerivedFO>
+IGL_INLINE void igl::connect_boundary_to_infinity(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const typename DerivedF::Scalar inf_index,
+ Eigen::PlainObjectBase<DerivedFO> & FO)
+{
+ // Determine boundary edges
+ Eigen::Matrix<typename DerivedFO::Scalar,Eigen::Dynamic,Eigen::Dynamic> O;
+ boundary_facets(F,O);
+ FO.resize(F.rows()+O.rows(),F.cols());
+ typedef Eigen::Matrix<typename DerivedFO::Scalar,Eigen::Dynamic,1> VectorXI;
+ FO.topLeftCorner(F.rows(),F.cols()) = F;
+ FO.bottomLeftCorner(O.rows(),O.cols()) = O.rowwise().reverse();
+ FO.bottomRightCorner(O.rows(),1).setConstant(inf_index);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVO,
+ typename DerivedFO>
+IGL_INLINE void igl::connect_boundary_to_infinity(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedVO> & VO,
+ Eigen::PlainObjectBase<DerivedFO> & FO)
+{
+ typename DerivedV::Index inf_index = V.rows();
+ connect_boundary_to_infinity(F,inf_index,FO);
+ VO.resize(V.rows()+1,V.cols());
+ VO.topLeftCorner(V.rows(),V.cols()) = V;
+ auto inf = std::numeric_limits<typename DerivedVO::Scalar>::infinity();
+ VO.row(V.rows()).setConstant(inf);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::connect_boundary_to_infinity<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/connect_boundary_to_infinity.h b/xs/src/igl/connect_boundary_to_infinity.h
new file mode 100644
index 000000000..2fa2783d6
--- /dev/null
+++ b/xs/src/igl/connect_boundary_to_infinity.h
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CONNECT_BOUNDARY_TO_INFINITY_H
+#define IGL_CONNECT_BOUNDARY_TO_INFINITY_H
+#include "igl_inline.h"
+#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).
+ template <typename DerivedF, typename DerivedFO>
+ IGL_INLINE void connect_boundary_to_infinity(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFO> & FO);
+ // Inputs:
+ // inf_index index of point at infinity (usually V.rows() or F.maxCoeff())
+ template <typename DerivedF, typename DerivedFO>
+ IGL_INLINE void connect_boundary_to_infinity(
+ const Eigen::PlainObjectBase<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
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVO,
+ typename DerivedFO>
+ IGL_INLINE void connect_boundary_to_infinity(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedVO> & VO,
+ Eigen::PlainObjectBase<DerivedFO> & FO);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "connect_boundary_to_infinity.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/README.md b/xs/src/igl/copyleft/README.md
new file mode 100644
index 000000000..78454affc
--- /dev/null
+++ b/xs/src/igl/copyleft/README.md
@@ -0,0 +1,14 @@
+## IGL copyleft subdirectory
+
+Functions in the `include/igl/copyleft/` subdirectory are in the
+`igl::copyleft::` namespace to indicate that they are under a more aggressive
+[copyleft](https://en.wikipedia.org/wiki/Copyleft) than
+[MPL2](https://en.wikipedia.org/wiki/Mozilla_Public_License) used for the main
+`include/igl` directory and `igl::` namespace. Most notably, this subdirectory
+includes code that is under
+[GPL](https://en.wikipedia.org/wiki/GNU_General_Public_License).
+
+Typically a company planning on developing software without releasing its
+source code will avoid or purchase licenses for such dependencies. If you do
+obtain such a license for the dependencies employed here, you are free to use
+the libigl functions here as per their MPL2 license.
diff --git a/xs/src/igl/copyleft/cgal/BinaryWindingNumberOperations.h b/xs/src/igl/copyleft/cgal/BinaryWindingNumberOperations.h
new file mode 100644
index 000000000..9bae0b7bb
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/BinaryWindingNumberOperations.h
@@ -0,0 +1,167 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H
+#define IGL_COPYLEFT_CGAL_BINARY_WINDING_NUMBER_OPERATIONS_H
+
+#include <stdexcept>
+#include "../../igl_inline.h"
+#include "../../MeshBooleanType.h"
+#include <Eigen/Core>
+
+// TODO: This is not written according to libigl style. These should be
+// function handles.
+//
+// Why is this templated on DerivedW
+//
+// These are all generalized to n-ary operations
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ template <igl::MeshBooleanType Op>
+ class BinaryWindingNumberOperations {
+ public:
+ template<typename DerivedW>
+ typename DerivedW::Scalar operator()(
+ const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
+ throw (std::runtime_error("not implemented!"));
+ }
+ };
+
+ // A ∪ B ∪ ... ∪ Z
+ template <>
+ class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_UNION> {
+ public:
+ template<typename DerivedW>
+ typename DerivedW::Scalar operator()(
+ const Eigen::PlainObjectBase<DerivedW>& win_nums) const
+ {
+ for(int i = 0;i<win_nums.size();i++)
+ {
+ if(win_nums(i) > 0) return true;
+ }
+ return false;
+ }
+ };
+
+ // A ∩ B ∩ ... ∩ Z
+ template <>
+ class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_INTERSECT> {
+ public:
+ template<typename DerivedW>
+ typename DerivedW::Scalar operator()(
+ const Eigen::PlainObjectBase<DerivedW>& win_nums) const
+ {
+ for(int i = 0;i<win_nums.size();i++)
+ {
+ if(win_nums(i)<=0) return false;
+ }
+ return true;
+ }
+ };
+
+ // A \ B \ ... \ Z = A \ (B ∪ ... ∪ Z)
+ template <>
+ class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_MINUS> {
+ public:
+ template<typename DerivedW>
+ typename DerivedW::Scalar operator()(
+ const Eigen::PlainObjectBase<DerivedW>& win_nums) const
+ {
+ assert(win_nums.size()>1);
+ // Union of objects 1 through n-1
+ bool union_rest = false;
+ for(int i = 1;i<win_nums.size();i++)
+ {
+ union_rest = union_rest || win_nums(i) > 0;
+ if(union_rest) break;
+ }
+ // Must be in object 0 and not in union of objects 1 through n-1
+ return win_nums(0) > 0 && !union_rest;
+ }
+ };
+
+ // A ∆ B ∆ ... ∆ Z (equivalent to set inside odd number of objects)
+ template <>
+ class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> {
+ public:
+ template<typename DerivedW>
+ typename DerivedW::Scalar operator()(
+ const Eigen::PlainObjectBase<DerivedW>& win_nums) const
+ {
+ // If inside an odd number of objects
+ int count = 0;
+ for(int i = 0;i<win_nums.size();i++)
+ {
+ if(win_nums(i) > 0) count++;
+ }
+ return count % 2 == 1;
+ }
+ };
+
+ template <>
+ class BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> {
+ public:
+ template<typename DerivedW>
+ typename DerivedW::Scalar operator()(
+ const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
+ return true;
+ }
+ };
+
+ typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_UNION> BinaryUnion;
+ typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_INTERSECT> BinaryIntersect;
+ typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_MINUS> BinaryMinus;
+ typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_XOR> BinaryXor;
+ typedef BinaryWindingNumberOperations<MESH_BOOLEAN_TYPE_RESOLVE> BinaryResolve;
+
+ enum KeeperType {
+ KEEP_INSIDE,
+ KEEP_ALL
+ };
+
+ template<KeeperType T>
+ class WindingNumberFilter {
+ public:
+ template<typename DerivedW>
+ short operator()(
+ const Eigen::PlainObjectBase<DerivedW>& /*win_nums*/) const {
+ throw std::runtime_error("Not implemented");
+ }
+ };
+
+ template<>
+ class WindingNumberFilter<KEEP_INSIDE> {
+ public:
+ template<typename T>
+ short operator()(T out_w, T in_w) const {
+ if (in_w > 0 && out_w <= 0) return 1;
+ else if (in_w <= 0 && out_w > 0) return -1;
+ else return 0;
+ }
+ };
+
+ template<>
+ class WindingNumberFilter<KEEP_ALL> {
+ public:
+ template<typename T>
+ short operator()(T /*out_w*/, T /*in_w*/) const {
+ return 1;
+ }
+ };
+
+ typedef WindingNumberFilter<KEEP_INSIDE> KeepInside;
+ typedef WindingNumberFilter<KEEP_ALL> KeepAll;
+ }
+ }
+}
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/CGAL_includes.hpp b/xs/src/igl/copyleft/cgal/CGAL_includes.hpp
new file mode 100644
index 000000000..38d2fc749
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/CGAL_includes.hpp
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CGAL_INCLUDES_H
+#define IGL_CGAL_INCLUDES_H
+
+// This causes unknown bugs during intersection meshing:
+//// http://www.alecjacobson.com/weblog/?p=4291
+//#define CGAL_INTERSECTION_VERSION 1
+// Use this instead to mute errors resulting from bad CGAL assertions
+#define CGAL_KERNEL_NO_ASSERTIONS
+// Triangle triangle intersection
+#include <CGAL/intersections.h>
+// THIS CANNOT BE INCLUDED IN THE SAME FILE AS <CGAL/intersections.h>
+// #include <CGAL/Boolean_set_operations_2.h>
+
+// Constrained Delaunay Triangulation types
+#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+#include <CGAL/Constrained_triangulation_plus_2.h>
+
+// Axis-align boxes for all-pairs self-intersection detection
+#include <CGAL/point_generators_3.h>
+#include <CGAL/Bbox_3.h>
+#include <CGAL/box_intersection_d.h>
+#include <CGAL/function_objects.h>
+#include <CGAL/Join_input_iterator.h>
+#include <CGAL/algorithm.h>
+#include <vector>
+
+// Axis-aligned bounding box tree for tet tri intersection
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+
+// Boolean operations
+#include <CGAL/Polyhedron_3.h>
+// Is this actually used?
+//#include <CGAL/Nef_polyhedron_3.h>
+
+// Delaunay Triangulation in 3D
+#include <CGAL/Delaunay_triangulation_3.h>
+
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/CSGTree.h b/xs/src/igl/copyleft/cgal/CSGTree.h
new file mode 100644
index 000000000..599572d3f
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/CSGTree.h
@@ -0,0 +1,189 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_CSG_TREE_H
+#define IGL_COPYLEFT_CGAL_CSG_TREE_H
+
+#include "../../MeshBooleanType.h"
+#include "string_to_mesh_boolean_type.h"
+#include "mesh_boolean.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/number_utils.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ 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 CSGTree
+ {
+ public:
+ typedef CGAL::Epeck::FT ExactScalar;
+ //typedef Eigen::PlainObjectBase<DerivedF> POBF;
+ typedef Eigen::MatrixXi POBF;
+ typedef POBF::Index FIndex;
+ typedef Eigen::Matrix<ExactScalar,Eigen::Dynamic,3> MatrixX3E;
+ typedef Eigen::Matrix<FIndex,Eigen::Dynamic,1> VectorJ;
+ private:
+ // Resulting mesh
+ MatrixX3E m_V;
+ POBF m_F;
+ VectorJ m_J;
+ // 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()
+ {
+ }
+ //typedef Eigen::MatrixXd MatrixX3E;
+ //typedef Eigen::MatrixXi POBF;
+ // http://stackoverflow.com/a/3279550/148668
+ CSGTree(const CSGTree & other)
+ :
+ // copy things
+ m_V(other.m_V),
+ // This is an issue if m_F is templated
+ // https://forum.kde.org/viewtopic.php?f=74&t=128414
+ m_F(other.m_F),
+ m_J(other.m_J),
+ m_number_of_birth_faces(other.m_number_of_birth_faces)
+ {
+ }
+ // copy-swap idiom
+ friend void swap(CSGTree& first, CSGTree& second)
+ {
+ using std::swap;
+ // swap things
+ swap(first.m_V,second.m_V);
+ // This is an issue if m_F is templated, similar to
+ // https://forum.kde.org/viewtopic.php?f=74&t=128414
+ swap(first.m_F,second.m_F);
+ swap(first.m_J,second.m_J);
+ swap(first.m_number_of_birth_faces,second.m_number_of_birth_faces);
+ }
+ // Pass-by-value (aka copy)
+ CSGTree& operator=(CSGTree other)
+ {
+ swap(*this,other);
+ return *this;
+ }
+ CSGTree(CSGTree&& other):
+ // initialize via default constructor
+ CSGTree()
+ {
+ 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
+ CSGTree(
+ const CSGTree & A,
+ const CSGTree & B,
+ const MeshBooleanType & type)
+ {
+ // conduct boolean operation
+ mesh_boolean(A.V(),A.F(),B.V(),B.F(),type,m_V,m_F,m_J);
+ // reindex m_J
+ std::for_each(m_J.data(),m_J.data()+m_J.size(),
+ [&](typename VectorJ::Scalar & j) -> void
+ {
+ if(j < A.F().rows())
+ {
+ j = A.J()(j);
+ }else
+ {
+ assert(j<(A.F().rows()+B.F().rows()));
+ j = A.number_of_birth_faces()+(B.J()(j-A.F().rows()));
+ }
+ });
+ m_number_of_birth_faces =
+ A.number_of_birth_faces() + B.number_of_birth_faces();
+ }
+ // Overload using string for type
+ CSGTree(
+ const CSGTree & A,
+ const CSGTree & B,
+ const std::string & s):
+ CSGTree(A,B,string_to_mesh_boolean_type(s))
+ {
+ // 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
+ template <typename DerivedV>
+ CSGTree(const Eigen::PlainObjectBase<DerivedV> & V, const POBF & F)//:
+ // Possible Eigen bug:
+ // https://forum.kde.org/viewtopic.php?f=74&t=128414
+ //m_V(V.template cast<ExactScalar>()),m_F(F)
+ {
+ m_V = V.template cast<ExactScalar>();
+ m_F = F;
+ // number of faces
+ m_number_of_birth_faces = m_F.rows();
+ // identity birth index
+ m_J = VectorJ::LinSpaced(
+ m_number_of_birth_faces,0,m_number_of_birth_faces-1);
+ }
+ // Returns reference to resulting mesh vertices m_V in exact scalar
+ // representation
+ const MatrixX3E & V() const
+ {
+ return m_V;
+ }
+ // Returns mesh vertices in the desired output type, casting when
+ // appropriate to floating precision.
+ template <typename DerivedV>
+ DerivedV cast_V() const
+ {
+ DerivedV dV;
+ dV.resize(m_V.rows(),m_V.cols());
+ for(int i = 0;i<m_V.rows();i++)
+ {
+ for(int j = 0;j<m_V.cols();j++)
+ {
+ dV(i,j) = CGAL::to_double(m_V(i,j));
+ }
+ }
+ return dV;
+ }
+ // Returns reference to resulting mesh faces m_F
+ const POBF & F() const
+ {
+ return m_F;
+ }
+ // Returns reference to "birth parents" indices into [F1;F2;...;Fn]
+ // where F1, ... , Fn are the face lists of the leaf ("original") input
+ // meshes.
+ const VectorJ & J() const
+ {
+ return m_J;
+ }
+ // The number of leaf faces = #F1 + #F2 + ... + #Fn
+ const size_t & number_of_birth_faces() const
+ {
+ return m_number_of_birth_faces;
+ }
+ };
+ }
+ }
+}
+
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h b/xs/src/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h
new file mode 100644
index 000000000..b2621224c
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/RemeshSelfIntersectionsParam.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
+#define IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_PARAM_H
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Optional Parameters
+ // DetectOnly Only compute IF, leave VV and FF alone
+ struct RemeshSelfIntersectionsParam
+ {
+ bool detect_only;
+ bool first_only;
+ bool stitch_all;
+ inline RemeshSelfIntersectionsParam(
+ bool _detect_only=false,
+ bool _first_only=false,
+ bool _stitch_all=false):
+ detect_only(_detect_only),
+ first_only(_first_only),
+ stitch_all(_stitch_all){};
+ };
+ }
+ }
+}
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/SelfIntersectMesh.h b/xs/src/igl/copyleft/cgal/SelfIntersectMesh.h
new file mode 100644
index 000000000..5a70fc39e
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/SelfIntersectMesh.h
@@ -0,0 +1,939 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H
+#define IGL_COPYLEFT_CGAL_SELFINTERSECTMESH_H
+
+#include "CGAL_includes.hpp"
+#include "RemeshSelfIntersectionsParam.h"
+#include "../../unique.h"
+
+#include <Eigen/Dense>
+#include <list>
+#include <map>
+#include <vector>
+#include <thread>
+#include <mutex>
+
+//#define IGL_SELFINTERSECTMESH_DEBUG
+#ifndef IGL_FIRST_HIT_EXCEPTION
+#define IGL_FIRST_HIT_EXCEPTION 10
+#endif
+
+// The easiest way to keep track of everything is to use a class
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Kernel is a CGAL kernel like:
+ // CGAL::Exact_predicates_inexact_constructions_kernel
+ // or
+ // CGAL::Exact_predicates_exact_constructions_kernel
+
+ template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+ class SelfIntersectMesh
+ {
+ typedef
+ SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM> Self;
+ public:
+ // 3D Primitives
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Segment_3<Kernel> Segment_3;
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ typedef CGAL::Plane_3<Kernel> Plane_3;
+ typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
+ // 2D Primitives
+ typedef CGAL::Point_2<Kernel> Point_2;
+ typedef CGAL::Segment_2<Kernel> Segment_2;
+ typedef CGAL::Triangle_2<Kernel> Triangle_2;
+ // 2D Constrained Delaunay Triangulation types
+ typedef CGAL::Exact_intersections_tag Itag;
+ // Axis-align boxes for all-pairs self-intersection detection
+ typedef std::vector<Triangle_3> Triangles;
+ typedef typename Triangles::iterator TrianglesIterator;
+ typedef typename Triangles::const_iterator TrianglesConstIterator;
+ typedef
+ CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator>
+ Box;
+
+ // Input mesh
+ const Eigen::MatrixBase<DerivedV> & V;
+ const Eigen::MatrixBase<DerivedF> & F;
+ // Number of self-intersecting triangle pairs
+ typedef typename DerivedF::Index Index;
+ Index count;
+ typedef std::vector<std::pair<Index, CGAL::Object>> ObjectList;
+ // Using a vector here makes this **not** output sensitive
+ Triangles T;
+ typedef std::vector<Index> IndexList;
+ IndexList lIF;
+ // #F-long list of faces with intersections mapping to the order in
+ // which they were first found
+ std::map<Index,ObjectList> offending;
+ // Make a short name for the edge map's key
+ typedef std::pair<Index,Index> EMK;
+ // Make a short name for the type stored at each edge, the edge map's
+ // value
+ typedef std::vector<Index> EMV;
+ // Make a short name for the edge map
+ typedef std::map<EMK,EMV> EdgeMap;
+ // Maps edges of offending faces to all incident offending faces
+ std::vector<std::pair<TrianglesIterator, TrianglesIterator> >
+ candidate_triangle_pairs;
+
+ public:
+ RemeshSelfIntersectionsParam params;
+ public:
+ // Constructs (VV,FF) a new mesh with self-intersections of (V,F)
+ // subdivided
+ //
+ // See also: remesh_self_intersections.h
+ inline SelfIntersectMesh(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const RemeshSelfIntersectionsParam & params,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedIF> & IF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM);
+ private:
+ // Helper function to mark a face as offensive
+ //
+ // Inputs:
+ // 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
+ 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
+ //
+ 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)
+ //
+ inline bool single_shared_vertex(
+ const Triangle_3 & A,
+ const Triangle_3 & B,
+ const Index fa,
+ const Index fb,
+ const Index va,
+ const Index vb);
+ // Helper handling one direction
+ 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.
+ inline bool double_shared_vertex(
+ const Triangle_3 & A,
+ const Triangle_3 & B,
+ const Index fa,
+ const Index fb,
+ 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
+ inline void box_intersect(const Box& a, const Box& b);
+ inline void process_intersecting_boxes();
+ public:
+ // Getters:
+ //const IndexList& get_lIF() const{ return lIF;}
+ static inline void box_intersect_static(
+ SelfIntersectMesh * SIM,
+ const Box &a,
+ const Box &b);
+ private:
+ std::mutex m_offending_lock;
+ };
+ }
+ }
+}
+
+// Implementation
+
+#include "mesh_to_cgal_triangle_list.h"
+#include "remesh_intersections.h"
+
+#include "../../REDRUM.h"
+#include "../../get_seconds.h"
+#include "../../C_STR.h"
+
+
+#include <functional>
+#include <algorithm>
+#include <exception>
+#include <cassert>
+#include <iostream>
+
+// References:
+// http://minregret.googlecode.com/svn/trunk/skyline/src/extern/CGAL-3.3.1/examples/Polyhedron/polyhedron_self_intersection.cpp
+// http://www.cgal.org/Manual/3.9/examples/Boolean_set_operations_2/do_intersect.cpp
+
+// Q: Should we be using CGAL::Polyhedron_3?
+// A: No! Input is just a list of unoriented triangles. Polyhedron_3 requires
+// a 2-manifold.
+// A: But! It seems we could use CGAL::Triangulation_3. Though it won't be easy
+// to take advantage of functions like insert_in_facet because we want to
+// constrain segments. Hmmm. Actually Triangulation_3 doesn't look right...
+
+// CGAL's box_self_intersection_d uses C-style function callbacks without
+// userdata. This is a leapfrog method for calling a member function. It should
+// be bound as if the prototype was:
+// static void box_intersect(const Box &a, const Box &b)
+// using boost:
+// boost::function<void(const Box &a,const Box &b)> cb
+// = boost::bind(&::box_intersect, this, _1,_2);
+//
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline void igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::box_intersect_static(
+ Self * SIM,
+ const typename Self::Box &a,
+ const typename Self::Box &b)
+{
+ SIM->box_intersect(a,b);
+}
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::SelfIntersectMesh(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const RemeshSelfIntersectionsParam & params,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedIF> & IF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM):
+ V(V),
+ F(F),
+ count(0),
+ T(),
+ lIF(),
+ offending(),
+ params(params)
+{
+ using namespace std;
+ using namespace Eigen;
+
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+ const auto & tictoc = []() -> double
+ {
+ static double t_start = igl::get_seconds();
+ double diff = igl::get_seconds()-t_start;
+ t_start += diff;
+ return diff;
+ };
+ const auto log_time = [&](const std::string& label) -> void{
+ std::cout << "SelfIntersectMesh." << label << ": "
+ << tictoc() << std::endl;
+ };
+ tictoc();
+#endif
+
+ // Compute and process self intersections
+ mesh_to_cgal_triangle_list(V,F,T);
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+ log_time("convert_to_triangle_list");
+#endif
+ // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5
+ // Create the corresponding vector of bounding boxes
+ std::vector<Box> boxes;
+ boxes.reserve(T.size());
+ for (
+ TrianglesIterator tit = T.begin();
+ tit != T.end();
+ ++tit)
+ {
+ if (!tit->is_degenerate())
+ {
+ boxes.push_back(Box(tit->bbox(), tit));
+ }
+ }
+ // Leapfrog callback
+ std::function<void(const Box &a,const Box &b)> cb =
+ std::bind(&box_intersect_static, this,
+ // Explicitly use std namespace to avoid confusion with boost (who puts
+ // _1 etc. in global namespace)
+ std::placeholders::_1,
+ std::placeholders::_2);
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+ log_time("box_and_bind");
+#endif
+ // Run the self intersection algorithm with all defaults
+ CGAL::box_self_intersection_d(boxes.begin(), boxes.end(),cb);
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+ log_time("box_intersection_d");
+#endif
+ try{
+ process_intersecting_boxes();
+ }catch(int e)
+ {
+ // Rethrow if not IGL_FIRST_HIT_EXCEPTION
+ if(e != IGL_FIRST_HIT_EXCEPTION)
+ {
+ throw e;
+ }
+ // Otherwise just fall through
+ }
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+ log_time("resolve_intersection");
+#endif
+
+ // Convert lIF to Eigen matrix
+ assert(lIF.size()%2 == 0);
+ IF.resize(lIF.size()/2,2);
+ {
+ Index i=0;
+ for(
+ typename IndexList::const_iterator ifit = lIF.begin();
+ ifit!=lIF.end();
+ )
+ {
+ IF(i,0) = (*ifit);
+ ifit++;
+ IF(i,1) = (*ifit);
+ ifit++;
+ i++;
+ }
+ }
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+ log_time("store_intersecting_face_pairs");
+#endif
+
+ if(params.detect_only)
+ {
+ return;
+ }
+
+ remesh_intersections(
+ V,F,T,offending,params.stitch_all,VV,FF,J,IM);
+
+#ifdef IGL_SELFINTERSECTMESH_DEBUG
+ log_time("remesh_intersection");
+#endif
+}
+
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline void igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::mark_offensive(const Index f)
+{
+ using namespace std;
+ lIF.push_back(f);
+ if(offending.count(f) == 0)
+ {
+ // first time marking, initialize with new id and empty list
+ offending[f] = {};
+ }
+}
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline void igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::count_intersection(
+ const Index fa,
+ const Index fb)
+{
+ std::lock_guard<std::mutex> guard(m_offending_lock);
+ mark_offensive(fa);
+ mark_offensive(fb);
+ this->count++;
+ // We found the first intersection
+ if(params.first_only && this->count >= 1)
+ {
+ throw IGL_FIRST_HIT_EXCEPTION;
+ }
+
+}
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline bool igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::intersect(
+ const Triangle_3 & A,
+ const Triangle_3 & B,
+ const Index fa,
+ const Index fb)
+{
+ // Determine whether there is an intersection
+ if(!CGAL::do_intersect(A,B))
+ {
+ return false;
+ }
+ count_intersection(fa,fb);
+ if(!params.detect_only)
+ {
+ // Construct intersection
+ CGAL::Object result = CGAL::intersection(A,B);
+ std::lock_guard<std::mutex> guard(m_offending_lock);
+ offending[fa].push_back({fb, result});
+ offending[fb].push_back({fa, result});
+ }
+ return true;
+}
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline bool igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::single_shared_vertex(
+ const Triangle_3 & A,
+ const Triangle_3 & B,
+ const Index fa,
+ const Index fb,
+ const Index va,
+ const Index vb)
+{
+ if(single_shared_vertex(A,B,fa,fb,va))
+ {
+ return true;
+ }
+ return single_shared_vertex(B,A,fb,fa,vb);
+}
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline bool igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::single_shared_vertex(
+ const Triangle_3 & A,
+ const Triangle_3 & B,
+ const Index fa,
+ const Index fb,
+ const Index va)
+{
+ // This was not a good idea. It will not handle coplanar triangles well.
+ using namespace std;
+ Segment_3 sa(
+ A.vertex((va+1)%3),
+ A.vertex((va+2)%3));
+
+ if(CGAL::do_intersect(sa,B))
+ {
+ // can't put count_intersection(fa,fb) here since we use intersect below
+ // and then it will be counted twice.
+ if(params.detect_only)
+ {
+ count_intersection(fa,fb);
+ return true;
+ }
+ CGAL::Object result = CGAL::intersection(sa,B);
+ if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
+ {
+ // Single intersection --> segment from shared point to intersection
+ CGAL::Object seg = CGAL::make_object(Segment_3(
+ A.vertex(va),
+ *p));
+ count_intersection(fa,fb);
+ std::lock_guard<std::mutex> guard(m_offending_lock);
+ offending[fa].push_back({fb, seg});
+ offending[fb].push_back({fa, seg});
+ return true;
+ }else if(CGAL::object_cast<Segment_3 >(&result))
+ {
+ // Need to do full test. Intersection could be a general poly.
+ bool test = intersect(A,B,fa,fb);
+ ((void)test);
+ assert(test && "intersect should agree with do_intersect");
+ return true;
+ }else
+ {
+ cerr<<REDRUM("Segment ∩ triangle neither point nor segment?")<<endl;
+ assert(false);
+ }
+ }
+
+ return false;
+}
+
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline bool igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::double_shared_vertex(
+ const Triangle_3 & A,
+ const Triangle_3 & B,
+ const Index fa,
+ const Index fb,
+ const std::vector<std::pair<Index,Index> > shared)
+{
+ using namespace std;
+
+ // must be co-planar
+ if(
+ A.supporting_plane() != B.supporting_plane() &&
+ A.supporting_plane() != B.supporting_plane().opposite())
+ {
+ return false;
+ }
+ // Since A and B are non-degenerate the intersection must be a polygon
+ // (triangle). Either
+ // - the vertex of A (B) opposite the shared edge of lies on B (A), or
+ // - an edge of A intersects and edge of B without sharing a vertex
+ //
+ // Determine if the vertex opposite edge (a0,a1) in triangle A lies in
+ // (intersects) triangle B
+ const auto & opposite_point_inside = [](
+ const Triangle_3 & A, const Index a0, const Index a1, const Triangle_3 & B)
+ -> bool
+ {
+ // get opposite index
+ Index a2 = -1;
+ for(int c = 0;c<3;c++)
+ {
+ if(c != a0 && c != a1)
+ {
+ a2 = c;
+ break;
+ }
+ }
+ assert(a2 != -1);
+ bool ret = CGAL::do_intersect(A.vertex(a2),B);
+ return ret;
+ };
+
+ // Determine if edge opposite vertex va in triangle A intersects edge
+ // opposite vertex vb in triangle B.
+ const auto & opposite_edges_intersect = [](
+ const Triangle_3 & A, const Index va,
+ const Triangle_3 & B, const Index vb) -> bool
+ {
+ Segment_3 sa( A.vertex((va+1)%3), A.vertex((va+2)%3));
+ Segment_3 sb( B.vertex((vb+1)%3), B.vertex((vb+2)%3));
+ bool ret = CGAL::do_intersect(sa,sb);
+ return ret;
+ };
+
+ if(
+ !opposite_point_inside(A,shared[0].first,shared[1].first,B) &&
+ !opposite_point_inside(B,shared[0].second,shared[1].second,A) &&
+ !opposite_edges_intersect(A,shared[0].first,B,shared[1].second) &&
+ !opposite_edges_intersect(A,shared[1].first,B,shared[0].second))
+ {
+ return false;
+ }
+
+ // there is an intersection indeed
+ count_intersection(fa,fb);
+ if(params.detect_only)
+ {
+ return true;
+ }
+ // Construct intersection
+ try
+ {
+ // This can fail for Epick but not Epeck
+ CGAL::Object result = CGAL::intersection(A,B);
+ if(!result.empty())
+ {
+ if(CGAL::object_cast<Segment_3 >(&result))
+ {
+ // not coplanar
+ assert(false &&
+ "Co-planar non-degenerate triangles should intersect over triangle");
+ return false;
+ } else if(CGAL::object_cast<Point_3 >(&result))
+ {
+ // this "shouldn't" happen but does for inexact
+ assert(false &&
+ "Co-planar non-degenerate triangles should intersect over triangle");
+ return false;
+ } else
+ {
+ // Triangle object
+ std::lock_guard<std::mutex> guard(m_offending_lock);
+ offending[fa].push_back({fb, result});
+ offending[fb].push_back({fa, result});
+ return true;
+ }
+ }else
+ {
+ // CGAL::intersection is disagreeing with do_intersect
+ assert(false && "CGAL::intersection should agree with predicate tests");
+ return false;
+ }
+ }catch(...)
+ {
+ // This catches some cgal assertion:
+ // CGAL error: assertion violation!
+ // Expression : is_finite(d)
+ // File : /opt/local/include/CGAL/GMP/Gmpq_type.h
+ // Line : 132
+ // Explanation:
+ // But only if NDEBUG is not defined, otherwise there's an uncaught
+ // "Floating point exception: 8" SIGFPE
+ return false;
+ }
+ // No intersection.
+ return false;
+}
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline void igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::box_intersect(
+ const Box& a,
+ const Box& b)
+{
+ candidate_triangle_pairs.push_back({a.handle(), b.handle()});
+}
+
+template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+inline void igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>::process_intersecting_boxes()
+{
+ std::vector<std::mutex> triangle_locks(T.size());
+ std::vector<std::mutex> vertex_locks(V.rows());
+ std::mutex index_lock;
+ std::mutex exception_mutex;
+ bool exception_fired = false;
+ int exception = -1;
+ auto process_chunk =
+ [&](
+ const size_t first,
+ const size_t last) -> void
+ {
+ try
+ {
+ assert(last >= first);
+
+ for (size_t i=first; i<last; i++)
+ {
+ if(exception_fired) return;
+ Index fa=T.size(), fb=T.size();
+ {
+ // Before knowing which triangles are involved, we need to lock
+ // everything to prevent race condition in updating reference
+ // counters.
+ std::lock_guard<std::mutex> guard(index_lock);
+ const auto& tri_pair = candidate_triangle_pairs[i];
+ fa = tri_pair.first - T.begin();
+ fb = tri_pair.second - T.begin();
+ }
+ assert(fa < T.size());
+ assert(fb < T.size());
+
+ // Lock triangles
+ std::lock_guard<std::mutex> guard_A(triangle_locks[fa]);
+ std::lock_guard<std::mutex> guard_B(triangle_locks[fb]);
+
+ // Lock vertices
+ std::list<std::lock_guard<std::mutex> > guard_vertices;
+ {
+ std::vector<typename DerivedF::Scalar> unique_vertices;
+ std::vector<size_t> tmp1, tmp2;
+ igl::unique({F(fa,0), F(fa,1), F(fa,2), F(fb,0), F(fb,1), F(fb,2)},
+ unique_vertices, tmp1, tmp2);
+ std::for_each(unique_vertices.begin(), unique_vertices.end(),
+ [&](const typename DerivedF::Scalar& vi) {
+ guard_vertices.emplace_back(vertex_locks[vi]);
+ });
+ }
+ if(exception_fired) return;
+
+ const Triangle_3& A = T[fa];
+ const Triangle_3& B = T[fb];
+
+ // Number of combinatorially shared vertices
+ Index comb_shared_vertices = 0;
+ // Number of geometrically shared vertices (*not* including
+ // combinatorially shared)
+ Index geo_shared_vertices = 0;
+ // Keep track of shared vertex indices
+ std::vector<std::pair<Index,Index> > shared;
+ Index ea,eb;
+ for(ea=0;ea<3;ea++)
+ {
+ for(eb=0;eb<3;eb++)
+ {
+ if(F(fa,ea) == F(fb,eb))
+ {
+ comb_shared_vertices++;
+ shared.emplace_back(ea,eb);
+ }else if(A.vertex(ea) == B.vertex(eb))
+ {
+ geo_shared_vertices++;
+ shared.emplace_back(ea,eb);
+ }
+ }
+ }
+ const Index total_shared_vertices =
+ comb_shared_vertices + geo_shared_vertices;
+ if(exception_fired) return;
+
+ if(comb_shared_vertices== 3)
+ {
+ assert(shared.size() == 3);
+ // Combinatorially duplicate face, these should be removed by
+ // preprocessing
+ continue;
+ }
+ if(total_shared_vertices== 3)
+ {
+ assert(shared.size() == 3);
+ // Geometrically duplicate face, these should be removed by
+ // preprocessing
+ continue;
+ }
+ if(total_shared_vertices == 2)
+ {
+ assert(shared.size() == 2);
+ // Q: What about coplanar?
+ //
+ // o o
+ // |\ /|
+ // | \/ |
+ // | /\ |
+ // |/ \|
+ // o----o
+ double_shared_vertex(A,B,fa,fb,shared);
+ continue;
+ }
+ assert(total_shared_vertices<=1);
+ if(total_shared_vertices==1)
+ {
+ single_shared_vertex(A,B,fa,fb,shared[0].first,shared[0].second);
+ }else
+ {
+ intersect(A,B,fa,fb);
+ }
+ }
+ }catch(int e)
+ {
+ std::lock_guard<std::mutex> exception_lock(exception_mutex);
+ exception_fired = true;
+ exception = e;
+ }
+ };
+ size_t num_threads=0;
+ const size_t hardware_limit = std::thread::hardware_concurrency();
+ if (const char* igl_num_threads = std::getenv("LIBIGL_NUM_THREADS")) {
+ num_threads = atoi(igl_num_threads);
+ }
+ if (num_threads == 0 || num_threads > hardware_limit) {
+ num_threads = hardware_limit;
+ }
+ assert(num_threads > 0);
+ const size_t num_pairs = candidate_triangle_pairs.size();
+ const size_t chunk_size = num_pairs / num_threads;
+ std::vector<std::thread> threads;
+ for (size_t i=0; i<num_threads-1; i++)
+ {
+ threads.emplace_back(process_chunk, i*chunk_size, (i+1)*chunk_size);
+ }
+ // Do some work in the master thread.
+ process_chunk((num_threads-1)*chunk_size, num_pairs);
+ for (auto& t : threads)
+ {
+ if (t.joinable()) t.join();
+ }
+ if(exception_fired) throw exception;
+ //process_chunk(0, candidate_triangle_pairs.size());
+}
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/assign.cpp b/xs/src/igl/copyleft/cgal/assign.cpp
new file mode 100644
index 000000000..0631b58a7
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/assign.cpp
@@ -0,0 +1,80 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "assign.h"
+#include "assign_scalar.h"
+
+template <typename DerivedC, typename DerivedD>
+IGL_INLINE void igl::copyleft::cgal::assign(
+ const Eigen::MatrixBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedD> & D)
+{
+ D.resizeLike(C);
+ for(int i = 0;i<C.rows();i++)
+ {
+ for(int j = 0;j<C.cols();j++)
+ {
+ assign_scalar(C(i,j),D(i,j));
+ }
+ }
+}
+
+template <typename ReturnScalar, typename DerivedC>
+IGL_INLINE
+Eigen::Matrix<
+ ReturnScalar,
+ DerivedC::RowsAtCompileTime,
+ DerivedC::ColsAtCompileTime,
+ 1,
+ DerivedC::MaxRowsAtCompileTime,
+ DerivedC::MaxColsAtCompileTime>
+igl::copyleft::cgal::assign(
+ const Eigen::MatrixBase<DerivedC> & C)
+{
+ Eigen::Matrix<
+ ReturnScalar,
+ DerivedC::RowsAtCompileTime,
+ DerivedC::ColsAtCompileTime,
+ 1,
+ DerivedC::MaxRowsAtCompileTime,
+ DerivedC::MaxColsAtCompileTime> D;
+ assign(C,D);
+ return D;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> >&);
+template void igl::copyleft::cgal::assign<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<double, 8, 3, 0, 8, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/assign.h b/xs/src/igl/copyleft/cgal/assign.h
new file mode 100644
index 000000000..db9081f23
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/assign.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_ASSIGN_H
+#define IGL_COPYLEFT_CGAL_ASSIGN_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ template <typename DerivedC, typename DerivedD>
+ IGL_INLINE void assign(
+ const Eigen::MatrixBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedD> & D);
+ template <typename ReturnScalar, typename DerivedC>
+ IGL_INLINE
+ Eigen::Matrix<
+ ReturnScalar,
+ DerivedC::RowsAtCompileTime,
+ DerivedC::ColsAtCompileTime,
+ 1,
+ DerivedC::MaxRowsAtCompileTime,
+ DerivedC::MaxColsAtCompileTime>
+ assign(
+ const Eigen::MatrixBase<DerivedC> & C);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "assign.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/assign_scalar.cpp b/xs/src/igl/copyleft/cgal/assign_scalar.cpp
new file mode 100644
index 000000000..c38ee03a1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/assign_scalar.cpp
@@ -0,0 +1,136 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "assign_scalar.h"
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Epeck::FT & cgal,
+ CGAL::Epeck::FT & d)
+{
+ d = cgal;
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Epeck::FT & _cgal,
+ double & d)
+{
+ // FORCE evaluation of the exact type otherwise interval might be huge.
+ const CGAL::Epeck::FT cgal = _cgal.exact();
+ const auto interval = CGAL::to_interval(cgal);
+ d = interval.first;
+ do {
+ const double next = nextafter(d, interval.second);
+ if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+ d = next;
+ } while (d < interval.second);
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Epeck::FT & _cgal,
+ float& d)
+{
+ // FORCE evaluation of the exact type otherwise interval might be huge.
+ const CGAL::Epeck::FT cgal = _cgal.exact();
+ const auto interval = CGAL::to_interval(cgal);
+ d = interval.first;
+ do {
+ const float next = nextafter(d, float(interval.second));
+ if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+ d = next;
+ } while (d < float(interval.second));
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const double & c,
+ double & d)
+{
+ d = c;
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const float& c,
+ float& d)
+{
+ d = c;
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const float& c,
+ double& d)
+{
+ d = c;
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
+ CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & d)
+{
+ d = cgal;
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
+ double & d)
+{
+ const auto interval = CGAL::to_interval(cgal);
+ d = interval.first;
+ do {
+ const double next = nextafter(d, interval.second);
+ if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+ d = next;
+ } while (d < interval.second);
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
+ float& d)
+{
+ const auto interval = CGAL::to_interval(cgal);
+ d = interval.first;
+ do {
+ const float next = nextafter(d, float(interval.second));
+ if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+ d = next;
+ } while (d < float(interval.second));
+}
+
+#ifndef WIN32
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+ CGAL::Simple_cartesian<mpq_class>::FT & d)
+{
+ d = cgal;
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+ double & d)
+{
+ const auto interval = CGAL::to_interval(cgal);
+ d = interval.first;
+ do {
+ const double next = nextafter(d, interval.second);
+ if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+ d = next;
+ } while (d < interval.second);
+}
+
+IGL_INLINE void igl::copyleft::cgal::assign_scalar(
+ const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+ float& d)
+{
+ const auto interval = CGAL::to_interval(cgal);
+ d = interval.first;
+ do {
+ const float next = nextafter(d, float(interval.second));
+ if (CGAL::abs(cgal-d) < CGAL::abs(cgal-next)) break;
+ d = next;
+ } while (d < float(interval.second));
+}
+
+#endif // WIN32
diff --git a/xs/src/igl/copyleft/cgal/assign_scalar.h b/xs/src/igl/copyleft/cgal/assign_scalar.h
new file mode 100644
index 000000000..feec928d5
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/assign_scalar.h
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
+#define IGL_COPYLEFT_CGAL_ASSIGN_SCALAR_H
+#include "../../igl_inline.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel_with_sqrt.h>
+#ifndef WIN32
+#include <CGAL/gmpxx.h>
+#endif
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Inputs:
+ // cgal cgal scalar
+ // Outputs:
+ // d output scalar
+ IGL_INLINE void assign_scalar(
+ const CGAL::Epeck::FT & cgal,
+ CGAL::Epeck::FT & d);
+ IGL_INLINE void assign_scalar(
+ const CGAL::Epeck::FT & cgal,
+ double & d);
+ IGL_INLINE void assign_scalar(
+ const CGAL::Epeck::FT & cgal,
+ float& d);
+ IGL_INLINE void assign_scalar(
+ const double & c,
+ double & d);
+ IGL_INLINE void assign_scalar(
+ const float& c,
+ float & d);
+ IGL_INLINE void assign_scalar(
+ const float& c,
+ double& d);
+
+ 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);
+ IGL_INLINE void assign_scalar(
+ const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
+ double & d);
+ IGL_INLINE void assign_scalar(
+ const CGAL::Exact_predicates_exact_constructions_kernel_with_sqrt::FT & cgal,
+ float& d);
+
+#ifndef WIN32
+ IGL_INLINE void assign_scalar(
+ const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+ CGAL::Simple_cartesian<mpq_class>::FT & d);
+ IGL_INLINE void assign_scalar(
+ const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+ double & d);
+ IGL_INLINE void assign_scalar(
+ const CGAL::Simple_cartesian<mpq_class>::FT & cgal,
+ float& d);
+#endif // WIN32
+
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "assign_scalar.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/barycenter.cpp b/xs/src/igl/copyleft/cgal/barycenter.cpp
new file mode 100644
index 000000000..b3ed8aeaf
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/barycenter.cpp
@@ -0,0 +1,15 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "../../barycenter.h"
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#ifdef IGL_STATIC_LIBRARY
+#undef IGL_STATIC_LIBRARY
+#include "../../barycenter.cpp"
+template void igl::barycenter<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/cell_adjacency.cpp b/xs/src/igl/copyleft/cgal/cell_adjacency.cpp
new file mode 100644
index 000000000..1824a37c8
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/cell_adjacency.cpp
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+
+#include "cell_adjacency.h"
+
+template <typename DerivedC>
+IGL_INLINE void igl::copyleft::cgal::cell_adjacency(
+ const Eigen::PlainObjectBase<DerivedC>& per_patch_cells,
+ const size_t num_cells,
+ std::vector<std::set<std::tuple<typename DerivedC::Scalar, bool, size_t> > >&
+ adjacency_list) {
+
+ const size_t num_patches = per_patch_cells.rows();
+ adjacency_list.resize(num_cells);
+ for (size_t i=0; i<num_patches; i++) {
+ const int positive_cell = per_patch_cells(i,0);
+ const int negative_cell = per_patch_cells(i,1);
+ adjacency_list[positive_cell].emplace(negative_cell, false, i);
+ adjacency_list[negative_cell].emplace(positive_cell, true, i);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::copyleft::cgal::cell_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, std::vector<std::set<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long>, std::less<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> >, std::allocator<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> > >, std::allocator<std::set<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long>, std::less<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> >, std::allocator<std::tuple<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, bool, unsigned long> > > > >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::cell_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, class std::vector<class std::set<class std::tuple<int, bool, unsigned __int64>, struct std::less<class std::tuple<int, bool, unsigned __int64>>, class std::allocator<class std::tuple<int, bool, unsigned __int64>>>, class std::allocator<class std::set<class std::tuple<int, bool, unsigned __int64>, struct std::less<class std::tuple<int, bool, unsigned __int64>>, class std::allocator<class std::tuple<int, bool, unsigned __int64>>>>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/cell_adjacency.h b/xs/src/igl/copyleft/cgal/cell_adjacency.h
new file mode 100644
index 000000000..2244d3c4a
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/cell_adjacency.h
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_CGAL_CELL_ADJACENCY_H
+#define IGL_COPYLEFT_CGAL_CELL_ADJACENCY_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <set>
+#include <tuple>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ 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}
+ template < typename DerivedC >
+ IGL_INLINE void cell_adjacency(
+ const Eigen::PlainObjectBase<DerivedC>& per_patch_cells,
+ const size_t num_cells,
+ std::vector<std::set<std::tuple<typename DerivedC::Scalar, bool, size_t> > >&
+ adjacency_list);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cell_adjacency.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/closest_facet.cpp b/xs/src/igl/copyleft/cgal/closest_facet.cpp
new file mode 100644
index 000000000..0b08dd4bc
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/closest_facet.cpp
@@ -0,0 +1,504 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#include "closest_facet.h"
+
+#include <vector>
+#include <stdexcept>
+#include <unordered_map>
+
+#include "order_facets_around_edge.h"
+#include "submesh_aabb_tree.h"
+#include "../../vertex_triangle_adjacency.h"
+#include "../../LinSpaced.h"
+//#include "../../writePLY.h"
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedP,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedR,
+ typename DerivedS >
+IGL_INLINE void igl::copyleft::cgal::closest_facet(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedS>& S)
+{
+
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
+ typedef Kernel::Point_3 Point_3;
+ typedef Kernel::Plane_3 Plane_3;
+ typedef Kernel::Segment_3 Segment_3;
+ typedef Kernel::Triangle_3 Triangle;
+ typedef std::vector<Triangle>::iterator Iterator;
+ typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
+ typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
+ typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
+
+ if (F.rows() <= 0 || I.rows() <= 0) {
+ throw std::runtime_error(
+ "Closest facet cannot be computed on empty mesh.");
+ }
+
+ std::vector<std::vector<size_t> > VF, VFi;
+ igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
+ std::vector<bool> in_I;
+ std::vector<Triangle> triangles;
+ Tree tree;
+ submesh_aabb_tree(V,F,I,tree,triangles,in_I);
+
+ return closest_facet(
+ V,F,I,P,uE2E,EMAP,VF,VFi,tree,triangles,in_I,R,S);
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedP,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename Kernel,
+ typename DerivedR,
+ typename DerivedS >
+IGL_INLINE void igl::copyleft::cgal::closest_facet(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ const std::vector<std::vector<size_t> > & VF,
+ const std::vector<std::vector<size_t> > & VFi,
+ const CGAL::AABB_tree<
+ CGAL::AABB_traits<
+ Kernel,
+ CGAL::AABB_triangle_primitive<
+ Kernel, typename std::vector<
+ typename Kernel::Triangle_3 >::iterator > > > & tree,
+ const std::vector<typename Kernel::Triangle_3 > & triangles,
+ const std::vector<bool> & in_I,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedS>& S)
+{
+ typedef typename Kernel::Point_3 Point_3;
+ typedef typename Kernel::Plane_3 Plane_3;
+ typedef typename Kernel::Segment_3 Segment_3;
+ typedef typename Kernel::Triangle_3 Triangle;
+ typedef typename std::vector<Triangle>::iterator Iterator;
+ typedef typename CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
+ typedef typename CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
+ typedef typename CGAL::AABB_tree<AABB_triangle_traits> Tree;
+
+ const size_t num_faces = I.rows();
+ if (F.rows() <= 0 || I.rows() <= 0) {
+ throw std::runtime_error(
+ "Closest facet cannot be computed on empty mesh.");
+ }
+
+ auto on_the_positive_side = [&](size_t fid, const Point_3& p) -> bool
+ {
+ const auto& f = F.row(fid).eval();
+ Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
+ Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
+ Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
+ auto ori = CGAL::orientation(v0, v1, v2, p);
+ switch (ori) {
+ case CGAL::POSITIVE:
+ return true;
+ case CGAL::NEGATIVE:
+ return false;
+ case CGAL::COPLANAR:
+ // Warning:
+ // This can only happen if fid contains a boundary edge.
+ // Categorized this ambiguous case as negative side.
+ return false;
+ default:
+ throw std::runtime_error("Unknown CGAL state.");
+ }
+ return false;
+ };
+
+ auto get_orientation = [&](size_t fid, size_t s, size_t d) -> bool
+ {
+ const auto& f = F.row(fid);
+ if ((size_t)f[0] == s && (size_t)f[1] == d) return false;
+ else if ((size_t)f[1] == s && (size_t)f[2] == d) return false;
+ else if ((size_t)f[2] == s && (size_t)f[0] == d) return false;
+ else if ((size_t)f[0] == d && (size_t)f[1] == s) return true;
+ else if ((size_t)f[1] == d && (size_t)f[2] == s) return true;
+ else if ((size_t)f[2] == d && (size_t)f[0] == s) return true;
+ else {
+ throw std::runtime_error(
+ "Cannot compute orientation due to incorrect connectivity");
+ return false;
+ }
+ };
+ auto index_to_signed_index = [&](size_t index, bool ori) -> int{
+ return (index+1) * (ori? 1:-1);
+ };
+ //auto signed_index_to_index = [&](int signed_index) -> size_t {
+ // return abs(signed_index) - 1;
+ //};
+
+ enum ElementType { VERTEX, EDGE, FACE };
+ auto determine_element_type = [&](const Point_3& p, const size_t fid,
+ size_t& element_index) -> ElementType {
+ const auto& tri = triangles[fid];
+ const Point_3 p0 = tri[0];
+ const Point_3 p1 = tri[1];
+ const Point_3 p2 = tri[2];
+
+ if (p == p0) { element_index = 0; return VERTEX; }
+ if (p == p1) { element_index = 1; return VERTEX; }
+ if (p == p2) { element_index = 2; return VERTEX; }
+ if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
+ if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
+ if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
+
+ element_index = 0;
+ return FACE;
+ };
+
+ auto process_edge_case = [&](
+ size_t query_idx,
+ const size_t s, const size_t d,
+ size_t preferred_facet,
+ bool& orientation) -> size_t
+ {
+ Point_3 query_point(
+ P(query_idx, 0),
+ P(query_idx, 1),
+ P(query_idx, 2));
+
+ size_t corner_idx = std::numeric_limits<size_t>::max();
+ if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 1)) ||
+ (s == F(preferred_facet, 1) && d == F(preferred_facet, 0)))
+ {
+ corner_idx = 2;
+ } else if ((s == F(preferred_facet, 0) && d == F(preferred_facet, 2)) ||
+ (s == F(preferred_facet, 2) && d == F(preferred_facet, 0)))
+ {
+ corner_idx = 1;
+ } else if ((s == F(preferred_facet, 1) && d == F(preferred_facet, 2)) ||
+ (s == F(preferred_facet, 2) && d == F(preferred_facet, 1)))
+ {
+ corner_idx = 0;
+ } else
+ {
+ std::cerr << "s: " << s << "\t d:" << d << std::endl;
+ std::cerr << F.row(preferred_facet) << std::endl;
+ throw std::runtime_error(
+ "Invalid connectivity, edge does not belong to facet");
+ }
+
+ auto ueid = EMAP(preferred_facet + corner_idx * F.rows());
+ auto eids = uE2E[ueid];
+ std::vector<size_t> intersected_face_indices;
+ for (auto eid : eids)
+ {
+ const size_t fid = eid % F.rows();
+ if (in_I[fid])
+ {
+ intersected_face_indices.push_back(fid);
+ }
+ }
+
+ const size_t num_intersected_faces = intersected_face_indices.size();
+ std::vector<int> intersected_face_signed_indices(num_intersected_faces);
+ std::transform(
+ intersected_face_indices.begin(),
+ intersected_face_indices.end(),
+ intersected_face_signed_indices.begin(),
+ [&](size_t index) {
+ return index_to_signed_index(
+ index, get_orientation(index, s,d));
+ });
+
+ assert(num_intersected_faces >= 1);
+ if (num_intersected_faces == 1)
+ {
+ // The edge must be a boundary edge. Thus, the orientation can be
+ // simply determined by checking if the query point is on the
+ // positive side of the facet.
+ const size_t fid = intersected_face_indices[0];
+ orientation = on_the_positive_side(fid, query_point);
+ return fid;
+ }
+
+ Eigen::VectorXi order;
+ DerivedP pivot = P.row(query_idx).eval();
+ igl::copyleft::cgal::order_facets_around_edge(V, F, s, d,
+ intersected_face_signed_indices,
+ pivot, order);
+
+ // Although first and last are equivalent, make the choice based on
+ // preferred_facet.
+ const size_t first = order[0];
+ const size_t last = order[num_intersected_faces-1];
+ if (intersected_face_indices[first] == preferred_facet) {
+ orientation = intersected_face_signed_indices[first] < 0;
+ return intersected_face_indices[first];
+ } else if (intersected_face_indices[last] == preferred_facet) {
+ orientation = intersected_face_signed_indices[last] > 0;
+ return intersected_face_indices[last];
+ } else {
+ orientation = intersected_face_signed_indices[order[0]] < 0;
+ return intersected_face_indices[order[0]];
+ }
+ };
+
+ auto process_face_case = [&](
+ const size_t query_idx, const Point_3& closest_point,
+ const size_t fid, bool& orientation) -> size_t {
+ const auto& f = F.row(I(fid, 0));
+ return process_edge_case(query_idx, f[0], f[1], I(fid, 0), orientation);
+ };
+
+ // Given that the closest point to query point P(query_idx,:) on (V,F(I,:))
+ // is the vertex at V(s,:) which is incident at least on triangle
+ // F(preferred_facet,:), determine a facet incident on V(s,:) that is
+ // _exposed_ to the query point and determine whether that facet is facing
+ // _toward_ or _away_ from the query point.
+ //
+ // Inputs:
+ // query_idx index into P of query point
+ // s index into V of closest point at vertex
+ // preferred_facet facet incident on s
+ // Outputs:
+ // orientation whether returned face is facing toward or away from
+ // query (parity unclear)
+ // Returns face guaranteed to be "exposed" to P(query_idx,:)
+ auto process_vertex_case = [&](
+ const size_t query_idx,
+ size_t s,
+ size_t preferred_facet,
+ bool& orientation) -> size_t
+ {
+ const Point_3 query_point(
+ P(query_idx, 0), P(query_idx, 1), P(query_idx, 2));
+ const Point_3 closest_point(V(s, 0), V(s, 1), V(s, 2));
+ std::vector<size_t> adj_faces;
+ std::vector<size_t> adj_face_corners;
+ {
+ // Gather adj faces to s within I.
+ const auto& all_adj_faces = VF[s];
+ const auto& all_adj_face_corners = VFi[s];
+ const size_t num_all_adj_faces = all_adj_faces.size();
+ for (size_t i=0; i<num_all_adj_faces; i++)
+ {
+ const size_t fid = all_adj_faces[i];
+ // Shouldn't this always be true if I is a full connected component?
+ if (in_I[fid])
+ {
+ adj_faces.push_back(fid);
+ adj_face_corners.push_back(all_adj_face_corners[i]);
+ }
+ }
+ }
+ const size_t num_adj_faces = adj_faces.size();
+ assert(num_adj_faces > 0);
+
+ std::set<size_t> adj_vertices_set;
+ std::unordered_multimap<size_t, size_t> v2f;
+ for (size_t i=0; i<num_adj_faces; i++)
+ {
+ const size_t fid = adj_faces[i];
+ const size_t cid = adj_face_corners[i];
+ const auto& f = F.row(adj_faces[i]);
+ const size_t next = f[(cid+1)%3];
+ const size_t prev = f[(cid+2)%3];
+ adj_vertices_set.insert(next);
+ adj_vertices_set.insert(prev);
+ v2f.insert({{next, fid}, {prev, fid}});
+ }
+ const size_t num_adj_vertices = adj_vertices_set.size();
+ std::vector<size_t> adj_vertices(num_adj_vertices);
+ std::copy(adj_vertices_set.begin(), adj_vertices_set.end(),
+ adj_vertices.begin());
+
+ std::vector<Point_3> adj_points;
+ for (size_t vid : adj_vertices)
+ {
+ adj_points.emplace_back(V(vid,0), V(vid,1), V(vid,2));
+ }
+
+ // A plane is on the exterior if all adj_points lies on or to
+ // one side of the plane.
+ auto is_on_exterior = [&](const Plane_3& separator) -> bool{
+ size_t positive=0;
+ size_t negative=0;
+ size_t coplanar=0;
+ for (const auto& point : adj_points) {
+ switch(separator.oriented_side(point)) {
+ case CGAL::ON_POSITIVE_SIDE:
+ positive++;
+ break;
+ case CGAL::ON_NEGATIVE_SIDE:
+ negative++;
+ break;
+ case CGAL::ON_ORIENTED_BOUNDARY:
+ coplanar++;
+ break;
+ default:
+ throw "Unknown plane-point orientation";
+ }
+ }
+ auto query_orientation = separator.oriented_side(query_point);
+ if (query_orientation == CGAL::ON_ORIENTED_BOUNDARY &&
+ (positive == 0 && negative == 0)) {
+ // All adj vertices and query point are coplanar.
+ // In this case, all separators are equally valid.
+ return true;
+ } else {
+ bool r = (positive == 0 && query_orientation == CGAL::POSITIVE)
+ || (negative == 0 && query_orientation == CGAL::NEGATIVE);
+ return r;
+ }
+ };
+
+ size_t d = std::numeric_limits<size_t>::max();
+ for (size_t i=0; i<num_adj_vertices; i++) {
+ const size_t vi = adj_vertices[i];
+ for (size_t j=i+1; j<num_adj_vertices; j++) {
+ Plane_3 separator(closest_point, adj_points[i], adj_points[j]);
+ if (separator.is_degenerate()) {
+ continue;
+ }
+ if (is_on_exterior(separator)) {
+ if (!CGAL::collinear(
+ query_point, adj_points[i], closest_point)) {
+ d = vi;
+ break;
+ } else {
+ d = adj_vertices[j];
+ assert(!CGAL::collinear(
+ query_point, adj_points[j], closest_point));
+ break;
+ }
+ }
+ }
+ }
+ if (d == std::numeric_limits<size_t>::max()) {
+ Eigen::MatrixXd tmp_vertices(V.rows(), V.cols());
+ for (size_t i=0; i<V.rows(); i++) {
+ for (size_t j=0; j<V.cols(); j++) {
+ tmp_vertices(i,j) = CGAL::to_double(V(i,j));
+ }
+ }
+ Eigen::MatrixXi tmp_faces(adj_faces.size(), 3);
+ for (size_t i=0; i<adj_faces.size(); i++) {
+ tmp_faces.row(i) = F.row(adj_faces[i]);
+ }
+ //igl::writePLY("debug.ply", tmp_vertices, tmp_faces, false);
+ throw std::runtime_error("Invalid vertex neighborhood");
+ }
+ const auto itr = v2f.equal_range(d);
+ assert(itr.first != itr.second);
+
+ return process_edge_case(query_idx, s, d, itr.first->second, orientation);
+ };
+
+ const size_t num_queries = P.rows();
+ R.resize(num_queries, 1);
+ S.resize(num_queries, 1);
+ for (size_t i=0; i<num_queries; i++) {
+ const Point_3 query(P(i,0), P(i,1), P(i,2));
+ auto projection = tree.closest_point_and_primitive(query);
+ const Point_3 closest_point = projection.first;
+ size_t fid = projection.second - triangles.begin();
+ bool fid_ori = false;
+
+ // Gether all facets sharing the closest point.
+ typename std::vector<typename Tree::Primitive_id> intersected_faces;
+ tree.all_intersected_primitives(Segment_3(closest_point, query),
+ std::back_inserter(intersected_faces));
+ const size_t num_intersected_faces = intersected_faces.size();
+ std::vector<size_t> intersected_face_indices(num_intersected_faces);
+ std::transform(intersected_faces.begin(),
+ intersected_faces.end(),
+ intersected_face_indices.begin(),
+ [&](const typename Tree::Primitive_id& itr) -> size_t
+ { return I(itr-triangles.begin(), 0); });
+
+ size_t element_index;
+ auto element_type = determine_element_type(closest_point, fid,
+ element_index);
+ switch(element_type) {
+ case VERTEX:
+ {
+ const auto& f = F.row(I(fid, 0));
+ const size_t s = f[element_index];
+ fid = process_vertex_case(i, s, I(fid, 0), fid_ori);
+ }
+ break;
+ case EDGE:
+ {
+ const auto& f = F.row(I(fid, 0));
+ const size_t s = f[(element_index+1)%3];
+ const size_t d = f[(element_index+2)%3];
+ fid = process_edge_case(i, s, d, I(fid, 0), fid_ori);
+ }
+ break;
+ case FACE:
+ {
+ fid = process_face_case(i, closest_point, fid, fid_ori);
+ }
+ break;
+ default:
+ throw std::runtime_error("Unknown element type.");
+ }
+
+
+ R(i,0) = fid;
+ S(i,0) = fid_ori;
+ }
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedR,
+ typename DerivedS >
+IGL_INLINE void igl::copyleft::cgal::closest_facet(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedS>& S) {
+ const size_t num_faces = F.rows();
+ Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(num_faces, 0, num_faces-1);
+ igl::copyleft::cgal::closest_facet(V, F, I, P, uE2E, EMAP, R, S);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > > const&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::closest_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::closest_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class CGAL::Epeck, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class CGAL::AABB_tree<class CGAL::AABB_traits<class CGAL::Epeck, class CGAL::AABB_triangle_primitive<class CGAL::Epeck, class std::_Vector_iterator<class std::_Vector_val<struct std::_Simple_types<class CGAL::Triangle_3<class CGAL::Epeck>>>>, struct CGAL::Boolean_tag<0>>>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::vector<bool, class std::allocator<bool>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/closest_facet.h b/xs/src/igl/copyleft/cgal/closest_facet.h
new file mode 100644
index 000000000..737ca2e22
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/closest_facet.h
@@ -0,0 +1,110 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLET_CGAL_CLOSEST_FACET_H
+#define IGL_COPYLET_CGAL_CLOSEST_FACET_H
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+#include <CGAL/intersections.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ 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.
+ //
+ // 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.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedP,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedR,
+ typename DerivedS >
+ IGL_INLINE void closest_facet(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedS>& S);
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedR,
+ typename DerivedS >
+ IGL_INLINE void closest_facet(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedS>& S);
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedP,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename Kernel,
+ typename DerivedR,
+ typename DerivedS >
+ IGL_INLINE void closest_facet(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ const std::vector<std::vector<size_t> > & VF,
+ const std::vector<std::vector<size_t> > & VFi,
+ const CGAL::AABB_tree<
+ CGAL::AABB_traits<
+ Kernel,
+ CGAL::AABB_triangle_primitive<
+ Kernel, typename std::vector<
+ typename Kernel::Triangle_3 >::iterator > > > & tree,
+ const std::vector<typename Kernel::Triangle_3 > & triangles,
+ const std::vector<bool> & in_I,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedS>& S);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "closest_facet.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/complex_to_mesh.cpp b/xs/src/igl/copyleft/cgal/complex_to_mesh.cpp
new file mode 100644
index 000000000..74bf085ab
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/complex_to_mesh.cpp
@@ -0,0 +1,152 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "complex_to_mesh.h"
+
+#include "../../centroid.h"
+#include "../../remove_unreferenced.h"
+
+#include <CGAL/Surface_mesh_default_triangulation_3.h>
+#include <CGAL/Delaunay_triangulation_cell_base_with_circumcenter_3.h>
+#include <set>
+#include <stack>
+
+template <typename Tr, typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::copyleft::cgal::complex_to_mesh(
+ const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F)
+{
+ using namespace Eigen;
+ // CGAL/IO/Complex_2_in_triangulation_3_file_writer.h
+ using CGAL::Surface_mesher::number_of_facets_on_surface;
+
+ typedef typename CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
+ typedef typename Tr::Finite_facets_iterator Finite_facets_iterator;
+ typedef typename Tr::Finite_vertices_iterator Finite_vertices_iterator;
+ typedef typename Tr::Facet Facet;
+ typedef typename Tr::Edge Edge;
+ typedef typename Tr::Vertex_handle Vertex_handle;
+
+ // Header.
+ const Tr& tr = c2t3.triangulation();
+
+ bool success = true;
+
+ const int n = tr.number_of_vertices();
+ const int m = c2t3.number_of_facets();
+
+ assert(m == number_of_facets_on_surface(tr));
+
+ // Finite vertices coordinates.
+ std::map<Vertex_handle, int> v2i;
+ V.resize(n,3);
+ {
+ int v = 0;
+ for(Finite_vertices_iterator vit = tr.finite_vertices_begin();
+ vit != tr.finite_vertices_end();
+ ++vit)
+ {
+ V(v,0) = vit->point().x();
+ V(v,1) = vit->point().y();
+ V(v,2) = vit->point().z();
+ v2i[vit] = v++;
+ }
+ }
+
+ {
+ Finite_facets_iterator fit = tr.finite_facets_begin();
+ std::set<Facet> oriented_set;
+ std::stack<Facet> stack;
+
+ while ((int)oriented_set.size() != m)
+ {
+ while ( fit->first->is_facet_on_surface(fit->second) == false ||
+ oriented_set.find(*fit) != oriented_set.end() ||
+ oriented_set.find(c2t3.opposite_facet(*fit)) !=
+ oriented_set.end() )
+ {
+ ++fit;
+ }
+ oriented_set.insert(*fit);
+ stack.push(*fit);
+ while(! stack.empty() )
+ {
+ Facet f = stack.top();
+ stack.pop();
+ for(int ih = 0 ; ih < 3 ; ++ih)
+ {
+ const int i1 = tr.vertex_triple_index(f.second, tr. cw(ih));
+ const int i2 = tr.vertex_triple_index(f.second, tr.ccw(ih));
+
+ const typename C2t3::Face_status face_status
+ = c2t3.face_status(Edge(f.first, i1, i2));
+ if(face_status == C2t3::REGULAR)
+ {
+ Facet fn = c2t3.neighbor(f, ih);
+ if (oriented_set.find(fn) == oriented_set.end())
+ {
+ if(oriented_set.find(c2t3.opposite_facet(fn)) == oriented_set.end())
+ {
+ oriented_set.insert(fn);
+ stack.push(fn);
+ }else {
+ success = false; // non-orientable
+ }
+ }
+ }else if(face_status != C2t3::BOUNDARY)
+ {
+ success = false; // non manifold, thus non-orientable
+ }
+ } // end "for each neighbor of f"
+ } // end "stack non empty"
+ } // end "oriented_set not full"
+
+ F.resize(m,3);
+ int f = 0;
+ for(typename std::set<Facet>::const_iterator fit =
+ oriented_set.begin();
+ fit != oriented_set.end();
+ ++fit)
+ {
+ const typename Tr::Cell_handle cell = fit->first;
+ const int& index = fit->second;
+ const int index1 = v2i[cell->vertex(tr.vertex_triple_index(index, 0))];
+ const int index2 = v2i[cell->vertex(tr.vertex_triple_index(index, 1))];
+ const int index3 = v2i[cell->vertex(tr.vertex_triple_index(index, 2))];
+ // This order is flipped
+ F(f,0) = index1;
+ F(f,1) = index2;
+ F(f,2) = index3;
+ f++;
+ }
+ assert(f == m);
+ } // end if(facets must be oriented)
+
+ // This CGAL code seems to randomly assign the global orientation
+ // Flip based on the signed volume.
+ Eigen::Vector3d cen;
+ double vol;
+ igl::centroid(V,F,cen,vol);
+ if(vol < 0)
+ {
+ // Flip
+ F = F.rowwise().reverse().eval();
+ }
+
+ // CGAL code somehow can end up with unreferenced vertices
+ {
+ VectorXi _1;
+ remove_unreferenced( MatrixXd(V), MatrixXi(F), V,F,_1);
+ }
+
+ return success;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::copyleft::cgal::complex_to_mesh<CGAL::Delaunay_triangulation_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_data_structure_3<CGAL::Surface_mesh_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_vertex_base_3<void> > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Surface_mesh_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_cell_base_3<void> > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Complex_2_in_triangulation_3<CGAL::Delaunay_triangulation_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_data_structure_3<CGAL::Surface_mesh_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_vertex_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_vertex_base_3<void> > >, CGAL::Delaunay_triangulation_cell_base_with_circumcenter_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Surface_mesh_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_cell_base_3<CGAL::Robust_circumcenter_traits_3<CGAL::Epick>, CGAL::Triangulation_ds_cell_base_3<void> > > >, CGAL::Sequential_tag>, CGAL::Default, CGAL::Default>, void> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/complex_to_mesh.h b/xs/src/igl/copyleft/cgal/complex_to_mesh.h
new file mode 100644
index 000000000..ed66064b7
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/complex_to_mesh.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_COMPLEX_TO_MESH_H
+#define IGL_COPYLEFT_CGAL_COMPLEX_TO_MESH_H
+#include "../../igl_inline.h"
+
+#include <Eigen/Dense>
+#include <CGAL/Complex_2_in_triangulation_3.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ 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.
+ //
+ template <typename Tr, typename DerivedV, typename DerivedF>
+ IGL_INLINE bool complex_to_mesh(
+ const CGAL::Complex_2_in_triangulation_3<Tr> & c2t3,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "complex_to_mesh.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/component_inside_component.cpp b/xs/src/igl/copyleft/cgal/component_inside_component.cpp
new file mode 100644
index 000000000..251e91949
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/component_inside_component.cpp
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "component_inside_component.h"
+
+#include "order_facets_around_edge.h"
+#include "../../LinSpaced.h"
+#include "points_inside_component.h"
+
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#include <cassert>
+#include <list>
+#include <limits>
+#include <vector>
+
+template <typename DerivedV, typename DerivedF, typename DerivedI>
+IGL_INLINE bool igl::copyleft::cgal::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) {
+ if (F1.rows() <= 0 || I1.rows() <= 0 || F2.rows() <= 0 || I2.rows() <= 0) {
+ throw "Component inside test cannot be done on empty component!";
+ }
+
+ const Eigen::Vector3i& f = F1.row(I1(0, 0));
+ const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> query(
+ (V1(f[0],0) + V1(f[1],0) + V1(f[2],0))/3.0,
+ (V1(f[0],1) + V1(f[1],1) + V1(f[2],1))/3.0,
+ (V1(f[0],2) + V1(f[1],2) + V1(f[2],2))/3.0);
+ Eigen::VectorXi inside;
+ igl::copyleft::cgal::points_inside_component(V2, F2, I2, query, inside);
+ assert(inside.size() == 1);
+ return inside[0];
+}
+
+template<typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::copyleft::cgal::component_inside_component(
+ const Eigen::PlainObjectBase<DerivedV>& V1,
+ const Eigen::PlainObjectBase<DerivedF>& F1,
+ const Eigen::PlainObjectBase<DerivedV>& V2,
+ const Eigen::PlainObjectBase<DerivedF>& F2) {
+ if (F1.rows() <= 0 || F2.rows() <= 0) {
+ throw "Component inside test cannot be done on empty component!";
+ }
+ Eigen::VectorXi I1(F1.rows()), I2(F2.rows());
+ I1 = igl::LinSpaced<Eigen::VectorXi>(F1.rows(), 0, F1.rows()-1);
+ I2 = igl::LinSpaced<Eigen::VectorXi>(F2.rows(), 0, F2.rows()-1);
+ return igl::copyleft::cgal::component_inside_component(V1, F1, I1, V2, F2, I2);
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::copyleft::cgal::component_inside_component<
+Eigen::Matrix<double, -1, -1, 0, -1, -1>,
+Eigen::Matrix< int, -1, -1, 0, -1, -1>,
+Eigen::Matrix< int, -1, -1, 0, -1, -1> > (
+Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&);
+
+template bool igl::copyleft::cgal::component_inside_component<
+Eigen::Matrix<double, -1, -1, 0, -1, -1>,
+Eigen::Matrix< int, -1, -1, 0, -1, -1> > (
+Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
+Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/component_inside_component.h b/xs/src/igl/copyleft/cgal/component_inside_component.h
new file mode 100644
index 000000000..17fdd6255
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/component_inside_component.h
@@ -0,0 +1,75 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT
+#define IGL_COPYLEFT_CGAL_COMONENT_INSIDE_COMPONENT
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+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);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "component_inside_component.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/convex_hull.cpp b/xs/src/igl/copyleft/cgal/convex_hull.cpp
new file mode 100644
index 000000000..8f89d5593
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/convex_hull.cpp
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "convex_hull.h"
+#include "../../ismember.h"
+#include "polyhedron_to_mesh.h"
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Polyhedron_3.h>
+#include <CGAL/Surface_mesh.h>
+#include <CGAL/convex_hull_3.h>
+#include <vector>
+
+template <
+ typename DerivedV,
+ typename DerivedW,
+ typename DerivedG>
+IGL_INLINE void igl::copyleft::cgal::convex_hull(
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedW> & W,
+ Eigen::PlainObjectBase<DerivedG> & G)
+{
+ typedef CGAL::Exact_predicates_inexact_constructions_kernel K;
+ typedef K::Point_3 Point_3;
+ //typedef CGAL::Delaunay_triangulation_3<K> Delaunay;
+ //typedef Delaunay::Vertex_handle Vertex_handle;
+ //typedef CGAL::Surface_mesh<Point_3> Surface_mesh;
+ typedef CGAL::Polyhedron_3<K> Polyhedron_3;
+ std::vector<Point_3> points(V.rows());
+ for(int i = 0;i<V.rows();i++)
+ {
+ points[i] = Point_3(V(i,0),V(i,1),V(i,2));
+ }
+ Polyhedron_3 poly;
+ CGAL::convex_hull_3(points.begin(),points.end(),poly);
+ assert(poly.is_pure_triangle() && "Assuming CGAL outputs a triangle mesh");
+ polyhedron_to_mesh(poly,W,G);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE void igl::copyleft::cgal::convex_hull(
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F)
+{
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> W;
+ Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, Eigen::Dynamic> G;
+ convex_hull(V,W,G);
+ // This is a lazy way to reindex into the original mesh
+ Eigen::Matrix<bool,Eigen::Dynamic,1> I;
+ Eigen::VectorXi J;
+ igl::ismember_rows(W,V,I,J);
+ assert(I.all() && "Should find all W in V");
+ F.resizeLike(G);
+ for(int f = 0;f<G.rows();f++)
+ {
+ for(int c = 0;c<3;c++)
+ {
+ F(f,c) = J(G(f,c));
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::convex_hull<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/convex_hull.h b/xs/src/igl/copyleft/cgal/convex_hull.h
new file mode 100644
index 000000000..ba04dd7cc
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/convex_hull.h
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_CONVEX_HULL_H
+#define IGL_COPYLEFT_CGAL_CONVEX_HULL_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ 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
+ template <
+ typename DerivedV,
+ typename DerivedW,
+ typename DerivedG>
+ IGL_INLINE void convex_hull(
+ 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
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE void convex_hull(
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "convex_hull.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/delaunay_triangulation.cpp b/xs/src/igl/copyleft/cgal/delaunay_triangulation.cpp
new file mode 100644
index 000000000..787f79f9e
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/delaunay_triangulation.cpp
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "delaunay_triangulation.h"
+#include "../../delaunay_triangulation.h"
+#include "orient2D.h"
+#include "incircle.h"
+
+template<
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE void igl::copyleft::cgal::delaunay_triangulation(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ typedef typename DerivedV::Scalar Scalar;
+ igl::delaunay_triangulation(V, orient2D<Scalar>, incircle<Scalar>, F);
+ // This function really exists to test our igl::delaunay_triangulation
+ //
+ // It's currently much faster to call cgal's native Delaunay routine
+ //
+//#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+//#include <CGAL/Delaunay_triangulation_2.h>
+//#include <CGAL/Triangulation_vertex_base_with_info_2.h>
+//#include <vector>
+// const auto delaunay =
+// [&](const Eigen::MatrixXd & V,Eigen::MatrixXi & F)
+// {
+// typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+// typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
+// typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
+// typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
+// typedef Kernel::Point_2 Point;
+// std::vector< std::pair<Point,unsigned> > points(V.rows());
+// for(int i = 0;i<V.rows();i++)
+// {
+// points[i] = std::make_pair(Point(V(i,0),V(i,1)),i);
+// }
+// Delaunay triangulation;
+// triangulation.insert(points.begin(),points.end());
+// F.resize(triangulation.number_of_faces(),3);
+// {
+// int j = 0;
+// for(Delaunay::Finite_faces_iterator fit = triangulation.finite_faces_begin();
+// fit != triangulation.finite_faces_end(); ++fit)
+// {
+// Delaunay::Face_handle face = fit;
+// F(j,0) = face->vertex(0)->info();
+// F(j,1) = face->vertex(1)->info();
+// F(j,2) = face->vertex(2)->info();
+// j++;
+// }
+// }
+// };
+}
+
diff --git a/xs/src/igl/copyleft/cgal/delaunay_triangulation.h b/xs/src/igl/copyleft/cgal/delaunay_triangulation.h
new file mode 100644
index 000000000..88cbf9fe0
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/delaunay_triangulation.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H
+#define IGL_COPYLEFT_CGAL_DELAUNAY_TRIANGULATION_H
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ 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.
+ template<
+ typename DerivedV,
+ typename DerivedF
+ >
+ IGL_INLINE void delaunay_triangulation(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ }
+ }
+}
+
+
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "delaunay_triangulation.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/extract_cells.cpp b/xs/src/igl/copyleft/cgal/extract_cells.cpp
new file mode 100644
index 000000000..a314edfae
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/extract_cells.cpp
@@ -0,0 +1,547 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#include "extract_cells.h"
+#include "closest_facet.h"
+#include "order_facets_around_edge.h"
+#include "outer_facet.h"
+#include "submesh_aabb_tree.h"
+#include "../../extract_manifold_patches.h"
+#include "../../facet_components.h"
+#include "../../get_seconds.h"
+#include "../../triangle_triangle_adjacency.h"
+#include "../../unique_edge_map.h"
+#include "../../vertex_triangle_adjacency.h"
+
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+#include <CGAL/intersections.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#include <iostream>
+#include <vector>
+#include <queue>
+#include <map>
+#include <set>
+
+//#define EXTRACT_CELLS_DEBUG
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedC >
+IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedC>& cells)
+{
+ const size_t num_faces = F.rows();
+ // Construct edge adjacency
+ Eigen::MatrixXi E, uE;
+ Eigen::VectorXi EMAP;
+ std::vector<std::vector<size_t> > uE2E;
+ igl::unique_edge_map(F, E, uE, EMAP, uE2E);
+ // Cluster into manifold patches
+ Eigen::VectorXi P;
+ igl::extract_manifold_patches(F, EMAP, uE2E, P);
+ // Extract cells
+ DerivedC per_patch_cells;
+ const size_t num_cells =
+ igl::copyleft::cgal::extract_cells(V,F,P,E,uE,uE2E,EMAP,per_patch_cells);
+ // Distribute per-patch cell information to each face
+ cells.resize(num_faces, 2);
+ for (size_t i=0; i<num_faces; i++)
+ {
+ cells.row(i) = per_patch_cells.row(P[i]);
+ }
+ return num_cells;
+}
+
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedE,
+ typename DeriveduE,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedC >
+IGL_INLINE size_t igl::copyleft::cgal::extract_cells(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const Eigen::PlainObjectBase<DerivedE>& E,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedC>& cells)
+{
+ // Trivial base case
+ if(P.size() == 0)
+ {
+ assert(F.size() == 0);
+ cells.resize(0,2);
+ return 0;
+ }
+
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
+ typedef Kernel::Point_3 Point_3;
+ typedef Kernel::Plane_3 Plane_3;
+ typedef Kernel::Segment_3 Segment_3;
+ typedef Kernel::Triangle_3 Triangle;
+ typedef std::vector<Triangle>::iterator Iterator;
+ typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
+ typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
+ typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
+
+#ifdef EXTRACT_CELLS_DEBUG
+ const auto & tictoc = []() -> double
+ {
+ static double t_start = igl::get_seconds();
+ double diff = igl::get_seconds()-t_start;
+ t_start += diff;
+ return diff;
+ };
+ const auto log_time = [&](const std::string& label) -> void {
+ std::cout << "extract_cells." << label << ": "
+ << tictoc() << std::endl;
+ };
+ tictoc();
+#else
+ // no-op
+ const auto log_time = [](const std::string){};
+#endif
+ const size_t num_faces = F.rows();
+ typedef typename DerivedF::Scalar Index;
+ assert(P.size() > 0);
+ const size_t num_patches = P.maxCoeff()+1;
+
+ // Extract all cells...
+ DerivedC raw_cells;
+ const size_t num_raw_cells =
+ extract_cells_single_component(V,F,P,uE,uE2E,EMAP,raw_cells);
+ log_time("extract_single_component_cells");
+
+ // Compute triangle-triangle adjacency data-structure
+ std::vector<std::vector<std::vector<Index > > > TT,_1;
+ igl::triangle_triangle_adjacency(E, EMAP, uE2E, false, TT, _1);
+ log_time("compute_face_adjacency");
+
+ // Compute connected components of the mesh
+ Eigen::VectorXi C, counts;
+ igl::facet_components(TT, C, counts);
+ log_time("form_components");
+
+ const size_t num_components = counts.size();
+ // components[c] --> list of face indices into F of faces in component c
+ std::vector<std::vector<size_t> > components(num_components);
+ // Loop over all faces
+ for (size_t i=0; i<num_faces; i++)
+ {
+ components[C[i]].push_back(i);
+ }
+ // Convert vector lists to Eigen lists...
+ // and precompute data-structures for each component
+ std::vector<std::vector<size_t> > VF,VFi;
+ igl::vertex_triangle_adjacency(V.rows(), F, VF, VFi);
+ std::vector<Eigen::VectorXi> Is(num_components);
+ std::vector<
+ CGAL::AABB_tree<
+ CGAL::AABB_traits<
+ Kernel,
+ CGAL::AABB_triangle_primitive<
+ Kernel, std::vector<
+ Kernel::Triangle_3 >::iterator > > > > trees(num_components);
+ std::vector< std::vector<Kernel::Triangle_3 > >
+ triangle_lists(num_components);
+ std::vector<std::vector<bool> > in_Is(num_components);
+
+ // Find outer facets, their orientations and cells for each component
+ Eigen::VectorXi outer_facets(num_components);
+ Eigen::VectorXi outer_facet_orientation(num_components);
+ Eigen::VectorXi outer_cells(num_components);
+ for (size_t i=0; i<num_components; i++)
+ {
+ Is[i].resize(components[i].size());
+ std::copy(components[i].begin(), components[i].end(),Is[i].data());
+ bool flipped;
+ igl::copyleft::cgal::outer_facet(V, F, Is[i], outer_facets[i], flipped);
+ outer_facet_orientation[i] = flipped?1:0;
+ outer_cells[i] = raw_cells(P[outer_facets[i]], outer_facet_orientation[i]);
+ }
+#ifdef EXTRACT_CELLS_DEBUG
+ log_time("outer_facet_per_component");
+#endif
+
+ // Compute barycenter of a triangle in mesh (V,F)
+ //
+ // Inputs:
+ // fid index into F
+ // Returns row-vector of barycenter coordinates
+ const auto get_triangle_center = [&V,&F](const size_t fid)
+ {
+ return ((V.row(F(fid,0))+V.row(F(fid,1))+V.row(F(fid,2)))/3.0).eval();
+ };
+ std::vector<std::vector<size_t> > nested_cells(num_raw_cells);
+ std::vector<std::vector<size_t> > ambient_cells(num_raw_cells);
+ std::vector<std::vector<size_t> > ambient_comps(num_components);
+ // Only bother if there's more than one component
+ if(num_components > 1)
+ {
+ // construct bounding boxes for each component
+ DerivedV bbox_min(num_components, 3);
+ DerivedV bbox_max(num_components, 3);
+ // Assuming our mesh (in exact numbers) fits in the range of double.
+ bbox_min.setConstant(std::numeric_limits<double>::max());
+ bbox_max.setConstant(std::numeric_limits<double>::min());
+ // Loop over faces
+ for (size_t i=0; i<num_faces; i++)
+ {
+ // component of this face
+ const auto comp_id = C[i];
+ const auto& f = F.row(i);
+ for (size_t j=0; j<3; j++)
+ {
+ for(size_t d=0;d<3;d++)
+ {
+ bbox_min(comp_id,d) = std::min(bbox_min(comp_id,d), V(f[j],d));
+ bbox_max(comp_id,d) = std::max(bbox_max(comp_id,d), V(f[j],d));
+ }
+ }
+ }
+ // Return true if box of component ci intersects that of cj
+ const auto bbox_intersects = [&bbox_max,&bbox_min](size_t ci, size_t cj)
+ {
+ return !(
+ bbox_max(ci,0) < bbox_min(cj,0) ||
+ bbox_max(ci,1) < bbox_min(cj,1) ||
+ bbox_max(ci,2) < bbox_min(cj,2) ||
+ bbox_max(cj,0) < bbox_min(ci,0) ||
+ bbox_max(cj,1) < bbox_min(ci,1) ||
+ bbox_max(cj,2) < bbox_min(ci,2));
+ };
+
+ // Loop over components. This section is O(m²)
+ for (size_t i=0; i<num_components; i++)
+ {
+ // List of components that could overlap with component i
+ std::vector<size_t> candidate_comps;
+ candidate_comps.reserve(num_components);
+ // Loop over components
+ for (size_t j=0; j<num_components; j++)
+ {
+ if (i == j) continue;
+ if (bbox_intersects(i,j)) candidate_comps.push_back(j);
+ }
+
+ const size_t num_candidate_comps = candidate_comps.size();
+ if (num_candidate_comps == 0) continue;
+
+ // Build aabb tree for this component.
+ submesh_aabb_tree(V,F,Is[i],trees[i],triangle_lists[i],in_Is[i]);
+
+ // Get query points on each candidate component: barycenter of
+ // outer-facet
+ DerivedV queries(num_candidate_comps, 3);
+ for (size_t j=0; j<num_candidate_comps; j++)
+ {
+ const size_t index = candidate_comps[j];
+ queries.row(j) = get_triangle_center(outer_facets[index]);
+ }
+
+ // Gather closest facets in ith component to each query point and their
+ // orientations
+ const auto& I = Is[i];
+ const auto& tree = trees[i];
+ const auto& in_I = in_Is[i];
+ const auto& triangles = triangle_lists[i];
+
+ Eigen::VectorXi closest_facets, closest_facet_orientations;
+ closest_facet(
+ V,
+ F,
+ I,
+ queries,
+ uE2E,
+ EMAP,
+ VF,
+ VFi,
+ tree,
+ triangles,
+ in_I,
+ closest_facets,
+ closest_facet_orientations);
+ // Loop over all candidates
+ for (size_t j=0; j<num_candidate_comps; j++)
+ {
+ const size_t index = candidate_comps[j];
+ const size_t closest_patch = P[closest_facets[j]];
+ const size_t closest_patch_side = closest_facet_orientations[j] ? 0:1;
+ // The cell id of the closest patch
+ const size_t ambient_cell =
+ raw_cells(closest_patch,closest_patch_side);
+ if (ambient_cell != (size_t)outer_cells[i])
+ {
+ // ---> component index inside component i, because the cell of the
+ // closest facet on i to component index is **not** the same as the
+ // "outer cell" of component i: component index is **not** outside of
+ // component i (therefore it's inside).
+ nested_cells[ambient_cell].push_back(outer_cells[index]);
+ ambient_cells[outer_cells[index]].push_back(ambient_cell);
+ ambient_comps[index].push_back(i);
+ }
+ }
+ }
+ }
+
+#ifdef EXTRACT_CELLS_DEBUG
+ log_time("nested_relationship");
+#endif
+
+ const size_t INVALID = std::numeric_limits<size_t>::max();
+ const size_t INFINITE_CELL = num_raw_cells;
+ std::vector<size_t> embedded_cells(num_raw_cells, INVALID);
+ for (size_t i=0; i<num_components; i++) {
+ const size_t outer_cell = outer_cells[i];
+ const auto& ambient_comps_i = ambient_comps[i];
+ const auto& ambient_cells_i = ambient_cells[outer_cell];
+ const size_t num_ambient_comps = ambient_comps_i.size();
+ assert(num_ambient_comps == ambient_cells_i.size());
+ if (num_ambient_comps > 0) {
+ size_t embedded_comp = INVALID;
+ size_t embedded_cell = INVALID;
+ for (size_t j=0; j<num_ambient_comps; j++) {
+ if (ambient_comps[ambient_comps_i[j]].size() ==
+ num_ambient_comps-1) {
+ embedded_comp = ambient_comps_i[j];
+ embedded_cell = ambient_cells_i[j];
+ break;
+ }
+ }
+ assert(embedded_comp != INVALID);
+ assert(embedded_cell != INVALID);
+ embedded_cells[outer_cell] = embedded_cell;
+ } else {
+ embedded_cells[outer_cell] = INFINITE_CELL;
+ }
+ }
+ for (size_t i=0; i<num_patches; i++) {
+ if (embedded_cells[raw_cells(i,0)] != INVALID) {
+ raw_cells(i,0) = embedded_cells[raw_cells(i, 0)];
+ }
+ if (embedded_cells[raw_cells(i,1)] != INVALID) {
+ raw_cells(i,1) = embedded_cells[raw_cells(i, 1)];
+ }
+ }
+
+ size_t count = 0;
+ std::vector<size_t> mapped_indices(num_raw_cells+1, INVALID);
+ // Always map infinite cell to index 0.
+ mapped_indices[INFINITE_CELL] = count;
+ count++;
+
+ for (size_t i=0; i<num_patches; i++) {
+ const size_t old_positive_cell_id = raw_cells(i, 0);
+ const size_t old_negative_cell_id = raw_cells(i, 1);
+ size_t positive_cell_id, negative_cell_id;
+ if (mapped_indices[old_positive_cell_id] == INVALID) {
+ mapped_indices[old_positive_cell_id] = count;
+ positive_cell_id = count;
+ count++;
+ } else {
+ positive_cell_id = mapped_indices[old_positive_cell_id];
+ }
+ if (mapped_indices[old_negative_cell_id] == INVALID) {
+ mapped_indices[old_negative_cell_id] = count;
+ negative_cell_id = count;
+ count++;
+ } else {
+ negative_cell_id = mapped_indices[old_negative_cell_id];
+ }
+ raw_cells(i, 0) = positive_cell_id;
+ raw_cells(i, 1) = negative_cell_id;
+ }
+ cells = raw_cells;
+#ifdef EXTRACT_CELLS_DEBUG
+ log_time("finalize");
+#endif
+ return count;
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DeriveduE,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedC>
+IGL_INLINE size_t igl::copyleft::cgal::extract_cells_single_component(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedC>& cells)
+{
+ const size_t num_faces = F.rows();
+ // Input:
+ // index index into #F*3 list of undirect edges
+ // Returns index into face
+ const auto edge_index_to_face_index = [&num_faces](size_t index)
+ {
+ return index % num_faces;
+ };
+ // Determine if a face (containing undirected edge {s,d} is consistently
+ // oriented with directed edge {s,d} (or otherwise it is with {d,s})
+ //
+ // Inputs:
+ // fid face index into F
+ // s source index of edge
+ // d destination index of edge
+ // Returns true if face F(fid,:) is consistent with {s,d}
+ const auto is_consistent =
+ [&F](const size_t fid, const size_t s, const size_t d) -> bool
+ {
+ if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return false;
+ if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return false;
+ if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return false;
+
+ if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return true;
+ if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return true;
+ if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return true;
+ throw "Invalid face!";
+ return false;
+ };
+
+ const size_t num_unique_edges = uE.rows();
+ const size_t num_patches = P.maxCoeff() + 1;
+
+ // Build patch-patch adjacency list.
+ std::vector<std::map<size_t, size_t> > patch_adj(num_patches);
+ for (size_t i=0; i<num_unique_edges; i++) {
+ const size_t s = uE(i,0);
+ const size_t d = uE(i,1);
+ const auto adj_faces = uE2E[i];
+ const size_t num_adj_faces = adj_faces.size();
+ if (num_adj_faces > 2) {
+ for (size_t j=0; j<num_adj_faces; j++) {
+ const size_t patch_j = P[edge_index_to_face_index(adj_faces[j])];
+ for (size_t k=j+1; k<num_adj_faces; k++) {
+ const size_t patch_k = P[edge_index_to_face_index(adj_faces[k])];
+ if (patch_adj[patch_j].find(patch_k) == patch_adj[patch_j].end()) {
+ patch_adj[patch_j].insert({patch_k, i});
+ }
+ if (patch_adj[patch_k].find(patch_j) == patch_adj[patch_k].end()) {
+ patch_adj[patch_k].insert({patch_j, i});
+ }
+ }
+ }
+ }
+ }
+
+
+ const int INVALID = std::numeric_limits<int>::max();
+ std::vector<size_t> cell_labels(num_patches * 2);
+ for (size_t i=0; i<num_patches; i++) cell_labels[i] = i;
+ std::vector<std::set<size_t> > equivalent_cells(num_patches*2);
+ std::vector<bool> processed(num_unique_edges, false);
+
+ size_t label_count=0;
+ for (size_t i=0; i<num_patches; i++) {
+ for (const auto& entry : patch_adj[i]) {
+ const size_t neighbor_patch = entry.first;
+ const size_t uei = entry.second;
+ if (processed[uei]) continue;
+ processed[uei] = true;
+
+ const auto& adj_faces = uE2E[uei];
+ const size_t num_adj_faces = adj_faces.size();
+ assert(num_adj_faces > 2);
+
+ const size_t s = uE(uei,0);
+ const size_t d = uE(uei,1);
+
+ std::vector<int> signed_adj_faces;
+ for (auto ej : adj_faces)
+ {
+ const size_t fid = edge_index_to_face_index(ej);
+ bool cons = is_consistent(fid, s, d);
+ signed_adj_faces.push_back((fid+1)*(cons ? 1:-1));
+ }
+ {
+ // Sort adjacent faces cyclically around {s,d}
+ Eigen::VectorXi order;
+ // order[f] will reveal the order of face f in signed_adj_faces
+ order_facets_around_edge(V, F, s, d, signed_adj_faces, order);
+ for (size_t j=0; j<num_adj_faces; j++) {
+ const size_t curr_idx = j;
+ const size_t next_idx = (j+1)%num_adj_faces;
+ const size_t curr_patch_idx =
+ P[edge_index_to_face_index(adj_faces[order[curr_idx]])];
+ const size_t next_patch_idx =
+ P[edge_index_to_face_index(adj_faces[order[next_idx]])];
+ const bool curr_cons = signed_adj_faces[order[curr_idx]] > 0;
+ const bool next_cons = signed_adj_faces[order[next_idx]] > 0;
+ const size_t curr_cell_idx = curr_patch_idx*2 + (curr_cons?0:1);
+ const size_t next_cell_idx = next_patch_idx*2 + (next_cons?1:0);
+ equivalent_cells[curr_cell_idx].insert(next_cell_idx);
+ equivalent_cells[next_cell_idx].insert(curr_cell_idx);
+ }
+ }
+ }
+ }
+
+ size_t count=0;
+ cells.resize(num_patches, 2);
+ cells.setConstant(INVALID);
+ const auto extract_equivalent_cells = [&](size_t i) {
+ if (cells(i/2, i%2) != INVALID) return;
+ std::queue<size_t> Q;
+ Q.push(i);
+ cells(i/2, i%2) = count;
+ while (!Q.empty()) {
+ const size_t index = Q.front();
+ Q.pop();
+ for (const auto j : equivalent_cells[index]) {
+ if (cells(j/2, j%2) == INVALID) {
+ cells(j/2, j%2) = count;
+ Q.push(j);
+ }
+ }
+ }
+ count++;
+ };
+ for (size_t i=0; i<num_patches; i++) {
+ extract_equivalent_cells(i*2);
+ extract_equivalent_cells(i*2+1);
+ }
+
+ assert((cells.array() != INVALID).all());
+ return count;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template unsigned long igl::copyleft::cgal::extract_cells<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#ifdef WIN32
+template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+template unsigned __int64 igl::copyleft::cgal::extract_cells<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/extract_cells.h b/xs/src/igl/copyleft/cgal/extract_cells.h
new file mode 100644
index 000000000..9575ffbae
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/extract_cells.h
@@ -0,0 +1,116 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_CGAL_EXTRACT_CELLS
+#define IGL_COPYLEFT_CGAL_EXTRACT_CELLS
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Extract connected 3D space partitioned by mesh (V, F).
+ //
+ // Inputs:
+ // V #V by 3 array of vertices.
+ // F #F by 3 array of faces.
+ //
+ // Output:
+ // cells #F by 2 array of cell indices. cells(i,0) represents the
+ // cell index on the positive side of face i, and cells(i,1)
+ // represents cell index of the negqtive side.
+ // By convension cell with index 0 is the infinite cell.
+ // Returns the number of cells
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedC >
+ IGL_INLINE size_t extract_cells(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedC>& cells);
+
+ // Extract connected 3D space partitioned by mesh (V, F).
+ //
+ // Inputs:
+ // V #V by 3 array of vertices.
+ // F #F by 3 array of faces.
+ // P #F list of patch indices.
+ // E #E by 2 array of vertex indices, one edge per row.
+ // uE #uE by 2 list of vertex_indices, represents undirected edges.
+ // uE2E #uE list of lists that maps uE to E. (a one-to-many map)
+ // EMAP #F*3 list of indices into uE.
+ //
+ // Output:
+ // cells #P by 2 array of cell indices. cells(i,0) represents the
+ // cell index on the positive side of patch i, and cells(i,1)
+ // represents cell index of the negqtive side.
+ // By convension cell with index 0 is the infinite cell.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedE,
+ typename DeriveduE,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedC >
+ IGL_INLINE size_t extract_cells(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const Eigen::PlainObjectBase<DerivedE>& E,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedC>& cells);
+
+ // Extract connected 3D space partitioned by mesh (V,F) composed of
+ // **possibly multiple components** (the name of this function is
+ // dubious).
+ //
+ // Inputs:
+ // V #V by 3 array of vertices.
+ // F #F by 3 array of faces.
+ // P #F list of patch indices.
+ // E #E by 2 array of vertex indices, one edge per row.
+ // uE #uE by 2 list of vertex_indices, represents undirected edges.
+ // uE2E #uE list of lists that maps uE to E. (a one-to-many map)
+ // EMAP #F*3 list of indices into uE.
+ // Output:
+ // cells #P by 2 array of cell indices. cells(i,0) represents the
+ // cell index on the positive side of patch i, and cells(i,1)
+ // represents cell index of the negative side.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DeriveduE,
+ typename uE2EType,
+ typename DerivedEMAP,
+ typename DerivedC >
+ IGL_INLINE size_t extract_cells_single_component(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedC>& cells);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "extract_cells.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/extract_feature.cpp b/xs/src/igl/copyleft/cgal/extract_feature.cpp
new file mode 100644
index 000000000..ff8205d35
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/extract_feature.cpp
@@ -0,0 +1,123 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "extract_feature.h"
+#include <igl/unique_edge_map.h>
+#include <CGAL/Kernel/global_functions.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedE >
+IGL_INLINE void igl::copyleft::cgal::extract_feature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const double tol,
+ Eigen::PlainObjectBase<DerivedE>& feature_edges) {
+
+ using IndexType = typename DerivedE::Scalar;
+ DerivedE E, uE;
+ Eigen::VectorXi EMAP;
+ std::vector<std::vector<IndexType> > uE2E;
+ igl::unique_edge_map(F, E, uE, EMAP, uE2E);
+
+ igl::copyleft::cgal::extract_feature(V, F, tol, E, uE, uE2E, feature_edges);
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedE >
+IGL_INLINE void igl::copyleft::cgal::extract_feature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const double tol,
+ const Eigen::PlainObjectBase<DerivedE>& E,
+ const Eigen::PlainObjectBase<DerivedE>& uE,
+ const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
+ Eigen::PlainObjectBase<DerivedE>& feature_edges) {
+
+ assert(V.cols() == 3);
+ assert(F.cols() == 3);
+ using Scalar = typename DerivedV::Scalar;
+ using IndexType = typename DerivedE::Scalar;
+ using Vertex = Eigen::Matrix<Scalar, 3, 1>;
+ using Kernel = typename CGAL::Exact_predicates_exact_constructions_kernel;
+ using Point = typename Kernel::Point_3;
+
+ const size_t num_unique_edges = uE.rows();
+ const size_t num_faces = F.rows();
+ // NOTE: CGAL's definition of dihedral angle measures the angle between two
+ // facets instead of facet normals.
+ const double cos_tol = cos(igl::PI - tol);
+ std::vector<size_t> result; // Indices into uE
+
+ auto is_non_manifold = [&uE2E](size_t ei) -> bool {
+ return uE2E[ei].size() > 2;
+ };
+
+ auto is_boundary = [&uE2E](size_t ei) -> bool {
+ return uE2E[ei].size() == 1;
+ };
+
+ auto opposite_vertex = [&uE, &F](size_t ei, size_t fi) -> IndexType {
+ const size_t v0 = uE(ei, 0);
+ const size_t v1 = uE(ei, 1);
+ for (size_t i=0; i<3; i++) {
+ const size_t v = F(fi, i);
+ if (v != v0 && v != v1) { return v; }
+ }
+ throw "Input face must be topologically degenerate!";
+ };
+
+ auto is_feature = [&V, &F, &uE, &uE2E, &opposite_vertex, num_faces](
+ size_t ei, double cos_tol) -> bool {
+ auto adj_faces = uE2E[ei];
+ assert(adj_faces.size() == 2);
+ const Vertex v0 = V.row(uE(ei, 0));
+ const Vertex v1 = V.row(uE(ei, 1));
+ const Vertex v2 = V.row(opposite_vertex(ei, adj_faces[0] % num_faces));
+ const Vertex v3 = V.row(opposite_vertex(ei, adj_faces[1] % num_faces));
+ const Point p0(v0[0], v0[1], v0[2]);
+ const Point p1(v1[0], v1[1], v1[2]);
+ const Point p2(v2[0], v2[1], v2[2]);
+ const Point p3(v3[0], v3[1], v3[2]);
+ const auto ori = CGAL::orientation(p0, p1, p2, p3);
+ switch (ori) {
+ case CGAL::POSITIVE:
+ return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
+ CGAL::SMALLER;
+ case CGAL::NEGATIVE:
+ return CGAL::compare_dihedral_angle(p0, p1, p3, p2, cos_tol) ==
+ CGAL::SMALLER;
+ case CGAL::COPLANAR:
+ if (!CGAL::collinear(p0, p1, p2) && !CGAL::collinear(p0, p1, p3)) {
+ return CGAL::compare_dihedral_angle(p0, p1, p2, p3, cos_tol) ==
+ CGAL::SMALLER;
+ } else {
+ throw "Dihedral angle (and feature edge) is not well defined for"
+ " degenerate triangles!";
+ }
+ default:
+ throw "Unknown CGAL orientation";
+ }
+ };
+
+ for (size_t i=0; i<num_unique_edges; i++) {
+ if (is_boundary(i) || is_non_manifold(i) || is_feature(i, cos_tol)) {
+ result.push_back(i);
+ }
+ }
+
+ const size_t num_feature_edges = result.size();
+ feature_edges.resize(num_feature_edges, 2);
+ for (size_t i=0; i<num_feature_edges; i++) {
+ feature_edges.row(i) = uE.row(result[i]);
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/extract_feature.h b/xs/src/igl/copyleft/cgal/extract_feature.h
new file mode 100644
index 000000000..90d469377
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/extract_feature.h
@@ -0,0 +1,90 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H
+#define IGL_COPYLEFT_CGAL_EXTRACT_FEATURE_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Extract feature edges based on dihedral angle.
+ // Here, dihedral angle is defined as the angle between surface
+ // __normals__ as described in
+ // http://mathworld.wolfram.com/DihedralAngle.html
+ //
+ // Non-manifold and boundary edges are automatically considered as
+ // features.
+ //
+ // Inputs:
+ // V #V by 3 array of vertices.
+ // F #F by 3 array of faces.
+ // tol Edges with dihedral angle larger than this are considered
+ // as features. Angle is measured in radian.
+ //
+ // Output:
+ // feature_edges: #E by 2 array of edges. Each edge satisfies at
+ // least one of the following criteria:
+ //
+ // * Edge has dihedral angle larger than tol.
+ // * Edge is boundary.
+ // * Edge is non-manifold (i.e. it has more than 2 adjacent
+ // faces).
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedE>
+ IGL_INLINE void extract_feature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const double tol,
+ Eigen::PlainObjectBase<DerivedE>& feature_edges);
+
+ // Inputs:
+ // V #V by 3 array of vertices.
+ // F #F by 3 array of faces.
+ // tol Edges with dihedral angle larger than this are considered
+ // as features. Angle is measured in radian.
+ // E #E by 2 array of directed edges.
+ // uE #uE by 2 array of undirected edges.
+ // uE2E #uE list of lists mapping undirected edges to all corresponding
+ // directed edges.
+ //
+ // Output:
+ // feature_edges: #E by 2 array of edges. Each edge satisfies at
+ // least one of the following criteria:
+ //
+ // * Edge has dihedral angle larger than tol.
+ // * Edge is boundary.
+ // * Edge is non-manifold (i.e. it has more than 2 adjacent
+ // faces).
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedE>
+ IGL_INLINE void extract_feature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const double tol,
+ const Eigen::PlainObjectBase<DerivedE>& E,
+ const Eigen::PlainObjectBase<DerivedE>& uE,
+ const std::vector<std::vector<typename DerivedE::Scalar> >& uE2E,
+ Eigen::PlainObjectBase<DerivedE>& feature_edges);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "extract_feature.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/fast_winding_number.cpp b/xs/src/igl/copyleft/cgal/fast_winding_number.cpp
new file mode 100644
index 000000000..682754a86
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/fast_winding_number.cpp
@@ -0,0 +1,82 @@
+#include "../../fast_winding_number.h"
+#include "../../octree.h"
+#include "../../knn.h"
+#include "../../parallel_for.h"
+#include "point_areas.h"
+#include <vector>
+
+namespace igl {
+ namespace copyleft{
+ namespace cgal{
+ template <typename DerivedP, typename DerivedN, typename DerivedQ,
+ typename BetaType, typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ const int expansion_order,
+ const BetaType beta,
+ Eigen::PlainObjectBase<DerivedWN>& WN
+ ){
+ typedef typename DerivedWN::Scalar real;
+ typedef typename Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic>
+ RealMatrix;
+
+ std::vector<std::vector<int> > point_indices;
+ Eigen::Matrix<int,Eigen::Dynamic,8> CH;
+ Eigen::Matrix<real,Eigen::Dynamic,3> CN;
+ Eigen::Matrix<real,Eigen::Dynamic,1> W;
+ Eigen::MatrixXi I;
+ Eigen::Matrix<real,Eigen::Dynamic,1> A;
+
+ octree(P,point_indices,CH,CN,W);
+ knn(P,21,point_indices,CH,CN,W,I);
+ point_areas(P,I,N,A);
+
+ Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
+ Eigen::Matrix<real,Eigen::Dynamic,3> CM;
+ Eigen::Matrix<real,Eigen::Dynamic,1> R;
+
+ igl::fast_winding_number(P,N,A,point_indices,CH,
+ expansion_order,CM,R,EC);
+ igl::fast_winding_number(P,N,A,point_indices,CH,
+ CM,R,EC,Q,beta,WN);
+ }
+
+ template <typename DerivedP, typename DerivedN,
+ typename DerivedQ, typename DerivedWN>
+ IGL_INLINE void fast_winding_number(
+ const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ Eigen::PlainObjectBase<DerivedWN>& WN
+ ){
+ fast_winding_number(P,N,Q,2,2.0,WN);
+ }
+ }
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xs/src/igl/copyleft/cgal/fast_winding_number.h b/xs/src/igl/copyleft/cgal/fast_winding_number.h
new file mode 100644
index 000000000..a4ab15316
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/fast_winding_number.h
@@ -0,0 +1,66 @@
+#ifndef IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
+#define IGL_COPYLEFT_CGAL_FAST_WINDING_NUMBER
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ // Evaluate the fast winding number for point data, without known areas. The
+ // areas are calculated using igl::knn and igl::copyleft::cgal::point_areas.
+ //
+ // This function performes the precomputation and evaluation all in one.
+ // If you need to acess the precomuptation for repeated evaluations, use the
+ // two functions designed for exposed precomputation, which are the first two
+ // functions see in igl/fast_winding_number.h
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ // N #P by 3 list of point normals
+ // Q #Q by 3 list of query points for the winding number
+ // beta This is a Barnes-Hut style accuracy term that separates near feild
+ // from far field. The higher the beta, the more accurate and slower
+ // the evaluation. We reccommend using a beta value of 2.
+ // expansion_order the order of the taylor expansion. We support 0,1,2.
+ // Outputs:
+ // WN #Q by 1 list of windinng number values at each query point
+ //
+ template <typename DerivedP, typename DerivedN, typename DerivedQ,
+ typename BetaType, typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ const int expansion_order,
+ const BetaType beta,
+ Eigen::PlainObjectBase<DerivedWN>& WN
+ );
+
+ // Evaluate the fast winding number for point data, without known areas. The
+ // areas are calculated using igl::knn and
+ // igl::point_areas. This function uses the default expansion
+ // order and beta (both are set to 2).
+ //
+ // This function performes the precomputation and evaluation all in one.
+ // If you need to acess the precomuptation for repeated evaluations, use the
+ // two functions designed for exposed precomputation (described above).
+
+ // Inputs:
+ // P #P by 3 list of point locations
+ // N #P by 3 list of point normals
+ // Q #Q by 3 list of query points for the winding number
+ // Outputs:
+ // WN #Q by 1 list of windinng number values at each query point
+ //
+ template <typename DerivedP, typename DerivedN, typename DerivedQ,
+ typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ Eigen::PlainObjectBase<DerivedWN>& WN
+ );
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "fast_winding_number.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/half_space_box.cpp b/xs/src/igl/copyleft/cgal/half_space_box.cpp
new file mode 100644
index 000000000..1bfa8ea52
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/half_space_box.cpp
@@ -0,0 +1,123 @@
+#include "half_space_box.h"
+#include "assign_scalar.h"
+#include <CGAL/Point_3.h>
+#include <CGAL/Vector_3.h>
+
+template <typename DerivedV>
+IGL_INLINE void igl::copyleft::cgal::half_space_box(
+ const CGAL::Plane_3<CGAL::Epeck> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
+ Eigen::Matrix<int,12,3> & BF)
+{
+ typedef CGAL::Plane_3<CGAL::Epeck> Plane;
+ typedef CGAL::Point_3<CGAL::Epeck> Point;
+ typedef CGAL::Vector_3<CGAL::Epeck> Vector;
+ typedef CGAL::Epeck::FT EScalar;
+ Eigen::Matrix<typename DerivedV::Scalar,1,3> avg(0,0,0);
+ for(int v = 0;v<V.rows();v++) for(int c = 0;c<V.cols();c++) avg(c) += V(v,c);
+ avg /= V.rows();
+
+ Point o3(avg(0),avg(1),avg(2));
+ Point o2 = P.projection(o3);
+ Vector u;
+ EScalar max_sqrd = -1;
+ for(int v = 0;v<V.rows();v++)
+ {
+ Vector v2 = P.projection(Point(V(v,0),V(v,1),V(v,2))) - o2;
+ const EScalar sqrd = v2.squared_length();
+ if(max_sqrd<0 || sqrd < max_sqrd)
+ {
+ u = v2;
+ max_sqrd = sqrd;
+ }
+ }
+ // L1 bbd
+ const EScalar bbd =
+ (EScalar(V.col(0).maxCoeff())- EScalar(V.col(0).minCoeff())) +
+ (EScalar(V.col(1).maxCoeff())- EScalar(V.col(1).minCoeff())) +
+ (EScalar(V.col(2).maxCoeff())- EScalar(V.col(2).minCoeff()));
+ Vector n = P.orthogonal_vector();
+ // now we have a center o2 and a vector u to the farthest point on the plane
+ std::vector<Point> vBV;vBV.reserve(8);
+ Vector v = CGAL::cross_product(u,n);
+ // Scale u,v,n to be longer than bbd
+ const auto & longer_than = [](const EScalar min_sqr, Vector & x)
+ {
+ assert(x.squared_length() > 0);
+ while(x.squared_length() < min_sqr)
+ {
+ x = 2.*x;
+ }
+ };
+ longer_than(bbd*bbd,u);
+ longer_than(bbd*bbd,v);
+ longer_than(bbd*bbd,n);
+ vBV.emplace_back( o2 + u + v);
+ vBV.emplace_back( o2 - u + v);
+ vBV.emplace_back( o2 - u - v);
+ vBV.emplace_back( o2 + u - v);
+ vBV.emplace_back( o2 + u + v - n);
+ vBV.emplace_back( o2 - u + v - n);
+ vBV.emplace_back( o2 - u - v - n);
+ vBV.emplace_back( o2 + u - v - n);
+ BV.resize(8,3);
+ for(int b = 0;b<8;b++)
+ {
+ igl::copyleft::cgal::assign_scalar(vBV[b].x(),BV(b,0));
+ igl::copyleft::cgal::assign_scalar(vBV[b].y(),BV(b,1));
+ igl::copyleft::cgal::assign_scalar(vBV[b].z(),BV(b,2));
+ }
+ BF.resize(12,3);
+ BF<<
+ 1,0,2,
+ 2,0,3,
+ 4,5,6,
+ 4,6,7,
+ 0,1,4,
+ 4,1,5,
+ 1,2,5,
+ 5,2,6,
+ 2,3,6,
+ 6,3,7,
+ 3,0,7,
+ 7,0,4;
+}
+
+template <typename Derivedp, typename Derivedn, typename DerivedV>
+IGL_INLINE void igl::copyleft::cgal::half_space_box(
+ const Eigen::MatrixBase<Derivedp> & p,
+ const Eigen::MatrixBase<Derivedn> & n,
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
+ Eigen::Matrix<int,12,3> & BF)
+{
+ typedef CGAL::Plane_3<CGAL::Epeck> Plane;
+ typedef CGAL::Point_3<CGAL::Epeck> Point;
+ typedef CGAL::Vector_3<CGAL::Epeck> Vector;
+ Plane P(Point(p(0),p(1),p(2)),Vector(n(0),n(1),n(2)));
+ return half_space_box(P,V,BV,BF);
+}
+
+template <typename Derivedequ, typename DerivedV>
+IGL_INLINE void igl::copyleft::cgal::half_space_box(
+ const Eigen::MatrixBase<Derivedequ> & equ,
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
+ Eigen::Matrix<int,12,3> & BF)
+{
+ typedef CGAL::Plane_3<CGAL::Epeck> Plane;
+ Plane P(equ(0),equ(1),equ(2),equ(3));
+ return half_space_box(P,V,BV,BF);
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<double, -1, 3, 1, -1, 3> >(CGAL::Plane_3<CGAL::Epeck> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<float, -1, 3, 1, -1, 3> >(CGAL::Plane_3<CGAL::Epeck> const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
+template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
+template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
+template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 4, 1, 1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
+template void igl::copyleft::cgal::half_space_box<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>&, Eigen::Matrix<int, 12, 3, 0, 12, 3>&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/half_space_box.h b/xs/src/igl/copyleft/cgal/half_space_box.h
new file mode 100644
index 000000000..275502235
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/half_space_box.h
@@ -0,0 +1,63 @@
+#ifndef IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H
+#define IGL_COPYLEFT_CGAL_HALF_SPACE_BOX_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Plane_3.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Construct a mesh of box (BV,BF) so that it contains the intersection of
+ // the half-space under the plane (P) and the bounding box of V, and does not
+ // contain any of the half-space above (P).
+ //
+ // Inputs:
+ // P plane so that normal points away from half-space
+ // V #V by 3 list of vertex positions
+ // Outputs:
+ // BV #BV by 3 list of box vertex positions
+ // BF #BF b3 list of box triangle indices into BV
+ template <typename DerivedV>
+ IGL_INLINE void half_space_box(
+ const CGAL::Plane_3<CGAL::Epeck> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
+ Eigen::Matrix<int,12,3> & BF);
+ // Inputs:
+ // p 3d point on plane
+ // n 3d vector of normal of plane pointing away from inside
+ // V #V by 3 list of vertex positions
+ // Outputs:
+ // BV #BV by 3 list of box vertex positions
+ // BF #BF b3 list of box triangle indices into BV
+ template <typename Derivedp, typename Derivedn, typename DerivedV>
+ IGL_INLINE void half_space_box(
+ const Eigen::MatrixBase<Derivedp> & p,
+ const Eigen::MatrixBase<Derivedn> & n,
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
+ Eigen::Matrix<int,12,3> & BF);
+ // Inputs:
+ // equ plane equation: a*x+b*y+c*z + d = 0
+ // V #V by 3 list of vertex positions
+ // Outputs:
+ // BV #BV by 3 list of box vertex positions
+ // BF #BF b3 list of box triangle indices into BV
+ template <typename Derivedequ, typename DerivedV>
+ IGL_INLINE void half_space_box(
+ const Eigen::MatrixBase<Derivedequ> & equ,
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::Matrix<CGAL::Epeck::FT,8,3> & BV,
+ Eigen::Matrix<int,12,3> & BF);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "half_space_box.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/hausdorff.cpp b/xs/src/igl/copyleft/cgal/hausdorff.cpp
new file mode 100644
index 000000000..382e9b476
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/hausdorff.cpp
@@ -0,0 +1,39 @@
+#include "hausdorff.h"
+#include "../../hausdorff.h"
+#include <functional>
+
+template <
+ typename DerivedV,
+ typename Kernel,
+ typename Scalar>
+IGL_INLINE void igl::copyleft::cgal::hausdorff(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const CGAL::AABB_tree<
+ CGAL::AABB_traits<Kernel,
+ CGAL::AABB_triangle_primitive<Kernel,
+ typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
+ >
+ >
+ > & treeB,
+ const std::vector<CGAL::Triangle_3<Kernel> > & /*TB*/,
+ Scalar & l,
+ Scalar & u)
+{
+ // Not sure why using `auto` here doesn't work with the `hausdorff` function
+ // parameter but explicitly naming the type does...
+ const std::function<double(const double &,const double &,const double &)>
+ dist_to_B = [&treeB](
+ const double & x, const double & y, const double & z)->double
+ {
+ CGAL::Point_3<Kernel> query(x,y,z);
+ typename CGAL::AABB_tree<
+ CGAL::AABB_traits<Kernel,
+ CGAL::AABB_triangle_primitive<Kernel,
+ typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
+ >
+ >
+ >::Point_and_primitive_id pp = treeB.closest_point_and_primitive(query);
+ return std::sqrt((query-pp.first).squared_length());
+ };
+ return igl::hausdorff(V,dist_to_B,l,u);
+}
diff --git a/xs/src/igl/copyleft/cgal/hausdorff.h b/xs/src/igl/copyleft/cgal/hausdorff.h
new file mode 100644
index 000000000..c377d4576
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/hausdorff.h
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_HAUSDORFF_H
+#define IGL_COPYLEFT_CGAL_HAUSDORFF_H
+#include "../../igl_inline.h"
+
+#include <Eigen/Dense>
+#include "CGAL_includes.hpp"
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Compute lower and upper bounds (l,u) on the Hausdorff distance between a triangle
+ // (V) and a pointset (e.g., mesh, triangle soup) given by a distance function
+ // handle (dist_to_B).
+ //
+ // Inputs:
+ // V 3 by 3 list of corner positions so that V.row(i) is the position of the
+ // ith corner
+ // treeB CGAL's AABB tree containing triangle soup (VB,FB)
+ // TB list of CGAL triangles in order of FB (for determining which was found
+ // in computation)
+ // Outputs:
+ // l lower bound on Hausdorff distance
+ // u upper bound on Hausdorff distance
+ //
+ template <
+ typename DerivedV,
+ typename Kernel,
+ typename Scalar>
+ IGL_INLINE void hausdorff(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const CGAL::AABB_tree<
+ CGAL::AABB_traits<Kernel,
+ CGAL::AABB_triangle_primitive<Kernel,
+ typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
+ >
+ >
+ > & treeB,
+ const std::vector<CGAL::Triangle_3<Kernel> > & TB,
+ Scalar & l,
+ Scalar & u);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "hausdorff.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/copyleft/cgal/incircle.cpp b/xs/src/igl/copyleft/cgal/incircle.cpp
new file mode 100644
index 000000000..d129d3b14
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/incircle.cpp
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "incircle.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+
+template<typename Scalar>
+IGL_INLINE short igl::copyleft::cgal::incircle(
+ const Scalar pa[2],
+ const Scalar pb[2],
+ const Scalar pc[2],
+ const Scalar pd[2])
+{
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
+ typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
+ typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
+ Epeck, Epick>::type Kernel;
+
+ switch(CGAL::side_of_oriented_circle(
+ typename Kernel::Point_2(pa[0], pa[1]),
+ typename Kernel::Point_2(pb[0], pb[1]),
+ typename Kernel::Point_2(pc[0], pc[1]),
+ typename Kernel::Point_2(pd[0], pd[1]))) {
+ case CGAL::ON_POSITIVE_SIDE:
+ return 1;
+ case CGAL::ON_NEGATIVE_SIDE:
+ return -1;
+ case CGAL::ON_ORIENTED_BOUNDARY:
+ return 0;
+ default:
+ throw "Invalid incircle result";
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/incircle.h b/xs/src/igl/copyleft/cgal/incircle.h
new file mode 100644
index 000000000..4088dc9b5
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/incircle.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_INCIRCLE_H
+#define IGL_COPYLEFT_CGAL_INCIRCLE_H
+
+#include "../../igl_inline.h"
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Inputs:
+ // pa,pb,pc,pd 2D points.
+ // Output:
+ // 1 if pd is inside of the oriented circle formed by pa,pb,pc.
+ // 0 if pd is co-circular with pa,pb,pc.
+ // -1 if pd is outside of the oriented circle formed by pa,pb,pc.
+ template <typename Scalar>
+ IGL_INLINE short incircle(
+ const Scalar pa[2],
+ const Scalar pb[2],
+ const Scalar pc[2],
+ const Scalar pd[2]);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "incircle.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/insert_into_cdt.cpp b/xs/src/igl/copyleft/cgal/insert_into_cdt.cpp
new file mode 100644
index 000000000..2ea4e6de1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/insert_into_cdt.cpp
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "insert_into_cdt.h"
+#include <CGAL/Point_3.h>
+#include <CGAL/Segment_3.h>
+#include <CGAL/Triangle_3.h>
+
+template <typename Kernel>
+IGL_INLINE void igl::copyleft::cgal::insert_into_cdt(
+ const CGAL::Object & obj,
+ const CGAL::Plane_3<Kernel> & P,
+ CGAL::Constrained_triangulation_plus_2<
+ CGAL::Constrained_Delaunay_triangulation_2<
+ Kernel,
+ CGAL::Triangulation_data_structure_2<
+ CGAL::Triangulation_vertex_base_2<Kernel>,
+ CGAL::Constrained_triangulation_face_base_2< Kernel>
+ >,
+ CGAL::Exact_intersections_tag
+ >
+ >
+ & cdt)
+{
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Segment_3<Kernel> Segment_3;
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+
+ if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
+ {
+ // Add segment constraint
+ cdt.insert_constraint( P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
+ }else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
+ {
+ // Add point
+ cdt.insert(P.to_2d(*ipoint));
+ } else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
+ {
+ // Add 3 segment constraints
+ cdt.insert_constraint( P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
+ cdt.insert_constraint( P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
+ cdt.insert_constraint( P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
+ } else if(const std::vector<Point_3 > *polyp =
+ CGAL::object_cast< std::vector<Point_3 > >(&obj))
+ {
+ const std::vector<Point_3 > & poly = *polyp;
+ const size_t m = poly.size();
+ assert(m>=2);
+ for(size_t p = 0;p<m;p++)
+ {
+ const size_t np = (p+1)%m;
+ cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
+ }
+ }else {
+ throw std::runtime_error("Unknown intersection object!");
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+template void igl::copyleft::cgal::insert_into_cdt<CGAL::Epick>(CGAL::Object const&, CGAL::Plane_3<CGAL::Epick> const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epick, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epick, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
+template void igl::copyleft::cgal::insert_into_cdt<CGAL::Epeck>(CGAL::Object const&, CGAL::Plane_3<CGAL::Epeck> const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epeck, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epeck, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/insert_into_cdt.h b/xs/src/igl/copyleft/cgal/insert_into_cdt.h
new file mode 100644
index 000000000..afca0233f
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/insert_into_cdt.h
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_INSERT_INTO_CDT_H
+#define IGL_COPYLEFT_CGAL_INSERT_INTO_CDT_H
+#include "../../igl_inline.h"
+
+#include <CGAL/double.h> // Workaround https://github.com/CGAL/cgal/issues/2182 with CGAL 4.10-1
+#include <CGAL/Plane_3.h>
+#include <CGAL/Constrained_Delaunay_triangulation_2.h>
+#include <CGAL/Constrained_triangulation_plus_2.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given a current 2D constrained Delaunay triangulation (cdt), insert a
+ // 3D "object" (e.g., resulting from intersecting two triangles) into the
+ // cdt, by projecting it via the given plane (P) and adding appropriate
+ // constraints.
+ //
+ // Inputs:
+ // obj CGAL::Object representing a vertex, segment, or (convex)
+ // polygon. All vertices should lie on the plane P. If not, then this
+ // adds the _projection_ of this object to the cdt and that might not
+ // be what you wanted to do.
+ // P plane obj lies on and upon which the cdt is being performed
+ // cdt current CDT, see output
+ // Outputs:
+ // cdt CDT updated to contain constraints for the given object
+ //
+ template <typename Kernel>
+ IGL_INLINE void insert_into_cdt(
+ const CGAL::Object & obj,
+ const CGAL::Plane_3<Kernel> & P,
+ CGAL::Constrained_triangulation_plus_2<
+ CGAL::Constrained_Delaunay_triangulation_2<
+ Kernel,
+ CGAL::Triangulation_data_structure_2<
+ CGAL::Triangulation_vertex_base_2<Kernel>,
+ CGAL::Constrained_triangulation_face_base_2< Kernel>
+ >,
+ CGAL::Exact_intersections_tag
+ >
+ >
+ & cdt);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "insert_into_cdt.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/insphere.cpp b/xs/src/igl/copyleft/cgal/insphere.cpp
new file mode 100644
index 000000000..db12fea33
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/insphere.cpp
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "insphere.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+
+template<typename Scalar>
+IGL_INLINE short igl::copyleft::cgal::insphere(
+ const Scalar pa[3],
+ const Scalar pb[3],
+ const Scalar pc[3],
+ const Scalar pd[3],
+ const Scalar pe[3])
+{
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
+ typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
+ typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
+ Epeck, Epick>::type Kernel;
+
+ switch(CGAL::side_of_oriented_sphere(
+ typename Kernel::Point_3(pa[0], pa[1], pa[2]),
+ typename Kernel::Point_3(pb[0], pb[1], pb[2]),
+ typename Kernel::Point_3(pc[0], pc[1], pc[2]),
+ typename Kernel::Point_3(pd[0], pd[1], pd[2]),
+ typename Kernel::Point_3(pe[0], pe[1], pe[2]))) {
+ case CGAL::ON_POSITIVE_SIDE:
+ return 1;
+ case CGAL::ON_NEGATIVE_SIDE:
+ return -1;
+ case CGAL::ON_ORIENTED_BOUNDARY:
+ return 0;
+ default:
+ throw "Invalid incircle result";
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/insphere.h b/xs/src/igl/copyleft/cgal/insphere.h
new file mode 100644
index 000000000..88a926668
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/insphere.h
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_INSPHERE_H
+#define IGL_COPYLEFT_CGAL_INSPHERE_H
+
+#include "../../igl_inline.h"
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Inputs:
+ // pa,pb,pc,pd,pe 3D points.
+ // Output:
+ // 1 if pe is inside of the oriented sphere formed by pa,pb,pc,pd.
+ // 0 if pe is co-spherical with pa,pb,pc,pd.
+ // -1 if pe is outside of the oriented sphere formed by pa,pb,pc,pd.
+ template <typename Scalar>
+ IGL_INLINE short insphere(
+ const Scalar pa[3],
+ const Scalar pb[3],
+ const Scalar pc[3],
+ const Scalar pd[3],
+ const Scalar pe[3]);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "insphere.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/intersect_other.cpp b/xs/src/igl/copyleft/cgal/intersect_other.cpp
new file mode 100644
index 000000000..9f984f956
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/intersect_other.cpp
@@ -0,0 +1,289 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "intersect_other.h"
+#include "CGAL_includes.hpp"
+#include "mesh_to_cgal_triangle_list.h"
+#include "remesh_intersections.h"
+#include "../../slice_mask.h"
+#include "../../remove_unreferenced.h"
+
+#ifndef IGL_FIRST_HIT_EXCEPTION
+#define IGL_FIRST_HIT_EXCEPTION 10
+#endif
+
+// Un-exposed helper functions
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ template <typename DerivedF>
+ static IGL_INLINE void push_result(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const int f,
+ const int f_other,
+ const CGAL::Object & result,
+ std::map<
+ typename DerivedF::Index,
+ std::vector<std::pair<typename DerivedF::Index, CGAL::Object> > > &
+ offending)
+ //std::map<
+ // std::pair<typename DerivedF::Index,typename DerivedF::Index>,
+ // std::vector<typename DerivedF::Index> > & edge2faces)
+ {
+ typedef typename DerivedF::Index Index;
+ typedef std::pair<Index,Index> EMK;
+ if(offending.count(f) == 0)
+ {
+ // first time marking, initialize with new id and empty list
+ offending[f] = {};
+ for(Index e = 0; e<3;e++)
+ {
+ // append face to edge's list
+ Index i = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+1)%3) : F(f,(e+2)%3);
+ Index j = F(f,(e+1)%3) < F(f,(e+2)%3) ? F(f,(e+2)%3) : F(f,(e+1)%3);
+ //edge2faces[EMK(i,j)].push_back(f);
+ }
+ }
+ offending[f].push_back({f_other,result});
+ }
+ template <
+ typename Kernel,
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedIF,
+ typename DerivedVVAB,
+ typename DerivedFFAB,
+ typename DerivedJAB,
+ typename DerivedIMAB>
+ static IGL_INLINE bool intersect_other_helper(
+ const Eigen::PlainObjectBase<DerivedVA> & VA,
+ const Eigen::PlainObjectBase<DerivedFA> & FA,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ const RemeshSelfIntersectionsParam & params,
+ Eigen::PlainObjectBase<DerivedIF> & IF,
+ Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
+ Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
+ Eigen::PlainObjectBase<DerivedJAB> & JAB,
+ Eigen::PlainObjectBase<DerivedIMAB> & IMAB)
+ {
+
+ using namespace std;
+ using namespace Eigen;
+
+ typedef typename DerivedFA::Index Index;
+ // 3D Primitives
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Segment_3<Kernel> Segment_3;
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ typedef CGAL::Plane_3<Kernel> Plane_3;
+ typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
+ // 2D Primitives
+ typedef CGAL::Point_2<Kernel> Point_2;
+ typedef CGAL::Segment_2<Kernel> Segment_2;
+ typedef CGAL::Triangle_2<Kernel> Triangle_2;
+ // 2D Constrained Delaunay Triangulation types
+ typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
+ typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTAB_2;
+ typedef CGAL::Triangulation_data_structure_2<TVB_2,CTAB_2> TDS_2;
+ typedef CGAL::Exact_intersections_tag Itag;
+ // Axis-align boxes for all-pairs self-intersection detection
+ typedef std::vector<Triangle_3> Triangles;
+ typedef typename Triangles::iterator TrianglesIterator;
+ typedef typename Triangles::const_iterator TrianglesConstIterator;
+ typedef
+ CGAL::Box_intersection_d::Box_with_handle_d<double,3,TrianglesIterator>
+ Box;
+ typedef
+ std::map<Index,std::vector<std::pair<Index,CGAL::Object> > >
+ OffendingMap;
+ typedef std::map<std::pair<Index,Index>,std::vector<Index> > EdgeMap;
+ typedef std::pair<Index,Index> EMK;
+
+ Triangles TA,TB;
+ // Compute and process self intersections
+ mesh_to_cgal_triangle_list(VA,FA,TA);
+ mesh_to_cgal_triangle_list(VB,FB,TB);
+ // http://www.cgal.org/Manual/latest/doc_html/cgal_manual/Box_intersection_d/Chapter_main.html#Section_63.5
+ // Create the corresponding vector of bounding boxes
+ std::vector<Box> A_boxes,B_boxes;
+ const auto box_up = [](Triangles & T, std::vector<Box> & boxes) -> void
+ {
+ boxes.reserve(T.size());
+ for (
+ TrianglesIterator tit = T.begin();
+ tit != T.end();
+ ++tit)
+ {
+ boxes.push_back(Box(tit->bbox(), tit));
+ }
+ };
+ box_up(TA,A_boxes);
+ box_up(TB,B_boxes);
+ OffendingMap offendingA,offendingB;
+ //EdgeMap edge2facesA,edge2facesB;
+
+ std::list<int> lIF;
+ const auto cb = [&](const Box &a, const Box &b) -> void
+ {
+ using namespace std;
+ // index in F and T
+ int fa = a.handle()-TA.begin();
+ int fb = b.handle()-TB.begin();
+ const Triangle_3 & A = *a.handle();
+ const Triangle_3 & B = *b.handle();
+ if(CGAL::do_intersect(A,B))
+ {
+ // There was an intersection
+ lIF.push_back(fa);
+ lIF.push_back(fb);
+ if(params.first_only)
+ {
+ throw IGL_FIRST_HIT_EXCEPTION;
+ }
+ if(!params.detect_only)
+ {
+ CGAL::Object result = CGAL::intersection(A,B);
+
+ push_result(FA,fa,fb,result,offendingA);
+ push_result(FB,fb,fa,result,offendingB);
+ }
+ }
+ };
+ try{
+ CGAL::box_intersection_d(
+ A_boxes.begin(), A_boxes.end(),
+ B_boxes.begin(), B_boxes.end(),
+ cb);
+ }catch(int e)
+ {
+ // Rethrow if not FIRST_HIT_EXCEPTION
+ if(e != IGL_FIRST_HIT_EXCEPTION)
+ {
+ throw e;
+ }
+ // Otherwise just fall through
+ }
+
+ // Convert lIF to Eigen matrix
+ assert(lIF.size()%2 == 0);
+ IF.resize(lIF.size()/2,2);
+ {
+ int i=0;
+ for(
+ list<int>::const_iterator ifit = lIF.begin();
+ ifit!=lIF.end();
+ )
+ {
+ IF(i,0) = (*ifit);
+ ifit++;
+ IF(i,1) = (*ifit);
+ ifit++;
+ i++;
+ }
+ }
+ if(!params.detect_only)
+ {
+ // Obsolete, now remesh_intersections expects a single mesh
+ // remesh_intersections(VA,FA,TA,offendingA,VVA,FFA,JA,IMA);
+ // remesh_intersections(VB,FB,TB,offendingB,VVB,FFB,JB,IMB);
+ // Combine mesh and offending maps
+ DerivedVA VAB(VA.rows()+VB.rows(),3);
+ VAB<<VA,VB;
+ DerivedFA FAB(FA.rows()+FB.rows(),3);
+ FAB<<FA,(FB.array()+VA.rows());
+ Triangles TAB;
+ TAB.reserve(TA.size()+TB.size());
+ TAB.insert(TAB.end(),TA.begin(),TA.end());
+ TAB.insert(TAB.end(),TB.begin(),TB.end());
+ OffendingMap offending;
+ //offending.reserve(offendingA.size() + offendingB.size());
+ for (const auto itr : offendingA)
+ {
+ // Remap offenders in FB to FAB
+ auto offenders = itr.second;
+ for(auto & offender : offenders)
+ {
+ offender.first += FA.rows();
+ }
+ offending[itr.first] = offenders;
+ }
+ for (const auto itr : offendingB)
+ {
+ // Store offenders for FB according to place in FAB
+ offending[FA.rows() + itr.first] = itr.second;
+ }
+
+ remesh_intersections(
+ VAB,FAB,TAB,offending,params.stitch_all,VVAB,FFAB,JAB,IMAB);
+ }
+
+ return IF.rows() > 0;
+ }
+ }
+ }
+}
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedIF,
+ typename DerivedVVAB,
+ typename DerivedFFAB,
+ typename DerivedJAB,
+ typename DerivedIMAB>
+IGL_INLINE bool igl::copyleft::cgal::intersect_other(
+ const Eigen::PlainObjectBase<DerivedVA> & VA,
+ const Eigen::PlainObjectBase<DerivedFA> & FA,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ const RemeshSelfIntersectionsParam & params,
+ Eigen::PlainObjectBase<DerivedIF> & IF,
+ Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
+ Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
+ Eigen::PlainObjectBase<DerivedJAB> & JAB,
+ Eigen::PlainObjectBase<DerivedIMAB> & IMAB)
+{
+ if(params.detect_only)
+ {
+ return intersect_other_helper<CGAL::Epick>
+ (VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB);
+ }else
+ {
+ return intersect_other_helper<CGAL::Epeck>
+ (VA,FA,VB,FB,params,IF,VVAB,FFAB,JAB,IMAB);
+ }
+}
+
+IGL_INLINE bool igl::copyleft::cgal::intersect_other(
+ const Eigen::MatrixXd & VA,
+ const Eigen::MatrixXi & FA,
+ const Eigen::MatrixXd & VB,
+ const Eigen::MatrixXi & FB,
+ const bool first_only,
+ Eigen::MatrixXi & IF)
+{
+ Eigen::MatrixXd VVAB;
+ Eigen::MatrixXi FFAB;
+ Eigen::VectorXi JAB,IMAB;
+ return intersect_other(
+ VA,FA,VB,FB,{true,first_only},IF,VVAB,FFAB,JAB,IMAB);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::intersect_other<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::intersect_other<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/intersect_other.h b/xs/src/igl/copyleft/cgal/intersect_other.h
new file mode 100644
index 000000000..c1afdf87d
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/intersect_other.h
@@ -0,0 +1,91 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_INTERSECT_OTHER_H
+#define IGL_COPYLEFT_CGAL_INTERSECT_OTHER_H
+#include "../../igl_inline.h"
+#include "RemeshSelfIntersectionsParam.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // INTERSECT_OTHER Given a triangle mesh (VA,FA) and another mesh (VB,FB)
+ // find all pairs of intersecting faces. Note that self-intersections are
+ // ignored.
+ //
+ // Inputs:
+ // VA #V by 3 list of vertex positions
+ // FA #F by 3 list of triangle indices into VA
+ // VB #V by 3 list of vertex positions
+ // FB #F by 3 list of triangle indices into VB
+ // params whether to detect only and then whether to only find first
+ // intersection
+ // Outputs:
+ // IF #intersecting face pairs by 2 list of intersecting face pairs,
+ // indexing FA and FB
+ // VVAB #VVAB by 3 list of vertex positions
+ // FFAB #FFAB by 3 list of triangle indices into VVA
+ // JAB #FFAB list of indices into [FA;FB] denoting birth triangle
+ // IMAB #VVAB list of indices stitching duplicates (resulting from
+ // mesh intersections) together
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedIF,
+ typename DerivedVVAB,
+ typename DerivedFFAB,
+ typename DerivedJAB,
+ typename DerivedIMAB>
+ IGL_INLINE bool intersect_other(
+ const Eigen::PlainObjectBase<DerivedVA> & VA,
+ const Eigen::PlainObjectBase<DerivedFA> & FA,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ const RemeshSelfIntersectionsParam & params,
+ Eigen::PlainObjectBase<DerivedIF> & IF,
+ Eigen::PlainObjectBase<DerivedVVAB> & VVAB,
+ Eigen::PlainObjectBase<DerivedFFAB> & FFAB,
+ Eigen::PlainObjectBase<DerivedJAB> & JAB,
+ Eigen::PlainObjectBase<DerivedIMAB> & IMAB);
+ // Legacy wrapper for detect only using common types.
+ //
+ // Inputs:
+ // VA #V by 3 list of vertex positions
+ // FA #F by 3 list of triangle indices into VA
+ // VB #V by 3 list of vertex positions
+ // FB #F by 3 list of triangle indices into VB
+ // first_only whether to only detect the first intersection.
+ // Outputs:
+ // IF #intersecting face pairs by 2 list of intersecting face pairs,
+ // indexing FA and FB
+ // Returns true if any intersections were found
+ //
+ // See also: remesh_self_intersections
+ IGL_INLINE bool intersect_other(
+ const Eigen::MatrixXd & VA,
+ const Eigen::MatrixXi & FA,
+ const Eigen::MatrixXd & VB,
+ const Eigen::MatrixXi & FB,
+ const bool first_only,
+ Eigen::MatrixXi & IF);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "intersect_other.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/intersect_with_half_space.cpp b/xs/src/igl/copyleft/cgal/intersect_with_half_space.cpp
new file mode 100644
index 000000000..c4ba4dbb8
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/intersect_with_half_space.cpp
@@ -0,0 +1,88 @@
+#include "intersect_with_half_space.h"
+#include "mesh_boolean.h"
+#include "half_space_box.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedp,
+ typename Derivedn,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
+ const Eigen::MatrixBase<DerivedV > & V,
+ const Eigen::MatrixBase<DerivedF > & F,
+ const Eigen::MatrixBase<Derivedp > & p,
+ const Eigen::MatrixBase<Derivedn > & n,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ typedef CGAL::Plane_3<CGAL::Epeck> Plane;
+ typedef CGAL::Point_3<CGAL::Epeck> Point;
+ typedef CGAL::Vector_3<CGAL::Epeck> Vector;
+ Plane P(Point(p(0),p(1),p(2)),Vector(n(0),n(1),n(2)));
+ return intersect_with_half_space(V,F,P,VC,FC,J);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedequ,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
+ const Eigen::MatrixBase<DerivedV > & V,
+ const Eigen::MatrixBase<DerivedF > & F,
+ const Eigen::MatrixBase<Derivedequ > & equ,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ typedef CGAL::Plane_3<CGAL::Epeck> Plane;
+ Plane P(equ(0),equ(1),equ(2),equ(3));
+ return intersect_with_half_space(V,F,P,VC,FC,J);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::intersect_with_half_space(
+ const Eigen::MatrixBase<DerivedV > & V,
+ const Eigen::MatrixBase<DerivedF > & F,
+ const CGAL::Plane_3<CGAL::Epeck> & P,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ Eigen::Matrix<CGAL::Epeck::FT,8,3> BV;
+ Eigen::Matrix<int,12,3> BF;
+ half_space_box(P,V,BV,BF);
+ // Disturbingly, (BV,BF) must be first argument
+ const bool ret = mesh_boolean(BV,BF,V,F,MESH_BOOLEAN_TYPE_INTERSECT,VC,FC,J);
+ // But now J is wrong...
+ std::for_each(
+ J.data(),
+ J.data()+J.size(),
+ [&BF,&F](typename DerivedJ::Scalar & j)
+ {j = (j<BF.rows()?F.rows()+j:j-BF.rows());}
+ );
+ return ret;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<double>, Eigen::Matrix<double, 1, 3, 1, 1, 3> const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::intersect_with_half_space<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<float>, Eigen::Matrix<float, 1, 3, 1, 1, 3> const>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::CwiseUnaryOp<Eigen::internal::scalar_opposite_op<float>, Eigen::Matrix<float, 1, 3, 1, 1, 3> const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/intersect_with_half_space.h b/xs/src/igl/copyleft/cgal/intersect_with_half_space.h
new file mode 100644
index 000000000..9fdf9ae2b
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/intersect_with_half_space.h
@@ -0,0 +1,96 @@
+#ifndef IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_H
+#define IGL_COPYLEFT_CGAL_INTERSECT_WITH_HALF_SPACE_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Plane_3.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Intersect a PWN mesh with a half-space. Point on plane, normal pointing
+ // outward.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // p 3d point on plane
+ // n 3d vector of normal of plane pointing away from inside
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth"
+ // facet
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedp,
+ typename Derivedn,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool intersect_with_half_space(
+ const Eigen::MatrixBase<DerivedV > & V,
+ const Eigen::MatrixBase<DerivedF > & F,
+ const Eigen::MatrixBase<Derivedp > & p,
+ const Eigen::MatrixBase<Derivedn > & n,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ // Intersect a PWN mesh with a half-space. Plane equation.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // equ plane equation: P(x,y,z) = a*x+b*y+c*z + d = 0, P(x,y,z) < 0 is
+ // _inside_.
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedequ,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool intersect_with_half_space(
+ const Eigen::MatrixBase<DerivedV > & V,
+ const Eigen::MatrixBase<DerivedF > & F,
+ const Eigen::MatrixBase<Derivedequ > & equ,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ // Intersect a PWN mesh with a half-space. CGAL Plane.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // P plane
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // J #FC list of indices into [F;F.rows()+[1;2]] revealing "birth" facet
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool intersect_with_half_space(
+ const Eigen::MatrixBase<DerivedV > & V,
+ const Eigen::MatrixBase<DerivedF > & F,
+ const CGAL::Plane_3<CGAL::Epeck> & P,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "intersect_with_half_space.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/lexicographic_triangulation.cpp b/xs/src/igl/copyleft/cgal/lexicographic_triangulation.cpp
new file mode 100644
index 000000000..719b50dbf
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/lexicographic_triangulation.cpp
@@ -0,0 +1,24 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+// Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "lexicographic_triangulation.h"
+#include "../../lexicographic_triangulation.h"
+#include "orient2D.h"
+
+template<
+ typename DerivedP,
+ typename DerivedF
+ >
+IGL_INLINE void igl::copyleft::cgal::lexicographic_triangulation(
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ typedef typename DerivedP::Scalar Scalar;
+ igl::lexicographic_triangulation(P, orient2D<Scalar>, F);
+}
diff --git a/xs/src/igl/copyleft/cgal/lexicographic_triangulation.h b/xs/src/igl/copyleft/cgal/lexicographic_triangulation.h
new file mode 100644
index 000000000..5773a3942
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/lexicographic_triangulation.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+// Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_LEXICOGRAPHIC_TRIANGULATION_H
+#define IGL_COPYLEFT_CGAL_LEXICOGRAPHIC_TRIANGULATION_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+
+ // Given a set of points in 2D, return a lexicographic triangulation of these
+ // points.
+ //
+ // Inputs:
+ // P #P by 2 list of vertex positions
+ //
+ // Outputs:
+ // F #F by 3 of faces in lexicographic triangulation.
+ template<
+ typename DerivedP,
+ typename DerivedF
+ >
+ IGL_INLINE void lexicographic_triangulation(
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ }
+ }
+}
+
+
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "lexicographic_triangulation.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/list_to_matrix.cpp b/xs/src/igl/copyleft/cgal/list_to_matrix.cpp
new file mode 100644
index 000000000..e94dde6b8
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/list_to_matrix.cpp
@@ -0,0 +1,15 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "../../list_to_matrix.h"
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#ifdef IGL_STATIC_LIBRARY
+#undef IGL_STATIC_LIBRARY
+#include "../../list_to_matrix.cpp"
+template bool igl::list_to_matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(std::vector<std::vector<CGAL::Lazy_exact_nt<CGAL::Gmpq>, std::allocator<CGAL::Lazy_exact_nt<CGAL::Gmpq> > >, std::allocator<std::vector<CGAL::Lazy_exact_nt<CGAL::Gmpq>, std::allocator<CGAL::Lazy_exact_nt<CGAL::Gmpq> > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_boolean.cpp b/xs/src/igl/copyleft/cgal/mesh_boolean.cpp
new file mode 100644
index 000000000..5d289f6c3
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_boolean.cpp
@@ -0,0 +1,466 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#include "mesh_boolean.h"
+#include "assign.h"
+#include "extract_cells.h"
+#include "mesh_boolean_type_to_funcs.h"
+#include "propagate_winding_numbers.h"
+#include "relabel_small_immersed_cells.h"
+#include "remesh_self_intersections.h"
+#include "string_to_mesh_boolean_type.h"
+#include "../../combine.h"
+#include "../../cumsum.h"
+#include "../../extract_manifold_patches.h"
+#include "../../get_seconds.h"
+#include "../../remove_unreferenced.h"
+#include "../../resolve_duplicated_faces.h"
+#include "../../slice.h"
+#include "../../unique_edge_map.h"
+#include "../../unique_simplices.h"
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <algorithm>
+
+//#define MESH_BOOLEAN_TIMING
+//#define DOUBLE_CHECK_EXACT_OUTPUT
+//#define SMALL_CELL_REMOVAL
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA > & VA,
+ const Eigen::MatrixBase<DerivedFA > & FA,
+ const Eigen::MatrixBase<DerivedVB > & VB,
+ const Eigen::MatrixBase<DerivedFB > & FB,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ std::function<int(const int, const int)> keep;
+ std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) > wind_num_op;
+ mesh_boolean_type_to_funcs(type,wind_num_op,keep);
+ return mesh_boolean(VA,FA,VB,FB,wind_num_op,keep,VC,FC,J);
+}
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA > & VA,
+ const Eigen::MatrixBase<DerivedFA > & FA,
+ const Eigen::MatrixBase<DerivedVB > & VB,
+ const Eigen::MatrixBase<DerivedFB > & FB,
+ const std::string & type_str,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ return mesh_boolean(
+ VA,FA,VB,FB,string_to_mesh_boolean_type(type_str),VC,FC,J);
+}
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::MatrixBase<DerivedVB> & VB,
+ const Eigen::MatrixBase<DerivedFB> & FB,
+ const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
+ const std::function<int(const int, const int)> & keep,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ // Generate combined mesh (VA,FA,VB,FB) -> (V,F)
+ Eigen::Matrix<size_t,2,1> sizes(FA.rows(),FB.rows());
+ // TODO: This is a precision template **bug** that results in failure to
+ // compile. If DerivedVA::Scalar is double and DerivedVB::Scalar is
+ // CGAL::Epeck::FT then the following assignment will not compile. This
+ // implies that VA must have the trumping precision (and a valid assignment
+ // operator from VB's type).
+ Eigen::Matrix<typename DerivedVA::Scalar,Eigen::Dynamic,3> VV(VA.rows() + VB.rows(), 3);
+ DerivedFC FF(FA.rows() + FB.rows(), 3);
+ // Can't use comma initializer
+ for(int a = 0;a<VA.rows();a++)
+ {
+ for(int d = 0;d<3;d++) VV(a,d) = VA(a,d);
+ }
+ for(int b = 0;b<VB.rows();b++)
+ {
+ for(int d = 0;d<3;d++) VV(VA.rows()+b,d) = VB(b,d);
+ }
+ FF.block(0, 0, FA.rows(), 3) = FA;
+ // Eigen struggles to assign nothing to nothing and will assert if FB is empty
+ if(FB.rows() > 0)
+ {
+ FF.block(FA.rows(), 0, FB.rows(), 3) = FB.array() + VA.rows();
+ }
+ return mesh_boolean(VV,FF,sizes,wind_num_op,keep,VC,FC,J);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+ const std::vector<DerivedV > & Vlist,
+ const std::vector<DerivedF > & Flist,
+ const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
+ const std::function<int(const int, const int)> & keep,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ DerivedV VV;
+ DerivedF FF;
+ Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
+ igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
+ return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+ const std::vector<DerivedV > & Vlist,
+ const std::vector<DerivedF > & Flist,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+ DerivedV VV;
+ DerivedF FF;
+ Eigen::Matrix<size_t,Eigen::Dynamic,1> Vsizes,Fsizes;
+ igl::combine(Vlist,Flist,VV,FF,Vsizes,Fsizes);
+ std::function<int(const int, const int)> keep;
+ std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) > wind_num_op;
+ mesh_boolean_type_to_funcs(type,wind_num_op,keep);
+ return mesh_boolean(VV,FF,Fsizes,wind_num_op,keep,VC,FC,J);
+}
+
+template <
+ typename DerivedVV,
+ typename DerivedFF,
+ typename Derivedsizes,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+ const Eigen::MatrixBase<DerivedVV > & VV,
+ const Eigen::MatrixBase<DerivedFF > & FF,
+ const Eigen::MatrixBase<Derivedsizes> & sizes,
+ const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
+ const std::function<int(const int, const int)> & keep,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J)
+{
+#ifdef MESH_BOOLEAN_TIMING
+ const auto & tictoc = []() -> double
+ {
+ static double t_start = igl::get_seconds();
+ double diff = igl::get_seconds()-t_start;
+ t_start += diff;
+ return diff;
+ };
+ const auto log_time = [&](const std::string& label) -> void {
+ std::cout << "mesh_boolean." << label << ": "
+ << tictoc() << std::endl;
+ };
+ tictoc();
+#endif
+ typedef typename DerivedVC::Scalar Scalar;
+ typedef CGAL::Epeck Kernel;
+ typedef Kernel::FT ExactScalar;
+ typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3> MatrixX3S;
+ typedef Eigen::Matrix<typename DerivedJ::Scalar,Eigen::Dynamic,1> VectorXJ;
+ typedef Eigen::Matrix<
+ ExactScalar,
+ Eigen::Dynamic,
+ Eigen::Dynamic,
+ DerivedVC::IsRowMajor> MatrixXES;
+ MatrixXES V;
+ DerivedFC F;
+ VectorXJ CJ;
+ {
+ Eigen::VectorXi I;
+ igl::copyleft::cgal::RemeshSelfIntersectionsParam params;
+ params.stitch_all = true;
+ MatrixXES Vr;
+ DerivedFC Fr;
+ Eigen::MatrixXi IF;
+ igl::copyleft::cgal::remesh_self_intersections(
+ VV, FF, params, Vr, Fr, IF, CJ, I);
+ assert(I.size() == Vr.rows());
+ // Merge coinciding vertices into non-manifold vertices.
+ std::for_each(Fr.data(), Fr.data()+Fr.size(),
+ [&I](typename DerivedFC::Scalar& a) { a=I[a]; });
+ // Remove unreferenced vertices.
+ Eigen::VectorXi UIM;
+ igl::remove_unreferenced(Vr, Fr, V, F, UIM);
+ }
+#ifdef MESH_BOOLEAN_TIMING
+ log_time("resolve_self_intersection");
+#endif
+
+ // Compute edges of (F) --> (E,uE,EMAP,uE2E)
+ Eigen::MatrixXi E, uE;
+ Eigen::VectorXi EMAP;
+ std::vector<std::vector<size_t> > uE2E;
+ igl::unique_edge_map(F, E, uE, EMAP, uE2E);
+
+ // Compute patches (F,EMAP,uE2E) --> (P)
+ Eigen::VectorXi P;
+ const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
+#ifdef MESH_BOOLEAN_TIMING
+ log_time("patch_extraction");
+#endif
+
+ // Compute cells (V,F,P,E,uE,EMAP) -> (per_patch_cells)
+ Eigen::MatrixXi per_patch_cells;
+ const size_t num_cells =
+ igl::copyleft::cgal::extract_cells(
+ V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
+#ifdef MESH_BOOLEAN_TIMING
+ log_time("cell_extraction");
+#endif
+
+ // Compute winding numbers on each side of each facet.
+ const size_t num_faces = F.rows();
+ // W(f,:) --> [w1out,w1in,w2out,w2in, ... wnout,wnint] winding numbers above
+ // and below each face w.r.t. each input mesh, so that W(f,2*i) is the
+ // winding number above face f w.r.t. input i, and W(f,2*i+1) is the winding
+ // number below face f w.r.t. input i.
+ Eigen::MatrixXi W;
+ // labels(f) = i means that face f comes from mesh i
+ Eigen::VectorXi labels(num_faces);
+ // cumulative sizes
+ Derivedsizes cumsizes;
+ igl::cumsum(sizes,1,cumsizes);
+ const size_t num_inputs = sizes.size();
+ std::transform(
+ CJ.data(),
+ CJ.data()+CJ.size(),
+ labels.data(),
+ // Determine which input mesh birth face i comes from
+ [&num_inputs,&cumsizes](int i)->int
+ {
+ for(int k = 0;k<num_inputs;k++)
+ {
+ if(i<cumsizes(k)) return k;
+ }
+ assert(false && "Birth parent index out of range");
+ return -1;
+ });
+ bool valid = true;
+ if (num_faces > 0)
+ {
+ valid = valid &
+ igl::copyleft::cgal::propagate_winding_numbers(
+ V, F, uE, uE2E, num_patches, P, num_cells, per_patch_cells, labels, W);
+ } else
+ {
+ W.resize(0, 2*num_inputs);
+ }
+ assert((size_t)W.rows() == num_faces);
+ // If W doesn't have enough columns, pad with zeros
+ if (W.cols() <= 2*num_inputs)
+ {
+ const int old_ncols = W.cols();
+ W.conservativeResize(num_faces,2*num_inputs);
+ W.rightCols(2*num_inputs-old_ncols).setConstant(0);
+ }
+ assert((size_t)W.cols() == 2*num_inputs);
+#ifdef MESH_BOOLEAN_TIMING
+ log_time("propagate_input_winding_number");
+#endif
+
+ // Compute resulting winding number.
+ Eigen::MatrixXi Wr(num_faces, 2);
+ for (size_t i=0; i<num_faces; i++)
+ {
+ // Winding number vectors above and below
+ Eigen::RowVectorXi w_out(1,num_inputs), w_in(1,num_inputs);
+ for(size_t k =0;k<num_inputs;k++)
+ {
+ w_out(k) = W(i,2*k+0);
+ w_in(k) = W(i,2*k+1);
+ }
+ Wr(i,0) = wind_num_op(w_out);
+ Wr(i,1) = wind_num_op(w_in);
+ }
+#ifdef MESH_BOOLEAN_TIMING
+ log_time("compute_output_winding_number");
+#endif
+
+#ifdef SMALL_CELL_REMOVAL
+ igl::copyleft::cgal::relabel_small_immersed_cells(
+ V, F, num_patches, P, num_cells, per_patch_cells, 1e-3, Wr);
+#endif
+
+ // Extract boundary separating inside from outside.
+ auto index_to_signed_index = [&](size_t i, bool ori) -> int
+ {
+ return (i+1)*(ori?1:-1);
+ };
+ //auto signed_index_to_index = [&](int i) -> size_t {
+ // return abs(i) - 1;
+ //};
+ std::vector<int> selected;
+ for(size_t i=0; i<num_faces; i++)
+ {
+ auto should_keep = keep(Wr(i,0), Wr(i,1));
+ if (should_keep > 0)
+ {
+ selected.push_back(index_to_signed_index(i, true));
+ } else if (should_keep < 0)
+ {
+ selected.push_back(index_to_signed_index(i, false));
+ }
+ }
+
+ const size_t num_selected = selected.size();
+ DerivedFC kept_faces(num_selected, 3);
+ DerivedJ kept_face_indices(num_selected, 1);
+ for (size_t i=0; i<num_selected; i++)
+ {
+ size_t idx = abs(selected[i]) - 1;
+ if (selected[i] > 0)
+ {
+ kept_faces.row(i) = F.row(idx);
+ } else
+ {
+ kept_faces.row(i) = F.row(idx).reverse();
+ }
+ kept_face_indices(i, 0) = CJ[idx];
+ }
+#ifdef MESH_BOOLEAN_TIMING
+ log_time("extract_output");
+#endif
+
+ // Finally, remove duplicated faces and unreferenced vertices.
+ {
+ DerivedFC G;
+ DerivedJ JJ;
+ igl::resolve_duplicated_faces(kept_faces, G, JJ);
+ igl::slice(kept_face_indices, JJ, 1, J);
+
+#ifdef DOUBLE_CHECK_EXACT_OUTPUT
+ {
+ // Sanity check on exact output.
+ igl::copyleft::cgal::RemeshSelfIntersectionsParam params;
+ params.detect_only = true;
+ params.first_only = true;
+ MatrixXES dummy_VV;
+ DerivedFC dummy_FF, dummy_IF;
+ Eigen::VectorXi dummy_J, dummy_IM;
+ igl::copyleft::cgal::SelfIntersectMesh<
+ Kernel,
+ MatrixXES, DerivedFC,
+ MatrixXES, DerivedFC,
+ DerivedFC,
+ Eigen::VectorXi,
+ Eigen::VectorXi
+ > checker(V, G, params,
+ dummy_VV, dummy_FF, dummy_IF, dummy_J, dummy_IM);
+ if (checker.count != 0)
+ {
+ throw "Self-intersection not fully resolved.";
+ }
+ }
+#endif
+
+ MatrixX3S Vs;
+ assign(V,Vs);
+ Eigen::VectorXi newIM;
+ igl::remove_unreferenced(Vs,G,VC,FC,newIM);
+ }
+#ifdef MESH_BOOLEAN_TIMING
+ log_time("clean_up");
+#endif
+ return valid;
+}
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC>
+IGL_INLINE bool igl::copyleft::cgal::mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA > & VA,
+ const Eigen::MatrixBase<DerivedFA > & FA,
+ const Eigen::MatrixBase<DerivedVB > & VB,
+ const Eigen::MatrixBase<DerivedFB > & FB,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC)
+{
+ Eigen::Matrix<typename DerivedFC::Index, Eigen::Dynamic,1> J;
+ return igl::copyleft::cgal::mesh_boolean(VA,FA,VB,FB,type,VC,FC,J);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, std::function<int (Eigen::Matrix<int, 1, -1, 1, 1, -1>)> const&, std::function<int (int, int)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::copyleft::cgal::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1> > > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1> > > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template bool igl::copyleft::cgal::mesh_boolean<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, enum igl::MeshBooleanType const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_boolean.h b/xs/src/igl/copyleft/cgal/mesh_boolean.h
new file mode 100644
index 000000000..24c99ed41
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_boolean.h
@@ -0,0 +1,229 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_CGAL_MESH_BOOLEAN_H
+#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_H
+
+#include "../../igl_inline.h"
+#include "../../MeshBooleanType.h"
+#include <Eigen/Core>
+#include <functional>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // MESH_BOOLEAN Compute boolean csg operations on "solid", consistently
+ // oriented meshes.
+ //
+ // Inputs:
+ // VA #VA by 3 list of vertex positions of first mesh
+ // FA #FA by 3 list of triangle indices into VA
+ // VB #VB by 3 list of vertex positions of second mesh
+ // FB #FB by 3 list of triangle indices into VB
+ // type type of boolean operation
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // J #FC list of indices into [FA;FA.rows()+FB] revealing "birth" facet
+ // Returns true if inputs induce a piecewise constant winding number
+ // field and type is valid
+ //
+ // See also: mesh_boolean_cork, intersect_other,
+ // remesh_self_intersections
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA > & VA,
+ const Eigen::MatrixBase<DerivedFA > & FA,
+ const Eigen::MatrixBase<DerivedVB > & VB,
+ const Eigen::MatrixBase<DerivedFB > & FB,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA > & VA,
+ const Eigen::MatrixBase<DerivedFA > & FA,
+ const Eigen::MatrixBase<DerivedVB > & VB,
+ const Eigen::MatrixBase<DerivedFB > & FB,
+ const std::string & type_str,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ //
+ // Inputs:
+ // VA #VA by 3 list of vertex positions of first mesh
+ // FA #FA by 3 list of triangle indices into VA
+ // VB #VB by 3 list of vertex positions of second mesh
+ // FB #FB by 3 list of triangle indices into VB
+ // wind_num_op function handle for filtering winding numbers from
+ // tuples of integer values to [0,1] outside/inside values
+ // keep function handle for determining if a patch should be "kept"
+ // in the output based on the winding number on either side
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // J #FC list of indices into [FA;FB] revealing "birth" facet
+ // Returns true iff inputs induce a piecewise constant winding number
+ // field
+ //
+ // See also: mesh_boolean_cork, intersect_other,
+ // remesh_self_intersections
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::MatrixBase<DerivedVB> & VB,
+ const Eigen::MatrixBase<DerivedFB> & FB,
+ const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
+ const std::function<int(const int, const int)> & keep,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ // MESH_BOOLEAN Variadic boolean operations
+ //
+ // Inputs:
+ // Vlist k-long list of lists of mesh vertex positions
+ // Flist k-long list of lists of mesh face indices, so that Flist[i] indexes
+ // vertices in Vlist[i]
+ // wind_num_op function handle for filtering winding numbers from
+ // n-tuples of integer values to [0,1] outside/inside values
+ // keep function handle for determining if a patch should be "kept"
+ // in the output based on the winding number on either side
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // J #FC list of indices into [Flist[0];Flist[1];...;Flist[k]]
+ // revealing "birth" facet
+ // Returns true iff inputs induce a piecewise constant winding number
+ // field
+ //
+ // See also: mesh_boolean_cork, intersect_other,
+ // remesh_self_intersections
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool mesh_boolean(
+ const std::vector<DerivedV > & Vlist,
+ const std::vector<DerivedF > & Flist,
+ const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
+ const std::function<int(const int, const int)> & keep,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool mesh_boolean(
+ const std::vector<DerivedV > & Vlist,
+ const std::vector<DerivedF > & Flist,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ // Given a merged mesh (V,F) and list of sizes of inputs
+ //
+ // Inputs:
+ // V #V by 3 list of merged mesh vertex positions
+ // F #F by 3 list of merged mesh face indices so that first sizes(0)
+ // faces come from the first input, and the next sizes(1) faces come
+ // from the second input, and so on.
+ // sizes #inputs list of sizes so that sizes(i) is the #faces in the
+ // ith input
+ // wind_num_op function handle for filtering winding numbers from
+ // tuples of integer values to [0,1] outside/inside values
+ // keep function handle for determining if a patch should be "kept"
+ // in the output based on the winding number on either side
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // J #FC list of birth parent indices
+ //
+ template <
+ typename DerivedVV,
+ typename DerivedFF,
+ typename Derivedsizes,
+ typename DerivedVC,
+ typename DerivedFC,
+ typename DerivedJ>
+ IGL_INLINE bool mesh_boolean(
+ const Eigen::MatrixBase<DerivedVV > & VV,
+ const Eigen::MatrixBase<DerivedFF > & FF,
+ const Eigen::MatrixBase<Derivedsizes> & sizes,
+ const std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
+ const std::function<int(const int, const int)> & keep,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC,
+ Eigen::PlainObjectBase<DerivedJ > & J);
+ // Inputs:
+ // VA #VA by 3 list of vertex positions of first mesh
+ // FA #FA by 3 list of triangle indices into VA
+ // VB #VB by 3 list of vertex positions of second mesh
+ // FB #FB by 3 list of triangle indices into VB
+ // type type of boolean operation
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of boolean result mesh
+ // FC #FC by 3 list of triangle indices into VC
+ // Returns true ff inputs induce a piecewise constant winding number
+ // field and type is valid
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC>
+ IGL_INLINE bool mesh_boolean(
+ const Eigen::MatrixBase<DerivedVA > & VA,
+ const Eigen::MatrixBase<DerivedFA > & FA,
+ const Eigen::MatrixBase<DerivedVB > & VB,
+ const Eigen::MatrixBase<DerivedFB > & FB,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mesh_boolean.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp b/xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp
new file mode 100644
index 000000000..41b67c1b7
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.cpp
@@ -0,0 +1,39 @@
+#include "mesh_boolean_type_to_funcs.h"
+#include "BinaryWindingNumberOperations.h"
+
+IGL_INLINE void igl::copyleft::cgal::mesh_boolean_type_to_funcs(
+ const MeshBooleanType & type,
+ std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >& wind_num_op,
+ std::function<int(const int, const int)> & keep)
+{
+ switch (type)
+ {
+ case MESH_BOOLEAN_TYPE_UNION:
+ wind_num_op = BinaryUnion();
+ keep = KeepInside();
+ return;
+ case MESH_BOOLEAN_TYPE_INTERSECT:
+ wind_num_op = BinaryIntersect();
+ keep = KeepInside();
+ return;
+ case MESH_BOOLEAN_TYPE_MINUS:
+ wind_num_op = BinaryMinus();
+ keep = KeepInside();
+ return;
+ case MESH_BOOLEAN_TYPE_XOR:
+ wind_num_op = BinaryXor();
+ keep = KeepInside();
+ return;
+ case MESH_BOOLEAN_TYPE_RESOLVE:
+ wind_num_op = BinaryResolve();
+ keep = KeepAll();
+ return;
+ default:
+ assert(false && "Unsupported boolean type.");
+ return;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h b/xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h
new file mode 100644
index 000000000..2a269d770
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_boolean_type_to_funcs.h
@@ -0,0 +1,37 @@
+#ifndef IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H
+#define IGL_COPYLEFT_CGAL_MESH_BOOLEAN_TYPE_TO_FUNCS_H
+
+#include "../../igl_inline.h"
+#include "../../MeshBooleanType.h"
+#include <Eigen/Core>
+#include <functional>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Convert a MeshBooleanType enum to a pair of winding number conversion
+ // function and "keep" function used by mesh_boolean
+ //
+ // Inputs:
+ // type MeshBooleanType enum value
+ // Outputs:
+ // wind_num_op function handle for filtering winding numbers from
+ // tuples of integer values to [0,1] outside/inside values
+ // keep function handle for determining if a patch should be "kept"
+ // in the output based on the winding number on either side
+ //
+ // See also: string_to_mesh_boolean_type
+ IGL_INLINE void mesh_boolean_type_to_funcs(
+ const MeshBooleanType & type,
+ std::function<int(const Eigen::Matrix<int,1,Eigen::Dynamic>) >&
+ wind_num_op,
+ std::function<int(const int, const int)> & keep);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "mesh_boolean_type_to_funcs.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp b/xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
new file mode 100644
index 000000000..7f3af539d
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.cpp
@@ -0,0 +1,76 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mesh_to_cgal_triangle_list.h"
+#include "assign.h"
+
+#include <cassert>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Kernel>
+IGL_INLINE void igl::copyleft::cgal::mesh_to_cgal_triangle_list(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<CGAL::Triangle_3<Kernel> > & T)
+{
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ // Must be 3D
+ assert(V.cols() == 3);
+ // **Copy** to convert to output type (this is especially/only needed if the
+ // input type DerivedV::Scalar is CGAL::Epeck
+ Eigen::Matrix<
+ typename Kernel::FT,
+ DerivedV::RowsAtCompileTime,
+ DerivedV::ColsAtCompileTime>
+ KV(V.rows(),V.cols());
+ assign(V,KV);
+ // Must be triangles
+ assert(F.cols() == 3);
+ T.reserve(F.rows());
+ // Loop over faces
+ for(int f = 0;f<(int)F.rows();f++)
+ {
+ T.push_back(
+ Triangle_3(
+ Point_3( KV(F(f,0),0), KV(F(f,0),1), KV(F(f,0),2)),
+ Point_3( KV(F(f,1),0), KV(F(f,1),1), KV(F(f,1),2)),
+ Point_3( KV(F(f,2),0), KV(F(f,2),1), KV(F(f,2),2))));
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > >&);
+template void igl::copyleft::cgal::mesh_to_cgal_triangle_list<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck>(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h b/xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h
new file mode 100644
index 000000000..492215bd5
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_to_cgal_triangle_list.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H
+#define IGL_COPYLEFT_CGAL_MESH_TO_CGAL_TRIANGLE_LIST_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include "CGAL_includes.hpp"
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Convert a mesh (V,F) to a list of CGAL triangles
+ //
+ // Templates:
+ // Kernal CGAL computation and construction kernel (e.g.
+ // CGAL::Exact_predicates_exact_constructions_kernel)
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // Outputs:
+ // T #F list of CGAL triangles
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Kernel>
+ IGL_INLINE void mesh_to_cgal_triangle_list(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<CGAL::Triangle_3<Kernel> > & T);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "mesh_to_cgal_triangle_list.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_to_polyhedron.cpp b/xs/src/igl/copyleft/cgal/mesh_to_polyhedron.cpp
new file mode 100644
index 000000000..b0bfe7079
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_to_polyhedron.cpp
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mesh_to_polyhedron.h"
+#include <CGAL/Polyhedron_3.h>
+#include <CGAL/Polyhedron_incremental_builder_3.h>
+
+
+template <typename Polyhedron>
+IGL_INLINE bool igl::copyleft::cgal::mesh_to_polyhedron(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ Polyhedron & poly)
+{
+ typedef typename Polyhedron::HalfedgeDS HalfedgeDS;
+ // Postcondition: hds is a valid polyhedral surface.
+ CGAL::Polyhedron_incremental_builder_3<HalfedgeDS> B(poly.hds());
+ B.begin_surface(V.rows(),F.rows());
+ typedef typename HalfedgeDS::Vertex Vertex;
+ typedef typename Vertex::Point Point;
+ assert(V.cols() == 3 && "V must be #V by 3");
+ for(int v = 0;v<V.rows();v++)
+ {
+ B.add_vertex(Point(V(v,0),V(v,1),V(v,2)));
+ }
+ assert(F.cols() == 3 && "F must be #F by 3");
+ for(int f=0;f<F.rows();f++)
+ {
+ B.begin_facet();
+ for(int c = 0;c<3;c++)
+ {
+ B.add_vertex_to_facet(F(f,c));
+ }
+ B.end_facet();
+ }
+ if(B.error())
+ {
+ B.rollback();
+ return false;
+ }
+ B.end_surface();
+ return poly.is_valid();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#include <CGAL/Simple_cartesian.h>
+#include <CGAL/Polyhedron_items_with_id_3.h>
+template bool igl::copyleft::cgal::mesh_to_polyhedron<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>, CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/mesh_to_polyhedron.h b/xs/src/igl/copyleft/cgal/mesh_to_polyhedron.h
new file mode 100644
index 000000000..de17d8aa2
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/mesh_to_polyhedron.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_MESH_TO_POLYHEDRON_H
+#define IGL_COPYLEFT_CGAL_MESH_TO_POLYHEDRON_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Convert a mesh (V,F) to a CGAL Polyhedron
+ //
+ // Templates:
+ // Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // Outputs:
+ // poly cgal polyhedron
+ // Returns true only if (V,F) can be converted to a valid polyhedron (i.e. if
+ // (V,F) is vertex and edge manifold).
+ template <typename Polyhedron>
+ IGL_INLINE bool mesh_to_polyhedron(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ Polyhedron & poly);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "mesh_to_polyhedron.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/minkowski_sum.cpp b/xs/src/igl/copyleft/cgal/minkowski_sum.cpp
new file mode 100644
index 000000000..c9045a4c7
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/minkowski_sum.cpp
@@ -0,0 +1,395 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "minkowski_sum.h"
+#include "mesh_boolean.h"
+
+#include "../../slice.h"
+#include "../../slice_mask.h"
+#include "../../LinSpaced.h"
+#include "../../unique_rows.h"
+#include "../../get_seconds.h"
+#include "../../edges.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <cassert>
+#include <vector>
+#include <iostream>
+
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedW,
+ typename DerivedG,
+ typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::MatrixBase<DerivedVB> & VB,
+ const Eigen::MatrixBase<DerivedFB> & FB,
+ const bool resolve_overlaps,
+ Eigen::PlainObjectBase<DerivedW> & W,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(FA.cols() == 3 && "FA must contain a closed triangle mesh");
+ assert(FB.cols() <= FA.cols() &&
+ "FB must contain lower diemnsional simplices than FA");
+ const auto tictoc = []()->double
+ {
+ static double t_start;
+ double now = igl::get_seconds();
+ double interval = now-t_start;
+ t_start = now;
+ return interval;
+ };
+ tictoc();
+ Matrix<typename DerivedFB::Scalar,Dynamic,2> EB;
+ edges(FB,EB);
+ Matrix<typename DerivedFA::Scalar,Dynamic,2> EA(0,2);
+ if(FB.cols() == 3)
+ {
+ edges(FA,EA);
+ }
+ // number of copies of A along edges of B
+ const int n_ab = EB.rows();
+ // number of copies of B along edges of A
+ const int n_ba = EA.rows();
+
+ vector<DerivedW> vW(n_ab + n_ba);
+ vector<DerivedG> vG(n_ab + n_ba);
+ vector<DerivedJ> vJ(n_ab + n_ba);
+ vector<int> offsets(n_ab + n_ba + 1);
+ offsets[0] = 0;
+ // sweep A along edges of B
+ for(int e = 0;e<n_ab;e++)
+ {
+ Matrix<typename DerivedJ::Scalar,Dynamic,1> eJ;
+ minkowski_sum(
+ VA,
+ FA,
+ VB.row(EB(e,0)).eval(),
+ VB.row(EB(e,1)).eval(),
+ false,
+ vW[e],
+ vG[e],
+ eJ);
+ assert(vG[e].rows() == eJ.rows());
+ assert(eJ.cols() == 1);
+ vJ[e].resize(vG[e].rows(),2);
+ vJ[e].col(0) = eJ;
+ vJ[e].col(1).setConstant(e);
+ offsets[e+1] = offsets[e] + vW[e].rows();
+ }
+ // sweep B along edges of A
+ for(int e = 0;e<n_ba;e++)
+ {
+ Matrix<typename DerivedJ::Scalar,Dynamic,1> eJ;
+ const int ee = n_ab+e;
+ minkowski_sum(
+ VB,
+ FB,
+ VA.row(EA(e,0)).eval(),
+ VA.row(EA(e,1)).eval(),
+ false,
+ vW[ee],
+ vG[ee],
+ eJ);
+ vJ[ee].resize(vG[ee].rows(),2);
+ vJ[ee].col(0) = eJ.array() + (FA.rows()+1);
+ vJ[ee].col(1).setConstant(ee);
+ offsets[ee+1] = offsets[ee] + vW[ee].rows();
+ }
+ // Combine meshes
+ int n=0,m=0;
+ for_each(vW.begin(),vW.end(),[&n](const DerivedW & w){n+=w.rows();});
+ for_each(vG.begin(),vG.end(),[&m](const DerivedG & g){m+=g.rows();});
+ assert(n == offsets.back());
+
+ W.resize(n,3);
+ G.resize(m,3);
+ J.resize(m,2);
+ {
+ int m_off = 0,n_off = 0;
+ for(int i = 0;i<vG.size();i++)
+ {
+ W.block(n_off,0,vW[i].rows(),3) = vW[i];
+ G.block(m_off,0,vG[i].rows(),3) = vG[i].array()+offsets[i];
+ J.block(m_off,0,vJ[i].rows(),2) = vJ[i];
+ n_off += vW[i].rows();
+ m_off += vG[i].rows();
+ }
+ assert(n == n_off);
+ assert(m == m_off);
+ }
+ if(resolve_overlaps)
+ {
+ Eigen::Matrix<typename DerivedJ::Scalar, Eigen::Dynamic,1> SJ;
+ mesh_boolean(
+ DerivedW(W),
+ DerivedG(G),
+ Matrix<typename DerivedW::Scalar,Dynamic,Dynamic>(),
+ Matrix<typename DerivedG::Scalar,Dynamic,Dynamic>(),
+ MESH_BOOLEAN_TYPE_UNION,
+ W,
+ G,
+ SJ);
+ slice(DerivedJ(J),SJ,1,J);
+ }
+}
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename sType, int sCols, int sOptions,
+ typename dType, int dCols, int dOptions,
+ typename DerivedW,
+ typename DerivedG,
+ typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::Matrix<sType,1,sCols,sOptions> & s,
+ const Eigen::Matrix<dType,1,dCols,dOptions> & d,
+ const bool resolve_overlaps,
+ Eigen::PlainObjectBase<DerivedW> & W,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(s.cols() == 3 && "s should be a 3d point");
+ assert(d.cols() == 3 && "d should be a 3d point");
+ // silly base case
+ if(FA.size() == 0)
+ {
+ W.resize(0,3);
+ G.resize(0,3);
+ return;
+ }
+ const int dim = VA.cols();
+ assert(dim == 3 && "dim must be 3D");
+ assert(s.size() == 3 && "s must be 3D point");
+ assert(d.size() == 3 && "d must be 3D point");
+ // segment vector
+ const CGAL::Vector_3<CGAL::Epeck> v(d(0)-s(0),d(1)-s(1),d(2)-s(2));
+ // number of vertices
+ const int n = VA.rows();
+ // duplicate vertices at s and d, we'll remove unreferernced later
+ W.resize(2*n,dim);
+ for(int i = 0;i<n;i++)
+ {
+ for(int j = 0;j<dim;j++)
+ {
+ W (i,j) = VA(i,j) + s(j);
+ W(i+n,j) = VA(i,j) + d(j);
+ }
+ }
+ // number of faces
+ const int m = FA.rows();
+ //// Mask whether positive dot product, or negative: because of exactly zero,
+ //// these are not necessarily complementary
+ // Nevermind, actually P = !N
+ Matrix<bool,Dynamic,1> P(m,1),N(m,1);
+ // loop over faces
+ int mp = 0,mn = 0;
+ for(int f = 0;f<m;f++)
+ {
+ const CGAL::Plane_3<CGAL::Epeck> plane(
+ CGAL::Point_3<CGAL::Epeck>(VA(FA(f,0),0),VA(FA(f,0),1),VA(FA(f,0),2)),
+ CGAL::Point_3<CGAL::Epeck>(VA(FA(f,1),0),VA(FA(f,1),1),VA(FA(f,1),2)),
+ CGAL::Point_3<CGAL::Epeck>(VA(FA(f,2),0),VA(FA(f,2),1),VA(FA(f,2),2)));
+ const auto normal = plane.orthogonal_vector();
+ const auto dt = normal * v;
+ if(dt > 0)
+ {
+ P(f) = true;
+ N(f) = false;
+ mp++;
+ }else
+ //}else if(dt < 0)
+ {
+ P(f) = false;
+ N(f) = true;
+ mn++;
+ //}else
+ //{
+ // P(f) = false;
+ // N(f) = false;
+ }
+ }
+
+ typedef Matrix<typename DerivedG::Scalar,Dynamic,Dynamic> MatrixXI;
+ typedef Matrix<typename DerivedG::Scalar,Dynamic,1> VectorXI;
+ MatrixXI GT(mp+mn,3);
+ GT<< slice_mask(FA,N,1), slice_mask((FA.array()+n).eval(),P,1);
+ // J indexes FA for parts at s and m+FA for parts at d
+ J.derived() = igl::LinSpaced<DerivedJ >(m,0,m-1);
+ DerivedJ JT(mp+mn);
+ JT << slice_mask(J,P,1), slice_mask(J,N,1);
+ JT.block(mp,0,mn,1).array()+=m;
+
+ // Original non-co-planar faces with positively oriented reversed
+ MatrixXI BA(mp+mn,3);
+ BA << slice_mask(FA,P,1).rowwise().reverse(), slice_mask(FA,N,1);
+ // Quads along **all** sides
+ MatrixXI GQ((mp+mn)*3,4);
+ GQ<<
+ BA.col(1), BA.col(0), BA.col(0).array()+n, BA.col(1).array()+n,
+ BA.col(2), BA.col(1), BA.col(1).array()+n, BA.col(2).array()+n,
+ BA.col(0), BA.col(2), BA.col(2).array()+n, BA.col(0).array()+n;
+
+ MatrixXI uGQ;
+ VectorXI S,sI,sJ;
+ // Inputs:
+ // F #F by d list of polygons
+ // Outputs:
+ // S #uF list of signed incidences for each unique face
+ // uF #uF by d list of unique faces
+ // I #uF index vector so that uF = sort(F,2)(I,:)
+ // J #F index vector so that sort(F,2) = uF(J,:)
+ [](
+ const MatrixXI & F,
+ VectorXI & S,
+ MatrixXI & uF,
+ VectorXI & I,
+ VectorXI & J)
+ {
+ const int m = F.rows();
+ const int d = F.cols();
+ MatrixXI sF = F;
+ const auto MN = sF.rowwise().minCoeff().eval();
+ // rotate until smallest index is first
+ for(int p = 0;p<d;p++)
+ {
+ for(int f = 0;f<m;f++)
+ {
+ if(sF(f,0) != MN(f))
+ {
+ for(int r = 0;r<d-1;r++)
+ {
+ std::swap(sF(f,r),sF(f,r+1));
+ }
+ }
+ }
+ }
+ // swap orienation so that last index is greater than first
+ for(int f = 0;f<m;f++)
+ {
+ if(sF(f,d-1) < sF(f,1))
+ {
+ sF.block(f,1,1,d-1) = sF.block(f,1,1,d-1).reverse().eval();
+ }
+ }
+ Matrix<bool,Dynamic,1> M = Matrix<bool,Dynamic,1>::Zero(m,1);
+ {
+ VectorXI P = igl::LinSpaced<VectorXI >(d,0,d-1);
+ for(int p = 0;p<d;p++)
+ {
+ for(int f = 0;f<m;f++)
+ {
+ bool all = true;
+ for(int r = 0;r<d;r++)
+ {
+ all = all && (sF(f,P(r)) == F(f,r));
+ }
+ M(f) = M(f) || all;
+ }
+ for(int r = 0;r<d-1;r++)
+ {
+ std::swap(P(r),P(r+1));
+ }
+ }
+ }
+ unique_rows(sF,uF,I,J);
+ S = VectorXI::Zero(uF.rows(),1);
+ assert(m == J.rows());
+ for(int f = 0;f<m;f++)
+ {
+ S(J(f)) += M(f) ? 1 : -1;
+ }
+ }(MatrixXI(GQ),S,uGQ,sI,sJ);
+ assert(S.rows() == uGQ.rows());
+ const int nq = (S.array().abs()==2).count();
+ GQ.resize(nq,4);
+ {
+ int k = 0;
+ for(int q = 0;q<uGQ.rows();q++)
+ {
+ switch(S(q))
+ {
+ case -2:
+ GQ.row(k++) = uGQ.row(q).reverse().eval();
+ break;
+ case 2:
+ GQ.row(k++) = uGQ.row(q);
+ break;
+ default:
+ // do not add
+ break;
+ }
+ }
+ assert(nq == k);
+ }
+
+ G.resize(GT.rows()+2*GQ.rows(),3);
+ G<<
+ GT,
+ GQ.col(0), GQ.col(1), GQ.col(2),
+ GQ.col(0), GQ.col(2), GQ.col(3);
+ J.resize(JT.rows()+2*GQ.rows(),1);
+ J<<JT,DerivedJ::Constant(2*GQ.rows(),1,2*m+1);
+ if(resolve_overlaps)
+ {
+ Eigen::Matrix<typename DerivedJ::Scalar, Eigen::Dynamic,1> SJ;
+ mesh_boolean(
+ DerivedW(W),DerivedG(G),
+ Matrix<typename DerivedVA::Scalar,Dynamic,Dynamic>(),MatrixXI(),
+ MESH_BOOLEAN_TYPE_UNION,
+ W,G,SJ);
+ J.derived() = slice(DerivedJ(J),SJ,1);
+ }
+}
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename sType, int sCols, int sOptions,
+ typename dType, int dCols, int dOptions,
+ typename DerivedW,
+ typename DerivedG,
+ typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::minkowski_sum(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::Matrix<sType,1,sCols,sOptions> & s,
+ const Eigen::Matrix<dType,1,dCols,dOptions> & d,
+ Eigen::PlainObjectBase<DerivedW> & W,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ return minkowski_sum(VA,FA,s,d,true,W,G,J);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::minkowski_sum<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, CGAL::Lazy_exact_nt<CGAL::Gmpq>, 3, 1, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::minkowski_sum<
+ Eigen::Matrix<float, -1, 3, 1, -1, 3>,
+ Eigen::Matrix<int, -1, 3, 1, -1, 3>,
+ double, 3, 1,
+ float, 3, 1,
+ Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>,
+ Eigen::Matrix<int, -1, -1, 0, -1, -1>,
+ Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<float, 1, 3, 1, 1, 3> const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/minkowski_sum.h b/xs/src/igl/copyleft/cgal/minkowski_sum.h
new file mode 100644
index 000000000..1631f0766
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/minkowski_sum.h
@@ -0,0 +1,110 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_MINKOWSKI_SUM_H
+#define IGL_COPYLEFT_CGAL_MINKOWSKI_SUM_H
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Compute the Minkowski sum of a closed triangle mesh (V,F) and a
+ // set of simplices in 3D.
+ //
+ // Inputs:
+ // VA #VA by 3 list of mesh vertices in 3D
+ // FA #FA by 3 list of triangle indices into VA
+ // VB #VB by 3 list of mesh vertices in 3D
+ // FB #FB by ss list of simplex indices into VB, ss<=3
+ // resolve_overlaps whether or not to resolve self-union. If false
+ // then result may contain self-intersections if input mesh is
+ // non-convex.
+ // Outputs:
+ // W #W by 3 list of mesh vertices in 3D
+ // G #G by 3 list of triangle indices into W
+ // J #G by 2 list of indices into
+ //
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedW,
+ typename DerivedG,
+ typename DerivedJ>
+ IGL_INLINE void minkowski_sum(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::MatrixBase<DerivedVB> & VB,
+ const Eigen::MatrixBase<DerivedFB> & FB,
+ const bool resolve_overlaps,
+ Eigen::PlainObjectBase<DerivedW> & W,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ // Compute the Minkowski sum of a closed triangle mesh (V,F) and a
+ // segment [s,d] in 3D.
+ //
+ // Inputs:
+ // VA #VA by 3 list of mesh vertices in 3D
+ // FA #FA by 3 list of triangle indices into VA
+ // s segment source endpoint in 3D
+ // d segment source endpoint in 3D
+ // resolve_overlaps whether or not to resolve self-union. If false
+ // then result may contain self-intersections if input mesh is
+ // non-convex.
+ // Outputs:
+ // W #W by 3 list of mesh vertices in 3D
+ // G #G by 3 list of triangle indices into W
+ // J #G list of indices into [F;#V+F;[s d]] of birth parents
+ //
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename sType, int sCols, int sOptions,
+ typename dType, int dCols, int dOptions,
+ typename DerivedW,
+ typename DerivedG,
+ typename DerivedJ>
+ IGL_INLINE void minkowski_sum(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::Matrix<sType,1,sCols,sOptions> & s,
+ const Eigen::Matrix<dType,1,dCols,dOptions> & d,
+ const bool resolve_overlaps,
+ Eigen::PlainObjectBase<DerivedW> & W,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename sType, int sCols, int sOptions,
+ typename dType, int dCols, int dOptions,
+ typename DerivedW,
+ typename DerivedG,
+ typename DerivedJ>
+ IGL_INLINE void minkowski_sum(
+ const Eigen::MatrixBase<DerivedVA> & VA,
+ const Eigen::MatrixBase<DerivedFA> & FA,
+ const Eigen::Matrix<sType,1,sCols,sOptions> & s,
+ const Eigen::Matrix<dType,1,dCols,dOptions> & d,
+ Eigen::PlainObjectBase<DerivedW> & W,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "minkowski_sum.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/order_facets_around_edge.cpp b/xs/src/igl/copyleft/cgal/order_facets_around_edge.cpp
new file mode 100644
index 000000000..13b585b50
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/order_facets_around_edge.cpp
@@ -0,0 +1,428 @@
+#include "order_facets_around_edge.h"
+#include <Eigen/Geometry>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#include <stdexcept>
+
+// adj_faces contains signed index starting from +- 1.
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI >
+void igl::copyleft::cgal::order_facets_around_edge(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ size_t s,
+ size_t d,
+ const std::vector<int>& adj_faces,
+ Eigen::PlainObjectBase<DerivedI>& order, bool debug)
+{
+ // Although we only need exact predicates in the algorithm,
+ // exact constructions are needed to avoid degeneracies due to
+ // casting to double.
+ typedef CGAL::Exact_predicates_exact_constructions_kernel K;
+ typedef K::Point_3 Point_3;
+ typedef K::Plane_3 Plane_3;
+
+ auto get_face_index = [&](int adj_f)->size_t
+ {
+ return abs(adj_f) - 1;
+ };
+
+ auto get_opposite_vertex = [&](size_t fid)->size_t
+ {
+ typedef typename DerivedF::Scalar Index;
+ if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0);
+ if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1);
+ if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2);
+ assert(false);
+ return -1;
+ };
+
+ // Handle base cases
+ if (adj_faces.size() == 0)
+ {
+ order.resize(0, 1);
+ return;
+ } else if (adj_faces.size() == 1)
+ {
+ order.resize(1, 1);
+ order(0, 0) = 0;
+ return;
+ } else if (adj_faces.size() == 2)
+ {
+ const size_t o1 = get_opposite_vertex(get_face_index(adj_faces[0]));
+ const size_t o2 = get_opposite_vertex(get_face_index(adj_faces[1]));
+ const Point_3 ps(V(s, 0), V(s, 1), V(s, 2));
+ const Point_3 pd(V(d, 0), V(d, 1), V(d, 2));
+ const Point_3 p1(V(o1, 0), V(o1, 1), V(o1, 2));
+ const Point_3 p2(V(o2, 0), V(o2, 1), V(o2, 2));
+ order.resize(2, 1);
+ switch (CGAL::orientation(ps, pd, p1, p2))
+ {
+ case CGAL::POSITIVE:
+ order(0, 0) = 1;
+ order(1, 0) = 0;
+ break;
+ case CGAL::NEGATIVE:
+ order(0, 0) = 0;
+ order(1, 0) = 1;
+ break;
+ case CGAL::COPLANAR:
+ {
+ switch (CGAL::coplanar_orientation(ps, pd, p1, p2)) {
+ case CGAL::POSITIVE:
+ // Duplicated face, use index to break tie.
+ order(0, 0) = adj_faces[0] < adj_faces[1] ? 0:1;
+ order(1, 0) = adj_faces[0] < adj_faces[1] ? 1:0;
+ break;
+ case CGAL::NEGATIVE:
+ // Coplanar faces, one on each side of the edge.
+ // It is equally valid to order them (0, 1) or (1, 0).
+ // I cannot think of any reason to prefer one to the
+ // other. So just use (0, 1) ordering by default.
+ order(0, 0) = 0;
+ order(1, 0) = 1;
+ break;
+ case CGAL::COLLINEAR:
+ std::cerr << "Degenerated triangle detected." <<
+ std::endl;
+ assert(false);
+ break;
+ default:
+ assert(false);
+ }
+ }
+ break;
+ default:
+ assert(false);
+ }
+ return;
+ }
+
+ const size_t num_adj_faces = adj_faces.size();
+ const size_t o = get_opposite_vertex( get_face_index(adj_faces[0]));
+ const Point_3 p_s(V(s, 0), V(s, 1), V(s, 2));
+ const Point_3 p_d(V(d, 0), V(d, 1), V(d, 2));
+ const Point_3 p_o(V(o, 0), V(o, 1), V(o, 2));
+ const Plane_3 separator(p_s, p_d, p_o);
+ if (separator.is_degenerate()) {
+ throw std::runtime_error(
+ "Cannot order facets around edge due to degenerated facets");
+ }
+
+ std::vector<Point_3> opposite_vertices;
+ for (size_t i=0; i<num_adj_faces; i++)
+ {
+ const size_t o = get_opposite_vertex( get_face_index(adj_faces[i]));
+ opposite_vertices.emplace_back(
+ V(o, 0), V(o, 1), V(o, 2));
+ }
+
+ std::vector<int> positive_side;
+ std::vector<int> negative_side;
+ std::vector<int> tie_positive_oriented;
+ std::vector<int> tie_negative_oriented;
+
+ std::vector<size_t> positive_side_index;
+ std::vector<size_t> negative_side_index;
+ std::vector<size_t> tie_positive_oriented_index;
+ std::vector<size_t> tie_negative_oriented_index;
+
+ for (size_t i=0; i<num_adj_faces; i++)
+ {
+ const int f = adj_faces[i];
+ const Point_3& p_a = opposite_vertices[i];
+ auto orientation = separator.oriented_side(p_a);
+ switch (orientation) {
+ case CGAL::ON_POSITIVE_SIDE:
+ positive_side.push_back(f);
+ positive_side_index.push_back(i);
+ break;
+ case CGAL::ON_NEGATIVE_SIDE:
+ negative_side.push_back(f);
+ negative_side_index.push_back(i);
+ break;
+ case CGAL::ON_ORIENTED_BOUNDARY:
+ {
+ auto inplane_orientation = CGAL::coplanar_orientation(
+ p_s, p_d, p_o, p_a);
+ switch (inplane_orientation) {
+ case CGAL::POSITIVE:
+ tie_positive_oriented.push_back(f);
+ tie_positive_oriented_index.push_back(i);
+ break;
+ case CGAL::NEGATIVE:
+ tie_negative_oriented.push_back(f);
+ tie_negative_oriented_index.push_back(i);
+ break;
+ case CGAL::COLLINEAR:
+ default:
+ throw std::runtime_error(
+ "Degenerated facet detected.");
+ break;
+ }
+ }
+ break;
+ default:
+ // Should not be here.
+ throw std::runtime_error("Unknown CGAL state detected.");
+ }
+ }
+ if (debug) {
+ std::cout << "tie positive: " << std::endl;
+ for (auto& f : tie_positive_oriented) {
+ std::cout << get_face_index(f) << " ";
+ }
+ std::cout << std::endl;
+ std::cout << "positive side: " << std::endl;
+ for (auto& f : positive_side) {
+ std::cout << get_face_index(f) << " ";
+ }
+ std::cout << std::endl;
+ std::cout << "tie negative: " << std::endl;
+ for (auto& f : tie_negative_oriented) {
+ std::cout << get_face_index(f) << " ";
+ }
+ std::cout << std::endl;
+ std::cout << "negative side: " << std::endl;
+ for (auto& f : negative_side) {
+ std::cout << get_face_index(f) << " ";
+ }
+ std::cout << std::endl;
+ }
+
+ auto index_sort = [](std::vector<int>& data) -> std::vector<size_t>{
+ const size_t len = data.size();
+ std::vector<size_t> order(len);
+ for (size_t i=0; i<len; i++) { order[i] = i; }
+ auto comp = [&](size_t i, size_t j) { return data[i] < data[j]; };
+ std::sort(order.begin(), order.end(), comp);
+ return order;
+ };
+
+ DerivedI positive_order, negative_order;
+ order_facets_around_edge(V, F, s, d, positive_side, positive_order, debug);
+ order_facets_around_edge(V, F, s, d, negative_side, negative_order, debug);
+ std::vector<size_t> tie_positive_order = index_sort(tie_positive_oriented);
+ std::vector<size_t> tie_negative_order = index_sort(tie_negative_oriented);
+
+ // Copy results into order vector.
+ const size_t tie_positive_size = tie_positive_oriented.size();
+ const size_t tie_negative_size = tie_negative_oriented.size();
+ const size_t positive_size = positive_order.size();
+ const size_t negative_size = negative_order.size();
+
+ order.resize(
+ tie_positive_size + positive_size + tie_negative_size + negative_size,1);
+
+ size_t count=0;
+ for (size_t i=0; i<tie_positive_size; i++)
+ {
+ order(count+i, 0) = tie_positive_oriented_index[tie_positive_order[i]];
+ }
+ count += tie_positive_size;
+
+ for (size_t i=0; i<negative_size; i++)
+ {
+ order(count+i, 0) = negative_side_index[negative_order(i, 0)];
+ }
+ count += negative_size;
+
+ for (size_t i=0; i<tie_negative_size; i++)
+ {
+ order(count+i, 0) = tie_negative_oriented_index[tie_negative_order[i]];
+ }
+ count += tie_negative_size;
+
+ for (size_t i=0; i<positive_size; i++)
+ {
+ order(count+i, 0) = positive_side_index[positive_order(i, 0)];
+ }
+ count += positive_size;
+ assert(count == num_adj_faces);
+
+ // Find the correct start point.
+ size_t start_idx = 0;
+ for (size_t i=0; i<num_adj_faces; i++)
+ {
+ const Point_3& p_a = opposite_vertices[order(i, 0)];
+ const Point_3& p_b =
+ opposite_vertices[order((i+1)%num_adj_faces, 0)];
+ auto orientation = CGAL::orientation(p_s, p_d, p_a, p_b);
+ if (orientation == CGAL::POSITIVE)
+ {
+ // Angle between triangle (p_s, p_d, p_a) and (p_s, p_d, p_b) is
+ // more than 180 degrees.
+ start_idx = (i+1)%num_adj_faces;
+ break;
+ } else if (orientation == CGAL::COPLANAR &&
+ Plane_3(p_s, p_d, p_a).orthogonal_direction() !=
+ Plane_3(p_s, p_d, p_b).orthogonal_direction())
+ {
+ // All 4 points are coplanar, but p_a and p_b are on each side of
+ // the edge (p_s, p_d). This means the angle between triangle
+ // (p_s, p_d, p_a) and (p_s, p_d, p_b) is exactly 180 degrees.
+ start_idx = (i+1)%num_adj_faces;
+ break;
+ }
+ }
+ DerivedI circular_order = order;
+ for (size_t i=0; i<num_adj_faces; i++)
+ {
+ order(i, 0) = circular_order((start_idx + i)%num_adj_faces, 0);
+ }
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI>
+IGL_INLINE
+void igl::copyleft::cgal::order_facets_around_edge(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ size_t s,
+ size_t d,
+ const std::vector<int>& adj_faces,
+ const Eigen::PlainObjectBase<DerivedV>& pivot_point,
+ Eigen::PlainObjectBase<DerivedI>& order)
+{
+ assert(V.cols() == 3);
+ assert(F.cols() == 3);
+ assert(pivot_point.cols() == 3);
+ auto signed_index_to_index = [&](int signed_idx)
+ {
+ return abs(signed_idx) -1;
+ };
+ auto get_opposite_vertex_index = [&](size_t fid) -> typename DerivedF::Scalar
+ {
+ typedef typename DerivedF::Scalar Index;
+ if (F(fid, 0) != (Index)s && F(fid, 0) != (Index)d) return F(fid, 0);
+ if (F(fid, 1) != (Index)s && F(fid, 1) != (Index)d) return F(fid, 1);
+ if (F(fid, 2) != (Index)s && F(fid, 2) != (Index)d) return F(fid, 2);
+ assert(false);
+ // avoid warning
+ return -1;
+ };
+
+ {
+ // Check if s, d and pivot are collinear.
+ typedef CGAL::Exact_predicates_exact_constructions_kernel K;
+ K::Point_3 ps(V(s,0), V(s,1), V(s,2));
+ K::Point_3 pd(V(d,0), V(d,1), V(d,2));
+ K::Point_3 pp(pivot_point(0,0), pivot_point(0,1), pivot_point(0,2));
+ if (CGAL::collinear(ps, pd, pp)) {
+ throw std::runtime_error(
+ "Pivot point is collinear with the outer edge!");
+ }
+ }
+
+ const size_t N = adj_faces.size();
+ const size_t num_faces = N + 1; // N adj faces + 1 pivot face
+
+ // Because face indices are used for tie breaking, the original face indices
+ // in the new faces array must be ascending.
+ auto comp = [&](int i, int j)
+ {
+ return signed_index_to_index(adj_faces[i]) <
+ signed_index_to_index(adj_faces[j]);
+ };
+ std::vector<size_t> adj_order(N);
+ for (size_t i=0; i<N; i++) adj_order[i] = i;
+ std::sort(adj_order.begin(), adj_order.end(), comp);
+
+ DerivedV vertices(num_faces + 2, 3);
+ for (size_t i=0; i<N; i++)
+ {
+ const size_t fid = signed_index_to_index(adj_faces[adj_order[i]]);
+ vertices.row(i) = V.row(get_opposite_vertex_index(fid));
+ }
+ vertices.row(N ) = pivot_point;
+ vertices.row(N+1) = V.row(s);
+ vertices.row(N+2) = V.row(d);
+
+ DerivedF faces(num_faces, 3);
+ for (size_t i=0; i<N; i++)
+ {
+ if (adj_faces[adj_order[i]] < 0)
+ {
+ faces(i,0) = N+1; // s
+ faces(i,1) = N+2; // d
+ faces(i,2) = i ;
+ } else
+ {
+ faces(i,0) = N+2; // d
+ faces(i,1) = N+1; // s
+ faces(i,2) = i ;
+ }
+ }
+ // Last face is the pivot face.
+ faces(N, 0) = N+1;
+ faces(N, 1) = N+2;
+ faces(N, 2) = N;
+
+ std::vector<int> adj_faces_with_pivot(num_faces);
+ for (size_t i=0; i<num_faces; i++)
+ {
+ if ((size_t)faces(i,0) == N+1 && (size_t)faces(i,1) == N+2)
+ {
+ adj_faces_with_pivot[i] = int(i+1) * -1;
+ } else
+ {
+ adj_faces_with_pivot[i] = int(i+1);
+ }
+ }
+
+ DerivedI order_with_pivot;
+ order_facets_around_edge(
+ vertices, faces, N+1, N+2, adj_faces_with_pivot, order_with_pivot);
+
+ assert((size_t)order_with_pivot.size() == num_faces);
+ order.resize(N);
+ size_t pivot_index = num_faces + 1;
+ for (size_t i=0; i<num_faces; i++)
+ {
+ if ((size_t)order_with_pivot[i] == N)
+ {
+ pivot_index = i;
+ break;
+ }
+ }
+ assert(pivot_index < num_faces);
+
+ for (size_t i=0; i<N; i++)
+ {
+ order[i] = adj_order[order_with_pivot[(pivot_index+i+1)%num_faces]];
+ }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::order_facets_around_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, unsigned long, unsigned long, std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, bool);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::order_facets_around_edge<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, unsigned __int64, unsigned __int64, class std::vector<int, class std::allocator<int>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/order_facets_around_edge.h b/xs/src/igl/copyleft/cgal/order_facets_around_edge.h
new file mode 100644
index 000000000..6e09129ac
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/order_facets_around_edge.h
@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGE_H
+#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGE_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given a directed edge, sort its adjacent faces. Assuming the
+ // directed edge is (s, d). Sort the adjacent faces clockwise around the
+ // axis (d - s), i.e. left-hand rule. An adjacent face is consistently
+ // oriented if it contains (d, s) as a directed edge.
+ //
+ // For overlapping faces, break the tie using signed face index, smaller
+ // signed index comes before the larger signed index. Signed index is
+ // computed as (consistent? 1:-1) * (face_index + 1).
+ //
+ // Inputs:
+ // V #V by 3 list of vertices.
+ // F #F by 3 list of faces
+ // s Index of source vertex.
+ // d Index of destination vertex.
+ // adj_faces List of adjacent face signed indices.
+ // Output:
+ // order List of face indices that orders adjacent faces around edge
+ // (s, d) clockwise.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI >
+ IGL_INLINE
+ void order_facets_around_edge(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ size_t s,
+ size_t d,
+ const std::vector<int>& adj_faces,
+ Eigen::PlainObjectBase<DerivedI>& order,
+ bool debug=false);
+
+ // This function is a wrapper around the one above. Since the ordering
+ // is circular, the pivot point is used to define a starting point. So
+ // order[0] is the index into adj_face that is immediately after the
+ // pivot face (s, d, pivot point) in clockwise order.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI>
+ IGL_INLINE
+ void order_facets_around_edge(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ size_t s,
+ size_t d,
+ const std::vector<int>& adj_faces,
+ const Eigen::PlainObjectBase<DerivedV>& pivot_point,
+ Eigen::PlainObjectBase<DerivedI>& order);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "order_facets_around_edge.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/order_facets_around_edges.cpp b/xs/src/igl/copyleft/cgal/order_facets_around_edges.cpp
new file mode 100644
index 000000000..767d3e899
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/order_facets_around_edges.cpp
@@ -0,0 +1,332 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "order_facets_around_edges.h"
+#include "order_facets_around_edge.h"
+#include "../../sort_angles.h"
+#include <Eigen/Geometry>
+#include <type_traits>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DeriveduE,
+ typename uE2EType,
+ typename uE2oEType,
+ typename uE2CType >
+IGL_INLINE
+typename std::enable_if<!std::is_same<typename DerivedV::Scalar,
+typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
+igl::copyleft::cgal::order_facets_around_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedN>& N,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<uE2oEType> >& uE2oE,
+ std::vector<std::vector<uE2CType > >& uE2C ) {
+
+ typedef Eigen::Matrix<typename DerivedN::Scalar, 3, 1> Vector3F;
+ const typename DerivedV::Scalar EPS = 1e-12;
+ const size_t num_faces = F.rows();
+ const size_t num_undirected_edges = uE.rows();
+
+ auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
+ auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
+
+ uE2oE.resize(num_undirected_edges);
+ uE2C.resize(num_undirected_edges);
+
+ for(size_t ui = 0;ui<num_undirected_edges;ui++)
+ {
+ const auto& adj_edges = uE2E[ui];
+ const size_t edge_valance = adj_edges.size();
+ assert(edge_valance > 0);
+
+ const auto ref_edge = adj_edges[0];
+ const auto ref_face = edge_index_to_face_index(ref_edge);
+ Vector3F ref_normal = N.row(ref_face);
+
+ const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
+ const auto ref_corner_s = (ref_corner_o+1)%3;
+ const auto ref_corner_d = (ref_corner_o+2)%3;
+
+ const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
+ const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
+ const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
+
+ Vector3F edge = V.row(d) - V.row(s);
+ auto edge_len = edge.norm();
+ bool degenerated = edge_len < EPS;
+ if (degenerated) {
+ if (edge_valance <= 2) {
+ // There is only one way to order 2 or less faces.
+ edge.setZero();
+ } else {
+ edge.setZero();
+ Eigen::Matrix<typename DerivedN::Scalar, Eigen::Dynamic, 3>
+ normals(edge_valance, 3);
+ for (size_t fei=0; fei<edge_valance; fei++) {
+ const auto fe = adj_edges[fei];
+ const auto f = edge_index_to_face_index(fe);
+ normals.row(fei) = N.row(f);
+ }
+ for (size_t i=0; i<edge_valance; i++) {
+ size_t j = (i+1) % edge_valance;
+ Vector3F ni = normals.row(i);
+ Vector3F nj = normals.row(j);
+ edge = ni.cross(nj);
+ edge_len = edge.norm();
+ if (edge_len >= EPS) {
+ edge.normalize();
+ break;
+ }
+ }
+
+ // Ensure edge direction are consistent with reference face.
+ Vector3F in_face_vec = V.row(o) - V.row(s);
+ if (edge.cross(in_face_vec).dot(ref_normal) < 0) {
+ edge *= -1;
+ }
+
+ if (edge.norm() < EPS) {
+ std::cerr << "=====================================" << std::endl;
+ std::cerr << " ui: " << ui << std::endl;
+ std::cerr << "edge: " << ref_edge << std::endl;
+ std::cerr << "face: " << ref_face << std::endl;
+ std::cerr << " vs: " << V.row(s) << std::endl;
+ std::cerr << " vd: " << V.row(d) << std::endl;
+ std::cerr << "adj face normals: " << std::endl;
+ std::cerr << normals << std::endl;
+ std::cerr << "Very degenerated case detected:" << std::endl;
+ std::cerr << "Near zero edge surrounded by "
+ << edge_valance << " neearly colinear faces" <<
+ std::endl;
+ std::cerr << "=====================================" << std::endl;
+ }
+ }
+ } else {
+ edge.normalize();
+ }
+
+ Eigen::MatrixXd angle_data(edge_valance, 3);
+ std::vector<bool> cons(edge_valance);
+
+ for (size_t fei=0; fei<edge_valance; fei++) {
+ const auto fe = adj_edges[fei];
+ const auto f = edge_index_to_face_index(fe);
+ const auto c = edge_index_to_corner_index(fe);
+ cons[fei] = (d == F(f, (c+1)%3));
+ assert( cons[fei] || (d == F(f,(c+2)%3)));
+ assert(!cons[fei] || (s == F(f,(c+2)%3)));
+ assert(!cons[fei] || (d == F(f,(c+1)%3)));
+ Vector3F n = N.row(f);
+ angle_data(fei, 0) = ref_normal.cross(n).dot(edge);
+ angle_data(fei, 1) = ref_normal.dot(n);
+ if (cons[fei]) {
+ angle_data(fei, 0) *= -1;
+ angle_data(fei, 1) *= -1;
+ }
+ angle_data(fei, 0) *= -1; // Sort clockwise.
+ angle_data(fei, 2) = (cons[fei]?1.:-1.)*(f+1);
+ }
+
+ Eigen::VectorXi order;
+ igl::sort_angles(angle_data, order);
+
+ auto& ordered_edges = uE2oE[ui];
+ auto& consistency = uE2C[ui];
+
+ ordered_edges.resize(edge_valance);
+ consistency.resize(edge_valance);
+ for (size_t fei=0; fei<edge_valance; fei++) {
+ ordered_edges[fei] = adj_edges[order[fei]];
+ consistency[fei] = cons[order[fei]];
+ }
+ }
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DeriveduE,
+ typename uE2EType,
+ typename uE2oEType,
+ typename uE2CType >
+IGL_INLINE
+typename std::enable_if<std::is_same<typename DerivedV::Scalar,
+typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
+igl::copyleft::cgal::order_facets_around_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedN>& N,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<uE2oEType> >& uE2oE,
+ std::vector<std::vector<uE2CType > >& uE2C ) {
+
+ typedef Eigen::Matrix<typename DerivedN::Scalar, 3, 1> Vector3F;
+ typedef Eigen::Matrix<typename DerivedV::Scalar, 3, 1> Vector3E;
+ const typename DerivedV::Scalar EPS = 1e-12;
+ const size_t num_faces = F.rows();
+ const size_t num_undirected_edges = uE.rows();
+
+ auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
+ auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
+
+ uE2oE.resize(num_undirected_edges);
+ uE2C.resize(num_undirected_edges);
+
+ for(size_t ui = 0;ui<num_undirected_edges;ui++)
+ {
+ const auto& adj_edges = uE2E[ui];
+ const size_t edge_valance = adj_edges.size();
+ assert(edge_valance > 0);
+
+ const auto ref_edge = adj_edges[0];
+ const auto ref_face = edge_index_to_face_index(ref_edge);
+ Vector3F ref_normal = N.row(ref_face);
+
+ const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
+ const auto ref_corner_s = (ref_corner_o+1)%3;
+ const auto ref_corner_d = (ref_corner_o+2)%3;
+
+ const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
+ const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
+ const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
+
+ Vector3E exact_edge = V.row(d) - V.row(s);
+ exact_edge.array() /= exact_edge.squaredNorm();
+ Vector3F edge(
+ CGAL::to_double(exact_edge[0]),
+ CGAL::to_double(exact_edge[1]),
+ CGAL::to_double(exact_edge[2]));
+ edge.normalize();
+
+ Eigen::MatrixXd angle_data(edge_valance, 3);
+ std::vector<bool> cons(edge_valance);
+
+ for (size_t fei=0; fei<edge_valance; fei++) {
+ const auto fe = adj_edges[fei];
+ const auto f = edge_index_to_face_index(fe);
+ const auto c = edge_index_to_corner_index(fe);
+ cons[fei] = (d == F(f, (c+1)%3));
+ assert( cons[fei] || (d == F(f,(c+2)%3)));
+ assert(!cons[fei] || (s == F(f,(c+2)%3)));
+ assert(!cons[fei] || (d == F(f,(c+1)%3)));
+ Vector3F n = N.row(f);
+ angle_data(fei, 0) = ref_normal.cross(n).dot(edge);
+ angle_data(fei, 1) = ref_normal.dot(n);
+ if (cons[fei]) {
+ angle_data(fei, 0) *= -1;
+ angle_data(fei, 1) *= -1;
+ }
+ angle_data(fei, 0) *= -1; // Sort clockwise.
+ angle_data(fei, 2) = (cons[fei]?1.:-1.)*(f+1);
+ }
+
+ Eigen::VectorXi order;
+ igl::sort_angles(angle_data, order);
+
+ auto& ordered_edges = uE2oE[ui];
+ auto& consistency = uE2C[ui];
+
+ ordered_edges.resize(edge_valance);
+ consistency.resize(edge_valance);
+ for (size_t fei=0; fei<edge_valance; fei++) {
+ ordered_edges[fei] = adj_edges[order[fei]];
+ consistency[fei] = cons[order[fei]];
+ }
+ }
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DeriveduE,
+ typename uE2EType,
+ typename uE2oEType,
+ typename uE2CType >
+IGL_INLINE void igl::copyleft::cgal::order_facets_around_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<uE2oEType> >& uE2oE,
+ std::vector<std::vector<uE2CType > >& uE2C ) {
+
+ //typedef Eigen::Matrix<typename DerivedV::Scalar, 3, 1> Vector3E;
+ const size_t num_faces = F.rows();
+ const size_t num_undirected_edges = uE.rows();
+
+ auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
+ auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
+
+ uE2oE.resize(num_undirected_edges);
+ uE2C.resize(num_undirected_edges);
+
+ for(size_t ui = 0;ui<num_undirected_edges;ui++)
+ {
+ const auto& adj_edges = uE2E[ui];
+ const size_t edge_valance = adj_edges.size();
+ assert(edge_valance > 0);
+
+ const auto ref_edge = adj_edges[0];
+ const auto ref_face = edge_index_to_face_index(ref_edge);
+
+ const auto ref_corner_o = edge_index_to_corner_index(ref_edge);
+ const auto ref_corner_s = (ref_corner_o+1)%3;
+ const auto ref_corner_d = (ref_corner_o+2)%3;
+
+ //const typename DerivedF::Scalar o = F(ref_face, ref_corner_o);
+ const typename DerivedF::Scalar s = F(ref_face, ref_corner_s);
+ const typename DerivedF::Scalar d = F(ref_face, ref_corner_d);
+
+ std::vector<bool> cons(edge_valance);
+ std::vector<int> adj_faces(edge_valance);
+ for (size_t fei=0; fei<edge_valance; fei++) {
+ const auto fe = adj_edges[fei];
+ const auto f = edge_index_to_face_index(fe);
+ const auto c = edge_index_to_corner_index(fe);
+ cons[fei] = (d == F(f, (c+1)%3));
+ adj_faces[fei] = (f+1) * (cons[fei] ? 1:-1);
+
+ assert( cons[fei] || (d == F(f,(c+2)%3)));
+ assert(!cons[fei] || (s == F(f,(c+2)%3)));
+ assert(!cons[fei] || (d == F(f,(c+1)%3)));
+ }
+
+ Eigen::VectorXi order;
+ order_facets_around_edge(V, F, s, d, adj_faces, order);
+ assert((size_t)order.size() == edge_valance);
+
+ auto& ordered_edges = uE2oE[ui];
+ auto& consistency = uE2C[ui];
+
+ ordered_edges.resize(edge_valance);
+ consistency.resize(edge_valance);
+ for (size_t fei=0; fei<edge_valance; fei++) {
+ ordered_edges[fei] = adj_edges[order[fei]];
+ consistency[fei] = cons[order[fei]];
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, int, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
+// generated by autoexplicit.sh
+template std::enable_if<!(std::is_same<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, CGAL::Lazy_exact_nt<CGAL::Gmpq> >::value), void>::type igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, int, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
+template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
+template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
+template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
+template void igl::copyleft::cgal::order_facets_around_edges<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, long, long, bool>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/order_facets_around_edges.h b/xs/src/igl/copyleft/cgal/order_facets_around_edges.h
new file mode 100644
index 000000000..89ac2918e
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/order_facets_around_edges.h
@@ -0,0 +1,107 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGES_H
+#define IGL_COPYLEFT_CGAL_ORDER_FACETS_AROUND_EDGES_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // For each undirected edge, sort its adjacent faces. Assuming the
+ // undirected edge is (s, d). Sort the adjacent faces clockwise around the
+ // axis (d - s), i.e. left-hand rule. An adjacent face is consistently
+ // oriented if it contains (d, s) as a directed edge.
+ //
+ // For overlapping faces, break the tie using signed face index, smaller
+ // signed index comes before the larger signed index. Signed index is
+ // computed as (consistent? 1:-1) * index.
+ //
+ // Inputs:
+ // V #V by 3 list of vertices.
+ // F #F by 3 list of faces
+ // N #F by 3 list of face normals.
+ // uE #uE by 2 list of vertex_indices, represents undirected edges.
+ // uE2E #uE list of lists that maps uE to E. (a one-to-many map)
+ //
+ // Outputs:
+ // uE2oE #uE list of lists that maps uE to an ordered list of E. (a
+ // one-to-many map)
+ // uE2C #uE list of lists of bools indicates whether each face in
+ // uE2oE[i] is consistently orientated as the ordering.
+ //
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DeriveduE,
+ typename uE2EType,
+ typename uE2oEType,
+ typename uE2CType >
+ IGL_INLINE
+ typename std::enable_if<!std::is_same<typename DerivedV::Scalar,
+ typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
+ order_facets_around_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedN>& N,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<uE2oEType> >& uE2oE,
+ std::vector<std::vector<uE2CType > >& uE2C );
+
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DeriveduE,
+ typename uE2EType,
+ typename uE2oEType,
+ typename uE2CType >
+ IGL_INLINE
+ typename std::enable_if<std::is_same<typename DerivedV::Scalar,
+ typename CGAL::Exact_predicates_exact_constructions_kernel::FT>::value, void>::type
+ order_facets_around_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedN>& N,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<uE2oEType> >& uE2oE,
+ std::vector<std::vector<uE2CType > >& uE2C );
+
+ // Order faces around each edge. Only exact predicate is used in the algorithm.
+ // Normal is not needed.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DeriveduE,
+ typename uE2EType,
+ typename uE2oEType,
+ typename uE2CType >
+ IGL_INLINE void order_facets_around_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<uE2oEType> >& uE2oE,
+ std::vector<std::vector<uE2CType > >& uE2C );
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "order_facets_around_edges.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/orient2D.cpp b/xs/src/igl/copyleft/cgal/orient2D.cpp
new file mode 100644
index 000000000..ee5933bb4
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/orient2D.cpp
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "orient2D.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+
+template<typename Scalar>
+IGL_INLINE short igl::copyleft::cgal::orient2D(
+ const Scalar pa[2],
+ const Scalar pb[2],
+ const Scalar pc[2])
+{
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
+ typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
+ typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
+ Epeck, Epick>::type Kernel;
+
+ switch(CGAL::orientation(
+ typename Kernel::Point_2(pa[0], pa[1]),
+ typename Kernel::Point_2(pb[0], pb[1]),
+ typename Kernel::Point_2(pc[0], pc[1]))) {
+ case CGAL::LEFT_TURN:
+ return 1;
+ case CGAL::RIGHT_TURN:
+ return -1;
+ case CGAL::COLLINEAR:
+ return 0;
+ default:
+ throw "Invalid orientation";
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/orient2D.h b/xs/src/igl/copyleft/cgal/orient2D.h
new file mode 100644
index 000000000..0f2483dfd
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/orient2D.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_ORIENT_2D_H
+#define IGL_COPYLEFT_CGAL_ORIENT_2D_H
+
+#include "../../igl_inline.h"
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Inputs:
+ // pa,pb,pc 2D points.
+ // Output:
+ // 1 if pa,pb,pc are counterclockwise oriented.
+ // 0 if pa,pb,pc are counterclockwise oriented.
+ // -1 if pa,pb,pc are clockwise oriented.
+ template <typename Scalar>
+ IGL_INLINE short orient2D(
+ const Scalar pa[2],
+ const Scalar pb[2],
+ const Scalar pc[2]);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "orient2D.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/orient3D.cpp b/xs/src/igl/copyleft/cgal/orient3D.cpp
new file mode 100644
index 000000000..3bdbfb80e
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/orient3D.cpp
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "orient3D.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+
+template<typename Scalar>
+IGL_INLINE short igl::copyleft::cgal::orient3D(
+ const Scalar pa[3],
+ const Scalar pb[3],
+ const Scalar pc[3],
+ const Scalar pd[3])
+{
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Epeck;
+ typedef CGAL::Exact_predicates_inexact_constructions_kernel Epick;
+ typedef typename std::conditional<std::is_same<Scalar, Epeck::FT>::value,
+ Epeck, Epick>::type Kernel;
+
+ switch(CGAL::orientation(
+ typename Kernel::Point_3(pa[0], pa[1], pa[2]),
+ typename Kernel::Point_3(pb[0], pb[1], pb[2]),
+ typename Kernel::Point_3(pc[0], pc[1], pc[2]),
+ typename Kernel::Point_3(pd[0], pd[1], pd[2]))) {
+ case CGAL::POSITIVE:
+ return 1;
+ case CGAL::NEGATIVE:
+ return -1;
+ case CGAL::COPLANAR:
+ return 0;
+ default:
+ throw "Invalid orientation";
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/orient3D.h b/xs/src/igl/copyleft/cgal/orient3D.h
new file mode 100644
index 000000000..029e208b1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/orient3D.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_ORIENT_3D_H
+#define IGL_COPYLEFT_CGAL_ORIENT_3D_H
+
+#include "../../igl_inline.h"
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Inputs:
+ // pa,pb,pc,pd 3D points.
+ // Output:
+ // 1 if pa,pb,pc,pd forms a tet of positive volume.
+ // 0 if pa,pb,pc,pd are coplanar.
+ // -1 if pa,pb,pc,pd forms a tet of negative volume.
+ template <typename Scalar>
+ IGL_INLINE short orient3D(
+ const Scalar pa[3],
+ const Scalar pb[3],
+ const Scalar pc[3],
+ const Scalar pd[3]);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "orient3D.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/outer_element.cpp b/xs/src/igl/copyleft/cgal/outer_element.cpp
new file mode 100644
index 000000000..2bef8cae1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/outer_element.cpp
@@ -0,0 +1,232 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "outer_element.h"
+#include <iostream>
+#include <vector>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+IGL_INLINE void igl::copyleft::cgal::outer_vertex(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v_index,
+ Eigen::PlainObjectBase<DerivedA> & A)
+{
+ // Algorithm:
+ // Find an outer vertex (i.e. vertex reachable from infinity)
+ // Return the vertex with the largest X value.
+ // If there is a tie, pick the one with largest Y value.
+ // If there is still a tie, pick the one with the largest Z value.
+ // If there is still a tie, then there are duplicated vertices within the
+ // mesh, which violates the precondition.
+ typedef typename DerivedF::Scalar Index;
+ const Index INVALID = std::numeric_limits<Index>::max();
+ const size_t num_selected_faces = I.rows();
+ std::vector<size_t> candidate_faces;
+ Index outer_vid = INVALID;
+ typename DerivedV::Scalar outer_val = 0;
+ for (size_t i=0; i<num_selected_faces; i++)
+ {
+ size_t f = I(i);
+ for (size_t j=0; j<3; j++)
+ {
+ Index v = F(f, j);
+ auto vx = V(v, 0);
+ if (outer_vid == INVALID || vx > outer_val)
+ {
+ outer_val = vx;
+ outer_vid = v;
+ candidate_faces = {f};
+ } else if (v == outer_vid)
+ {
+ candidate_faces.push_back(f);
+ } else if (vx == outer_val)
+ {
+ // Break tie.
+ auto vy = V(v,1);
+ auto vz = V(v, 2);
+ auto outer_y = V(outer_vid, 1);
+ auto outer_z = V(outer_vid, 2);
+ assert(!(vy == outer_y && vz == outer_z));
+ bool replace = (vy > outer_y) ||
+ ((vy == outer_y) && (vz > outer_z));
+ if (replace)
+ {
+ outer_val = vx;
+ outer_vid = v;
+ candidate_faces = {f};
+ }
+ }
+ }
+ }
+
+ assert(outer_vid != INVALID);
+ assert(candidate_faces.size() > 0);
+ v_index = outer_vid;
+ A.resize(candidate_faces.size());
+ std::copy(candidate_faces.begin(), candidate_faces.end(), A.data());
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+IGL_INLINE void igl::copyleft::cgal::outer_edge(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v1,
+ IndexType & v2,
+ Eigen::PlainObjectBase<DerivedA> & A) {
+ // Algorithm:
+ // Find an outer vertex first.
+ // Find the incident edge with largest abs slope when projected onto XY plane.
+ // If there is a tie, check the signed slope and use the positive one.
+ // If there is still a tie, break it using the projected slope onto ZX plane.
+ // If there is still a tie, again check the signed slope and use the positive one.
+ // If there is still a tie, then there are multiple overlapping edges,
+ // which violates the precondition.
+ typedef typename DerivedV::Scalar Scalar;
+ typedef typename DerivedV::Index Index;
+ typedef typename Eigen::Matrix<Scalar, 3, 1> ScalarArray3;
+ typedef typename Eigen::Matrix<typename DerivedF::Scalar, 3, 1> IndexArray3;
+ const Index INVALID = std::numeric_limits<Index>::max();
+
+ Index outer_vid;
+ Eigen::Matrix<Index,Eigen::Dynamic,1> candidate_faces;
+ outer_vertex(V, F, I, outer_vid, candidate_faces);
+ const ScalarArray3& outer_v = V.row(outer_vid);
+ assert(candidate_faces.size() > 0);
+
+ auto get_vertex_index = [&](const IndexArray3& f, Index vid) -> Index
+ {
+ if (f[0] == vid) return 0;
+ if (f[1] == vid) return 1;
+ if (f[2] == vid) return 2;
+ assert(false);
+ return -1;
+ };
+
+ auto unsigned_value = [](Scalar v) -> Scalar {
+ if (v < 0) return v * -1;
+ else return v;
+ };
+
+ Scalar outer_slope_YX = 0;
+ Scalar outer_slope_ZX = 0;
+ Index outer_opp_vid = INVALID;
+ bool infinite_slope_detected = false;
+ std::vector<Index> incident_faces;
+ auto check_and_update_outer_edge = [&](Index opp_vid, Index fid) -> void {
+ if (opp_vid == outer_opp_vid)
+ {
+ incident_faces.push_back(fid);
+ return;
+ }
+
+ const ScalarArray3 opp_v = V.row(opp_vid);
+ if (!infinite_slope_detected && outer_v[0] != opp_v[0])
+ {
+ // Finite slope
+ const ScalarArray3 diff = opp_v - outer_v;
+ const Scalar slope_YX = diff[1] / diff[0];
+ const Scalar slope_ZX = diff[2] / diff[0];
+ const Scalar u_slope_YX = unsigned_value(slope_YX);
+ const Scalar u_slope_ZX = unsigned_value(slope_ZX);
+ bool update = false;
+ if (outer_opp_vid == INVALID) {
+ update = true;
+ } else {
+ const Scalar u_outer_slope_YX = unsigned_value(outer_slope_YX);
+ if (u_slope_YX > u_outer_slope_YX) {
+ update = true;
+ } else if (u_slope_YX == u_outer_slope_YX &&
+ slope_YX > outer_slope_YX) {
+ update = true;
+ } else if (slope_YX == outer_slope_YX) {
+ const Scalar u_outer_slope_ZX =
+ unsigned_value(outer_slope_ZX);
+ if (u_slope_ZX > u_outer_slope_ZX) {
+ update = true;
+ } else if (u_slope_ZX == u_outer_slope_ZX &&
+ slope_ZX > outer_slope_ZX) {
+ update = true;
+ } else if (slope_ZX == u_outer_slope_ZX) {
+ assert(false);
+ }
+ }
+ }
+
+ if (update) {
+ outer_opp_vid = opp_vid;
+ outer_slope_YX = slope_YX;
+ outer_slope_ZX = slope_ZX;
+ incident_faces = {fid};
+ }
+ } else if (!infinite_slope_detected)
+ {
+ // Infinite slope
+ outer_opp_vid = opp_vid;
+ infinite_slope_detected = true;
+ incident_faces = {fid};
+ }
+ };
+
+ const size_t num_candidate_faces = candidate_faces.size();
+ for (size_t i=0; i<num_candidate_faces; i++)
+ {
+ const Index fid = candidate_faces(i);
+ const IndexArray3& f = F.row(fid);
+ size_t id = get_vertex_index(f, outer_vid);
+ Index next_vid = f((id+1)%3);
+ Index prev_vid = f((id+2)%3);
+ check_and_update_outer_edge(next_vid, fid);
+ check_and_update_outer_edge(prev_vid, fid);
+ }
+
+ v1 = outer_vid;
+ v2 = outer_opp_vid;
+ A.resize(incident_faces.size());
+ std::copy(incident_faces.begin(), incident_faces.end(), A.data());
+}
+
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_edge<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, long&, long&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 1, -1, -1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 1, -1, -1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::outer_edge<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<long, -1, 1, 0, -1, 1>, __int64, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<long, -1, 1, 0, -1, 1>> const &, __int64 &, __int64 &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/outer_element.h b/xs/src/igl/copyleft/cgal/outer_element.h
new file mode 100644
index 000000000..adaef3464
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/outer_element.h
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_OUTER_ELEMENT_H
+#define IGL_COPYLEFT_CGAL_OUTER_ELEMENT_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Find a vertex that is reachable from infinite without crossing any faces.
+ // Such vertex is called "outer vertex."
+ //
+ // Precondition: The input mesh must have all self-intersection resolved and
+ // no duplicated vertices. See cgal::remesh_self_intersections.h for how to
+ // obtain such input.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // I #I list of facets to consider
+ // Outputs:
+ // v_index index of outer vertex
+ // A #A list of facets incident to the outer vertex
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+ IGL_INLINE void outer_vertex(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v_index,
+ Eigen::PlainObjectBase<DerivedA> & A);
+ // Find an edge that is reachable from infinity without crossing any faces.
+ // Such edge is called "outer edge."
+ //
+ // Precondition: The input mesh must have all self-intersection resolved
+ // and no duplicated vertices. The correctness of the output depends on
+ // the fact that there is no edge overlap. See
+ // cgal::remesh_self_intersections.h for how to obtain such input.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // I #I list of facets to consider
+ // Outputs:
+ // v1 index of the first end point of outer edge
+ // v2 index of the second end point of outer edge
+ // A #A list of facets incident to the outer edge
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+ IGL_INLINE void outer_edge(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v1,
+ IndexType & v2,
+ Eigen::PlainObjectBase<DerivedA> & A);
+
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "outer_element.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/outer_facet.cpp b/xs/src/igl/copyleft/cgal/outer_facet.cpp
new file mode 100644
index 000000000..4525dd856
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/outer_facet.cpp
@@ -0,0 +1,180 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "outer_facet.h"
+#include "outer_element.h"
+#include "order_facets_around_edge.h"
+#include <algorithm>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType
+ >
+IGL_INLINE void igl::copyleft::cgal::outer_facet(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & f,
+ bool & flipped) {
+
+ // Algorithm:
+ //
+ // 1. Find an outer edge (s, d).
+ //
+ // 2. Order adjacent facets around this edge. Because the edge is an
+ // outer edge, there exists a plane passing through it such that all its
+ // adjacent facets lie on the same side. The implementation of
+ // order_facets_around_edge() will find a natural start facet such that
+ // The first and last facets according to this order are on the outside.
+ //
+ // 3. Because the vertex s is an outer vertex by construction (see
+ // implemnetation of outer_edge()). The first adjacent facet is facing
+ // outside (i.e. flipped=false) if it has positive X normal component.
+ // If it has zero normal component, it is facing outside if it contains
+ // directed edge (s, d).
+
+ //typedef typename DerivedV::Scalar Scalar;
+ typedef typename DerivedV::Index Index;
+
+ Index s,d;
+ Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
+ outer_edge(V, F, I, s, d, incident_faces);
+ assert(incident_faces.size() > 0);
+
+ auto convert_to_signed_index = [&](size_t fid) -> int{
+ if ((F(fid, 0) == s && F(fid, 1) == d) ||
+ (F(fid, 1) == s && F(fid, 2) == d) ||
+ (F(fid, 2) == s && F(fid, 0) == d) ) {
+ return int(fid+1) * -1;
+ } else {
+ return int(fid+1);
+ }
+ };
+
+ auto signed_index_to_index = [&](int signed_id) -> size_t {
+ return size_t(abs(signed_id) - 1);
+ };
+
+ std::vector<int> adj_faces(incident_faces.size());
+ std::transform(incident_faces.data(),
+ incident_faces.data() + incident_faces.size(),
+ adj_faces.begin(),
+ convert_to_signed_index);
+
+ DerivedV pivot_point = V.row(s);
+ pivot_point(0, 0) += 1.0;
+
+ Eigen::VectorXi order;
+ order_facets_around_edge(V, F, s, d, adj_faces, pivot_point, order);
+
+ f = signed_index_to_index(adj_faces[order[0]]);
+ flipped = adj_faces[order[0]] > 0;
+}
+
+
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedI,
+ typename IndexType
+ >
+IGL_INLINE void igl::copyleft::cgal::outer_facet(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & f,
+ bool & flipped) {
+ // Algorithm:
+ // Find an outer edge.
+ // Find the incident facet with the largest absolute X normal component.
+ // If there is a tie, keep the one with positive X component.
+ // If there is still a tie, pick the face with the larger signed index
+ // (flipped face has negative index).
+ typedef typename DerivedV::Scalar Scalar;
+ typedef typename DerivedV::Index Index;
+ const size_t INVALID = std::numeric_limits<size_t>::max();
+
+ Index v1,v2;
+ Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
+ outer_edge(V, F, I, v1, v2, incident_faces);
+ assert(incident_faces.size() > 0);
+
+ auto generic_fabs = [&](const Scalar& val) -> const Scalar {
+ if (val >= 0) return val;
+ else return -val;
+ };
+
+ Scalar max_nx = 0;
+ size_t outer_fid = INVALID;
+ const size_t num_incident_faces = incident_faces.size();
+ for (size_t i=0; i<num_incident_faces; i++)
+ {
+ const auto& fid = incident_faces(i);
+ const Scalar nx = N(fid, 0);
+ if (outer_fid == INVALID) {
+ max_nx = nx;
+ outer_fid = fid;
+ } else {
+ if (generic_fabs(nx) > generic_fabs(max_nx)) {
+ max_nx = nx;
+ outer_fid = fid;
+ } else if (nx == -max_nx && nx > 0) {
+ max_nx = nx;
+ outer_fid = fid;
+ } else if (nx == max_nx) {
+ if ((max_nx >= 0 && outer_fid < fid) ||
+ (max_nx < 0 && outer_fid > fid)) {
+ max_nx = nx;
+ outer_fid = fid;
+ }
+ }
+ }
+ }
+
+ assert(outer_fid != INVALID);
+ f = outer_fid;
+ flipped = max_nx < 0;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, unsigned long&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::copyleft::cgal::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int&, bool&);
+#ifdef WIN32
+template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
+template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
+template void igl::copyleft::cgal::outer_facet<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64 &, bool &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/outer_facet.h b/xs/src/igl/copyleft/cgal/outer_facet.h
new file mode 100644
index 000000000..b025a94ab
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/outer_facet.h
@@ -0,0 +1,91 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_COPYLEFT_CGAL_OUTER_FACET_H
+#define IGL_COPYLEFT_CGAL_OUTER_FACET_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Find a facet that is reachable from infinity without crossing any faces.
+ // Such facet is called "outer facet."
+ //
+ // Precondition: The input mesh must have all self-intersection resolved. I.e
+ // there is no duplicated vertices, no overlapping edge and no intersecting
+ // faces (the only exception is there could be topologically duplicated faces).
+ // See cgal::remesh_self_intersections.h for how to obtain such input.
+ //
+ // This function differ from igl::outer_facet() in the fact this
+ // function is more robust because it does not rely on facet normals.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // I #I list of facets to consider
+ // Outputs:
+ // f Index of the outer facet.
+ // flipped true iff the normal of f points inwards.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType
+ >
+ IGL_INLINE void outer_facet(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & f,
+ bool & flipped);
+
+ // Find a facet that is reachable from infinity without crossing any faces.
+ // Such facet is called "outer facet."
+ //
+ // Precondition: The input mesh must have all self-intersection resolved.
+ // I.e there is no duplicated vertices, no overlapping edge and no
+ // intersecting faces (the only exception is there could be topologically
+ // duplicated faces). See cgal::remesh_self_intersections.h for how to
+ // obtain such input.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // N #N by 3 list of face normals
+ // I #I list of facets to consider
+ // Outputs:
+ // f Index of the outer facet.
+ // flipped true iff the normal of f points inwards.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedI,
+ typename IndexType
+ >
+ IGL_INLINE void outer_facet(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & f,
+ bool & flipped);
+
+ }
+
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "outer_facet.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/outer_hull.cpp b/xs/src/igl/copyleft/cgal/outer_hull.cpp
new file mode 100644
index 000000000..71586f707
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/outer_hull.cpp
@@ -0,0 +1,535 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "outer_hull.h"
+#include "extract_cells.h"
+#include "remesh_self_intersections.h"
+#include "assign.h"
+#include "../../remove_unreferenced.h"
+
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+#include <CGAL/intersections.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedHV,
+ typename DerivedHF,
+ typename DerivedJ,
+ typename Derivedflip>
+IGL_INLINE void igl::copyleft::cgal::outer_hull(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedHV> & HV,
+ Eigen::PlainObjectBase<DerivedHF> & HF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<Derivedflip> & flip)
+{
+ // Exact types
+ typedef CGAL::Epeck Kernel;
+ typedef Kernel::FT ExactScalar;
+ typedef
+ Eigen::Matrix<
+ ExactScalar,
+ Eigen::Dynamic,
+ Eigen::Dynamic,
+ DerivedHV::IsRowMajor>
+ MatrixXES;
+ // Remesh self-intersections
+ MatrixXES Vr;
+ DerivedHF Fr;
+ DerivedJ Jr;
+ {
+ RemeshSelfIntersectionsParam params;
+ params.stitch_all = true;
+ Eigen::VectorXi I;
+ Eigen::MatrixXi IF;
+ remesh_self_intersections(V, F, params, Vr, Fr, IF, Jr, I);
+ // Merge coinciding vertices into non-manifold vertices.
+ std::for_each(Fr.data(), Fr.data()+Fr.size(),
+ [&I](typename DerivedHF::Scalar& a) { a=I[a]; });
+ // Remove unreferenced vertices.
+ Eigen::VectorXi UIM;
+ remove_unreferenced(MatrixXES(Vr),DerivedHF(Fr), Vr, Fr, UIM);
+ }
+ // Extract cells for each face
+ Eigen::MatrixXi C;
+ extract_cells(Vr,Fr,C);
+ // Extract faces on ambient cell
+ int num_outer = 0;
+ for(int i = 0;i<C.rows();i++)
+ {
+ num_outer += ( C(i,0) == 0 || C(i,1) == 0 ) ? 1 : 0;
+ }
+ HF.resize(num_outer,3);
+ J.resize(num_outer,1);
+ flip.resize(num_outer,1);
+ {
+ int h = 0;
+ for(int i = 0;i<C.rows();i++)
+ {
+ if(C(i,0)==0)
+ {
+ HF.row(h) = Fr.row(i);
+ J(h) = Jr(i);
+ flip(h) = false;
+ h++;
+ }else if(C(i,1) == 0)
+ {
+ HF.row(h) = Fr.row(i).reverse();
+ J(h) = Jr(i);
+ flip(h) = true;
+ h++;
+ }
+ }
+ assert(h == num_outer);
+ }
+ // Remove unreferenced vertices and re-index faces
+ {
+ // Cast to output type
+ DerivedHV Vr_cast;
+ assign(Vr,Vr_cast);
+ Eigen::VectorXi I;
+ remove_unreferenced(Vr_cast,DerivedHF(HF),HV,HF,I);
+ }
+}
+
+#include "points_inside_component.h"
+#include "order_facets_around_edges.h"
+#include "outer_facet.h"
+#include "../../sortrows.h"
+#include "../../facet_components.h"
+#include "../../winding_number.h"
+#include "../../triangle_triangle_adjacency.h"
+#include "../../unique_edge_map.h"
+#include "../../barycenter.h"
+#include "../../per_face_normals.h"
+#include "../../sort_angles.h"
+#include <Eigen/Geometry>
+#include <vector>
+#include <map>
+#include <queue>
+#include <iostream>
+#include <type_traits>
+#include <CGAL/number_utils.h>
+//#define IGL_OUTER_HULL_DEBUG
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedG,
+ typename DerivedJ,
+ typename Derivedflip>
+IGL_INLINE void igl::copyleft::cgal::outer_hull_legacy(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<Derivedflip> & flip)
+{
+#ifdef IGL_OUTER_HULL_DEBUG
+ std::cerr << "Extracting outer hull" << std::endl;
+#endif
+ using namespace Eigen;
+ using namespace std;
+ typedef typename DerivedF::Index Index;
+ Matrix<Index,DerivedF::RowsAtCompileTime,1> C;
+ typedef Matrix<typename DerivedV::Scalar,Dynamic,DerivedV::ColsAtCompileTime> MatrixXV;
+ //typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
+ typedef Matrix<typename DerivedG::Scalar,Dynamic,DerivedG::ColsAtCompileTime> MatrixXG;
+ typedef Matrix<typename DerivedJ::Scalar,Dynamic,DerivedJ::ColsAtCompileTime> MatrixXJ;
+ const Index m = F.rows();
+
+ // UNUSED:
+ //const auto & duplicate_simplex = [&F](const int f, const int g)->bool
+ //{
+ // return
+ // (F(f,0) == F(g,0) && F(f,1) == F(g,1) && F(f,2) == F(g,2)) ||
+ // (F(f,1) == F(g,0) && F(f,2) == F(g,1) && F(f,0) == F(g,2)) ||
+ // (F(f,2) == F(g,0) && F(f,0) == F(g,1) && F(f,1) == F(g,2)) ||
+ // (F(f,0) == F(g,2) && F(f,1) == F(g,1) && F(f,2) == F(g,0)) ||
+ // (F(f,1) == F(g,2) && F(f,2) == F(g,1) && F(f,0) == F(g,0)) ||
+ // (F(f,2) == F(g,2) && F(f,0) == F(g,1) && F(f,1) == F(g,0));
+ //};
+
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"outer hull..."<<endl;
+#endif
+
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"edge map..."<<endl;
+#endif
+ typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
+ typedef Matrix<typename DerivedF::Index,Dynamic,1> VectorXI;
+ //typedef Matrix<typename DerivedV::Scalar, 3, 1> Vector3F;
+ MatrixX2I E,uE;
+ VectorXI EMAP;
+ vector<vector<typename DerivedF::Index> > uE2E;
+ unique_edge_map(F,E,uE,EMAP,uE2E);
+#ifdef IGL_OUTER_HULL_DEBUG
+ for (size_t ui=0; ui<uE.rows(); ui++) {
+ std::cout << ui << ": " << uE2E[ui].size() << " -- (";
+ for (size_t i=0; i<uE2E[ui].size(); i++) {
+ std::cout << uE2E[ui][i] << ", ";
+ }
+ std::cout << ")" << std::endl;
+ }
+#endif
+
+ std::vector<std::vector<typename DerivedF::Index> > uE2oE;
+ std::vector<std::vector<bool> > uE2C;
+ order_facets_around_edges(V, F, uE, uE2E, uE2oE, uE2C);
+ uE2E = uE2oE;
+ VectorXI diIM(3*m);
+ for (auto ue : uE2E) {
+ for (size_t i=0; i<ue.size(); i++) {
+ auto fe = ue[i];
+ diIM[fe] = i;
+ }
+ }
+
+ vector<vector<vector<Index > > > TT,_1;
+ triangle_triangle_adjacency(E,EMAP,uE2E,false,TT,_1);
+ VectorXI counts;
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"facet components..."<<endl;
+#endif
+ facet_components(TT,C,counts);
+ assert(C.maxCoeff()+1 == counts.rows());
+ const size_t ncc = counts.rows();
+ G.resize(0,F.cols());
+ J.resize(0,1);
+ flip.setConstant(m,1,false);
+
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"reindex..."<<endl;
+#endif
+ // H contains list of faces on outer hull;
+ vector<bool> FH(m,false);
+ vector<bool> EH(3*m,false);
+ vector<MatrixXG> vG(ncc);
+ vector<MatrixXJ> vJ(ncc);
+ vector<MatrixXJ> vIM(ncc);
+ //size_t face_count = 0;
+ for(size_t id = 0;id<ncc;id++)
+ {
+ vIM[id].resize(counts[id],1);
+ }
+ // current index into each IM
+ vector<size_t> g(ncc,0);
+ // place order of each face in its respective component
+ for(Index f = 0;f<m;f++)
+ {
+ vIM[C(f)](g[C(f)]++) = f;
+ }
+
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"barycenters..."<<endl;
+#endif
+ // assumes that "resolve" has handled any coplanar cases correctly and nearly
+ // coplanar cases can be sorted based on barycenter.
+ MatrixXV BC;
+ barycenter(V,F,BC);
+
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"loop over CCs (="<<ncc<<")..."<<endl;
+#endif
+ for(Index id = 0;id<(Index)ncc;id++)
+ {
+ auto & IM = vIM[id];
+ // starting face that's guaranteed to be on the outer hull and in this
+ // component
+ int f;
+ bool f_flip;
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"outer facet..."<<endl;
+#endif
+ igl::copyleft::cgal::outer_facet(V,F,IM,f,f_flip);
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"outer facet: "<<f<<endl;
+ //cout << V.row(F(f, 0)) << std::endl;
+ //cout << V.row(F(f, 1)) << std::endl;
+ //cout << V.row(F(f, 2)) << std::endl;
+#endif
+ int FHcount = 1;
+ FH[f] = true;
+ // Q contains list of face edges to continue traversing upong
+ queue<int> Q;
+ Q.push(f+0*m);
+ Q.push(f+1*m);
+ Q.push(f+2*m);
+ flip(f) = f_flip;
+ //std::cout << "face " << face_count++ << ": " << f << std::endl;
+ //std::cout << "f " << F.row(f).array()+1 << std::endl;
+ //cout<<"flip("<<f<<") = "<<(flip(f)?"true":"false")<<endl;
+#ifdef IGL_OUTER_HULL_DEBUG
+ cout<<"BFS..."<<endl;
+#endif
+ while(!Q.empty())
+ {
+ // face-edge
+ const int e = Q.front();
+ Q.pop();
+ // face
+ const int f = e%m;
+ // corner
+ const int c = e/m;
+#ifdef IGL_OUTER_HULL_DEBUG
+ std::cout << "edge: " << e << ", ue: " << EMAP(e) << std::endl;
+ std::cout << "face: " << f << std::endl;
+ std::cout << "corner: " << c << std::endl;
+ std::cout << "consistent: " << uE2C[EMAP(e)][diIM[e]] << std::endl;
+#endif
+ // Should never see edge again...
+ if(EH[e] == true)
+ {
+ continue;
+ }
+ EH[e] = true;
+ // source of edge according to f
+ const int fs = flip(f)?F(f,(c+2)%3):F(f,(c+1)%3);
+ // destination of edge according to f
+ const int fd = flip(f)?F(f,(c+1)%3):F(f,(c+2)%3);
+ // edge valence
+ const size_t val = uE2E[EMAP(e)].size();
+#ifdef IGL_OUTER_HULL_DEBUG
+ //std::cout << "vd: " << V.row(fd) << std::endl;
+ //std::cout << "vs: " << V.row(fs) << std::endl;
+ //std::cout << "edge: " << V.row(fd) - V.row(fs) << std::endl;
+ for (size_t i=0; i<val; i++) {
+ if (i == diIM(e)) {
+ std::cout << "* ";
+ } else {
+ std::cout << " ";
+ }
+ std::cout << i << ": "
+ << " (e: " << uE2E[EMAP(e)][i] << ", f: "
+ << uE2E[EMAP(e)][i] % m * (uE2C[EMAP(e)][i] ? 1:-1) << ")" << std::endl;
+ }
+#endif
+
+ // is edge consistent with edge of face used for sorting
+ const int e_cons = (uE2C[EMAP(e)][diIM(e)] ? 1: -1);
+ int nfei = -1;
+ // Loop once around trying to find suitable next face
+ for(size_t step = 1; step<val+2;step++)
+ {
+ const int nfei_new = (diIM(e) + 2*val + e_cons*step*(flip(f)?-1:1))%val;
+ const int nf = uE2E[EMAP(e)][nfei_new] % m;
+ {
+#ifdef IGL_OUTER_HULL_DEBUG
+ //cout<<"Next facet: "<<(f+1)<<" --> "<<(nf+1)<<", |"<<
+ // di[EMAP(e)][diIM(e)]<<" - "<<di[EMAP(e)][nfei_new]<<"| = "<<
+ // abs(di[EMAP(e)][diIM(e)] - di[EMAP(e)][nfei_new])
+ // <<endl;
+#endif
+
+
+
+ // Only use this face if not already seen
+ if(!FH[nf])
+ {
+ nfei = nfei_new;
+ //} else {
+ // std::cout << "skipping face " << nfei_new << " because it is seen before"
+ // << std::endl;
+ }
+ break;
+ //} else {
+ // std::cout << di[EMAP(e)][diIM(e)].transpose() << std::endl;
+ // std::cout << di[EMAP(e)][diIM(nfei_new)].transpose() << std::endl;
+ // std::cout << "skipping face " << nfei_new << " with identical dihedral angle"
+ // << std::endl;
+ }
+//#ifdef IGL_OUTER_HULL_DEBUG
+// cout<<"Skipping co-planar facet: "<<(f+1)<<" --> "<<(nf+1)<<endl;
+//#endif
+ }
+
+ int max_ne = -1;
+ if(nfei >= 0)
+ {
+ max_ne = uE2E[EMAP(e)][nfei];
+ }
+
+ if(max_ne>=0)
+ {
+ // face of neighbor
+ const int nf = max_ne%m;
+#ifdef IGL_OUTER_HULL_DEBUG
+ if(!FH[nf])
+ {
+ // first time seeing face
+ cout<<(f+1)<<" --> "<<(nf+1)<<endl;
+ }
+#endif
+ FH[nf] = true;
+ //std::cout << "face " << face_count++ << ": " << nf << std::endl;
+ //std::cout << "f " << F.row(nf).array()+1 << std::endl;
+ FHcount++;
+ // corner of neighbor
+ const int nc = max_ne/m;
+ const int nd = F(nf,(nc+2)%3);
+ const bool cons = (flip(f)?fd:fs) == nd;
+ flip(nf) = (cons ? flip(f) : !flip(f));
+ //cout<<"flip("<<nf<<") = "<<(flip(nf)?"true":"false")<<endl;
+ const int ne1 = nf+((nc+1)%3)*m;
+ const int ne2 = nf+((nc+2)%3)*m;
+ if(!EH[ne1])
+ {
+ Q.push(ne1);
+ }
+ if(!EH[ne2])
+ {
+ Q.push(ne2);
+ }
+ }
+ }
+
+ {
+ vG[id].resize(FHcount,3);
+ vJ[id].resize(FHcount,1);
+ //nG += FHcount;
+ size_t h = 0;
+ assert(counts(id) == IM.rows());
+ for(int i = 0;i<counts(id);i++)
+ {
+ const size_t f = IM(i);
+ //if(f_flip)
+ //{
+ // flip(f) = !flip(f);
+ //}
+ if(FH[f])
+ {
+ vG[id].row(h) = (flip(f)?F.row(f).reverse().eval():F.row(f));
+ vJ[id](h,0) = f;
+ h++;
+ }
+ }
+ assert((int)h == FHcount);
+ }
+ }
+
+ // Is A inside B? Assuming A and B are consistently oriented but closed and
+ // non-intersecting.
+ const auto & has_overlapping_bbox = [](
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const MatrixXG & A,
+ const MatrixXG & B)->bool
+ {
+ const auto & bounding_box = [](
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const MatrixXG & F)->
+ DerivedV
+ {
+ DerivedV BB(2,3);
+ BB<<
+ 1e26,1e26,1e26,
+ -1e26,-1e26,-1e26;
+ const size_t m = F.rows();
+ for(size_t f = 0;f<m;f++)
+ {
+ for(size_t c = 0;c<3;c++)
+ {
+ const auto & vfc = V.row(F(f,c)).eval();
+ BB(0,0) = std::min(BB(0,0), vfc(0,0));
+ BB(0,1) = std::min(BB(0,1), vfc(0,1));
+ BB(0,2) = std::min(BB(0,2), vfc(0,2));
+ BB(1,0) = std::max(BB(1,0), vfc(0,0));
+ BB(1,1) = std::max(BB(1,1), vfc(0,1));
+ BB(1,2) = std::max(BB(1,2), vfc(0,2));
+ }
+ }
+ return BB;
+ };
+ // A lot of the time we're dealing with unrelated, distant components: cull
+ // them.
+ DerivedV ABB = bounding_box(V,A);
+ DerivedV BBB = bounding_box(V,B);
+ if( (BBB.row(0)-ABB.row(1)).maxCoeff()>0 ||
+ (ABB.row(0)-BBB.row(1)).maxCoeff()>0 )
+ {
+ // bounding boxes do not overlap
+ return false;
+ } else {
+ return true;
+ }
+ };
+
+ // Reject components which are completely inside other components
+ vector<bool> keep(ncc,true);
+ size_t nG = 0;
+ // This is O( ncc * ncc * m)
+ for(size_t id = 0;id<ncc;id++)
+ {
+ if (!keep[id]) continue;
+ std::vector<size_t> unresolved;
+ for(size_t oid = 0;oid<ncc;oid++)
+ {
+ if(id == oid || !keep[oid])
+ {
+ continue;
+ }
+ if (has_overlapping_bbox(V, vG[id], vG[oid])) {
+ unresolved.push_back(oid);
+ }
+ }
+ const size_t num_unresolved_components = unresolved.size();
+ DerivedV query_points(num_unresolved_components, 3);
+ for (size_t i=0; i<num_unresolved_components; i++) {
+ const size_t oid = unresolved[i];
+ DerivedF f = vG[oid].row(0);
+ query_points(i,0) = (V(f(0,0), 0) + V(f(0,1), 0) + V(f(0,2), 0))/3.0;
+ query_points(i,1) = (V(f(0,0), 1) + V(f(0,1), 1) + V(f(0,2), 1))/3.0;
+ query_points(i,2) = (V(f(0,0), 2) + V(f(0,1), 2) + V(f(0,2), 2))/3.0;
+ }
+ Eigen::VectorXi inside;
+ igl::copyleft::cgal::points_inside_component(V, vG[id], query_points, inside);
+ assert((size_t)inside.size() == num_unresolved_components);
+ for (size_t i=0; i<num_unresolved_components; i++) {
+ if (inside(i, 0)) {
+ const size_t oid = unresolved[i];
+ keep[oid] = false;
+ }
+ }
+ }
+ for (size_t id = 0; id<ncc; id++) {
+ if (keep[id]) {
+ nG += vJ[id].rows();
+ }
+ }
+
+ // collect G and J across components
+ G.resize(nG,3);
+ J.resize(nG,1);
+ {
+ size_t off = 0;
+ for(Index id = 0;id<(Index)ncc;id++)
+ {
+ if(keep[id])
+ {
+ assert(vG[id].rows() == vJ[id].rows());
+ G.block(off,0,vG[id].rows(),vG[id].cols()) = vG[id];
+ J.block(off,0,vJ[id].rows(),vJ[id].cols()) = vJ[id];
+ off += vG[id].rows();
+ }
+ }
+ }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cgal::outer_hull<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
+template void igl::copyleft::cgal::outer_hull_legacy< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::outer_hull_legacy<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/outer_hull.h b/xs/src/igl/copyleft/cgal/outer_hull.h
new file mode 100644
index 000000000..191a8d492
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/outer_hull.h
@@ -0,0 +1,84 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_OUTER_HULL_H
+#define IGL_COPYLEFT_CGAL_OUTER_HULL_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Compute the "outer hull" of a piecewise constant winding number induce
+ // triangle mesh (V,F).
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // Outputs:
+ // HV #HV by 3 list of output vertex positions
+ // HF #HF by 3 list of output triangle indices into HV
+ // J #HF list of indices into F
+ // flip #HF list of whether facet was flipped when added to HF
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedHV,
+ typename DerivedHF,
+ typename DerivedJ,
+ typename Derivedflip>
+ IGL_INLINE void outer_hull(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedHV> & HV,
+ Eigen::PlainObjectBase<DerivedHF> & HF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<Derivedflip> & flip);
+ // Compute the "outer hull" of a potentially non-manifold mesh (V,F) whose
+ // intersections have been "resolved" (e.g. using `cork` or
+ // `igl::copyleft::cgal::selfintersect`). The outer hull is defined to be all facets
+ // (regardless of orientation) for which there exists some path from infinity
+ // to the face without intersecting any other facets. For solids, this is the
+ // surface of the solid. In general this includes any thin "wings" or
+ // "flaps". This implementation largely follows Section 3.6 of "Direct
+ // repair of self-intersecting meshes" [Attene 2014].
+ //
+ // Note: This doesn't require the input mesh to be piecewise constant
+ // winding number, but won't handle multiple non-nested connected
+ // components.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // Outputs:
+ // G #G by 3 list of output triangle indices into V
+ // J #G list of indices into F
+ // flip #F list of whether facet was added to G **and** flipped orientation
+ // (false for faces not added to G)
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedG,
+ typename DerivedJ,
+ typename Derivedflip>
+ IGL_INLINE void outer_hull_legacy(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<Derivedflip> & flip);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "outer_hull.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/peel_outer_hull_layers.cpp b/xs/src/igl/copyleft/cgal/peel_outer_hull_layers.cpp
new file mode 100644
index 000000000..73ae07eea
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/peel_outer_hull_layers.cpp
@@ -0,0 +1,124 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "peel_outer_hull_layers.h"
+#include "outer_hull.h"
+#include "../../LinSpaced.h"
+#include <vector>
+#include <iostream>
+//#define IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+#include "../../writePLY.h"
+#include "../../writeDMAT.h"
+#include "../../STR.h"
+#endif
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename Derivedflip>
+IGL_INLINE size_t igl::copyleft::cgal::peel_outer_hull_layers(
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<Derivedflip > & flip)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef typename DerivedF::Index Index;
+ typedef Matrix<typename DerivedF::Scalar,Dynamic,DerivedF::ColsAtCompileTime> MatrixXF;
+ typedef Matrix<Index,Dynamic,1> MatrixXI;
+ typedef Matrix<typename Derivedflip::Scalar,Dynamic,Derivedflip::ColsAtCompileTime> MatrixXflip;
+ const Index m = F.rows();
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+ cout<<"peel outer hull layers..."<<endl;
+#endif
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+ cout<<"calling outer hull..."<<endl;
+ writePLY(STR("peel-outer-hull-input.ply"),V,F);
+#endif
+
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+ cout<<"resize output ..."<<endl;
+#endif
+ // keep track of iteration parity and whether flipped in hull
+ MatrixXF Fr = F;
+ I.resize(m,1);
+ flip.resize(m,1);
+ // Keep track of index map
+ MatrixXI IM = igl::LinSpaced<MatrixXI >(m,0,m-1);
+ // This is O(n * layers)
+ MatrixXI P(m,1);
+ Index iter = 0;
+ while(Fr.size() > 0)
+ {
+ assert(Fr.rows() == IM.rows());
+ // Compute outer hull of current Fr
+ MatrixXF Fo;
+ MatrixXI Jo;
+ MatrixXflip flipr;
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+ {
+ cout<<"calling outer hull..." << iter <<endl;
+ std::stringstream ss;
+ ss << "outer_hull_" << iter << ".ply";
+ Eigen::MatrixXd vertices(V.rows(), V.cols());
+ std::transform(V.data(), V.data() + V.rows()*V.cols(),
+ vertices.data(),
+ [](typename DerivedV::Scalar val)
+ {return CGAL::to_double(val); });
+ writePLY(ss.str(), vertices, Fr);
+ }
+#endif
+ outer_hull_legacy(V,Fr,Fo,Jo,flipr);
+#ifdef IGL_PEEL_OUTER_HULL_LAYERS_DEBUG
+ writePLY(STR("outer-hull-output-"<<iter<<".ply"),V,Fo);
+ cout<<"reindex, flip..."<<endl;
+#endif
+ assert(Fo.rows() != 0);
+ assert(Fo.rows() == Jo.rows());
+ // all faces in Fo of Fr
+ vector<bool> in_outer(Fr.rows(),false);
+ for(Index g = 0;g<Jo.rows();g++)
+ {
+ I(IM(Jo(g))) = iter;
+ P(IM(Jo(g))) = iter;
+ in_outer[Jo(g)] = true;
+ flip(IM(Jo(g))) = flipr(Jo(g));
+ }
+ // Fr = Fr - Fo
+ // update IM
+ MatrixXF prev_Fr = Fr;
+ MatrixXI prev_IM = IM;
+ Fr.resize(prev_Fr.rows() - Fo.rows(),F.cols());
+ IM.resize(Fr.rows());
+ {
+ Index g = 0;
+ for(Index f = 0;f<prev_Fr.rows();f++)
+ {
+ if(!in_outer[f])
+ {
+ Fr.row(g) = prev_Fr.row(f);
+ IM(g) = prev_IM(f);
+ g++;
+ }
+ }
+ }
+ iter++;
+ }
+ return iter;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+template unsigned long igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template size_t igl::copyleft::cgal::peel_outer_hull_layers<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/peel_outer_hull_layers.h b/xs/src/igl/copyleft/cgal/peel_outer_hull_layers.h
new file mode 100644
index 000000000..ee2752b29
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/peel_outer_hull_layers.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_PEEL_OUTER_HULL_LAYERS_H
+#define IGL_COPYLEFT_CGAL_PEEL_OUTER_HULL_LAYERS_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Computes necessary generic information for boolean operations by
+ // successively "peeling" off the "outer hull" of a mesh (V,F) resulting from
+ // "resolving" all (self-)intersections.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // Outputs:
+ // I #F list of which peel Iation a facet belongs
+ // flip #F list of whether a facet's orientation was flipped when facet
+ // "peeled" into its associated outer hull layer.
+ // Returns number of peels
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename Derivedflip>
+ IGL_INLINE size_t peel_outer_hull_layers(
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::PlainObjectBase<DerivedI > & I,
+ Eigen::PlainObjectBase<Derivedflip > & flip);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "peel_outer_hull_layers.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/peel_winding_number_layers.cpp b/xs/src/igl/copyleft/cgal/peel_winding_number_layers.cpp
new file mode 100644
index 000000000..2bb71a780
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/peel_winding_number_layers.cpp
@@ -0,0 +1,33 @@
+#include "peel_winding_number_layers.h"
+
+#include <cassert>
+
+#include "propagate_winding_numbers.h"
+
+template<
+typename DerivedV,
+typename DerivedF,
+typename DerivedW >
+IGL_INLINE size_t igl::copyleft::cgal::peel_winding_number_layers(
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::PlainObjectBase<DerivedW>& W) {
+ const size_t num_faces = F.rows();
+ Eigen::VectorXi labels(num_faces);
+ labels.setZero();
+
+ Eigen::MatrixXi winding_numbers;
+ igl::copyleft::cgal::propagate_winding_numbers(V, F, labels, winding_numbers);
+ assert(winding_numbers.rows() == num_faces);
+ assert(winding_numbers.cols() == 2);
+
+ int min_w = winding_numbers.minCoeff();
+ int max_w = winding_numbers.maxCoeff();
+ assert(max_w > min_w);
+
+ W.resize(num_faces, 1);
+ for (size_t i=0; i<num_faces; i++) {
+ W(i, 0) = winding_numbers(i, 1);
+ }
+ return max_w - min_w;
+}
diff --git a/xs/src/igl/copyleft/cgal/peel_winding_number_layers.h b/xs/src/igl/copyleft/cgal/peel_winding_number_layers.h
new file mode 100644
index 000000000..644c361e3
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/peel_winding_number_layers.h
@@ -0,0 +1,24 @@
+#ifndef IGL_COPYLEFT_CGAL_PEEL_WINDING_NUMBER_LAYERS_H
+#define IGL_COPYLEFT_CGAL_PEEL_WINDING_NUMBER_LAYERS_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl {
+ namespace copyleft {
+ namespace cgal {
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedW >
+ IGL_INLINE size_t peel_winding_number_layers(
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::PlainObjectBase<DerivedW>& W);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "peel_winding_number_layers.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.cpp b/xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.cpp
new file mode 100644
index 000000000..0156edbe2
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.cpp
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "piecewise_constant_winding_number.h"
+#include "../../piecewise_constant_winding_number.h"
+#include "remesh_self_intersections.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <algorithm>
+
+template < typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::copyleft::cgal::piecewise_constant_winding_number(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F)
+{
+ Eigen::Matrix<CGAL::Epeck::FT,Eigen::Dynamic,3> VV;
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,3> FF;
+ Eigen::Matrix<typename DerivedF::Index,Eigen::Dynamic,2> IF;
+ Eigen::Matrix<typename DerivedF::Index,Eigen::Dynamic,1> J;
+ Eigen::Matrix<typename DerivedV::Index,Eigen::Dynamic,1> UIM,IM;
+ // resolve intersections
+ remesh_self_intersections(V,F,{false,false,true},VV,FF,IF,J,IM);
+ return igl::piecewise_constant_winding_number(FF);
+}
diff --git a/xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.h b/xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.h
new file mode 100644
index 000000000..2b93913b3
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/piecewise_constant_winding_number.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_PIECEWISE_CONSTANT_WINDING_NUMBER_H
+#define IGL_COPYLEFT_CGAL_PIECEWISE_CONSTANT_WINDING_NUMBER_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // PIECEWISE_CONSTANT_WINDING_NUMBER Determine if a given mesh induces a
+ // piecewise constant winding number field: Is this mesh valid input to
+ // solid set operations.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of triangle indices into V
+ // Returns true if the mesh _combinatorially_ induces a piecewise
+ // constant winding number field.
+ template <
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE bool piecewise_constant_winding_number(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF>& F);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "piecewise_constant_winding_number.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/point_areas.cpp b/xs/src/igl/copyleft/cgal/point_areas.cpp
new file mode 100644
index 000000000..bb98bac3c
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_areas.cpp
@@ -0,0 +1,181 @@
+#include "point_areas.h"
+#include "delaunay_triangulation.h"
+
+#include "../../colon.h"
+#include "../../slice.h"
+#include "../../slice_mask.h"
+#include "../../parallel_for.h"
+
+#include "CGAL/Exact_predicates_inexact_constructions_kernel.h"
+#include "CGAL/Triangulation_vertex_base_with_info_2.h"
+#include "CGAL/Triangulation_data_structure_2.h"
+#include "CGAL/Delaunay_triangulation_2.h"
+
+
+
+typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+typedef CGAL::Triangulation_vertex_base_with_info_2<unsigned int, Kernel> Vb;
+typedef CGAL::Triangulation_data_structure_2<Vb> Tds;
+typedef CGAL::Delaunay_triangulation_2<Kernel, Tds> Delaunay;
+typedef Kernel::Point_2 Point;
+
+namespace igl {
+ namespace copyleft{
+ namespace cgal{
+
+ template <typename DerivedP, typename DerivedI, typename DerivedN,
+ typename DerivedA>
+ IGL_INLINE void point_areas(
+ const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedI>& I,
+ const Eigen::MatrixBase<DerivedN>& N,
+ Eigen::PlainObjectBase<DerivedA> & A)
+ {
+ Eigen::MatrixXd T;
+ point_areas(P,I,N,A,T);
+ }
+
+
+ template <typename DerivedP, typename DerivedI, typename DerivedN,
+ typename DerivedA, typename DerivedT>
+ IGL_INLINE void point_areas(
+ const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedI>& I,
+ const Eigen::MatrixBase<DerivedN>& N,
+ Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedT> & T)
+ {
+ typedef typename DerivedP::Scalar real;
+ typedef typename DerivedN::Scalar scalarN;
+ typedef typename DerivedA::Scalar scalarA;
+ typedef Eigen::Matrix<real,1,3> RowVec3;
+ typedef Eigen::Matrix<real,1,2> RowVec2;
+
+ typedef Eigen::Matrix<real, Eigen::Dynamic, Eigen::Dynamic> MatrixP;
+ typedef Eigen::Matrix<scalarN, Eigen::Dynamic, Eigen::Dynamic> MatrixN;
+ typedef Eigen::Matrix<typename DerivedN::Scalar,
+ Eigen::Dynamic, Eigen::Dynamic> VecotorO;
+ typedef Eigen::Matrix<typename DerivedI::Scalar,
+ Eigen::Dynamic, Eigen::Dynamic> MatrixI;
+
+
+
+ const int n = P.rows();
+
+ assert(P.cols() == 3 && "P must have exactly 3 columns");
+ assert(P.rows() == N.rows()
+ && "P and N must have the same number of rows");
+ assert(P.rows() == I.rows()
+ && "P and I must have the same number of rows");
+
+ A.setZero(n,1);
+ T.setZero(n,3);
+ igl::parallel_for(P.rows(),[&](int i)
+ {
+ MatrixI neighbor_index = I.row(i);
+ MatrixP neighbors;
+ igl::slice(P,neighbor_index,1,neighbors);
+ if(N.rows() && neighbors.rows() > 1){
+ MatrixN neighbor_normals;
+ igl::slice(N,neighbor_index,1,neighbor_normals);
+ Eigen::Matrix<scalarN,1,3> poi_normal = neighbor_normals.row(0);
+ Eigen::Matrix<scalarN,Eigen::Dynamic,1> dotprod =
+ poi_normal(0)*neighbor_normals.col(0)
+ + poi_normal(1)*neighbor_normals.col(1)
+ + poi_normal(2)*neighbor_normals.col(2);
+ Eigen::Array<bool,Eigen::Dynamic,1> keep = dotprod.array() > 0;
+ igl::slice_mask(Eigen::MatrixXd(neighbors),keep,1,neighbors);
+ }
+ if(neighbors.rows() <= 2){
+ A(i) = 0;
+ } else {
+ //subtract the mean from neighbors, then take svd,
+ //the scores will be U*S. This is our pca plane fitting
+ RowVec3 mean = neighbors.colwise().mean();
+ MatrixP mean_centered = neighbors.rowwise() - mean;
+ Eigen::JacobiSVD<MatrixP> svd(mean_centered,
+ Eigen::ComputeThinU | Eigen::ComputeThinV);
+ MatrixP scores = svd.matrixU() * svd.singularValues().asDiagonal();
+
+ T.row(i) = svd.matrixV().col(2).transpose();
+ if(T.row(i).dot(N.row(i)) < 0){
+ T.row(i) *= -1;
+ }
+
+ MatrixP plane;
+ igl::slice(scores,igl::colon<int>(0,scores.rows()-1),
+ igl::colon<int>(0,1),plane);
+
+ std::vector< std::pair<Point,unsigned> > points;
+ //This is where we obtain a delaunay triangulation of the points
+ for(unsigned iter = 0; iter < plane.rows(); iter++){
+ points.push_back( std::make_pair(
+ Point(plane(iter,0),plane(iter,1)), iter ) );
+ }
+ Delaunay triangulation;
+ triangulation.insert(points.begin(),points.end());
+ Eigen::MatrixXi F(triangulation.number_of_faces(),3);
+ int f_row = 0;
+ for(Delaunay::Finite_faces_iterator fit =
+ triangulation.finite_faces_begin();
+ fit != triangulation.finite_faces_end(); ++fit) {
+ Delaunay::Face_handle face = fit;
+ F.row(f_row) = Eigen::RowVector3i((int)face->vertex(0)->info(),
+ (int)face->vertex(1)->info(),
+ (int)face->vertex(2)->info());
+ f_row++;
+ }
+
+ //Here we calculate the voronoi area of the point
+ scalarA area_accumulator = 0;
+ for(int f = 0; f < F.rows(); f++){
+ int X = -1;
+ for(int face_iter = 0; face_iter < 3; face_iter++){
+ if(F(f,face_iter) == 0){
+ X = face_iter;
+ }
+ }
+ if(X >= 0){
+ //Triangle XYZ with X being the point we want the area of
+ int Y = (X+1)%3;
+ int Z = (X+2)%3;
+ scalarA x = (plane.row(F(f,Y))-plane.row(F(f,Z))).norm();
+ scalarA y = (plane.row(F(f,X))-plane.row(F(f,Z))).norm();
+ scalarA z = (plane.row(F(f,Y))-plane.row(F(f,X))).norm();
+ scalarA cosX = (z*z + y*y - x*x)/(2*y*z);
+ scalarA cosY = (z*z + x*x - y*y)/(2*x*z);
+ scalarA cosZ = (x*x + y*y - z*z)/(2*y*x);
+ Eigen::Matrix<scalarA,1,3> barycentric;
+ barycentric << x*cosX, y*cosY, z*cosZ;
+ barycentric /= (barycentric(0)+barycentric(1)+barycentric(2));
+
+ //TODO: to make numerically stable, reorder so that x≥y≥z:
+ scalarA full_area = 0.25*std::sqrt(
+ (x+(y+z))*(z-(x-y))*(z+(x-y))*(x+(y-z)));
+ Eigen::Matrix<scalarA,1,3> partial_area =
+ barycentric * full_area;
+ if(cosX < 0){
+ area_accumulator += 0.5*full_area;
+ } else if (cosY < 0 || cosZ < 0){
+ area_accumulator += 0.25*full_area;
+ } else {
+ area_accumulator += (partial_area(1) + partial_area(2))/2;
+ }
+ }
+ }
+
+ if(std::isfinite(area_accumulator)){
+ A(i) = area_accumulator;
+ } else {
+ A(i) = 0;
+ }
+ }
+ },1000);
+ }
+ }
+ }
+}
+
+
+
+
diff --git a/xs/src/igl/copyleft/cgal/point_areas.h b/xs/src/igl/copyleft/cgal/point_areas.h
new file mode 100644
index 000000000..ec0366488
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_areas.h
@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Gavin Barill <gavinpcb@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/
+
+#ifndef IGL_POINT_AREAS_H
+#define IGL_POINT_AREAS_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given a 3D set of points P, each with a list of k-nearest-neighbours,
+ // estimate the geodesic voronoi area associated with each point.
+ //
+ // The k nearest neighbours may be known from running igl::knn_octree on
+ // the output data from igl::octree. We reccomend using a k value
+ // between 15 and 20 inclusive for accurate area estimation.
+ //
+ // N is used filter the neighbours, to ensure area estimation only occurs
+ // using neighbors that are on the same side of the surface (ie for thin
+ // sheets), as well as to solve the orientation ambiguity of the tangent
+ // plane normal.
+ //
+ // Note: This function *should* be implemented by pre-filtering I, rather
+ // than filtering in this function using N. In this case, the function
+ // would only take P and I as input.
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ // I #P by k list of k-nearest-neighbor indices into P
+ // N #P by 3 list of point normals
+ // Outputs:
+ // A #P list of estimated areas
+ template <typename DerivedP, typename DerivedI, typename DerivedN,
+ typename DerivedA>
+ IGL_INLINE void point_areas(
+ const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedI>& I,
+ const Eigen::MatrixBase<DerivedN>& N,
+ Eigen::PlainObjectBase<DerivedA> & A);
+
+ // This version can be used to output the tangent plane normal at each
+ // point. Since we area already fitting a plane to each point's neighbour
+ // set, the tangent plane normals come "for free"
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ // I #P by k list of k-nearest-neighbor indices into P
+ // N #P by 3 list of point normals
+ // Outputs:
+ // A #P list of estimated areas
+ // T #P by 3 list of tangent plane normals for each point
+ template <typename DerivedP, typename DerivedI, typename DerivedN,
+ typename DerivedA, typename DerivedT>
+ IGL_INLINE void point_areas(
+ const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedI>& I,
+ const Eigen::MatrixBase<DerivedN>& N,
+ Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedT> & T);
+
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "point_areas.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/point_mesh_squared_distance.cpp b/xs/src/igl/copyleft/cgal/point_mesh_squared_distance.cpp
new file mode 100644
index 000000000..18b5706ae
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_mesh_squared_distance.cpp
@@ -0,0 +1,138 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_mesh_squared_distance.h"
+#include "mesh_to_cgal_triangle_list.h"
+#include "assign_scalar.h"
+
+template <
+ typename Kernel,
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ using namespace std;
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ typedef typename std::vector<Triangle_3>::iterator Iterator;
+ typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
+ typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
+ typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
+ Tree tree;
+ vector<Triangle_3> T;
+ point_mesh_squared_distance_precompute(V,F,tree,T);
+ return point_mesh_squared_distance(P,tree,T,sqrD,I,C);
+}
+
+template <typename Kernel, typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance_precompute(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ CGAL::AABB_tree<
+ CGAL::AABB_traits<Kernel,
+ CGAL::AABB_triangle_primitive<Kernel,
+ typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
+ >
+ >
+ > & tree,
+ std::vector<CGAL::Triangle_3<Kernel> > & T)
+{
+ using namespace std;
+
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef typename std::vector<Triangle_3>::iterator Iterator;
+ typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
+ typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
+ typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
+
+ // Must be 3D
+ assert(V.cols() == 3);
+ // Must be triangles
+ assert(F.cols() == 3);
+
+ // WTF ALERT!!!!
+ //
+ // There's a bug in clang probably or at least in cgal. Without calling this
+ // line (I guess invoking some compilation from <vector>), clang will vomit
+ // errors inside CGAL.
+ //
+ // http://stackoverflow.com/questions/27748442/is-clangs-c11-support-reliable
+ T.reserve(0);
+
+ // Make list of cgal triangles
+ mesh_to_cgal_triangle_list(V,F,T);
+ tree.clear();
+ tree.insert(T.begin(),T.end());
+ tree.accelerate_distance_queries();
+ // accelerate_distance_queries doesn't seem actually to do _all_ of the
+ // precomputation. the tree (despite being const) will still do more
+ // precomputation and reorganizing on the first call of `closest_point` or
+ // `closest_point_and_primitive`. Therefore, call it once here.
+ tree.closest_point_and_primitive(Point_3(0,0,0));
+}
+
+template <
+ typename Kernel,
+ typename DerivedP,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+IGL_INLINE void igl::copyleft::cgal::point_mesh_squared_distance(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const CGAL::AABB_tree<
+ CGAL::AABB_traits<Kernel,
+ CGAL::AABB_triangle_primitive<Kernel,
+ typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
+ >
+ >
+ > & tree,
+ const std::vector<CGAL::Triangle_3<Kernel> > & T,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ typedef typename std::vector<Triangle_3>::iterator Iterator;
+ typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
+ typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
+ typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
+ typedef typename Tree::Point_and_primitive_id Point_and_primitive_id;
+ typedef CGAL::Point_3<Kernel> Point_3;
+ assert(P.cols() == 3);
+ const int n = P.rows();
+ sqrD.resize(n,1);
+ I.resize(n,1);
+ C.resize(n,P.cols());
+ for(int p = 0;p < n;p++)
+ {
+ Point_3 query(P(p,0),P(p,1),P(p,2));
+ // Find closest point and primitive id
+ Point_and_primitive_id pp = tree.closest_point_and_primitive(query);
+ Point_3 closest_point = pp.first;
+ assign_scalar(closest_point[0],C(p,0));
+ assign_scalar(closest_point[1],C(p,1));
+ assign_scalar(closest_point[2],C(p,2));
+ assign_scalar((closest_point-query).squared_length(),sqrD(p));
+ I(p) = pp.second - T.begin();
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::point_mesh_squared_distance<CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/point_mesh_squared_distance.h b/xs/src/igl/copyleft/cgal/point_mesh_squared_distance.h
new file mode 100644
index 000000000..b525bddda
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_mesh_squared_distance.h
@@ -0,0 +1,104 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_POINT_MESH_SQUARED_DISTANCE_H
+#define IGL_COPYLEFT_CGAL_POINT_MESH_SQUARED_DISTANCE_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include "CGAL_includes.hpp"
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Compute distances from a set of points P to a triangle mesh (V,F)
+ //
+ // Templates:
+ // Kernal CGAL computation and construction kernel (e.g.
+ // CGAL::Simple_cartesian<double>)
+ // Inputs:
+ // P #P by 3 list of query point positions
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // Outputs:
+ // sqrD #P list of smallest squared distances
+ // I #P list of facet indices corresponding to smallest distances
+ // C #P by 3 list of closest points
+ //
+ // Known bugs: This only computes distances to triangles. So unreferenced
+ // vertices and degenerate triangles (segments) are ignored.
+ template <
+ typename Kernel,
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+ IGL_INLINE void point_mesh_squared_distance(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ // Probably can do this in a way that we don't pass around `tree` and `T`
+ //
+ // Outputs:
+ // tree CGAL's AABB tree
+ // T list of CGAL triangles in order of F (for determining which was found
+ // in computation)
+ template <
+ typename Kernel,
+ typename DerivedV,
+ typename DerivedF
+ >
+ IGL_INLINE void point_mesh_squared_distance_precompute(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ CGAL::AABB_tree<
+ CGAL::AABB_traits<Kernel,
+ CGAL::AABB_triangle_primitive<Kernel,
+ typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
+ >
+ >
+ > & tree,
+ std::vector<CGAL::Triangle_3<Kernel> > & T);
+ // Inputs:
+ // see above
+ // Outputs:
+ // see above
+ template <
+ typename Kernel,
+ typename DerivedP,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+ IGL_INLINE void point_mesh_squared_distance(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const CGAL::AABB_tree<
+ CGAL::AABB_traits<Kernel,
+ CGAL::AABB_triangle_primitive<Kernel,
+ typename std::vector<CGAL::Triangle_3<Kernel> >::iterator
+ >
+ >
+ > & tree,
+ const std::vector<CGAL::Triangle_3<Kernel> > & T,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "point_mesh_squared_distance.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/point_segment_squared_distance.cpp b/xs/src/igl/copyleft/cgal/point_segment_squared_distance.cpp
new file mode 100644
index 000000000..257206ae6
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_segment_squared_distance.cpp
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_segment_squared_distance.h"
+
+template < typename Kernel>
+IGL_INLINE void igl::copyleft::cgal::point_segment_squared_distance(
+ const CGAL::Point_3<Kernel> & P1,
+ const CGAL::Segment_3<Kernel> & S2,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & d)
+{
+ if(S2.is_degenerate())
+ {
+ P2 = S2.source();
+ d = (P1-P2).squared_length();
+ return;
+ }
+ // http://stackoverflow.com/a/1501725/148668
+ const auto sqr_len = S2.squared_length();
+ assert(sqr_len != 0);
+ const auto & V = S2.source();
+ const auto & W = S2.target();
+ const auto t = (P1-V).dot(W-V)/sqr_len;
+ if(t<0)
+ {
+ P2 = V;
+ }else if(t>1)
+ {
+ P2 = W;
+ }else
+ {
+ P2 = V + t*(W-V);
+ }
+ d = (P1-P2).squared_length();
+}
+
diff --git a/xs/src/igl/copyleft/cgal/point_segment_squared_distance.h b/xs/src/igl/copyleft/cgal/point_segment_squared_distance.h
new file mode 100644
index 000000000..eac628b2a
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_segment_squared_distance.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_POINT_SEGMENT_SQUARED_DISTANCE_H
+#define IGL_COPYLEFT_CGAL_POINT_SEGMENT_SQUARED_DISTANCE_H
+#include "../../igl_inline.h"
+#include <CGAL/Segment_3.h>
+#include <CGAL/Point_3.h>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given a point P1 and segment S2 find the points on each of closest
+ // approach and the squared distance thereof.
+ //
+ // Inputs:
+ // P1 point
+ // S2 segment
+ // Outputs:
+ // P2 point on S2 closest to P1
+ // d distance betwee P1 and S2
+ template < typename Kernel>
+ IGL_INLINE void point_segment_squared_distance(
+ const CGAL::Point_3<Kernel> & P1,
+ const CGAL::Segment_3<Kernel> & S2,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & d
+ );
+
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "point_segment_squared_distance.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.cpp b/xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.cpp
new file mode 100644
index 000000000..7aef2efd1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.cpp
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_solid_signed_squared_distance.h"
+#include "points_inside_component.h"
+#include "point_mesh_squared_distance.h"
+#include "../../list_to_matrix.h"
+#include "../../slice_mask.h"
+#include <vector>
+#include <Eigen/Core>
+
+template <
+ typename DerivedQ,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedD>
+IGL_INLINE void igl::copyleft::cgal::point_solid_signed_squared_distance(
+ const Eigen::PlainObjectBase<DerivedQ> & Q,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ Eigen::PlainObjectBase<DerivedD> & D)
+{
+ // compute unsigned distances
+ Eigen::VectorXi I;
+ DerivedVB C;
+ point_mesh_squared_distance<CGAL::Epeck>(Q,VB,FB,D,I,C);
+ // Collect queries that have non-zero distance
+ Eigen::Array<bool,Eigen::Dynamic,1> NZ = D.array()!=0;
+ // Compute sign for non-zero distance queries
+ DerivedQ QNZ;
+ slice_mask(Q,NZ,1,QNZ);
+ Eigen::Array<bool,Eigen::Dynamic,1> DNZ;
+ igl::copyleft::cgal::points_inside_component(VB,FB,QNZ,DNZ);
+ // Apply sign to distances
+ DerivedD S = DerivedD::Zero(Q.rows(),1);
+ {
+ int k = 0;
+ for(int q = 0;q<Q.rows();q++)
+ {
+ if(NZ(q))
+ {
+ D(q) *= DNZ(k++) ? -1. : 1.;
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::point_solid_signed_squared_distance<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.h b/xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.h
new file mode 100644
index 000000000..845fad133
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_solid_signed_squared_distance.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_POINT_SOLID_SIGNED_SQUARED_DISTANCE_H
+#define IGL_COPYLEFT_CGAL_POINT_SOLID_SIGNED_SQUARED_DISTANCE_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // POINT_SOLID_SIGNED_SQUARED_DISTANCE Given a set of points (Q) and the
+ // boundary mesh (VB,FB) of a solid (as defined in [Zhou et al. 2016],
+ // determine the signed squared distance for each point q in Q so that d(q,B) is
+ // negative if inside and positive if outside.
+ //
+ // Inputs:
+ // Q #Q by 3 list of query point positions
+ // VB #VB by 3 list of mesh vertex positions of B
+ // FB #FB by 3 list of mesh triangle indices into VB
+ // Outputs:
+ // D
+ template <
+ typename DerivedQ,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedD>
+ IGL_INLINE void point_solid_signed_squared_distance(
+ const Eigen::PlainObjectBase<DerivedQ> & Q,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ Eigen::PlainObjectBase<DerivedD> & D);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "point_solid_signed_squared_distance.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/point_triangle_squared_distance.cpp b/xs/src/igl/copyleft/cgal/point_triangle_squared_distance.cpp
new file mode 100644
index 000000000..2ea29bc37
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_triangle_squared_distance.cpp
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_triangle_squared_distance.h"
+#include <CGAL/Segment_3.h>
+template < typename Kernel>
+IGL_INLINE void point_triangle_squared_distance(
+ const CGAL::Point_3<Kernel> & P1,
+ const CGAL::Triangle_3<Kernel> & T2,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & d)
+{
+ assert(!T2.is_degenerate());
+ if(T2.has_on(P1))
+ {
+ P2 = P1;
+ d = 0;
+ return;
+ }
+ const auto proj_1 = T2.supporting_plane().projection(P2);
+ if(T2.has_on(proj_1))
+ {
+ P2 = proj_1;
+ d = (proj_1-P1).squared_length();
+ return;
+ }
+ // closest point must be on the boundary
+ bool first = true;
+ // loop over edges
+ for(int i=0;i<3;i++)
+ {
+ CGAL::Point_3<Kernel> P2i;
+ typename Kernel::FT di;
+ const CGAL::Segment_3<Kernel> si( T2.vertex(i+1), T2.vertex(i+2));
+ point_segment_squared_distance(P1,si,P2i,di);
+ if(first || di < d)
+ {
+ first = false;
+ d = di;
+ P2 = P2i;
+ }
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/point_triangle_squared_distance.h b/xs/src/igl/copyleft/cgal/point_triangle_squared_distance.h
new file mode 100644
index 000000000..37b63adcb
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/point_triangle_squared_distance.h
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_POINT_TRIANGLE_SQUARED_DISTANCE_H
+#define IGL_COPYLEFT_CGAL_POINT_TRIANGLE_SQUARED_DISTANCE_H
+#include "../../igl_inline.h"
+#include <CGAL/Triangle_3.h>
+#include <CGAL/Point_3.h>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given a point P1 and triangle T2 find the points on each of closest
+ // approach and the squared distance thereof.
+ //
+ // Inputs:
+ // P1 point
+ // T2 triangle
+ // Outputs:
+ // P2 point on T2 closest to P1
+ // d distance betwee P1 and T2
+ template < typename Kernel>
+ IGL_INLINE void point_triangle_squared_distance(
+ const CGAL::Point_3<Kernel> & P1,
+ const CGAL::Triangle_3<Kernel> & T2,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & d
+ );
+
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "point_triangle_squared_distance.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/copyleft/cgal/points_inside_component.cpp b/xs/src/igl/copyleft/cgal/points_inside_component.cpp
new file mode 100644
index 000000000..1558e130d
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/points_inside_component.cpp
@@ -0,0 +1,350 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "points_inside_component.h"
+#include "../../LinSpaced.h"
+#include "order_facets_around_edge.h"
+#include "assign_scalar.h"
+
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#include <cassert>
+#include <list>
+#include <limits>
+#include <vector>
+
+
+namespace igl {
+ namespace copyleft
+ {
+ namespace cgal {
+ namespace points_inside_component_helper {
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
+ typedef Kernel::Ray_3 Ray_3;
+ typedef Kernel::Point_3 Point_3;
+ typedef Kernel::Vector_3 Vector_3;
+ typedef Kernel::Triangle_3 Triangle;
+ typedef Kernel::Plane_3 Plane_3;
+ typedef std::vector<Triangle>::iterator Iterator;
+ typedef CGAL::AABB_triangle_primitive<Kernel, Iterator> Primitive;
+ typedef CGAL::AABB_traits<Kernel, Primitive> AABB_triangle_traits;
+ typedef CGAL::AABB_tree<AABB_triangle_traits> Tree;
+
+ template<typename DerivedF, typename DerivedI>
+ void extract_adj_faces(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const size_t s, const size_t d,
+ std::vector<int>& adj_faces) {
+ const size_t num_faces = I.rows();
+ for (size_t i=0; i<num_faces; i++) {
+ Eigen::Vector3i f = F.row(I(i, 0));
+ if (((size_t)f[0] == s && (size_t)f[1] == d) ||
+ ((size_t)f[1] == s && (size_t)f[2] == d) ||
+ ((size_t)f[2] == s && (size_t)f[0] == d)) {
+ adj_faces.push_back((I(i, 0)+1) * -1);
+ continue;
+ }
+ if (((size_t)f[0] == d && (size_t)f[1] == s) ||
+ ((size_t)f[1] == d && (size_t)f[2] == s) ||
+ ((size_t)f[2] == d && (size_t)f[0] == s)) {
+ adj_faces.push_back(I(i, 0)+1);
+ continue;
+ }
+ }
+ }
+
+ template<typename DerivedF, typename DerivedI>
+ void extract_adj_vertices(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const size_t v, std::vector<int>& adj_vertices) {
+ std::set<size_t> unique_adj_vertices;
+ const size_t num_faces = I.rows();
+ for (size_t i=0; i<num_faces; i++) {
+ Eigen::Vector3i f = F.row(I(i, 0));
+ if ((size_t)f[0] == v) {
+ unique_adj_vertices.insert(f[1]);
+ unique_adj_vertices.insert(f[2]);
+ } else if ((size_t)f[1] == v) {
+ unique_adj_vertices.insert(f[0]);
+ unique_adj_vertices.insert(f[2]);
+ } else if ((size_t)f[2] == v) {
+ unique_adj_vertices.insert(f[0]);
+ unique_adj_vertices.insert(f[1]);
+ }
+ }
+ adj_vertices.resize(unique_adj_vertices.size());
+ std::copy(unique_adj_vertices.begin(),
+ unique_adj_vertices.end(),
+ adj_vertices.begin());
+ }
+
+ template<typename DerivedV, typename DerivedF, typename DerivedI>
+ bool determine_point_edge_orientation(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Point_3& query, size_t s, size_t d) {
+ // Algorithm:
+ //
+ // Order the adj faces around the edge (s,d) clockwise using
+ // query point as pivot. (i.e. The first face of the ordering
+ // is directly after the pivot point, and the last face is
+ // directly before the pivot.)
+ //
+ // The point is outside if the first and last faces of the
+ // ordering forms a convex angle. This check can be done
+ // without any construction by looking at the orientation of the
+ // faces. The angle is convex iff the first face contains (s,d)
+ // as an edge and the last face contains (d,s) as an edge.
+ //
+ // The point is inside if the first and last faces of the
+ // ordering forms a concave angle. That is the first face
+ // contains (d,s) as an edge and the last face contains (s,d) as
+ // an edge.
+ //
+ // In the special case of duplicated faces. I.e. multiple faces
+ // sharing the same 3 corners, but not necessarily the same
+ // orientation. The ordering will always rank faces containing
+ // edge (s,d) before faces containing edge (d,s).
+ //
+ // Therefore, if there are any duplicates of the first faces,
+ // the ordering will always choose the one with edge (s,d) if
+ // possible. The same for the last face.
+ //
+ // In the very degenerated case where the first and last face
+ // are duplicates, but with different orientations, it is
+ // equally valid to think the angle formed by them is either 0
+ // or 360 degrees. By default, 0 degree is used, and thus the
+ // query point is outside.
+
+ std::vector<int> adj_faces;
+ extract_adj_faces(F, I, s, d, adj_faces);
+ const size_t num_adj_faces = adj_faces.size();
+ assert(num_adj_faces > 0);
+
+ DerivedV pivot_point(1, 3);
+ igl::copyleft::cgal::assign_scalar(query.x(), pivot_point(0, 0));
+ igl::copyleft::cgal::assign_scalar(query.y(), pivot_point(0, 1));
+ igl::copyleft::cgal::assign_scalar(query.z(), pivot_point(0, 2));
+ Eigen::VectorXi order;
+ order_facets_around_edge(V, F, s, d,
+ adj_faces, pivot_point, order);
+ assert((size_t)order.size() == num_adj_faces);
+ if (adj_faces[order[0]] > 0 &&
+ adj_faces[order[num_adj_faces-1] < 0]) {
+ return true;
+ } else if (adj_faces[order[0]] < 0 &&
+ adj_faces[order[num_adj_faces-1] > 0]) {
+ return false;
+ } else {
+ throw "The input mesh does not represent a valid volume";
+ }
+ throw "The input mesh does not represent a valid volume";
+ return false;
+ }
+
+ template<typename DerivedV, typename DerivedF, typename DerivedI>
+ bool determine_point_vertex_orientation(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Point_3& query, size_t s) {
+ std::vector<int> adj_vertices;
+ extract_adj_vertices(F, I, s, adj_vertices);
+ const size_t num_adj_vertices = adj_vertices.size();
+
+ std::vector<Point_3> adj_points;
+ for (size_t i=0; i<num_adj_vertices; i++) {
+ const size_t vi = adj_vertices[i];
+ adj_points.emplace_back(V(vi,0), V(vi,1), V(vi,2));
+ }
+
+ // A plane is on the exterior if all adj_points lies on or to
+ // one side of the plane.
+ auto is_on_exterior = [&](const Plane_3& separator) -> bool{
+ size_t positive=0;
+ size_t negative=0;
+ size_t coplanar=0;
+ for (const auto& point : adj_points) {
+ switch(separator.oriented_side(point)) {
+ case CGAL::ON_POSITIVE_SIDE:
+ positive++;
+ break;
+ case CGAL::ON_NEGATIVE_SIDE:
+ negative++;
+ break;
+ case CGAL::ON_ORIENTED_BOUNDARY:
+ coplanar++;
+ break;
+ default:
+ throw "Unknown plane-point orientation";
+ }
+ }
+ auto query_orientation = separator.oriented_side(query);
+ bool r =
+ (positive == 0 && query_orientation == CGAL::POSITIVE)
+ ||
+ (negative == 0 && query_orientation == CGAL::NEGATIVE);
+ return r;
+ };
+
+ size_t d = std::numeric_limits<size_t>::max();
+ Point_3 p(V(s,0), V(s,1), V(s,2));
+ for (size_t i=0; i<num_adj_vertices; i++) {
+ const size_t vi = adj_vertices[i];
+ for (size_t j=i+1; j<num_adj_vertices; j++) {
+ Plane_3 separator(p, adj_points[i], adj_points[j]);
+ if (separator.is_degenerate()) {
+ throw "Input mesh contains degenerated faces";
+ }
+ if (is_on_exterior(separator)) {
+ d = vi;
+ assert(!CGAL::collinear(p, adj_points[i], query));
+ break;
+ }
+ }
+ if (d < (size_t)V.rows()) break;
+ }
+ if (d > (size_t)V.rows()) {
+ // All adj faces are coplanar, use the first edge.
+ d = adj_vertices[0];
+ }
+ return determine_point_edge_orientation(V, F, I, query, s, d);
+ }
+
+ template<typename DerivedV, typename DerivedF, typename DerivedI>
+ bool determine_point_face_orientation(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Point_3& query, size_t fid) {
+ // Algorithm: A point is on the inside of a face if the
+ // tetrahedron formed by them is negatively oriented.
+
+ Eigen::Vector3i f = F.row(I(fid, 0));
+ const Point_3 v0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
+ const Point_3 v1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
+ const Point_3 v2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
+ auto result = CGAL::orientation(v0, v1, v2, query);
+ if (result == CGAL::COPLANAR) {
+ throw "Cannot determine inside/outside because query point lies exactly on the input surface.";
+ }
+ return result == CGAL::NEGATIVE;
+ }
+ }
+ }
+ }
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedI,
+ typename DerivedP, typename DerivedB>
+IGL_INLINE void igl::copyleft::cgal::points_inside_component(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedB>& inside) {
+ using namespace igl::copyleft::cgal::points_inside_component_helper;
+ if (F.rows() <= 0 || I.rows() <= 0) {
+ throw "Inside check cannot be done on empty facet component.";
+ }
+
+ const size_t num_faces = I.rows();
+ std::vector<Triangle> triangles;
+ for (size_t i=0; i<num_faces; i++) {
+ const Eigen::Vector3i f = F.row(I(i, 0));
+ triangles.emplace_back(
+ Point_3(V(f[0], 0), V(f[0], 1), V(f[0], 2)),
+ Point_3(V(f[1], 0), V(f[1], 1), V(f[1], 2)),
+ Point_3(V(f[2], 0), V(f[2], 1), V(f[2], 2)));
+ if (triangles.back().is_degenerate()) {
+ throw "Input facet components contains degenerated triangles";
+ }
+ }
+ Tree tree(triangles.begin(), triangles.end());
+ tree.accelerate_distance_queries();
+
+ enum ElementType { VERTEX, EDGE, FACE };
+ auto determine_element_type = [&](
+ size_t fid, const Point_3& p, size_t& element_index) -> ElementType{
+ const Eigen::Vector3i f = F.row(I(fid, 0));
+ const Point_3 p0(V(f[0], 0), V(f[0], 1), V(f[0], 2));
+ const Point_3 p1(V(f[1], 0), V(f[1], 1), V(f[1], 2));
+ const Point_3 p2(V(f[2], 0), V(f[2], 1), V(f[2], 2));
+
+ if (p == p0) { element_index = 0; return VERTEX; }
+ if (p == p1) { element_index = 1; return VERTEX; }
+ if (p == p2) { element_index = 2; return VERTEX; }
+ if (CGAL::collinear(p0, p1, p)) { element_index = 2; return EDGE; }
+ if (CGAL::collinear(p1, p2, p)) { element_index = 0; return EDGE; }
+ if (CGAL::collinear(p2, p0, p)) { element_index = 1; return EDGE; }
+
+ element_index = 0;
+ return FACE;
+ };
+
+ const size_t num_queries = P.rows();
+ inside.resize(num_queries, 1);
+ for (size_t i=0; i<num_queries; i++) {
+ const Point_3 query(P(i,0), P(i,1), P(i,2));
+ auto projection = tree.closest_point_and_primitive(query);
+ auto closest_point = projection.first;
+ size_t fid = projection.second - triangles.begin();
+
+ size_t element_index;
+ switch (determine_element_type(fid, closest_point, element_index)) {
+ case VERTEX:
+ {
+ const size_t s = F(I(fid, 0), element_index);
+ inside(i,0) = determine_point_vertex_orientation(
+ V, F, I, query, s);
+ }
+ break;
+ case EDGE:
+ {
+ const size_t s = F(I(fid, 0), (element_index+1)%3);
+ const size_t d = F(I(fid, 0), (element_index+2)%3);
+ inside(i,0) = determine_point_edge_orientation(
+ V, F, I, query, s, d);
+ }
+ break;
+ case FACE:
+ inside(i,0) = determine_point_face_orientation(V, F, I, query, fid);
+ break;
+ default:
+ throw "Unknown closest element type!";
+ }
+ }
+}
+
+template<typename DerivedV, typename DerivedF, typename DerivedP,
+ typename DerivedB>
+IGL_INLINE void igl::copyleft::cgal::points_inside_component(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedB>& inside) {
+ Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(F.rows(), 0, F.rows()-1);
+ igl::copyleft::cgal::points_inside_component(V, F, I, P, inside);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::points_inside_component< Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix< int, -1, -1, 0, -1, -1> > ( Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix< int, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::points_inside_component<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/points_inside_component.h b/xs/src/igl/copyleft/cgal/points_inside_component.h
new file mode 100644
index 000000000..f21354455
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/points_inside_component.h
@@ -0,0 +1,71 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_POINTS_INSIDE_COMPONENTS
+#define IGL_COPYLEFT_CGAL_POINTS_INSIDE_COMPONENTS
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal {
+
+ // Determine if queries points P are inside of connected facet component
+ // (V, F, I), where I indicates a subset of facets that forms the
+ // component.
+ //
+ // Precondition:
+ // The input mesh must be a closed, self-intersection free,
+ // non-degenerated surface. Queries points must be either inside or
+ // outside of the mesh (i.e. not on the surface of the mesh).
+ //
+ // Inputs:
+ // V #V by 3 array of vertex positions.
+ // F #F by 3 array of triangles.
+ // I #I list of triangle indices to consider.
+ // P #P by 3 array of query points.
+ //
+ // Outputs:
+ // inside #P list of booleans that is true iff the corresponding
+ // query point is inside of the mesh.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedP,
+ typename DerivedB>
+ IGL_INLINE void points_inside_component(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedB>& inside);
+
+ // Determine if query points P is inside of the mesh (V, F).
+ // See above for precondition and I/O specs.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedB>
+ IGL_INLINE void points_inside_component(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedB>& inside);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "points_inside_component.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/polyhedron_to_mesh.cpp b/xs/src/igl/copyleft/cgal/polyhedron_to_mesh.cpp
new file mode 100644
index 000000000..b51e41b60
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/polyhedron_to_mesh.cpp
@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "polyhedron_to_mesh.h"
+#include <CGAL/Polyhedron_3.h>
+
+template <
+ typename Polyhedron,
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE void igl::copyleft::cgal::polyhedron_to_mesh(
+ const Polyhedron & poly,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F)
+{
+ using namespace std;
+ V.resize(poly.size_of_vertices(),3);
+ F.resize(poly.size_of_facets(),3);
+ typedef typename Polyhedron::Vertex_const_iterator Vertex_iterator;
+ std::map<Vertex_iterator,size_t> vertex_to_index;
+ {
+ size_t v = 0;
+ for(
+ typename Polyhedron::Vertex_const_iterator p = poly.vertices_begin();
+ p != poly.vertices_end();
+ p++)
+ {
+ V(v,0) = p->point().x();
+ V(v,1) = p->point().y();
+ V(v,2) = p->point().z();
+ vertex_to_index[p] = v;
+ v++;
+ }
+ }
+ {
+ size_t f = 0;
+ for(
+ typename Polyhedron::Facet_const_iterator facet = poly.facets_begin();
+ facet != poly.facets_end();
+ ++facet)
+ {
+ typename Polyhedron::Halfedge_around_facet_const_circulator he =
+ facet->facet_begin();
+ // Facets in polyhedral surfaces are at least triangles.
+ assert(CGAL::circulator_size(he) == 3 && "Facets should be triangles");
+ size_t c = 0;
+ do {
+ //// This is stooopidly slow
+ // F(f,c) = std::distance(poly.vertices_begin(), he->vertex());
+ F(f,c) = vertex_to_index[he->vertex()];
+ c++;
+ } while ( ++he != facet->facet_begin());
+ f++;
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#include <CGAL/Simple_cartesian.h>
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Polyhedron_items_with_id_3.h>
+template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Epick, CGAL::Polyhedron_items_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cgal::polyhedron_to_mesh<CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> >, Eigen::Matrix<double, -1, -1, 0,-1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CGAL::Polyhedron_3<CGAL::Simple_cartesian<double>,CGAL::Polyhedron_items_with_id_3, CGAL::HalfedgeDS_default, std::allocator<int> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0,-1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/polyhedron_to_mesh.h b/xs/src/igl/copyleft/cgal/polyhedron_to_mesh.h
new file mode 100644
index 000000000..3f8c66a88
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/polyhedron_to_mesh.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_POLYHEDRON_TO_MESH_H
+#define IGL_COPYLEFT_CGAL_POLYHEDRON_TO_MESH_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Convert a CGAL Polyhedron to a mesh (V,F)
+ //
+ // Templates:
+ // Polyhedron CGAL Polyhedron type (e.g. Polyhedron_3)
+ // Inputs:
+ // poly cgal polyhedron
+ // Outputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ template <
+ typename Polyhedron,
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE void polyhedron_to_mesh(
+ const Polyhedron & poly,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "polyhedron_to_mesh.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/projected_cdt.cpp b/xs/src/igl/copyleft/cgal/projected_cdt.cpp
new file mode 100644
index 000000000..f34352c66
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/projected_cdt.cpp
@@ -0,0 +1,82 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "projected_cdt.h"
+#include "insert_into_cdt.h"
+#include "assign_scalar.h"
+#include "../../list_to_matrix.h"
+template <typename Kernel, typename Index>
+IGL_INLINE void igl::copyleft::cgal::projected_cdt(
+ const std::vector<CGAL::Object> & objects,
+ const CGAL::Plane_3<Kernel> & P,
+ std::vector<CGAL::Point_3<Kernel> >& vertices,
+ std::vector<std::vector<Index> >& faces)
+{
+ typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
+ typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
+ typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
+ typedef CGAL::Exact_intersections_tag Itag;
+ typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag> CDT_2;
+ typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+ CDT_plus_2 cdt;
+ for(const auto & obj : objects) insert_into_cdt(obj,P,cdt);
+ // Read off vertices of the cdt, remembering index
+ std::map<typename CDT_plus_2::Vertex_handle,Index> v2i;
+ size_t count=0;
+ for (
+ auto itr = cdt.finite_vertices_begin();
+ itr != cdt.finite_vertices_end();
+ itr++)
+ {
+ vertices.push_back(P.to_3d(itr->point()));
+ v2i[itr] = count;
+ count++;
+ }
+ // Read off faces and store index triples
+ for (
+ auto itr = cdt.finite_faces_begin();
+ itr != cdt.finite_faces_end();
+ itr++)
+ {
+ faces.push_back(
+ { v2i[itr->vertex(0)], v2i[itr->vertex(1)], v2i[itr->vertex(2)] });
+ }
+}
+
+template < typename Kernel, typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::cgal::projected_cdt(
+ const std::vector<CGAL::Object> & objects,
+ const CGAL::Plane_3<Kernel> & P,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F)
+{
+ std::vector<CGAL::Point_3<Kernel> > vertices;
+ std::vector<std::vector<typename DerivedF::Scalar> > faces;
+ projected_cdt(objects,P,vertices,faces);
+ V.resize(vertices.size(),3);
+ for(int v = 0;v<vertices.size();v++)
+ {
+ for(int d = 0;d<3;d++)
+ {
+ assign_scalar(vertices[v][d], V(v,d));
+ }
+ }
+ list_to_matrix(faces,F);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::projected_cdt<CGAL::Epick, long>(std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Plane_3<CGAL::Epick> const&, std::vector<CGAL::Point_3<CGAL::Epick>, std::allocator<CGAL::Point_3<CGAL::Epick> > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::projected_cdt<CGAL::Epeck, long>(std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Plane_3<CGAL::Epeck> const&, std::vector<CGAL::Point_3<CGAL::Epeck>, std::allocator<CGAL::Point_3<CGAL::Epeck> > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#ifdef WIN32
+template void igl::copyleft::cgal::projected_cdt<class CGAL::Epeck, __int64>(class std::vector<class CGAL::Object, class std::allocator<class CGAL::Object>> const &, class CGAL::Plane_3<class CGAL::Epeck> const &, class std::vector<class CGAL::Point_3<class CGAL::Epeck>, class std::allocator<class CGAL::Point_3<class CGAL::Epeck>>> &, class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>> &);
+template void igl::copyleft::cgal::projected_cdt<class CGAL::Epick, __int64>(class std::vector<class CGAL::Object, class std::allocator<class CGAL::Object>> const &, class CGAL::Plane_3<class CGAL::Epick> const &, class std::vector<class CGAL::Point_3<class CGAL::Epick>, class std::allocator<class CGAL::Point_3<class CGAL::Epick>>> &, class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/projected_cdt.h b/xs/src/igl/copyleft/cgal/projected_cdt.h
new file mode 100644
index 000000000..a161cc450
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/projected_cdt.h
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_PROJECTED_CDT_H
+#define IGL_COPYLEFT_CGAL_PROJECTED_CDT_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <CGAL/Plane_3.h>
+#include <CGAL/Point_3.h>
+#include <CGAL/Object.h>
+#include <vector>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given a list of objects (e.g., resulting from intersecting a triangle
+ // with many other triangles), construct a constrained Delaunay
+ // triangulation on a given plane (P), by inersting constraints for each
+ // object projected onto that plane.
+ //
+ // Inputs:
+ // objects list of objects. This should lie on the given plane (P),
+ // otherwise they are added to the cdt _after_ their non-trivial
+ // projection
+ // P plane upon which all objects lie and upon which the CDT is
+ // conducted
+ // Outputs:
+ // vertices list of vertices of the CDT mesh _back on the 3D plane_
+ // faces list of list of triangle indices into vertices
+ //
+ template <typename Kernel, typename Index>
+ IGL_INLINE void projected_cdt(
+ const std::vector<CGAL::Object> & objects,
+ const CGAL::Plane_3<Kernel> & P,
+ std::vector<CGAL::Point_3<Kernel> >& vertices,
+ std::vector<std::vector<Index> >& faces);
+ // Outputs:
+ // V #V by 3 list of vertices of the CDT mesh _back on the 3D plane_,
+ // **cast** from the number type of Kernel to the number type of
+ // DerivedV
+ // F #F by 3 list of triangle indices into V
+ template < typename Kernel, typename DerivedV, typename DerivedF>
+ IGL_INLINE void projected_cdt(
+ const std::vector<CGAL::Object> & objects,
+ const CGAL::Plane_3<Kernel> & P,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "projected_cdt.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/projected_delaunay.cpp b/xs/src/igl/copyleft/cgal/projected_delaunay.cpp
new file mode 100644
index 000000000..52ea49274
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/projected_delaunay.cpp
@@ -0,0 +1,106 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "projected_delaunay.h"
+#include "../../REDRUM.h"
+#include <iostream>
+#include <cassert>
+
+#if CGAL_VERSION_NR < 1040611000
+# warning "CGAL Version < 4.6.1 may result in crashes. Please upgrade CGAL"
+#endif
+
+template <typename Kernel>
+IGL_INLINE void igl::copyleft::cgal::projected_delaunay(
+ const CGAL::Triangle_3<Kernel> & A,
+ const std::vector<CGAL::Object> & A_objects_3,
+ CGAL::Constrained_triangulation_plus_2<
+ CGAL::Constrained_Delaunay_triangulation_2<
+ Kernel,
+ CGAL::Triangulation_data_structure_2<
+ CGAL::Triangulation_vertex_base_2<Kernel>,
+ CGAL::Constrained_triangulation_face_base_2<Kernel> >,
+ CGAL::Exact_intersections_tag> > & cdt)
+{
+ using namespace std;
+ // 3D Primitives
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Segment_3<Kernel> Segment_3;
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ typedef CGAL::Plane_3<Kernel> Plane_3;
+ //typedef CGAL::Tetrahedron_3<Kernel> Tetrahedron_3;
+ typedef CGAL::Point_2<Kernel> Point_2;
+ //typedef CGAL::Segment_2<Kernel> Segment_2;
+ //typedef CGAL::Triangle_2<Kernel> Triangle_2;
+ typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
+ typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
+ typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
+ typedef CGAL::Exact_intersections_tag Itag;
+ typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag>
+ CDT_2;
+ typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+
+ // http://www.cgal.org/Manual/3.2/doc_html/cgal_manual/Triangulation_2/Chapter_main.html#Section_2D_Triangulations_Constrained_Plus
+ // Plane of triangle A
+ Plane_3 P(A.vertex(0),A.vertex(1),A.vertex(2));
+ // Insert triangle into vertices
+ typename CDT_plus_2::Vertex_handle corners[3];
+ typedef size_t Index;
+ for(Index i = 0;i<3;i++)
+ {
+ const Point_3 & p3 = A.vertex(i);
+ const Point_2 & p2 = P.to_2d(p3);
+ typename CDT_plus_2::Vertex_handle corner = cdt.insert(p2);
+ corners[i] = corner;
+ }
+ // Insert triangle edges as constraints
+ for(Index i = 0;i<3;i++)
+ {
+ cdt.insert_constraint( corners[(i+1)%3], corners[(i+2)%3]);
+ }
+ // Insert constraints for intersection objects
+ for( const auto & obj : A_objects_3)
+ {
+ if(const Segment_3 *iseg = CGAL::object_cast<Segment_3 >(&obj))
+ {
+ // Add segment constraint
+ cdt.insert_constraint(P.to_2d(iseg->vertex(0)),P.to_2d(iseg->vertex(1)));
+ }else if(const Point_3 *ipoint = CGAL::object_cast<Point_3 >(&obj))
+ {
+ // Add point
+ cdt.insert(P.to_2d(*ipoint));
+ } else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&obj))
+ {
+ // Add 3 segment constraints
+ cdt.insert_constraint(P.to_2d(itri->vertex(0)),P.to_2d(itri->vertex(1)));
+ cdt.insert_constraint(P.to_2d(itri->vertex(1)),P.to_2d(itri->vertex(2)));
+ cdt.insert_constraint(P.to_2d(itri->vertex(2)),P.to_2d(itri->vertex(0)));
+ } else if(const std::vector<Point_3 > *polyp =
+ CGAL::object_cast< std::vector<Point_3 > >(&obj))
+ {
+ //cerr<<REDRUM("Poly...")<<endl;
+ const std::vector<Point_3 > & poly = *polyp;
+ const Index m = poly.size();
+ assert(m>=2);
+ for(Index p = 0;p<m;p++)
+ {
+ const Index np = (p+1)%m;
+ cdt.insert_constraint(P.to_2d(poly[p]),P.to_2d(poly[np]));
+ }
+ }else
+ {
+ cerr<<REDRUM("What is this object?!")<<endl;
+ assert(false);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cgal::projected_delaunay<CGAL::Epeck>(CGAL::Triangle_3<CGAL::Epeck> const&, std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epeck, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epeck, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_face_base_2<CGAL::Epeck, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
+template void igl::copyleft::cgal::projected_delaunay<CGAL::Epick>(CGAL::Triangle_3<CGAL::Epick> const&, std::vector<CGAL::Object, std::allocator<CGAL::Object> > const&, CGAL::Constrained_triangulation_plus_2<CGAL::Constrained_Delaunay_triangulation_2<CGAL::Epick, CGAL::Triangulation_data_structure_2<CGAL::Triangulation_vertex_base_2<CGAL::Epick, CGAL::Triangulation_ds_vertex_base_2<void> >, CGAL::Constrained_triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_face_base_2<CGAL::Epick, CGAL::Triangulation_ds_face_base_2<void> > > >, CGAL::Exact_intersections_tag> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/projected_delaunay.h b/xs/src/igl/copyleft/cgal/projected_delaunay.h
new file mode 100644
index 000000000..ee72305cd
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/projected_delaunay.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_PROJECTED_DELAUNAY_H
+#define IGL_COPYLEFT_CGAL_PROJECTED_DELAUNAY_H
+#include "../../igl_inline.h"
+#include "CGAL_includes.hpp"
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Compute 2D delaunay triangulation of a given 3d triangle and a list of
+ // intersection objects (points,segments,triangles). CGAL uses an affine
+ // projection rather than an isometric projection, so we're not guaranteed
+ // that the 2D delaunay triangulation here will be a delaunay triangulation
+ // in 3D.
+ //
+ // Inputs:
+ // A triangle in 3D
+ // A_objects_3 updated list of intersection objects for A
+ // Outputs:
+ // cdt Contrained delaunay triangulation in projected 2D plane
+ template <typename Kernel>
+ IGL_INLINE void projected_delaunay(
+ const CGAL::Triangle_3<Kernel> & A,
+ const std::vector<CGAL::Object> & A_objects_3,
+ CGAL::Constrained_triangulation_plus_2<
+ CGAL::Constrained_Delaunay_triangulation_2<
+ Kernel,
+ CGAL::Triangulation_data_structure_2<
+ CGAL::Triangulation_vertex_base_2<Kernel>,
+ CGAL::Constrained_triangulation_face_base_2<Kernel> >,
+ CGAL::Exact_intersections_tag> > & cdt);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "projected_delaunay.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/propagate_winding_numbers.cpp b/xs/src/igl/copyleft/cgal/propagate_winding_numbers.cpp
new file mode 100644
index 000000000..7de9d98d2
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/propagate_winding_numbers.cpp
@@ -0,0 +1,324 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#include "propagate_winding_numbers.h"
+#include "../../extract_manifold_patches.h"
+#include "../../extract_non_manifold_edge_curves.h"
+#include "../../facet_components.h"
+#include "../../unique_edge_map.h"
+#include "../../piecewise_constant_winding_number.h"
+#include "../../writeOBJ.h"
+#include "../../writePLY.h"
+#include "../../get_seconds.h"
+#include "../../LinSpaced.h"
+#include "order_facets_around_edge.h"
+#include "outer_facet.h"
+#include "closest_facet.h"
+#include "assign.h"
+#include "extract_cells.h"
+#include "cell_adjacency.h"
+
+#include <stdexcept>
+#include <limits>
+#include <vector>
+#include <tuple>
+#include <queue>
+
+//#define PROPAGATE_WINDING_NUMBER_TIMING
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedL,
+ typename DerivedW>
+IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedL>& labels,
+ Eigen::PlainObjectBase<DerivedW>& W)
+{
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ const auto & tictoc = []() -> double
+ {
+ static double t_start = igl::get_seconds();
+ double diff = igl::get_seconds()-t_start;
+ t_start += diff;
+ return diff;
+ };
+ const auto log_time = [&](const std::string& label) -> void {
+ std::cout << "propagate_winding_num." << label << ": "
+ << tictoc() << std::endl;
+ };
+ tictoc();
+#endif
+
+ Eigen::MatrixXi E, uE;
+ Eigen::VectorXi EMAP;
+ std::vector<std::vector<size_t> > uE2E;
+ igl::unique_edge_map(F, E, uE, EMAP, uE2E);
+
+ Eigen::VectorXi P;
+ const size_t num_patches = igl::extract_manifold_patches(F, EMAP, uE2E, P);
+
+ DerivedW per_patch_cells;
+ const size_t num_cells =
+ igl::copyleft::cgal::extract_cells(
+ V, F, P, E, uE, uE2E, EMAP, per_patch_cells);
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ log_time("cell_extraction");
+#endif
+
+ return propagate_winding_numbers(V, F,
+ uE, uE2E,
+ num_patches, P,
+ num_cells, per_patch_cells,
+ labels, W);
+}
+
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DeriveduE,
+ typename uE2EType,
+ typename DerivedP,
+ typename DerivedC,
+ typename DerivedL,
+ typename DerivedW>
+IGL_INLINE bool igl::copyleft::cgal::propagate_winding_numbers(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const size_t num_patches,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const size_t num_cells,
+ const Eigen::PlainObjectBase<DerivedC>& C,
+ const Eigen::PlainObjectBase<DerivedL>& labels,
+ Eigen::PlainObjectBase<DerivedW>& W)
+{
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ const auto & tictoc = []() -> double
+ {
+ static double t_start = igl::get_seconds();
+ double diff = igl::get_seconds()-t_start;
+ t_start += diff;
+ return diff;
+ };
+ const auto log_time = [&](const std::string& label) -> void {
+ std::cout << "propagate_winding_num." << label << ": "
+ << tictoc() << std::endl;
+ };
+ tictoc();
+#endif
+
+ bool valid = true;
+ // https://github.com/libigl/libigl/issues/674
+ if (!igl::piecewise_constant_winding_number(F, uE, uE2E))
+ {
+ assert(false && "Input mesh is not PWN");
+ std::cerr << "Input mesh is not PWN!" << std::endl;
+ valid = false;
+ }
+
+ const size_t num_faces = F.rows();
+ typedef std::tuple<typename DerivedC::Scalar, bool, size_t> CellConnection;
+ std::vector<std::set<CellConnection> > cell_adj;
+ igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj);
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ log_time("cell_connectivity");
+#endif
+
+ auto save_cell = [&](const std::string& filename, size_t cell_id) -> void{
+ std::vector<size_t> faces;
+ for (size_t i=0; i<num_patches; i++) {
+ if ((C.row(i).array() == cell_id).any()) {
+ for (size_t j=0; j<num_faces; j++) {
+ if ((size_t)P[j] == i) {
+ faces.push_back(j);
+ }
+ }
+ }
+ }
+ Eigen::MatrixXi cell_faces(faces.size(), 3);
+ for (size_t i=0; i<faces.size(); i++) {
+ cell_faces.row(i) = F.row(faces[i]);
+ }
+ Eigen::MatrixXd vertices;
+ assign(V,vertices);
+ writePLY(filename, vertices, cell_faces);
+ };
+
+#ifndef NDEBUG
+ {
+ // Check for odd cycle.
+ Eigen::VectorXi cell_labels(num_cells);
+ cell_labels.setZero();
+ Eigen::VectorXi parents(num_cells);
+ parents.setConstant(-1);
+ auto trace_parents = [&](size_t idx) -> std::list<size_t> {
+ std::list<size_t> path;
+ path.push_back(idx);
+ while ((size_t)parents[path.back()] != path.back()) {
+ path.push_back(parents[path.back()]);
+ }
+ return path;
+ };
+ for (size_t i=0; i<num_cells; i++) {
+ if (cell_labels[i] == 0) {
+ cell_labels[i] = 1;
+ std::queue<size_t> Q;
+ Q.push(i);
+ parents[i] = i;
+ while (!Q.empty()) {
+ size_t curr_idx = Q.front();
+ Q.pop();
+ int curr_label = cell_labels[curr_idx];
+ for (const auto& neighbor : cell_adj[curr_idx]) {
+ if (cell_labels[std::get<0>(neighbor)] == 0)
+ {
+ cell_labels[std::get<0>(neighbor)] = curr_label * -1;
+ Q.push(std::get<0>(neighbor));
+ parents[std::get<0>(neighbor)] = curr_idx;
+ } else
+ {
+ if (cell_labels[std::get<0>(neighbor)] != curr_label * -1)
+ {
+ std::cerr << "Odd cell cycle detected!" << std::endl;
+ auto path = trace_parents(curr_idx);
+ path.reverse();
+ auto path2 = trace_parents(std::get<0>(neighbor));
+ path.insert(path.end(), path2.begin(), path2.end());
+ for (auto cell_id : path)
+ {
+ std::cout << cell_id << " ";
+ std::stringstream filename;
+ filename << "cell_" << cell_id << ".ply";
+ save_cell(filename.str(), cell_id);
+ }
+ std::cout << std::endl;
+ valid = false;
+ }
+ // Do not fail when odd cycle is detected because the resulting
+ // integer winding number field, although inconsistent, may still
+ // be used if the problem region is local and embedded within a
+ // valid volume.
+ //assert(cell_labels[std::get<0>(neighbor)] == curr_label * -1);
+ }
+ }
+ }
+ }
+ }
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ log_time("odd_cycle_check");
+#endif
+ }
+#endif
+
+ size_t outer_facet;
+ bool flipped;
+ Eigen::VectorXi I = igl::LinSpaced<Eigen::VectorXi>(num_faces, 0, num_faces-1);
+ igl::copyleft::cgal::outer_facet(V, F, I, outer_facet, flipped);
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ log_time("outer_facet");
+#endif
+
+ const size_t outer_patch = P[outer_facet];
+ const size_t infinity_cell = C(outer_patch, flipped?1:0);
+
+ Eigen::VectorXi patch_labels(num_patches);
+ const int INVALID = std::numeric_limits<int>::max();
+ patch_labels.setConstant(INVALID);
+ for (size_t i=0; i<num_faces; i++) {
+ if (patch_labels[P[i]] == INVALID) {
+ patch_labels[P[i]] = labels[i];
+ } else {
+ assert(patch_labels[P[i]] == labels[i]);
+ }
+ }
+ assert((patch_labels.array() != INVALID).all());
+ const size_t num_labels = patch_labels.maxCoeff()+1;
+
+ Eigen::MatrixXi per_cell_W(num_cells, num_labels);
+ per_cell_W.setConstant(INVALID);
+ per_cell_W.row(infinity_cell).setZero();
+ std::queue<size_t> Q;
+ Q.push(infinity_cell);
+ while (!Q.empty()) {
+ size_t curr_cell = Q.front();
+ Q.pop();
+ for (const auto& neighbor : cell_adj[curr_cell]) {
+ size_t neighbor_cell, patch_idx;
+ bool direction;
+ std::tie(neighbor_cell, direction, patch_idx) = neighbor;
+ if ((per_cell_W.row(neighbor_cell).array() == INVALID).any()) {
+ per_cell_W.row(neighbor_cell) = per_cell_W.row(curr_cell);
+ for (size_t i=0; i<num_labels; i++) {
+ int inc = (patch_labels[patch_idx] == (int)i) ?
+ (direction ? -1:1) :0;
+ per_cell_W(neighbor_cell, i) =
+ per_cell_W(curr_cell, i) + inc;
+ }
+ Q.push(neighbor_cell);
+ } else {
+#ifndef NDEBUG
+ // Checking for winding number consistency.
+ // This check would inevitably fail for meshes that contain open
+ // boundary or non-orientable. However, the inconsistent winding number
+ // field would still be useful in some cases such as when problem region
+ // is local and embedded within the volume. This, unfortunately, is the
+ // best we can do because the problem of computing integer winding
+ // number is ill-defined for open and non-orientable surfaces.
+ for (size_t i=0; i<num_labels; i++) {
+ if ((int)i == patch_labels[patch_idx]) {
+ int inc = direction ? -1:1;
+ //assert(per_cell_W(neighbor_cell, i) ==
+ // per_cell_W(curr_cell, i) + inc);
+ } else {
+ //assert(per_cell_W(neighbor_cell, i) ==
+ // per_cell_W(curr_cell, i));
+ }
+ }
+#endif
+ }
+ }
+ }
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ log_time("propagate_winding_number");
+#endif
+
+ W.resize(num_faces, num_labels*2);
+ for (size_t i=0; i<num_faces; i++)
+ {
+ const size_t patch = P[i];
+ const size_t positive_cell = C(patch, 0);
+ const size_t negative_cell = C(patch, 1);
+ for (size_t j=0; j<num_labels; j++) {
+ W(i,j*2 ) = per_cell_W(positive_cell, j);
+ W(i,j*2+1) = per_cell_W(negative_cell, j);
+ }
+ }
+#ifdef PROPAGATE_WINDING_NUMBER_TIMING
+ log_time("store_result");
+#endif
+ return valid;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, unsigned long, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::copyleft::cgal::propagate_winding_numbers<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#ifdef WIN32
+template bool igl::copyleft::cgal::propagate_winding_numbers<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+template bool igl::copyleft::cgal::propagate_winding_numbers<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>, class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 1, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, unsigned __int64, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/propagate_winding_numbers.h b/xs/src/igl/copyleft/cgal/propagate_winding_numbers.h
new file mode 100644
index 000000000..77d8e7666
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/propagate_winding_numbers.h
@@ -0,0 +1,103 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_CGAL_PROPAGATE_WINDING_NUMBERS_H
+#define IGL_COPYLEFT_CGAL_PROPAGATE_WINDING_NUMBERS_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+// The following methods compute the winding number on each side of each facet
+// or patch of a 3D mesh. The input mesh is valid if it splits the ambient
+// space, R^3, into subspaces with constant integer winding numbers. That is
+// the input mesh should be closed and for each directed edge the number of
+// clockwise facing facets should equal the number of counterclockwise facing
+// facets.
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // TODO: This shouldn't need to be in igl::copyleft::cgal, it should
+ // instead take as input an index of the ambient cell and the winding
+ // number vector there.
+ //
+ // Compute winding number on each side of the face. The input mesh
+ // could contain multiple connected components. The input mesh must
+ // represent the boundary of a valid 3D volume, which means it is
+ // closed, consistently oriented and induces integer winding numbers.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions.
+ // F #F by 3 list of triangle indices into V.
+ // labels #F list of facet labels ranging from 0 to k-1.
+ // Output:
+ // W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding
+ // number on the positive side of facet ``i`` with respect to the
+ // facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding
+ // number on the negative side of facet ``i`` with respect to the
+ // facets labeled ``j``.
+ // Returns true iff the input induces a piecewise-constant winding number
+ // field.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedL,
+ typename DerivedW>
+ IGL_INLINE bool propagate_winding_numbers(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedL>& labels,
+ Eigen::PlainObjectBase<DerivedW>& W);
+
+ // Inputs:
+ // V #V by 3 list of vertex positions.
+ // F #F by 3 list of triangle indices into V.
+ // uE #uE by 2 list of vertex_indices, represents undirected edges.
+ // uE2E #uE list of lists that maps uE to E. (a one-to-many map)
+ // num_patches number of patches
+ // P #F list of patch ids.
+ // num_cells number of cells
+ // C #P by 2 list of cell ids on each side of each patch.
+ // labels #F list of facet labels ranging from 0 to k-1.
+ // Output:
+ // W #F by k*2 list of winding numbers. ``W(i,j*2)`` is the winding
+ // number on the positive side of facet ``i`` with respect to the
+ // facets labeled ``j``. Similarly, ``W(i,j*2+1)`` is the winding
+ // number on the negative side of facet ``i`` with respect to the
+ // facets labeled ``j``.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DeriveduE,
+ typename uE2EType,
+ typename DerivedP,
+ typename DerivedC,
+ typename DerivedL,
+ typename DerivedW>
+ IGL_INLINE bool propagate_winding_numbers(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ const size_t num_patches,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const size_t num_cells,
+ const Eigen::PlainObjectBase<DerivedC>& C,
+ const Eigen::PlainObjectBase<DerivedL>& labels,
+ Eigen::PlainObjectBase<DerivedW>& W);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "propagate_winding_numbers.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/read_triangle_mesh.cpp b/xs/src/igl/copyleft/cgal/read_triangle_mesh.cpp
new file mode 100644
index 000000000..24ebbb127
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/read_triangle_mesh.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "read_triangle_mesh.h"
+#include "assign.h"
+#include "../../read_triangle_mesh.h"
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::copyleft::cgal::read_triangle_mesh(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ Eigen::MatrixXd Vd;
+ bool ret = igl::read_triangle_mesh(str,Vd,F);
+ if(ret)
+ {
+ assign(Vd,V);
+ }
+ return ret;
+}
diff --git a/xs/src/igl/copyleft/cgal/read_triangle_mesh.h b/xs/src/igl/copyleft/cgal/read_triangle_mesh.h
new file mode 100644
index 000000000..c1dae2a22
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/read_triangle_mesh.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_READ_TRIANGLE_MESH_H
+#define IGL_COPYLEFT_CGAL_READ_TRIANGLE_MESH_H
+#include "../../igl_inline.h"
+
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Simple wrapper, reads floating point precision but assigns to
+ // DerivedV::Scalar which may be a CGAL type
+ //
+ // Inputs:
+ // str path to file
+ // Outputs:
+ // V eigen double matrix #V by 3
+ // F eigen int matrix #F by 3
+ // Returns true iff success
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool read_triangle_mesh(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "read_triangle_mesh.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.cpp b/xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.cpp
new file mode 100644
index 000000000..993e009ec
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.cpp
@@ -0,0 +1,117 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+
+#include "relabel_small_immersed_cells.h"
+#include "../../centroid.h"
+#include "assign.h"
+#include "cell_adjacency.h"
+
+#include <vector>
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedC,
+ typename FT,
+ typename DerivedW>
+IGL_INLINE void igl::copyleft::cgal::relabel_small_immersed_cells(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const size_t num_patches,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const size_t num_cells,
+ const Eigen::PlainObjectBase<DerivedC>& C,
+ const FT vol_threashold,
+ Eigen::PlainObjectBase<DerivedW>& W)
+{
+ const size_t num_vertices = V.rows();
+ const size_t num_faces = F.rows();
+ typedef std::tuple<typename DerivedC::Scalar, bool, size_t> CellConnection;
+ std::vector<std::set<CellConnection> > cell_adj;
+ igl::copyleft::cgal::cell_adjacency(C, num_cells, cell_adj);
+
+ Eigen::MatrixXd VV;
+ assign(V,VV);
+
+ auto compute_cell_volume = [&](size_t cell_id) {
+ std::vector<short> is_involved(num_patches, 0);
+ for (size_t i=0; i<num_patches; i++) {
+ if (C(i,0) == cell_id) {
+ // cell is on positive side of patch i.
+ is_involved[i] = 1;
+ }
+ if (C(i,1) == cell_id) {
+ // cell is on negative side of patch i.
+ is_involved[i] = -1;
+ }
+ }
+
+ std::vector<size_t> involved_positive_faces;
+ std::vector<size_t> involved_negative_faces;
+ for (size_t i=0; i<num_faces; i++) {
+ switch (is_involved[P[i]]) {
+ case 1:
+ involved_negative_faces.push_back(i);
+ break;
+ case -1:
+ involved_positive_faces.push_back(i);
+ break;
+ }
+ }
+
+ const size_t num_positive_faces = involved_positive_faces.size();
+ const size_t num_negative_faces = involved_negative_faces.size();
+ DerivedF selected_faces(num_positive_faces + num_negative_faces, 3);
+ for (size_t i=0; i<num_positive_faces; i++) {
+ selected_faces.row(i) = F.row(involved_positive_faces[i]);
+ }
+ for (size_t i=0; i<num_negative_faces; i++) {
+ selected_faces.row(num_positive_faces+i) =
+ F.row(involved_negative_faces[i]).reverse();
+ }
+
+ Eigen::VectorXd c(3);
+ double vol;
+ igl::centroid(VV, selected_faces, c, vol);
+ return vol;
+ };
+
+ std::vector<typename DerivedV::Scalar> cell_volumes(num_cells);
+ for (size_t i=0; i<num_cells; i++) {
+ cell_volumes[i] = compute_cell_volume(i);
+ }
+
+ std::vector<typename DerivedW::Scalar> cell_values(num_cells);
+ for (size_t i=0; i<num_faces; i++) {
+ cell_values[C(P[i], 0)] = W(i, 0);
+ cell_values[C(P[i], 1)] = W(i, 1);
+ }
+
+ for (size_t i=1; i<num_cells; i++) {
+ std::cout << cell_volumes[i] << std::endl;
+ if (cell_volumes[i] >= vol_threashold) continue;
+ std::set<typename DerivedW::Scalar> neighbor_values;
+ const auto neighbors = cell_adj[i];
+ for (const auto& entry : neighbors) {
+ const auto& j = std::get<0>(entry);
+ neighbor_values.insert(cell_values[j]);
+ }
+ // If cell i is immersed, assign its value to be the immersed value.
+ if (neighbor_values.size() == 1) {
+ cell_values[i] = *neighbor_values.begin();
+ }
+ }
+
+ for (size_t i=0; i<num_faces; i++) {
+ W(i,0) = cell_values[C(P[i], 0)];
+ W(i,1) = cell_values[C(P[i], 1)];
+ }
+}
+
diff --git a/xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.h b/xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.h
new file mode 100644
index 000000000..a783914a3
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/relabel_small_immersed_cells.h
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_RELABEL_SMALL_IMMERSED_CELLS
+#define IGL_RELABEL_SMALL_IMMERSED_CELLS
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Inputs:
+ // V #V by 3 list of vertex positions.
+ // F #F by 3 list of triangle indices into V.
+ // num_patches number of patches
+ // P #F list of patch ids.
+ // num_cells number of cells
+ // C #P by 2 list of cell ids on each side of each patch.
+ // vol_threshold Volume threshold, cells smaller than this
+ // and is completely immersed will be relabeled.
+ //
+ // In/Output:
+ // W #F by 2 cell labels. W(i,0) is the label on the positive side of
+ // face i, W(i,1) is the label on the negative side of face i. W
+ // will be modified in place by this method.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedC,
+ typename FT,
+ typename DerivedW>
+ IGL_INLINE void relabel_small_immersed_cells(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const size_t num_patches,
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ const size_t num_cells,
+ const Eigen::PlainObjectBase<DerivedC>& C,
+ const FT vol_threashold,
+ Eigen::PlainObjectBase<DerivedW>& W);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "relabel_small_immersed_cells.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/remesh_intersections.cpp b/xs/src/igl/copyleft/cgal/remesh_intersections.cpp
new file mode 100644
index 000000000..56a715c23
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/remesh_intersections.cpp
@@ -0,0 +1,533 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#include "remesh_intersections.h"
+#include "assign_scalar.h"
+#include "projected_cdt.h"
+#include "../../get_seconds.h"
+#include "../../parallel_for.h"
+#include "../../LinSpaced.h"
+#include "../../unique_rows.h"
+
+#include <vector>
+#include <map>
+#include <queue>
+#include <unordered_map>
+#include <iostream>
+
+//#define REMESH_INTERSECTIONS_TIMING
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Kernel,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedJ,
+ typename DerivedIM>
+IGL_INLINE void igl::copyleft::cgal::remesh_intersections(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const std::vector<CGAL::Triangle_3<Kernel> > & T,
+ const std::map<
+ typename DerivedF::Index,
+ std::vector<
+ std::pair<typename DerivedF::Index, CGAL::Object> > > & offending,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM)
+{
+ // by default, no stitching
+ igl::copyleft::cgal::remesh_intersections(V,F,T,offending,false,VV,FF,J,IM);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Kernel,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedJ,
+ typename DerivedIM>
+IGL_INLINE void igl::copyleft::cgal::remesh_intersections(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const std::vector<CGAL::Triangle_3<Kernel> > & T,
+ const std::map<
+ typename DerivedF::Index,
+ std::vector<
+ std::pair<typename DerivedF::Index, CGAL::Object> > > & offending,
+ bool stitch_all,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM)
+{
+
+#ifdef REMESH_INTERSECTIONS_TIMING
+ const auto & tictoc = []() -> double
+ {
+ static double t_start = igl::get_seconds();
+ double diff = igl::get_seconds()-t_start;
+ t_start += diff;
+ return diff;
+ };
+ const auto log_time = [&](const std::string& label) -> void {
+ std::cout << "remesh_intersections." << label << ": "
+ << tictoc() << std::endl;
+ };
+ tictoc();
+#endif
+
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Segment_3<Kernel> Segment_3;
+ typedef CGAL::Plane_3<Kernel> Plane_3;
+ typedef CGAL::Triangulation_vertex_base_2<Kernel> TVB_2;
+ typedef CGAL::Constrained_triangulation_face_base_2<Kernel> CTFB_2;
+ typedef CGAL::Triangulation_data_structure_2<TVB_2,CTFB_2> TDS_2;
+ typedef CGAL::Exact_intersections_tag Itag;
+ typedef CGAL::Constrained_Delaunay_triangulation_2<Kernel,TDS_2,Itag>
+ CDT_2;
+ typedef CGAL::Constrained_triangulation_plus_2<CDT_2> CDT_plus_2;
+
+ typedef typename DerivedF::Index Index;
+ typedef std::pair<Index, Index> Edge;
+ struct EdgeHash {
+ size_t operator()(const Edge& e) const {
+ return (e.first * 805306457) ^ (e.second * 201326611);
+ }
+ };
+ typedef std::unordered_map<Edge, std::vector<Index>, EdgeHash > EdgeMap;
+
+ const size_t num_faces = F.rows();
+ const size_t num_base_vertices = V.rows();
+ assert(num_faces == T.size());
+
+ std::vector<bool> is_offending(num_faces, false);
+ for (const auto itr : offending)
+ {
+ const auto& fid = itr.first;
+ is_offending[fid] = true;
+ }
+
+ // Cluster overlaps so that co-planar clusters are resolved only once
+ std::unordered_map<Index, std::vector<Index> > intersecting_and_coplanar;
+ for (const auto itr : offending)
+ {
+ const auto& fi = itr.first;
+ const auto P = T[fi].supporting_plane();
+ assert(!P.is_degenerate());
+ for (const auto jtr : itr.second)
+ {
+ const auto& fj = jtr.first;
+ const auto& tj = T[fj];
+ if (P.has_on(tj[0]) && P.has_on(tj[1]) && P.has_on(tj[2]))
+ {
+ auto loc = intersecting_and_coplanar.find(fi);
+ if (loc == intersecting_and_coplanar.end())
+ {
+ intersecting_and_coplanar[fi] = {fj};
+ } else
+ {
+ loc->second.push_back(fj);
+ }
+ }
+ }
+ }
+#ifdef REMESH_INTERSECTIONS_TIMING
+ log_time("overlap_analysis");
+#endif
+
+ std::vector<std::vector<Index> > resolved_faces;
+ std::vector<Index> source_faces;
+ std::vector<Point_3> new_vertices;
+ EdgeMap edge_vertices;
+ // face_vertices: Given a face Index, find vertices inside the face
+ std::unordered_map<Index, std::vector<Index>> face_vertices;
+
+ // Run constraint Delaunay triangulation on the plane.
+ //
+ // Inputs:
+ // P plane to triangulate upone
+ // involved_faces #F list of indices into triangle of involved faces
+ // Outputs:
+ // vertices #V list of vertex positions of output triangulation
+ // faces #F list of face indices into vertices of output triangulation
+ //
+ auto delaunay_triangulation = [&offending, &T](
+ const Plane_3& P,
+ const std::vector<Index>& involved_faces,
+ std::vector<Point_3>& vertices,
+ std::vector<std::vector<Index> >& faces) -> void
+ {
+ std::vector<CGAL::Object> objects;
+
+ CDT_plus_2 cdt;
+ // insert each face into a common cdt
+ for (const auto& fid : involved_faces)
+ {
+ const auto itr = offending.find(fid);
+ const auto& triangle = T[fid];
+ objects.push_back(CGAL::make_object(triangle));
+ if (itr == offending.end())
+ {
+ continue;
+ }
+ for (const auto& index_obj : itr->second)
+ {
+ //const auto& ofid = index_obj.first;
+ const auto& obj = index_obj.second;
+ objects.push_back(obj);
+ }
+ }
+ projected_cdt(objects,P,vertices,faces);
+ };
+
+ // Given p on triangle indexed by ori_f, add point to list of vertices return index of p.
+ //
+ // Input:
+ // p point to search for
+ // ori_f index of triangle p is corner of
+ // Returns global index of vertex (dependent on whether stitch_all flag is
+ // set)
+ //
+ auto find_or_append_point = [&](
+ const Point_3& p,
+ const size_t ori_f) -> Index
+ {
+ if (stitch_all)
+ {
+ // No need to check if p shared by multiple triangles because all shared
+ // vertices would be merged later on.
+ const size_t index = num_base_vertices + new_vertices.size();
+ new_vertices.push_back(p);
+ return index;
+ } else
+ {
+ // Stitching triangles according to input connectivity.
+ // This step is potentially costly.
+ const auto& triangle = T[ori_f];
+ const auto& f = F.row(ori_f).eval();
+
+ // Check if p is one of the triangle corners.
+ for (size_t i=0; i<3; i++)
+ {
+ if (p == triangle[i]) return f[i];
+ }
+
+ // Check if p is on one of the edges.
+ for (size_t i=0; i<3; i++) {
+ const Point_3 curr_corner = triangle[i];
+ const Point_3 next_corner = triangle[(i+1)%3];
+ const Segment_3 edge(curr_corner, next_corner);
+ if (edge.has_on(p)) {
+ const Index curr = f[i];
+ const Index next = f[(i+1)%3];
+ Edge key;
+ key.first = curr<next?curr:next;
+ key.second = curr<next?next:curr;
+ auto itr = edge_vertices.find(key);
+ if (itr == edge_vertices.end()) {
+ const Index index =
+ num_base_vertices + new_vertices.size();
+ edge_vertices.insert({key, {index}});
+ new_vertices.push_back(p);
+ return index;
+ } else {
+ for (const auto vid : itr->second) {
+ if (p == new_vertices[vid - num_base_vertices]) {
+ return vid;
+ }
+ }
+ const size_t index = num_base_vertices + new_vertices.size();
+ new_vertices.push_back(p);
+ itr->second.push_back(index);
+ return index;
+ }
+ }
+ }
+
+ // p must be in the middle of the triangle.
+ auto & existing_face_vertices = face_vertices[ori_f];
+ for(const auto vid : existing_face_vertices) {
+ if (p == new_vertices[vid - num_base_vertices]) {
+ return vid;
+ }
+ }
+ const size_t index = num_base_vertices + new_vertices.size();
+ new_vertices.push_back(p);
+ existing_face_vertices.push_back(index);
+ return index;
+ }
+ };
+
+ // Determine the vertex indices for each corner of each output triangle.
+ //
+ // Inputs:
+ // vertices #V list of vertices of cdt
+ // faces #F list of list of face indices into vertices of cdt
+ // involved_faces list of involved faces on the plane of cdt
+ // Side effects:
+ // - add faces to resolved_faces
+ // - add corresponding original face to source_faces
+ // -
+ auto post_triangulation_process = [&](
+ const std::vector<Point_3>& vertices,
+ const std::vector<std::vector<Index> >& faces,
+ const std::vector<Index>& involved_faces) -> void
+ {
+ assert(involved_faces.size() > 0);
+ // for all faces of the cdt
+ for (const auto& f : faces)
+ {
+ const Point_3& v0 = vertices[f[0]];
+ const Point_3& v1 = vertices[f[1]];
+ const Point_3& v2 = vertices[f[2]];
+ Point_3 center(
+ (v0[0] + v1[0] + v2[0]) / 3.0,
+ (v0[1] + v1[1] + v2[1]) / 3.0,
+ (v0[2] + v1[2] + v2[2]) / 3.0);
+ if (involved_faces.size() == 1)
+ {
+ // If only there is only one involved face, all sub-triangles must
+ // belong to it and have the correct orientation.
+ const auto& ori_f = involved_faces[0];
+ std::vector<Index> corners(3);
+ corners[0] = find_or_append_point(v0, ori_f);
+ corners[1] = find_or_append_point(v1, ori_f);
+ corners[2] = find_or_append_point(v2, ori_f);
+ resolved_faces.emplace_back(corners);
+ source_faces.push_back(ori_f);
+ } else
+ {
+ for (const auto& ori_f : involved_faces)
+ {
+ const auto& triangle = T[ori_f];
+ const Plane_3 P = triangle.supporting_plane();
+ if (triangle.has_on(center)) {
+ std::vector<Index> corners(3);
+ corners[0] = find_or_append_point(v0, ori_f);
+ corners[1] = find_or_append_point(v1, ori_f);
+ corners[2] = find_or_append_point(v2, ori_f);
+ if (CGAL::orientation(
+ P.to_2d(v0), P.to_2d(v1), P.to_2d(v2))
+ == CGAL::RIGHT_TURN) {
+ std::swap(corners[0], corners[1]);
+ }
+ resolved_faces.emplace_back(corners);
+ source_faces.push_back(ori_f);
+ }
+ }
+ }
+ }
+ };
+
+ // Process un-touched faces.
+ for (size_t i=0; i<num_faces; i++)
+ {
+ if (!is_offending[i] && !T[i].is_degenerate())
+ {
+ resolved_faces.push_back( { F(i,0), F(i,1), F(i,2) } );
+ source_faces.push_back(i);
+ }
+ }
+
+ // Process self-intersecting faces.
+ std::vector<bool> processed(num_faces, false);
+ std::vector<std::pair<Plane_3, std::vector<Index> > > cdt_inputs;
+ for (const auto itr : offending)
+ {
+ const auto fid = itr.first;
+ if (processed[fid]) continue;
+ processed[fid] = true;
+
+ const auto loc = intersecting_and_coplanar.find(fid);
+ std::vector<Index> involved_faces;
+ if (loc == intersecting_and_coplanar.end())
+ {
+ involved_faces.push_back(fid);
+ } else
+ {
+ std::queue<Index> Q;
+ Q.push(fid);
+ while (!Q.empty())
+ {
+ const auto index = Q.front();
+ involved_faces.push_back(index);
+ Q.pop();
+
+ const auto overlapping_faces = intersecting_and_coplanar.find(index);
+ assert(overlapping_faces != intersecting_and_coplanar.end());
+
+ for (const auto other_index : overlapping_faces->second)
+ {
+ if (processed[other_index]) continue;
+ processed[other_index] = true;
+ Q.push(other_index);
+ }
+ }
+ }
+
+ Plane_3 P = T[fid].supporting_plane();
+ cdt_inputs.emplace_back(P, involved_faces);
+ }
+#ifdef REMESH_INTERSECTIONS_TIMING
+ log_time("preprocess");
+#endif
+
+ const size_t num_cdts = cdt_inputs.size();
+ std::vector<std::vector<Point_3> > cdt_vertices(num_cdts);
+ std::vector<std::vector<std::vector<Index> > > cdt_faces(num_cdts);
+
+ //// Not clear whether this is safe because of reference counting on Point_3
+ //// objects...
+ ////
+ //// I tried it and got random segfaults (via MATLAB). Seems this is not
+ //// safe.
+ //igl::parallel_for(num_cdts,[&](int i)
+ for (size_t i=0; i<num_cdts; i++)
+ {
+ auto& vertices = cdt_vertices[i];
+ auto& faces = cdt_faces[i];
+ const auto& P = cdt_inputs[i].first;
+ const auto& involved_faces = cdt_inputs[i].second;
+ delaunay_triangulation(P, involved_faces, vertices, faces);
+ }
+ //,1000);
+#ifdef REMESH_INTERSECTIONS_TIMING
+ log_time("cdt");
+#endif
+
+ for (size_t i=0; i<num_cdts; i++)
+ {
+ const auto& vertices = cdt_vertices[i];
+ const auto& faces = cdt_faces[i];
+ const auto& involved_faces = cdt_inputs[i].second;
+ post_triangulation_process(vertices, faces, involved_faces);
+ }
+#ifdef REMESH_INTERSECTIONS_TIMING
+ log_time("stitching");
+#endif
+
+ // Output resolved mesh.
+ const size_t num_out_vertices = new_vertices.size() + num_base_vertices;
+ VV.resize(num_out_vertices, 3);
+ for (size_t i=0; i<num_base_vertices; i++)
+ {
+ assign_scalar(V(i,0), VV(i,0));
+ assign_scalar(V(i,1), VV(i,1));
+ assign_scalar(V(i,2), VV(i,2));
+ }
+
+ for (size_t i=num_base_vertices; i<num_out_vertices; i++)
+ {
+ assign_scalar(new_vertices[i-num_base_vertices][0], VV(i,0));
+ assign_scalar(new_vertices[i-num_base_vertices][1], VV(i,1));
+ assign_scalar(new_vertices[i-num_base_vertices][2], VV(i,2));
+ }
+
+ const size_t num_out_faces = resolved_faces.size();
+ FF.resize(num_out_faces, 3);
+ for (size_t i=0; i<num_out_faces; i++)
+ {
+ FF(i,0) = resolved_faces[i][0];
+ FF(i,1) = resolved_faces[i][1];
+ FF(i,2) = resolved_faces[i][2];
+ }
+
+ J.resize(num_out_faces);
+ std::copy(source_faces.begin(), source_faces.end(), J.data());
+
+ // Extract unique vertex indices.
+ const size_t VV_size = VV.rows();
+ IM.resize(VV_size,1);
+
+ DerivedVV unique_vv;
+ Eigen::VectorXi unique_to_vv, vv_to_unique;
+ // This is not stable... So even if offending is empty V != VV in
+ // general...
+ igl::unique_rows(VV, unique_vv, unique_to_vv, vv_to_unique);
+ if(stitch_all)
+ {
+ // Merge all vertices having the same coordinates into a single vertex
+ // and set IM to identity map.
+ VV = unique_vv;
+ std::transform(FF.data(), FF.data() + FF.rows()*FF.cols(),
+ FF.data(), [&vv_to_unique](const typename DerivedFF::Scalar& a)
+ { return vv_to_unique[a]; });
+ IM.resize(unique_vv.rows());
+ // Have to use << instead of = because Eigen's PlainObjectBase is annoying
+ IM << igl::LinSpaced<
+ Eigen::Matrix<typename DerivedIM::Scalar, Eigen::Dynamic,1 >
+ >(unique_vv.rows(), 0, unique_vv.rows()-1);
+ }else
+ {
+ // Vertices with the same coordinates would be represented by one vertex.
+ // The IM value of a vertex is the index of the representative vertex.
+ for (Index v=0; v<(Index)VV_size; v++) {
+ IM(v) = unique_to_vv[vv_to_unique[v]];
+ }
+ }
+
+#ifdef REMESH_INTERSECTIONS_TIMING
+ log_time("store_results");
+#endif
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epick, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epick>, std::allocator<CGAL::Triangle_3<CGAL::Epick> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, CGAL::Epeck, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<CGAL::Triangle_3<CGAL::Epeck>, std::allocator<CGAL::Triangle_3<CGAL::Epeck> > > const&, std::map<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > >, std::less<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index const, std::vector<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object>, std::allocator<std::pair<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, CGAL::Object> > > > > > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::remesh_intersections<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class CGAL::Epeck, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::map<__int64, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>, struct std::less<__int64>, class std::allocator<struct std::pair<__int64 const, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>>>> const &, bool, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::remesh_intersections<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class CGAL::Epick, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epick>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epick>>> const &, class std::map<__int64, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>, struct std::less<__int64>, class std::allocator<struct std::pair<__int64 const, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>>>> const &, bool, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::remesh_intersections<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class CGAL::Epeck, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epeck>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epeck>>> const &, class std::map<__int64, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>, struct std::less<__int64>, class std::allocator<struct std::pair<__int64 const, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>>>> const &, bool, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::remesh_intersections<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class CGAL::Epick, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class CGAL::Triangle_3<class CGAL::Epick>, class std::allocator<class CGAL::Triangle_3<class CGAL::Epick>>> const &, class std::map<__int64, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>, struct std::less<__int64>, class std::allocator<struct std::pair<__int64 const, class std::vector<struct std::pair<__int64, class CGAL::Object>, class std::allocator<struct std::pair<__int64, class CGAL::Object>>>>>> const &, bool, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/remesh_intersections.h b/xs/src/igl/copyleft/cgal/remesh_intersections.h
new file mode 100644
index 000000000..2b6a44a57
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/remesh_intersections.h
@@ -0,0 +1,94 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_CGAL_REMESH_INTERSECTIONS_H
+#define IGL_COPYLEFT_CGAL_REMESH_INTERSECTIONS_H
+
+#include "../../igl_inline.h"
+#include <Eigen/Dense>
+#include "CGAL_includes.hpp"
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Remesh faces according to results of intersection detection and
+ // construction (e.g. from `igl::copyleft::cgal::intersect_other` or
+ // `igl::copyleft::cgal::SelfIntersectMesh`)
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // T #F list of cgal triangles
+ // offending #offending map taking face indices into F to pairs of order
+ // of first finding and list of intersection objects from all
+ // intersections
+ // stitch_all if true, merge all vertices with the same coordinate.
+ // Outputs:
+ // VV #VV by 3 list of vertex positions, if stitch_all = false then
+ // first #V vertices will always be V
+ // FF #FF by 3 list of triangle indices into V
+ // IF #intersecting face pairs by 2 list of intersecting face pairs,
+ // indexing F
+ // J #FF list of indices into F denoting birth triangle
+ // IM / stitch_all = true #VV list from 0 to #VV-1
+ // \ stitch_all = false #VV list of indices into VV of unique vertices.
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Kernel,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedJ,
+ typename DerivedIM>
+ IGL_INLINE void remesh_intersections(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const std::vector<CGAL::Triangle_3<Kernel> > & T,
+ const std::map<
+ typename DerivedF::Index,
+ std::vector<
+ std::pair<typename DerivedF::Index, CGAL::Object> > > & offending,
+ bool stitch_all,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM);
+ // Same as above except stitch_all is assumed "false"
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Kernel,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedJ,
+ typename DerivedIM>
+ IGL_INLINE void remesh_intersections(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const std::vector<CGAL::Triangle_3<Kernel> > & T,
+ const std::map<
+ typename DerivedF::Index,
+ std::vector<
+ std::pair<typename DerivedF::Index, CGAL::Object> > > & offending,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "remesh_intersections.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/remesh_self_intersections.cpp b/xs/src/igl/copyleft/cgal/remesh_self_intersections.cpp
new file mode 100644
index 000000000..871152b30
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/remesh_self_intersections.cpp
@@ -0,0 +1,108 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "remesh_self_intersections.h"
+#include "SelfIntersectMesh.h"
+#include "../../C_STR.h"
+#include <list>
+#include <iostream>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+IGL_INLINE void igl::copyleft::cgal::remesh_self_intersections(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const RemeshSelfIntersectionsParam & params,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedIF> & IF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM)
+{
+ using namespace std;
+ if(params.detect_only)
+ {
+ //// This is probably a terrible idea, but CGAL is throwing floating point
+ //// exceptions.
+
+//#ifdef __APPLE__
+//#define IGL_THROW_FPE 11
+// const auto & throw_fpe = [](int e)
+// {
+// throw "IGL_THROW_FPE";
+// };
+// signal(SIGFPE,throw_fpe);
+//#endif
+
+ typedef CGAL::Exact_predicates_inexact_constructions_kernel Kernel;
+ typedef
+ SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>
+ SelfIntersectMeshK;
+ SelfIntersectMeshK SIM(V,F,params,VV,FF,IF,J,IM);
+
+//#ifdef __APPLE__
+// signal(SIGFPE,SIG_DFL);
+//#endif
+
+ }else
+ {
+ typedef CGAL::Exact_predicates_exact_constructions_kernel Kernel;
+ typedef
+ SelfIntersectMesh<
+ Kernel,
+ DerivedV,
+ DerivedF,
+ DerivedVV,
+ DerivedFF,
+ DerivedIF,
+ DerivedJ,
+ DerivedIM>
+ SelfIntersectMeshK;
+ SelfIntersectMeshK SIM(V,F,params,VV,FF,IF,J,IM);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::cgal::remesh_self_intersections<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::cgal::RemeshSelfIntersectionsParam const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::copyleft::cgal::remesh_self_intersections<class Eigen::Matrix<double, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<double, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, struct igl::copyleft::cgal::RemeshSelfIntersectionsParam const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template void igl::copyleft::cgal::remesh_self_intersections<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, 3, 0, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, struct igl::copyleft::cgal::RemeshSelfIntersectionsParam const &, class Eigen::PlainObjectBase<class Eigen::Matrix<class CGAL::Lazy_exact_nt<class CGAL::Gmpq>, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/remesh_self_intersections.h b/xs/src/igl/copyleft/cgal/remesh_self_intersections.h
new file mode 100644
index 000000000..e8e8cc492
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/remesh_self_intersections.h
@@ -0,0 +1,81 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_H
+#define IGL_COPYLEFT_CGAL_REMESH_SELF_INTERSECTIONS_H
+#include "../../igl_inline.h"
+#include "RemeshSelfIntersectionsParam.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given a triangle mesh (V,F) compute a new mesh (VV,FF) which is the same
+ // as (V,F) except that any self-intersecting triangles in (V,F) have been
+ // subdivided (new vertices and face created) so that the self-intersection
+ // contour lies exactly on edges in (VV,FF). New vertices will appear in
+ // original faces or on original edges. New vertices on edges are "merged"
+ // only across original faces sharing that edge. This means that if the input
+ // triangle mesh is a closed manifold the output will be too.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // params struct of optional parameters
+ // Outputs:
+ // VV #VV by 3 list of vertex positions
+ // FF #FF by 3 list of triangle indices into VV
+ // IF #intersecting face pairs by 2 list of intersecting face pairs,
+ // indexing F
+ // J #FF list of indices into F denoting birth triangle
+ // IM #VV list of indices into VV of unique vertices.
+ //
+ // Known bugs: If an existing edge in (V,F) lies exactly on another face then
+ // any resulting additional vertices along that edge may not get properly
+ // connected so that the output mesh has the same global topology. This is
+ // because
+ //
+ // Example:
+ // // resolve intersections
+ // igl::copyleft::cgal::remesh_self_intersections(V,F,params,VV,FF,IF,J,IM);
+ // // _apply_ duplicate vertex mapping IM to FF
+ // for_each(FF.data(),FF.data()+FF.size(),[&IM](int & a){a=IM(a);});
+ // // remove any vertices now unreferenced after duplicate mapping.
+ // igl::remove_unreferenced(VV,FF,SV,SF,UIM);
+ // // Now (SV,SF) is ready to extract outer hull
+ // igl::copyleft::cgal::outer_hull(SV,SF,G,J,flip);
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVV,
+ typename DerivedFF,
+ typename DerivedIF,
+ typename DerivedJ,
+ typename DerivedIM>
+ IGL_INLINE void remesh_self_intersections(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const RemeshSelfIntersectionsParam & params,
+ Eigen::PlainObjectBase<DerivedVV> & VV,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedIF> & IF,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "remesh_self_intersections.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/remove_unreferenced.cpp b/xs/src/igl/copyleft/cgal/remove_unreferenced.cpp
new file mode 100644
index 000000000..03c8864cb
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/remove_unreferenced.cpp
@@ -0,0 +1,20 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "../../remove_unreferenced.h"
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#ifdef IGL_STATIC_LIBRARY
+#undef IGL_STATIC_LIBRARY
+#include "../../remove_unreferenced.cpp"
+template void igl::remove_unreferenced<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/resolve_intersections.cpp b/xs/src/igl/copyleft/cgal/resolve_intersections.cpp
new file mode 100644
index 000000000..2252d87e1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/resolve_intersections.cpp
@@ -0,0 +1,90 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "resolve_intersections.h"
+#include "subdivide_segments.h"
+#include "row_to_point.h"
+#include "../../unique.h"
+#include "../../list_to_matrix.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Segment_2.h>
+#include <CGAL/Point_2.h>
+#include <algorithm>
+#include <vector>
+
+template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedVI,
+ typename DerivedEI,
+ typename DerivedJ,
+ typename DerivedIM>
+IGL_INLINE void igl::copyleft::cgal::resolve_intersections(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedVI> & VI,
+ Eigen::PlainObjectBase<DerivedEI> & EI,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM)
+{
+ using namespace Eigen;
+ using namespace igl;
+ using namespace std;
+ // Exact scalar type
+ typedef CGAL::Epeck K;
+ typedef K::FT EScalar;
+ typedef CGAL::Segment_2<K> Segment_2;
+ typedef CGAL::Point_2<K> Point_2;
+ typedef Matrix<EScalar,Dynamic,Dynamic> MatrixXE;
+
+ // Convert vertex positions to exact kernel
+ MatrixXE VE(V.rows(),V.cols());
+ for(int i = 0;i<V.rows();i++)
+ {
+ for(int j = 0;j<V.cols();j++)
+ {
+ VE(i,j) = V(i,j);
+ }
+ }
+
+ const int m = E.rows();
+ // resolve all intersections: silly O(n²) implementation
+ std::vector<std::vector<Point_2> > steiner(m);
+ for(int i = 0;i<m;i++)
+ {
+ Segment_2 si(row_to_point<K>(VE,E(i,0)),row_to_point<K>(VE,E(i,1)));
+ steiner[i].push_back(si.vertex(0));
+ steiner[i].push_back(si.vertex(1));
+ for(int j = i+1;j<m;j++)
+ {
+ Segment_2 sj(row_to_point<K>(VE,E(j,0)),row_to_point<K>(VE,E(j,1)));
+ // do they intersect?
+ if(CGAL::do_intersect(si,sj))
+ {
+ CGAL::Object result = CGAL::intersection(si,sj);
+ if(const Point_2 * p = CGAL::object_cast<Point_2 >(&result))
+ {
+ steiner[i].push_back(*p);
+ steiner[j].push_back(*p);
+ // add intersection point
+ }else if(const Segment_2 * s = CGAL::object_cast<Segment_2 >(&result))
+ {
+ // add both endpoints
+ steiner[i].push_back(s->vertex(0));
+ steiner[j].push_back(s->vertex(0));
+ steiner[i].push_back(s->vertex(1));
+ steiner[j].push_back(s->vertex(1));
+ }else
+ {
+ assert(false && "Unknown intersection type");
+ }
+ }
+ }
+ }
+
+ subdivide_segments(V,E,steiner,VI,EI,J,IM);
+}
diff --git a/xs/src/igl/copyleft/cgal/resolve_intersections.h b/xs/src/igl/copyleft/cgal/resolve_intersections.h
new file mode 100644
index 000000000..086ef1361
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/resolve_intersections.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_RESOLVE_INTERSECTIONS_H
+#define IGL_COPYLEFT_CGAL_RESOLVE_INTERSECTIONS_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ // RESOLVE_INTERSECTIONS Given a list of possible intersecting segments with
+ // endpoints, split segments to overlap only at endpoints
+ //
+ // Inputs:
+ // V #V by 2 list of vertex positions
+ // E #E by 2 list of segment indices into V
+ // Outputs:
+ // VI #VI by 2 list of output vertex positions, copies of V are always
+ // the first #V vertices
+ // EI #EI by 2 list of segment indices into V, #EI ≥ #E
+ // J #EI list of indices into E revealing "parent segments"
+ // IM #VI list of indices into VV of unique vertices.
+ namespace cgal
+ {
+ template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedVI,
+ typename DerivedEI,
+ typename DerivedJ,
+ typename DerivedIM>
+ IGL_INLINE void resolve_intersections(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedVI> & VI,
+ Eigen::PlainObjectBase<DerivedEI> & EI,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "resolve_intersections.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/row_to_point.cpp b/xs/src/igl/copyleft/cgal/row_to_point.cpp
new file mode 100644
index 000000000..97a4b991e
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/row_to_point.cpp
@@ -0,0 +1,18 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "row_to_point.h"
+
+template <
+ typename Kernel,
+ typename DerivedV>
+IGL_INLINE CGAL::Point_2<Kernel> igl::copyleft::cgal::row_to_point(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const typename DerivedV::Index & i)
+{
+ return CGAL::Point_2<Kernel>(V(i,0),V(i,1));
+}
diff --git a/xs/src/igl/copyleft/cgal/row_to_point.h b/xs/src/igl/copyleft/cgal/row_to_point.h
new file mode 100644
index 000000000..54e27ad4f
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/row_to_point.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_ROW_TO_POINT_H
+#define IGL_COPYLEFT_CGAL_ROW_TO_POINT_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <CGAL/Point_2.h>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Extract a row from V and treat as a 2D cgal point (only first two
+ // columns of V are used).
+ //
+ // Inputs:
+ // V #V by 2 list of vertex positions
+ // i row index
+ // Returns 2D cgal point
+ template <
+ typename Kernel,
+ typename DerivedV>
+ IGL_INLINE CGAL::Point_2<Kernel> row_to_point(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const typename DerivedV::Index & i);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "row_to_point.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/segment_segment_squared_distance.cpp b/xs/src/igl/copyleft/cgal/segment_segment_squared_distance.cpp
new file mode 100644
index 000000000..1ca695995
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/segment_segment_squared_distance.cpp
@@ -0,0 +1,129 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "segment_segment_squared_distance.h"
+#include <CGAL/Vector_3.h>
+
+// http://geomalgorithms.com/a07-_distance.html
+template < typename Kernel>
+IGL_INLINE bool igl::copyleft::cgal::segment_segment_squared_distance(
+ const CGAL::Segment_3<Kernel> & S1,
+ const CGAL::Segment_3<Kernel> & S2,
+ CGAL::Point_3<Kernel> & P1,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & dst)
+{
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Vector_3<Kernel> Vector_3;
+ typedef typename Kernel::FT EScalar;
+ if(S1.is_degenerate())
+ {
+ // All points on S1 are the same
+ P1 = S1.source();
+ point_segment_squared_distance(P1,S2,P2,dst);
+ return true;
+ }else if(S2.is_degenerate())
+ {
+ assert(!S1.is_degenerate());
+ // All points on S2 are the same
+ P2 = S2.source();
+ point_segment_squared_distance(P2,S1,P1,dst);
+ return true;
+ }
+
+ assert(!S1.is_degenerate());
+ assert(!S2.is_degenerate());
+
+ Vector_3 u = S1.target() - S1.source();
+ Vector_3 v = S2.target() - S2.source();
+ Vector_3 w = S1.source() - S2.source();
+
+ const auto a = u.dot(u); // always >= 0
+ const auto b = u.dot(v);
+ const auto c = v.dot(v); // always >= 0
+ const auto d = u.dot(w);
+ const auto e = v.dot(w);
+ const auto D = a*c - b*b; // always >= 0
+ assert(D>=0);
+ const auto sc=D, sN=D, sD = D; // sc = sN / sD, default sD = D >= 0
+ const auto tc=D, tN=D, tD = D; // tc = tN / tD, default tD = D >= 0
+
+ bool parallel = false;
+ // compute the line parameters of the two closest points
+ if (D==0)
+ {
+ // the lines are almost parallel
+ parallel = true;
+ sN = 0.0; // force using source point on segment S1
+ sD = 1.0; // to prevent possible division by 0.0 later
+ tN = e;
+ tD = c;
+ } else
+ {
+ // get the closest points on the infinite lines
+ sN = (b*e - c*d);
+ tN = (a*e - b*d);
+ if (sN < 0.0)
+ {
+ // sc < 0 => the s=0 edge is visible
+ sN = 0.0;
+ tN = e;
+ tD = c;
+ } else if (sN > sD)
+ { // sc > 1 => the s=1 edge is visible
+ sN = sD;
+ tN = e + b;
+ tD = c;
+ }
+ }
+
+ if (tN < 0.0)
+ {
+ // tc < 0 => the t=0 edge is visible
+ tN = 0.0;
+ // recompute sc for this edge
+ if (-d < 0.0)
+ {
+ sN = 0.0;
+ }else if (-d > a)
+ {
+ sN = sD;
+ }else
+ {
+ sN = -d;
+ sD = a;
+ }
+ }else if (tN > tD)
+ {
+ // tc > 1 => the t=1 edge is visible
+ tN = tD;
+ // recompute sc for this edge
+ if ((-d + b) < 0.0)
+ {
+ sN = 0;
+ }else if ((-d + b) > a)
+ {
+ sN = sD;
+ }else
+ {
+ sN = (-d + b);
+ sD = a;
+ }
+ }
+ // finally do the division to get sc and tc
+ sc = (abs(sN) == 0 ? 0.0 : sN / sD);
+ tc = (abs(tN) == 0 ? 0.0 : tN / tD);
+
+ // get the difference of the two closest points
+ P1 = S1.source() + sc*(S1.target()-S1.source());
+ P2 = S2.source() + sc*(S2.target()-S2.source());
+ Vector_3 dP = w + (sc * u) - (tc * v); // = S1(sc) - S2(tc)
+ assert(dP == (P1-P2));
+
+ dst = dP.squared_length(); // return the closest distance
+ return parallel;
+}
diff --git a/xs/src/igl/copyleft/cgal/segment_segment_squared_distance.h b/xs/src/igl/copyleft/cgal/segment_segment_squared_distance.h
new file mode 100644
index 000000000..5bfbfdcab
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/segment_segment_squared_distance.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_SEGMENT_SEGMENT_SQUARED_DISTANCE_H
+#define IGL_COPYLEFT_CGAL_SEGMENT_SEGMENT_SQUARED_DISTANCE_H
+#include "../../igl_inline.h"
+#include <CGAL/Segment_3.h>
+#include <CGAL/Point_3.h>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given two segments S1 and S2 find the points on each of closest
+ // approach and the squared distance thereof.
+ //
+ // Inputs:
+ // S1 first segment
+ // S2 second segment
+ // Outputs:
+ // P1 point on S1 closest to S2
+ // P2 point on S2 closest to S1
+ // d distance betwee P1 and S2
+ // Returns true if the closest approach is unique.
+ template < typename Kernel>
+ IGL_INLINE bool segment_segment_squared_distance(
+ const CGAL::Segment_3<Kernel> & S1,
+ const CGAL::Segment_3<Kernel> & S2,
+ CGAL::Point_3<Kernel> & P1,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & d
+ );
+
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "segment_segment_squared_distance.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/signed_distance_isosurface.cpp b/xs/src/igl/copyleft/cgal/signed_distance_isosurface.cpp
new file mode 100644
index 000000000..eeb6c03c5
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/signed_distance_isosurface.cpp
@@ -0,0 +1,138 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "signed_distance_isosurface.h"
+#include "point_mesh_squared_distance.h"
+#include "complex_to_mesh.h"
+
+#include "../../AABB.h"
+#include "../../per_face_normals.h"
+#include "../../per_edge_normals.h"
+#include "../../per_vertex_normals.h"
+#include "../../centroid.h"
+#include "../../WindingNumberAABB.h"
+
+#include <CGAL/Surface_mesh_default_triangulation_3.h>
+#include <CGAL/Complex_2_in_triangulation_3.h>
+#include <CGAL/make_surface_mesh.h>
+#include <CGAL/Implicit_surface_3.h>
+#include <CGAL/IO/output_surface_facets_to_polyhedron.h>
+// Axis-aligned bounding box tree for tet tri intersection
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+#include <vector>
+
+IGL_INLINE bool igl::copyleft::cgal::signed_distance_isosurface(
+ const Eigen::MatrixXd & IV,
+ const Eigen::MatrixXi & IF,
+ const double level,
+ const double angle_bound,
+ const double radius_bound,
+ const double distance_bound,
+ const SignedDistanceType sign_type,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // default triangulation for Surface_mesher
+ typedef CGAL::Surface_mesh_default_triangulation_3 Tr;
+ // c2t3
+ typedef CGAL::Complex_2_in_triangulation_3<Tr> C2t3;
+ typedef Tr::Geom_traits GT;//Kernel
+ typedef GT::Sphere_3 Sphere_3;
+ typedef GT::Point_3 Point_3;
+ typedef GT::FT FT;
+ typedef std::function<FT (Point_3)> Function;
+ typedef CGAL::Implicit_surface_3<GT, Function> Surface_3;
+
+ AABB<Eigen::MatrixXd,3> tree;
+ tree.init(IV,IF);
+
+ Eigen::MatrixXd FN,VN,EN;
+ Eigen::MatrixXi E;
+ Eigen::VectorXi EMAP;
+ WindingNumberAABB< Eigen::Vector3d, Eigen::MatrixXd, Eigen::MatrixXi > hier;
+ switch(sign_type)
+ {
+ default:
+ assert(false && "Unknown SignedDistanceType");
+ case SIGNED_DISTANCE_TYPE_UNSIGNED:
+ // do nothing
+ break;
+ case SIGNED_DISTANCE_TYPE_DEFAULT:
+ case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
+ hier.set_mesh(IV,IF);
+ hier.grow();
+ break;
+ case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
+ // "Signed Distance Computation Using the Angle Weighted Pseudonormal"
+ // [Bærentzen & Aanæs 2005]
+ per_face_normals(IV,IF,FN);
+ per_vertex_normals(IV,IF,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
+ per_edge_normals(
+ IV,IF,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP);
+ break;
+ }
+
+ Tr tr; // 3D-Delaunay triangulation
+ C2t3 c2t3 (tr); // 2D-complex in 3D-Delaunay triangulation
+ // defining the surface
+ const auto & IVmax = IV.colwise().maxCoeff();
+ const auto & IVmin = IV.colwise().minCoeff();
+ const double bbd = (IVmax-IVmin).norm();
+ const double r = bbd/2.;
+ const auto & IVmid = 0.5*(IVmax + IVmin);
+ // Supposedly the implict needs to evaluate to <0 at cmid...
+ // http://doc.cgal.org/latest/Surface_mesher/classCGAL_1_1Implicit__surface__3.html
+ Point_3 cmid(IVmid(0),IVmid(1),IVmid(2));
+ Function fun;
+ switch(sign_type)
+ {
+ default:
+ assert(false && "Unknown SignedDistanceType");
+ case SIGNED_DISTANCE_TYPE_UNSIGNED:
+ fun =
+ [&tree,&IV,&IF,&level](const Point_3 & q) -> FT
+ {
+ int i;
+ RowVector3d c;
+ const double sd = tree.squared_distance(
+ IV,IF,RowVector3d(q.x(),q.y(),q.z()),i,c);
+ return sd-level;
+ };
+ case SIGNED_DISTANCE_TYPE_DEFAULT:
+ case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
+ fun =
+ [&tree,&IV,&IF,&hier,&level](const Point_3 & q) -> FT
+ {
+ const double sd = signed_distance_winding_number(
+ tree,IV,IF,hier,Vector3d(q.x(),q.y(),q.z()));
+ return sd-level;
+ };
+ break;
+ case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
+ fun = [&tree,&IV,&IF,&FN,&VN,&EN,&EMAP,&level](const Point_3 & q) -> FT
+ {
+ const double sd =
+ igl::signed_distance_pseudonormal(
+ tree,IV,IF,FN,VN,EN,EMAP,RowVector3d(q.x(),q.y(),q.z()));
+ return sd- level;
+ };
+ break;
+ }
+ Sphere_3 bounding_sphere(cmid, (r+level)*(r+level));
+ Surface_3 surface(fun,bounding_sphere);
+ CGAL::Surface_mesh_default_criteria_3<Tr>
+ criteria(angle_bound,radius_bound,distance_bound);
+ // meshing surface
+ CGAL::make_surface_mesh(c2t3, surface, criteria, CGAL::Manifold_tag());
+ // complex to (V,F)
+ return igl::copyleft::cgal::complex_to_mesh(c2t3,V,F);
+}
diff --git a/xs/src/igl/copyleft/cgal/signed_distance_isosurface.h b/xs/src/igl/copyleft/cgal/signed_distance_isosurface.h
new file mode 100644
index 000000000..149ea5e3d
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/signed_distance_isosurface.h
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_SIGNED_DISTANCE_ISOSURFACE_H
+#define IGL_COPYLEFT_CGAL_SIGNED_DISTANCE_ISOSURFACE_H
+#include "../../igl_inline.h"
+#include "../../signed_distance.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // SIGNED_DISTANCE_ISOSURFACE Compute the contour of an iso-level of the
+ // signed distance field to a given mesh.
+ //
+ // Inputs:
+ // IV #IV by 3 list of input mesh vertex positions
+ // IF #IF by 3 list of input triangle indices
+ // level iso-level to contour in world coords, negative is inside.
+ // angle_bound lower bound on triangle angles (mesh quality) (e.g. 28)
+ // radius_bound upper bound on triangle size (mesh density?) (e.g. 0.02)
+ // distance_bound cgal mysterious parameter (mesh density?) (e.g. 0.01)
+ // sign_type method for computing distance _sign_ (see
+ // ../signed_distance.h)
+ // Outputs:
+ // V #V by 3 list of input mesh vertex positions
+ // F #F by 3 list of input triangle indices
+ //
+ IGL_INLINE bool signed_distance_isosurface(
+ const Eigen::MatrixXd & IV,
+ const Eigen::MatrixXi & IF,
+ const double level,
+ const double angle_bound,
+ const double radius_bound,
+ const double distance_bound,
+ const SignedDistanceType sign_type,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "signed_distance_isosurface.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/slice.cpp b/xs/src/igl/copyleft/cgal/slice.cpp
new file mode 100644
index 000000000..2e274a2f2
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/slice.cpp
@@ -0,0 +1,12 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "../../slice.h"
+#ifdef IGL_STATIC_LIBRARY
+#undef IGL_STATIC_LIBRARY
+#include "../../slice.cpp"
+#endif
diff --git a/xs/src/igl/copyleft/cgal/slice_mask.cpp b/xs/src/igl/copyleft/cgal/slice_mask.cpp
new file mode 100644
index 000000000..ec920e0d1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/slice_mask.cpp
@@ -0,0 +1,15 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "../../slice_mask.h"
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#ifdef IGL_STATIC_LIBRARY
+#undef IGL_STATIC_LIBRARY
+#include "../../slice_mask.cpp"
+template void igl::slice_mask<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/snap_rounding.cpp b/xs/src/igl/copyleft/cgal/snap_rounding.cpp
new file mode 100644
index 000000000..ccebfd1b8
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/snap_rounding.cpp
@@ -0,0 +1,206 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "snap_rounding.h"
+#include "resolve_intersections.h"
+#include "subdivide_segments.h"
+#include "../../remove_unreferenced.h"
+#include "../../unique.h"
+#include <CGAL/Segment_2.h>
+#include <CGAL/Point_2.h>
+#include <CGAL/Vector_2.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <algorithm>
+
+template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedVI,
+ typename DerivedEI,
+ typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::snap_rounding(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedVI> & VI,
+ Eigen::PlainObjectBase<DerivedEI> & EI,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ using namespace Eigen;
+ using namespace igl;
+ using namespace igl::copyleft::cgal;
+ using namespace std;
+ // Exact scalar type
+ typedef CGAL::Epeck Kernel;
+ typedef Kernel::FT EScalar;
+ typedef CGAL::Segment_2<Kernel> Segment_2;
+ typedef CGAL::Point_2<Kernel> Point_2;
+ typedef CGAL::Vector_2<Kernel> Vector_2;
+ typedef Matrix<EScalar,Dynamic,Dynamic> MatrixXE;
+ // Convert vertex positions to exact kernel
+
+ MatrixXE VE;
+ {
+ VectorXi IM;
+ resolve_intersections(V,E,VE,EI,J,IM);
+ for_each(
+ EI.data(),
+ EI.data()+EI.size(),
+ [&IM](typename DerivedEI::Scalar& i){i=IM(i);});
+ VectorXi _;
+ remove_unreferenced( MatrixXE(VE), DerivedEI(EI), VE,EI,_);
+ }
+
+ // find all hot pixels
+ //// southwest and north east corners
+ //const RowVector2i SW(
+ // round(VE.col(0).minCoeff()),
+ // round(VE.col(1).minCoeff()));
+ //const RowVector2i NE(
+ // round(VE.col(0).maxCoeff()),
+ // round(VE.col(1).maxCoeff()));
+
+ // https://github.com/CGAL/cgal/issues/548
+ // Round an exact scalar to the nearest integer. A priori can't just round
+ // double. Suppose e=0.5+ε but double(e)<0.5
+ //
+ // Inputs:
+ // e exact number
+ // Outputs:
+ // i closest integer
+ const auto & round = [](const EScalar & e)->int
+ {
+ const double d = CGAL::to_double(e);
+ // get an integer that's near the closest int
+ int i = std::round(d);
+ EScalar di_sqr = CGAL::square((e-EScalar(i)));
+ const auto & search = [&i,&di_sqr,&e](const int dir)
+ {
+ while(true)
+ {
+ const int j = i+dir;
+ const EScalar dj_sqr = CGAL::square((e-EScalar(j)));
+ if(dj_sqr < di_sqr)
+ {
+ i = j;
+ di_sqr = dj_sqr;
+ }else
+ {
+ break;
+ }
+ }
+ };
+ // Try to increase/decrease int
+ search(1);
+ search(-1);
+ return i;
+ };
+ vector<Point_2> hot;
+ for(int i = 0;i<VE.rows();i++)
+ {
+ hot.emplace_back(round(VE(i,0)),round(VE(i,1)));
+ }
+ {
+ std::vector<size_t> _1,_2;
+ igl::unique(vector<Point_2>(hot),hot,_1,_2);
+ }
+
+ // find all segments intersecting hot pixels
+ // split edge at closest point to hot pixel center
+ vector<vector<Point_2>> steiner(EI.rows());
+ // initialize each segment with endpoints
+ for(int i = 0;i<EI.rows();i++)
+ {
+ steiner[i].emplace_back(VE(EI(i,0),0),VE(EI(i,0),1));
+ steiner[i].emplace_back(VE(EI(i,1),0),VE(EI(i,1),1));
+ }
+ // silly O(n²) implementation
+ for(const Point_2 & h : hot)
+ {
+ // North, East, South, West
+ Segment_2 wall[4] =
+ {
+ {h+Vector_2(-0.5, 0.5),h+Vector_2( 0.5, 0.5)},
+ {h+Vector_2( 0.5, 0.5),h+Vector_2( 0.5,-0.5)},
+ {h+Vector_2( 0.5,-0.5),h+Vector_2(-0.5,-0.5)},
+ {h+Vector_2(-0.5,-0.5),h+Vector_2(-0.5, 0.5)}
+ };
+ // consider all segments
+ for(int i = 0;i<EI.rows();i++)
+ {
+ // endpoints
+ const Point_2 s(VE(EI(i,0),0),VE(EI(i,0),1));
+ const Point_2 d(VE(EI(i,1),0),VE(EI(i,1),1));
+ // if either end-point is in h's pixel then ignore
+ const Point_2 rs(round(s.x()),round(s.y()));
+ const Point_2 rd(round(d.x()),round(d.y()));
+ if(h == rs || h == rd)
+ {
+ continue;
+ }
+ // otherwise check for intersections with walls consider all walls
+ const Segment_2 si(s,d);
+ vector<Point_2> hits;
+ for(int j = 0;j<4;j++)
+ {
+ const Segment_2 & sj = wall[j];
+ if(CGAL::do_intersect(si,sj))
+ {
+ CGAL::Object result = CGAL::intersection(si,sj);
+ if(const Point_2 * p = CGAL::object_cast<Point_2 >(&result))
+ {
+ hits.push_back(*p);
+ }else if(const Segment_2 * s = CGAL::object_cast<Segment_2 >(&result))
+ {
+ // add both endpoints
+ hits.push_back(s->vertex(0));
+ hits.push_back(s->vertex(1));
+ }
+ }
+ }
+ if(hits.size() == 0)
+ {
+ continue;
+ }
+ // centroid of hits
+ Vector_2 cen(0,0);
+ for(const Point_2 & hit : hits)
+ {
+ cen = Vector_2(cen.x()+hit.x(), cen.y()+hit.y());
+ }
+ cen = Vector_2(cen.x()/EScalar(hits.size()),cen.y()/EScalar(hits.size()));
+ const Point_2 rcen(round(cen.x()),round(cen.y()));
+ // after all of that, don't add as a steiner unless it's going to round
+ // to h
+ if(rcen == h)
+ {
+ steiner[i].emplace_back(cen.x(),cen.y());
+ }
+ }
+ }
+ {
+ DerivedJ prevJ = J;
+ VectorXi IM;
+ subdivide_segments(MatrixXE(VE),MatrixXi(EI),steiner,VE,EI,J,IM);
+ for_each(J.data(),J.data()+J.size(),[&prevJ](typename DerivedJ::Scalar & j){j=prevJ(j);});
+ for_each(
+ EI.data(),
+ EI.data()+EI.size(),
+ [&IM](typename DerivedEI::Scalar& i){i=IM(i);});
+ VectorXi _;
+ remove_unreferenced( MatrixXE(VE), DerivedEI(EI), VE,EI,_);
+ }
+
+
+ VI.resizeLike(VE);
+ for(int i = 0;i<VE.rows();i++)
+ {
+ for(int j = 0;j<VE.cols();j++)
+ {
+ VI(i,j) = round(CGAL::to_double(VE(i,j)));
+ }
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/snap_rounding.h b/xs/src/igl/copyleft/cgal/snap_rounding.h
new file mode 100644
index 000000000..48d2757f1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/snap_rounding.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_SNAP_ROUNDING_H
+#define IGL_COPYLEFT_CGAL_SNAP_ROUNDING_H
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // SNAP_ROUNDING Snap a list of possible intersecting segments with
+ // endpoints in any precision to _the_ integer grid.
+ //
+ // Inputs:
+ // V #V by 2 list of vertex positions
+ // E #E by 2 list of segment indices into V
+ // Outputs:
+ // VI #VI by 2 list of output integer vertex positions, rounded copies
+ // of V are always the first #V vertices
+ // EI #EI by 2 list of segment indices into V, #EI ≥ #E
+ // J #EI list of indices into E revealing "parent segments"
+ template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedVI,
+ typename DerivedEI,
+ typename DerivedJ>
+ IGL_INLINE void snap_rounding(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedVI> & VI,
+ Eigen::PlainObjectBase<DerivedEI> & EI,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "snap_rounding.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.cpp b/xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.cpp
new file mode 100644
index 000000000..8ff1a03c4
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.cpp
@@ -0,0 +1,53 @@
+#include "string_to_mesh_boolean_type.h"
+#include <algorithm>
+#include <cassert>
+#include <vector>
+
+IGL_INLINE bool igl::copyleft::cgal::string_to_mesh_boolean_type(
+ const std::string & s,
+ MeshBooleanType & type)
+{
+ using namespace std;
+ string eff_s = s;
+ transform(eff_s.begin(), eff_s.end(), eff_s.begin(), ::tolower);
+ const auto & find_any =
+ [](const vector<string> & haystack, const string & needle)->bool
+ {
+ return find(haystack.begin(), haystack.end(), needle) != haystack.end();
+ };
+ if(find_any({"union","unite","u","∪"},eff_s))
+ {
+ type = MESH_BOOLEAN_TYPE_UNION;
+ }else if(find_any({"intersect","intersection","i","∩"},eff_s))
+ {
+ type = MESH_BOOLEAN_TYPE_INTERSECT;
+ }else if(
+ find_any(
+ {"minus","subtract","difference","relative complement","m","\\"},eff_s))
+ {
+ type = MESH_BOOLEAN_TYPE_MINUS;
+ }else if(find_any({"xor","symmetric difference","x","∆"},eff_s))
+ {
+ type = MESH_BOOLEAN_TYPE_XOR;
+ }else if(find_any({"resolve"},eff_s))
+ {
+ type = MESH_BOOLEAN_TYPE_RESOLVE;
+ }else
+ {
+ return false;
+ }
+ return true;
+}
+
+IGL_INLINE igl::MeshBooleanType
+igl::copyleft::cgal::string_to_mesh_boolean_type(
+ const std::string & s)
+{
+ MeshBooleanType type;
+#ifndef NDEBUG
+ const bool ret =
+#endif
+ string_to_mesh_boolean_type(s,type);
+ assert(ret && "Unknown MeshBooleanType name");
+ return type;
+}
diff --git a/xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.h b/xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.h
new file mode 100644
index 000000000..4781099f1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/string_to_mesh_boolean_type.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_STRING_TO_MESH_BOOLEAN_H
+#define IGL_COPYLEFT_CGAL_STRING_TO_MESH_BOOLEAN_H
+
+#include "../../igl_inline.h"
+#include "../../MeshBooleanType.h"
+#include <string>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Convert string to boolean type
+ //
+ // Inputs:
+ // s string identifying type, one of the following:
+ // "union","intersect","minus","xor","resolve"
+ // Outputs:
+ // type type of boolean operation
+ // Returns true only on success
+ //
+ IGL_INLINE bool string_to_mesh_boolean_type(
+ const std::string & s,
+ MeshBooleanType & type);
+ // Returns type without error handling
+ IGL_INLINE MeshBooleanType string_to_mesh_boolean_type(
+ const std::string & s);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "string_to_mesh_boolean_type.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/subdivide_segments.cpp b/xs/src/igl/copyleft/cgal/subdivide_segments.cpp
new file mode 100644
index 000000000..6cf7df93c
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/subdivide_segments.cpp
@@ -0,0 +1,134 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "subdivide_segments.h"
+#include "row_to_point.h"
+#include "assign_scalar.h"
+#include "../../unique.h"
+#include "../../list_to_matrix.h"
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#include <CGAL/Segment_2.h>
+#include <CGAL/Point_2.h>
+#include <algorithm>
+#include <vector>
+
+template <
+ typename DerivedV,
+ typename DerivedE,
+ typename Kernel,
+ typename DerivedVI,
+ typename DerivedEI,
+ typename DerivedJ,
+ typename DerivedIM>
+IGL_INLINE void igl::copyleft::cgal::subdivide_segments(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ const std::vector<std::vector<CGAL::Point_2<Kernel> > > & _steiner,
+ Eigen::PlainObjectBase<DerivedVI> & VI,
+ Eigen::PlainObjectBase<DerivedEI> & EI,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM)
+{
+ using namespace Eigen;
+ using namespace igl;
+ using namespace std;
+
+ // Exact scalar type
+ typedef Kernel K;
+ typedef typename Kernel::FT EScalar;
+ typedef CGAL::Segment_2<Kernel> Segment_2;
+ typedef CGAL::Point_2<Kernel> Point_2;
+ typedef Matrix<EScalar,Dynamic,Dynamic> MatrixXE;
+
+ // non-const copy
+ std::vector<std::vector<CGAL::Point_2<Kernel> > > steiner = _steiner;
+
+ // Convert vertex positions to exact kernel
+ MatrixXE VE(V.rows(),V.cols());
+ for(int i = 0;i<V.rows();i++)
+ {
+ for(int j = 0;j<V.cols();j++)
+ {
+ VE(i,j) = V(i,j);
+ }
+ }
+
+ // number of original vertices
+ const int n = V.rows();
+ // number of original segments
+ const int m = E.rows();
+ // now steiner contains lists of points (unsorted) for each edge. Sort them
+ // and count total number of vertices and edges
+ int ni = 0;
+ int mi = 0;
+ // new steiner points
+ std::vector<Point_2> S;
+ std::vector<std::vector<typename DerivedE::Scalar> > vEI;
+ std::vector<typename DerivedJ::Scalar> vJ;
+ for(int i = 0;i<m;i++)
+ {
+ {
+ const Point_2 s = row_to_point<K>(VE,E(i,0));
+ std::sort(
+ steiner[i].begin(),
+ steiner[i].end(),
+ [&s](const Point_2 & A, const Point_2 & B)->bool
+ {
+ return (A-s).squared_length() < (B-s).squared_length();
+ });
+ }
+ // remove duplicates
+ steiner[i].erase(
+ std::unique(steiner[i].begin(), steiner[i].end()),
+ steiner[i].end());
+ {
+ int s = E(i,0);
+ // legs to each steiner in order
+ for(int j = 1;j<steiner[i].size()-1;j++)
+ {
+ int d = n+S.size();
+ S.push_back(steiner[i][j]);
+ vEI.push_back({s,d});
+ vJ.push_back(i);
+ s = d;
+ }
+ // don't forget last (which might only) leg
+ vEI.push_back({s,E(i,1)});
+ vJ.push_back(i);
+ }
+ }
+ // potentially unnecessary copying ...
+ VI.resize(n+S.size(),2);
+ for(int i = 0;i<V.rows();i++)
+ {
+ for(int j = 0;j<V.cols();j++)
+ {
+ assign_scalar(V(i,j),VI(i,j));
+ }
+ }
+ for(int i = 0;i<S.size();i++)
+ {
+ assign_scalar(S[i].x(),VI(n+i,0));
+ assign_scalar(S[i].y(),VI(n+i,1));
+ }
+ list_to_matrix(vEI,EI);
+ list_to_matrix(vJ,J);
+ {
+ // Find unique mapping
+ std::vector<Point_2> vVES,_1;
+ for(int i = 0;i<n;i++)
+ {
+ vVES.push_back(row_to_point<K>(VE,i));
+ }
+ vVES.insert(vVES.end(),S.begin(),S.end());
+ std::vector<size_t> vA,vIM;
+ igl::unique(vVES,_1,vA,vIM);
+ // Push indices back into vVES
+ for_each(vIM.data(),vIM.data()+vIM.size(),[&vA](size_t & i){i=vA[i];});
+ list_to_matrix(vIM,IM);
+ }
+}
diff --git a/xs/src/igl/copyleft/cgal/subdivide_segments.h b/xs/src/igl/copyleft/cgal/subdivide_segments.h
new file mode 100644
index 000000000..cd7d41a00
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/subdivide_segments.h
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_SUBDIVIDE_SEGMENTS_H
+#define IGL_COPYLEFT_CGAL_SUBDIVIDE_SEGMENTS_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <CGAL/Segment_2.h>
+#include <CGAL/Point_2.h>
+#include <vector>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Insert steiner points to subdivide a given set of line segments
+ //
+ // Inputs:
+ // V #V by 2 list of vertex positions
+ // E #E by 2 list of segment indices into V
+ // steiner #E list of lists of unsorted steiner points (including
+ // endpoints) along the #E original segments
+ // Outputs:
+ // VI #VI by 2 list of output vertex positions, copies of V are always
+ // the first #V vertices
+ // EI #EI by 2 list of segment indices into V, #EI ≥ #E
+ // J #EI list of indices into E revealing "parent segments"
+ // IM #VI list of indices into VV of unique vertices.
+ template <
+ typename DerivedV,
+ typename DerivedE,
+ typename Kernel,
+ typename DerivedVI,
+ typename DerivedEI,
+ typename DerivedJ,
+ typename DerivedIM>
+ IGL_INLINE void subdivide_segments(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ const std::vector<std::vector<CGAL::Point_2<Kernel> > > & steiner,
+ Eigen::PlainObjectBase<DerivedVI> & VI,
+ Eigen::PlainObjectBase<DerivedEI> & EI,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedIM> & IM);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "subdivide_segments.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/submesh_aabb_tree.cpp b/xs/src/igl/copyleft/cgal/submesh_aabb_tree.cpp
new file mode 100644
index 000000000..4351ec0a9
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/submesh_aabb_tree.cpp
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "submesh_aabb_tree.h"
+#include <stdexcept>
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename Kernel>
+IGL_INLINE void igl::copyleft::cgal::submesh_aabb_tree(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ CGAL::AABB_tree<
+ CGAL::AABB_traits<
+ Kernel,
+ CGAL::AABB_triangle_primitive<
+ Kernel, typename std::vector<
+ typename Kernel::Triangle_3 >::iterator > > > & tree,
+ std::vector<typename Kernel::Triangle_3 > & triangles,
+ std::vector<bool> & in_I)
+{
+ in_I.resize(F.rows(), false);
+ const size_t num_faces = I.rows();
+ for (size_t i=0; i<num_faces; i++)
+ {
+ const Eigen::Vector3i f = F.row(I(i, 0));
+ in_I[I(i,0)] = true;
+ triangles.emplace_back(
+ typename Kernel::Point_3(V(f[0], 0), V(f[0], 1), V(f[0], 2)),
+ typename Kernel::Point_3(V(f[1], 0), V(f[1], 1), V(f[1], 2)),
+ typename Kernel::Point_3(V(f[2], 0), V(f[2], 1), V(f[2], 2)));
+#ifndef NDEBUG
+ if (triangles.back().is_degenerate())
+ {
+ throw std::runtime_error(
+ "Input facet components contains degenerated triangles");
+ }
+#endif
+ }
+ tree.insert(triangles.begin(), triangles.end());
+ tree.accelerate_distance_queries();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::submesh_aabb_tree<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > >&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >&, std::vector<bool, std::allocator<bool> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::cgal::submesh_aabb_tree<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > >&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >&, std::vector<bool, std::allocator<bool> >&);
+template void igl::copyleft::cgal::submesh_aabb_tree<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, CGAL::Epeck>(Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, CGAL::AABB_tree<CGAL::AABB_traits<CGAL::Epeck, CGAL::AABB_triangle_primitive<CGAL::Epeck, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >::iterator, CGAL::Boolean_tag<false> > > >&, std::vector<CGAL::Epeck::Triangle_3, std::allocator<CGAL::Epeck::Triangle_3> >&, std::vector<bool, std::allocator<bool> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/submesh_aabb_tree.h b/xs/src/igl/copyleft/cgal/submesh_aabb_tree.h
new file mode 100644
index 000000000..eec9c030f
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/submesh_aabb_tree.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLET_CGAL_SUBMESH_AABB_TREE_H
+#define IGL_COPYLET_CGAL_SUBMESH_AABB_TREE_H
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+#include <CGAL/AABB_tree.h>
+#include <CGAL/AABB_traits.h>
+#include <CGAL/AABB_triangle_primitive.h>
+#include <CGAL/intersections.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Build an AABB tree for a submesh indicated by a face selection list I
+ // of a full mesh (V,F)
+ //
+ // Inputs:
+ // V #V by 3 array of vertices.
+ // F #F by 3 array of faces.
+ // I #I list of triangle indices to consider.
+ // Outputs:
+ // tree aabb containing triangles of (V,F(I,:))
+ // triangles #I list of cgal triangles
+ // in_I #F list of whether in submesh
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename Kernel>
+ IGL_INLINE void submesh_aabb_tree(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedI>& I,
+ CGAL::AABB_tree<
+ CGAL::AABB_traits<
+ Kernel,
+ CGAL::AABB_triangle_primitive<
+ Kernel, typename std::vector<
+ typename Kernel::Triangle_3 >::iterator > > > & tree,
+ std::vector<typename Kernel::Triangle_3 > & triangles,
+ std::vector<bool> & in_I);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "submesh_aabb_tree.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.cpp b/xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.cpp
new file mode 100644
index 000000000..0c512f800
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.cpp
@@ -0,0 +1,114 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "triangle_triangle_squared_distance.h"
+#include "point_triangle_squared_distance.h"
+#include <CGAL/Vector_3.h>
+#include <CGAL/Segment_3.h>
+#include <CGAL/intersections.h>
+
+template < typename Kernel>
+IGL_INLINE bool igl::copyleft::cgal::triangle_triangle_squared_distance(
+ const CGAL::Triangle_3<Kernel> & T1,
+ const CGAL::Triangle_3<Kernel> & T2,
+ CGAL::Point_3<Kernel> & P1,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & d)
+{
+ typedef CGAL::Point_3<Kernel> Point_3;
+ typedef CGAL::Vector_3<Kernel> Vector_3;
+ typedef CGAL::Triangle_3<Kernel> Triangle_3;
+ typedef CGAL::Segment_3<Kernel> Segment_3;
+ typedef typename Kernel::FT EScalar;
+ assert(!T1.is_degenerate());
+ assert(!T2.is_degenerate());
+
+ bool unique = true;
+ if(CGAL::do_intersect(T1,T2))
+ {
+ // intersecting triangles have zero (squared) distance
+ CGAL::Object result = CGAL::intersection(T1,T2);
+ // Some point on the intersection result
+ CGAL::Point_3<Kernel> Q;
+ if(const Point_3 * p = CGAL::object_cast<Point_3 >(&result))
+ {
+ Q = *p;
+ }else if(const Segment_3 * s = CGAL::object_cast<Segment_3 >(&result))
+ {
+ unique = false;
+ Q = s->source();
+ }else if(const Triangle_3 *itri = CGAL::object_cast<Triangle_3 >(&result))
+ {
+ Q = s->vertex(0);
+ unique = false;
+ }else if(const std::vector<Point_3 > *polyp =
+ CGAL::object_cast< std::vector<Point_3 > >(&result))
+ {
+ assert(polyp->size() > 0 && "intersection poly should not be empty");
+ Q = polyp[0];
+ unique = false;
+ }else
+ {
+ assert(false && "Unknown intersection result");
+ }
+ P1 = Q;
+ P2 = Q;
+ d = 0;
+ return unique;
+ }
+ // triangles do not intersect: the points of closest approach must be on the
+ // boundary of one of the triangles
+ d = std::numeric_limits<double>::infinity();
+ const auto & vertices_face = [&unique](
+ const Triangle_3 & T1,
+ const Triangle_3 & T2,
+ Point_3 & P1,
+ Point_3 & P2,
+ EScalar & d)
+ {
+ for(int i = 0;i<3;i++)
+ {
+ const Point_3 vi = T1.vertex(i);
+ Point_3 P2i;
+ EScalar di;
+ point_triangle_squared_distance(vi,T2,P2i,di);
+ if(di<d)
+ {
+ d = di;
+ P1 = vi;
+ P2 = P2i;
+ unique = true;
+ }else if(d == di)
+ {
+ // edge of T1 floating parallel above T2
+ unique = false;
+ }
+ }
+ };
+ vertices_face(T1,T2,P1,P2,d);
+ vertices_face(T2,T1,P1,P2,d);
+ for(int i = 0;i<3;i++)
+ {
+ const Segment_3 s1( T1.vertex(i+1), T1.vertex(i+2));
+ for(int j = 0;j<3;j++)
+ {
+ const Segment_3 s2( T2.vertex(i+1), T2.vertex(i+2));
+ Point_3 P1ij;
+ Point_3 P2ij;
+ EScalar dij;
+ bool uniqueij = segment_segment_squared_distance(s1,s2,P1ij,P2ij,dij);
+ if(dij < d)
+ {
+ P1 = P1ij;
+ P2 = P2ij;
+ d = dij;
+ unique = uniqueij;
+ }
+ }
+ }
+ return unique;
+}
diff --git a/xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.h b/xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.h
new file mode 100644
index 000000000..118023488
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/triangle_triangle_squared_distance.h
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_TRIANGLE_TRIANGLE_SQUARED_DISTANCE_H
+#define IGL_COPYLEFT_CGAL_TRIANGLE_TRIANGLE_SQUARED_DISTANCE_H
+#include "../../igl_inline.h"
+#include <CGAL/Triangle_3.h>
+#include <CGAL/Point_3.h>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Given two triangles T1 and T2 find the points on each of closest
+ // approach and the squared distance thereof.
+ //
+ // Inputs:
+ // T1 first triangle
+ // T2 second triangle
+ // Outputs:
+ // P1 point on T1 closest to T2
+ // P2 point on T2 closest to T1
+ // d distance betwee P1 and T2
+ // Returns true if the closest approach is unique.
+ template < typename Kernel>
+ IGL_INLINE bool triangle_triangle_squared_distance(
+ const CGAL::Triangle_3<Kernel> & T1,
+ const CGAL::Triangle_3<Kernel> & T2,
+ CGAL::Point_3<Kernel> & P1,
+ CGAL::Point_3<Kernel> & P2,
+ typename Kernel::FT & d);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "triangle_triangle_squared_distance.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/trim_with_solid.cpp b/xs/src/igl/copyleft/cgal/trim_with_solid.cpp
new file mode 100644
index 000000000..1e67da71e
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/trim_with_solid.cpp
@@ -0,0 +1,105 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "trim_with_solid.h"
+#include "assign.h"
+#include "intersect_other.h"
+#include "point_solid_signed_squared_distance.h"
+
+#include "../../extract_manifold_patches.h"
+#include "../../list_to_matrix.h"
+#include "../../remove_unreferenced.h"
+#include "../../slice_mask.h"
+
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+
+#include <vector>
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedD,
+ typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::trim_with_solid(
+ const Eigen::PlainObjectBase<DerivedVA> & VA,
+ const Eigen::PlainObjectBase<DerivedFA> & FA,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ Eigen::PlainObjectBase<DerivedV> & Vd,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedD> & D,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ // resolve intersections using exact representation
+ typedef Eigen::Matrix<CGAL::Epeck::FT,Eigen::Dynamic,3> MatrixX3E;
+ typedef Eigen::Matrix<CGAL::Epeck::FT,Eigen::Dynamic,1> VectorXE;
+ typedef Eigen::Matrix<CGAL::Epeck::FT,1,3> RowVector3E;
+ MatrixX3E V;
+ Eigen::MatrixXi _1;
+ Eigen::VectorXi _2;
+ // Intersect A and B meshes and stitch together new faces
+ igl::copyleft::cgal::intersect_other(
+ VA,FA,VB,FB,{false,false,true},_1,V,F,J,_2);
+ // Partition result into manifold patches
+ Eigen::VectorXi P;
+ const size_t num_patches = igl::extract_manifold_patches(F,P);
+ // only keep faces from A
+ Eigen::Matrix<bool,Eigen::Dynamic,1> A = J.array()< FA.rows();
+ igl::slice_mask(Eigen::MatrixXi(F),A,1,F);
+ igl::slice_mask(Eigen::VectorXi(P),A,1,P);
+ igl::slice_mask(Eigen::VectorXi(J),A,1,J);
+ // Aggregate representative query points for each patch
+ std::vector<bool> flag(num_patches);
+ std::vector<std::vector<CGAL::Epeck::FT> > vQ;
+ Eigen::VectorXi P2Q(num_patches);
+ for(int f = 0;f<P.rows();f++)
+ {
+ const auto p = P(f);
+ // if not yet processed this patch
+ if(!flag[p])
+ {
+ P2Q(p) = vQ.size();
+ std::vector<CGAL::Epeck::FT> q = {
+ (V(F(f,0),0)+ V(F(f,1),0)+ V(F(f,2),0))/3.,
+ (V(F(f,0),1)+ V(F(f,1),1)+ V(F(f,2),1))/3.,
+ (V(F(f,0),2)+ V(F(f,1),2)+ V(F(f,2),2))/3.};
+ vQ.emplace_back(q);
+ flag[p] = true;
+ }
+ }
+ MatrixX3E Q;
+ igl::list_to_matrix(vQ,Q);
+ VectorXE SP;
+ point_solid_signed_squared_distance(Q,VB,FB,SP);
+ Eigen::Matrix<bool,Eigen::Dynamic,1> DP = SP.array()>0;
+ // distribute flag to all faces
+ D.resize(F.rows());
+ for(int f = 0;f<F.rows();f++)
+ {
+ D(f) = DP(P2Q(P(f)));
+ }
+ Eigen::VectorXi _;
+ igl::remove_unreferenced(MatrixX3E(V),DerivedF(F),V,F,_);
+ assign(V,Vd);
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::copyleft::cgal::trim_with_solid<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1,
+ -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0,
+ -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>
+ >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int,
+ -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&,
+ Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1,
+ -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&,
+ Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1,
+ 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/trim_with_solid.h b/xs/src/igl/copyleft/cgal/trim_with_solid.h
new file mode 100644
index 000000000..aa45d80f7
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/trim_with_solid.h
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CGAL_TRIM_WITH_SOLID_H
+#define IGL_COPYLEFT_CGAL_TRIM_WITH_SOLID_H
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // TRIM_WITH_SOLID Given an arbitrary mesh (VA,FA) and the boundary mesh
+ // (VB,FB) of a solid (as defined in [Zhou et al. 2016]), Resolve intersections
+ // between A and B subdividing faces of A so that intersections with B exists
+ // only along edges and vertices (and coplanar faces). Then determine whether
+ // each of these faces is inside or outside of B. This can be used to extract
+ // the part of A inside or outside of B.
+ //
+ // Inputs:
+ // VA #VA by 3 list of mesh vertex positions of A
+ // FA #FA by 3 list of mesh triangle indices into VA
+ // VB #VB by 3 list of mesh vertex positions of B
+ // FB #FB by 3 list of mesh triangle indices into VB
+ // Outputs:
+ // V #V by 3 list of mesh vertex positions of output
+ // F #F by 3 list of mesh triangle indices into V
+ // D #F list of bools whether face is inside B
+ // J #F list of indices into FA revealing birth parent
+ //
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedD,
+ typename DerivedJ>
+ IGL_INLINE void trim_with_solid(
+ const Eigen::PlainObjectBase<DerivedVA> & VA,
+ const Eigen::PlainObjectBase<DerivedFA> & FA,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ Eigen::PlainObjectBase<DerivedV> & Vd,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedD> & D,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "trim_with_solid.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cgal/unique.cpp b/xs/src/igl/copyleft/cgal/unique.cpp
new file mode 100644
index 000000000..5e45f82b1
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/unique.cpp
@@ -0,0 +1,14 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "../../unique.h"
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#ifdef IGL_STATIC_LIBRARY
+#undef IGL_STATIC_LIBRARY
+#include "../../unique.cpp"
+#endif
diff --git a/xs/src/igl/copyleft/cgal/unique_rows.cpp b/xs/src/igl/copyleft/cgal/unique_rows.cpp
new file mode 100644
index 000000000..e4d946f77
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/unique_rows.cpp
@@ -0,0 +1,18 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "../../unique_rows.h"
+#include <CGAL/Exact_predicates_inexact_constructions_kernel.h>
+#include <CGAL/Exact_predicates_exact_constructions_kernel.h>
+#ifdef IGL_STATIC_LIBRARY
+#undef IGL_STATIC_LIBRARY
+#include "../../unique_rows.cpp"
+template void igl::unique_rows<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<CGAL::Lazy_exact_nt<CGAL::Gmpq>, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
+
diff --git a/xs/src/igl/copyleft/cgal/wire_mesh.cpp b/xs/src/igl/copyleft/cgal/wire_mesh.cpp
new file mode 100644
index 000000000..0e9609501
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/wire_mesh.cpp
@@ -0,0 +1,215 @@
+#include "wire_mesh.h"
+
+#include "../../list_to_matrix.h"
+#include "../../slice.h"
+#include "../../PI.h"
+#include "convex_hull.h"
+#include "mesh_boolean.h"
+#include <Eigen/Geometry>
+#include <vector>
+
+template <
+ typename DerivedWV,
+ typename DerivedWE,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::wire_mesh(
+ const Eigen::MatrixBase<DerivedWV> & WV,
+ const Eigen::MatrixBase<DerivedWE> & WE,
+ const double th,
+ const int poly_size,
+ const bool solid,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+
+ typedef typename DerivedWV::Scalar Scalar;
+ // Canonical polygon to place at each endpoint
+ typedef Eigen::Matrix<Scalar,Eigen::Dynamic,3> MatrixX3S;
+ MatrixX3S PV(poly_size,3);
+ for(int p =0;p<PV.rows();p++)
+ {
+ const Scalar phi = (Scalar(p)/Scalar(PV.rows()))*2.*igl::PI;
+ PV(p,0) = 0.5*cos(phi);
+ PV(p,1) = 0.5*sin(phi);
+ PV(p,2) = 0;
+ }
+
+ V.resize(WV.rows() + PV.rows() * 2 * WE.rows(),3);
+ V.topLeftCorner(WV.rows(),3) = WV;
+ // Signed adjacency list
+ std::vector<std::vector<std::pair<int,int> > > A(WV.rows());
+ // Inputs:
+ // e index of edge
+ // c index of endpoint [0,1]
+ // p index of polygon vertex
+ // Returns index of corresponding vertex in V
+ const auto index =
+ [&PV,&WV](const int e, const int c, const int p)->int
+ {
+ return WV.rows() + e*2*PV.rows() + PV.rows()*c + p;
+ };
+ const auto unindex =
+ [&PV,&WV](int v, int & e, int & c, int & p)
+ {
+ assert(v>=WV.rows());
+ v = v-WV.rows();
+ e = v/(2*PV.rows());
+ v = v-e*(2*PV.rows());
+ c = v/(PV.rows());
+ v = v-c*(PV.rows());
+ p = v;
+ };
+ // loop over all edges
+ for(int e = 0;e<WE.rows();e++)
+ {
+ // Fill in adjacency list as we go
+ A[WE(e,0)].emplace_back(e,0);
+ A[WE(e,1)].emplace_back(e,1);
+ typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
+ const RowVector3S ev = WV.row(WE(e,1))-WV.row(WE(e,0));
+ const Scalar len = ev.norm();
+ // Unit edge vector
+ const RowVector3S uv = ev.normalized();
+ Eigen::Quaternion<Scalar> q;
+ q = q.FromTwoVectors(RowVector3S(0,0,1),uv);
+ // loop over polygon vertices
+ for(int p = 0;p<PV.rows();p++)
+ {
+ RowVector3S qp = q*(PV.row(p)*th);
+ // loop over endpoints
+ for(int c = 0;c<2;c++)
+ {
+ // Direction moving along edge vector
+ const Scalar dir = c==0?1:-1;
+ // Amount (distance) to move along edge vector
+ // Start with factor of thickness;
+ // Max out amount at 1/3 of edge length so that there's always some
+ // amount of edge
+ Scalar dist = std::min(1.*th,len/3.0);
+ // Move to endpoint, offset by amount
+ V.row(index(e,c,p)) =
+ qp+WV.row(WE(e,c)) + dist*dir*uv;
+ }
+ }
+ }
+
+ std::vector<std::vector<typename DerivedF::Index> > vF;
+ std::vector<int> vJ;
+ const auto append_hull =
+ [&V,&vF,&vJ,&unindex,&WV](const Eigen::VectorXi & I, const int j)
+ {
+ MatrixX3S Vv;
+ igl::slice(V,I,1,Vv);
+ Eigen::MatrixXi Fv;
+ convex_hull(Vv,Fv);
+ for(int f = 0;f<Fv.rows();f++)
+ {
+ const Eigen::Array<int,1,3> face(I(Fv(f,0)), I(Fv(f,1)), I(Fv(f,2)));
+ //const bool on_vertex = (face<WV.rows()).any();
+ //if(!on_vertex)
+ //{
+ // // This correctly prunes fcaes on the "caps" of convex hulls around
+ // // edges, but for convex hulls around vertices this will only work if
+ // // the incoming edges are not overlapping.
+ // //
+ // // Q: For convex hulls around vertices, is the correct thing to do:
+ // // check if all corners of face lie *on or _outside_* of plane of "cap"?
+ // //
+ // // H: Maybe, but if there's an intersection then the boundary of the
+ // // incoming convex hulls around edges is still not going to match up
+ // // with the boundary on the convex hull around the vertices.
+ // //
+ // // Might have to bite the bullet and always call self-union.
+ // bool all_same = true;
+ // int e0,c0,p0;
+ // unindex(face(0),e0,c0,p0);
+ // for(int i = 1;i<3;i++)
+ // {
+ // int ei,ci,pi;
+ // unindex(face(i),ei,ci,pi);
+ // all_same = all_same && (e0==ei && c0==ci);
+ // }
+ // if(all_same)
+ // {
+ // // don't add this face
+ // continue;
+ // }
+ //}
+ vF.push_back( { face(0),face(1),face(2)});
+ vJ.push_back(j);
+ }
+ };
+ // loop over each vertex
+ for(int v = 0;v<WV.rows();v++)
+ {
+ // Gather together this vertex and the polygon vertices of all incident
+ // edges
+ Eigen::VectorXi I(1+A[v].size()*PV.rows());
+ // This vertex
+ I(0) = v;
+ for(int n = 0;n<A[v].size();n++)
+ {
+ for(int p = 0;p<PV.rows();p++)
+ {
+ const int e = A[v][n].first;
+ const int c = A[v][n].second;
+ I(1+n*PV.rows()+p) = index(e,c,p);
+ }
+ }
+ append_hull(I,v);
+ }
+ // loop over each edge
+ for(int e = 0;e<WE.rows();e++)
+ {
+ // Gether together polygon vertices of both endpoints
+ Eigen::VectorXi I(PV.rows()*2);
+ for(int c = 0;c<2;c++)
+ {
+ for(int p = 0;p<PV.rows();p++)
+ {
+ I(c*PV.rows()+p) = index(e,c,p);
+ }
+ }
+ append_hull(I,WV.rows()+e);
+ }
+
+ list_to_matrix(vF,F);
+ if(solid)
+ {
+ // Self-union to clean up
+ igl::copyleft::cgal::mesh_boolean(
+ Eigen::MatrixXd(V),Eigen::MatrixXi(F),Eigen::MatrixXd(),Eigen::MatrixXi(),
+ "union",
+ V,F,J);
+ for(int j=0;j<J.size();j++) J(j) = vJ[J(j)];
+ }else
+ {
+ list_to_matrix(vJ,J);
+ }
+}
+
+template <
+ typename DerivedWV,
+ typename DerivedWE,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedJ>
+IGL_INLINE void igl::copyleft::cgal::wire_mesh(
+ const Eigen::MatrixBase<DerivedWV> & WV,
+ const Eigen::MatrixBase<DerivedWE> & WE,
+ const double th,
+ const int poly_size,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ return wire_mesh(WV,WE,th,poly_size,true,V,F,J);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cgal::wire_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cgal/wire_mesh.h b/xs/src/igl/copyleft/cgal/wire_mesh.h
new file mode 100644
index 000000000..9b798e6fd
--- /dev/null
+++ b/xs/src/igl/copyleft/cgal/wire_mesh.h
@@ -0,0 +1,67 @@
+#ifndef IGL_COPYLEFT_CGAL_WIRE_MESH_H
+#define IGL_COPYLEFT_CGAL_WIRE_MESH_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cgal
+ {
+ // Construct a "wire" or "wireframe" or "strut" surface mesh, given a
+ // one-dimensional network of straight edges.
+ //
+ // Inputs:
+ // WV #WV by 3 list of vertex positions
+ // WE #WE by 2 list of edge indices into WV
+ // th diameter thickness of wire
+ // poly_size number of sides on each wire (e.g., 4 would produce wires by
+ // connecting rectangular prisms).
+ // solid whether to resolve self-intersections to
+ // create a "solid" output mesh (cf., [Zhou et al. 2016]
+ // Outputs:
+ // V #V by 3 list of output vertices
+ // F #F by 3 list of output triangle indices into V
+ // J #F list of indices into [0,#WV+#WE) revealing "birth simplex" of
+ // output faces J(j) < #WV means the face corresponds to the J(j)th
+ // vertex in WV. J(j) >= #WV means the face corresponds to the
+ // (J(j)-#WV)th edge in WE.
+ template <
+ typename DerivedWV,
+ typename DerivedWE,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedJ>
+ IGL_INLINE void wire_mesh(
+ const Eigen::MatrixBase<DerivedWV> & WV,
+ const Eigen::MatrixBase<DerivedWE> & WE,
+ const double th,
+ const int poly_size,
+ const bool solid,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ // Default with solid=true
+ template <
+ typename DerivedWV,
+ typename DerivedWE,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedJ>
+ IGL_INLINE void wire_mesh(
+ const Eigen::MatrixBase<DerivedWV> & WV,
+ const Eigen::MatrixBase<DerivedWE> & WE,
+ const double th,
+ const int poly_size,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "wire_mesh.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/comiso/frame_field.cpp b/xs/src/igl/copyleft/comiso/frame_field.cpp
new file mode 100644
index 000000000..c3549eeff
--- /dev/null
+++ b/xs/src/igl/copyleft/comiso/frame_field.cpp
@@ -0,0 +1,688 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "frame_field.h"
+
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/edge_topology.h>
+#include <igl/per_face_normals.h>
+#include <igl/copyleft/comiso/nrosy.h>
+#include <iostream>
+
+namespace igl
+{
+namespace copyleft
+{
+namespace comiso
+{
+
+class FrameInterpolator
+{
+public:
+ // Init
+ IGL_INLINE FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F);
+ IGL_INLINE ~FrameInterpolator();
+
+ // Reset constraints (at least one constraint must be present or solve will fail)
+ IGL_INLINE void resetConstraints();
+
+ IGL_INLINE void setConstraint(const int fid, const Eigen::VectorXd& v);
+
+ IGL_INLINE void interpolateSymmetric();
+
+ // Generate the frame field
+ IGL_INLINE void solve();
+
+ // Convert the frame field in the canonical representation
+ IGL_INLINE void frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S);
+
+ // Convert the canonical representation in a frame field
+ IGL_INLINE void canonical2frame(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S, Eigen::RowVectorXd& v);
+
+ IGL_INLINE Eigen::MatrixXd getFieldPerFace();
+
+ IGL_INLINE void PolarDecomposition(Eigen::MatrixXd V, Eigen::MatrixXd& U, Eigen::MatrixXd& P);
+
+ // Symmetric
+ Eigen::MatrixXd S;
+ std::vector<bool> S_c;
+
+ // -------------------------------------------------
+
+ // Face Topology
+ Eigen::MatrixXi TT, TTi;
+
+ // Two faces are consistent if their representative vector are taken modulo PI
+ std::vector<bool> edge_consistency;
+ Eigen::MatrixXi edge_consistency_TT;
+
+private:
+ IGL_INLINE double mod2pi(double d);
+ IGL_INLINE double modpi2(double d);
+ IGL_INLINE double modpi(double d);
+
+ // Convert a direction on the tangent space into an angle
+ IGL_INLINE double vector2theta(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v);
+
+ // Convert an angle in a vector in the tangent space
+ IGL_INLINE Eigen::RowVectorXd theta2vector(const Eigen::MatrixXd& TP, const double theta);
+
+ // Interpolate the cross field (theta)
+ IGL_INLINE void interpolateCross();
+
+ // Compute difference between reference frames
+ IGL_INLINE void computek();
+
+ // Compute edge consistency
+ IGL_INLINE void compute_edge_consistency();
+
+ // Cross field direction
+ Eigen::VectorXd thetas;
+ std::vector<bool> thetas_c;
+
+ // Edge Topology
+ Eigen::MatrixXi EV, FE, EF;
+ std::vector<bool> isBorderEdge;
+
+ // Angle between two reference frames
+ // R(k) * t0 = t1
+ Eigen::VectorXd k;
+
+ // Mesh
+ Eigen::MatrixXd V;
+ Eigen::MatrixXi F;
+
+ // Normals per face
+ Eigen::MatrixXd N;
+
+ // Reference frame per triangle
+ std::vector<Eigen::MatrixXd> TPs;
+
+};
+
+FrameInterpolator::FrameInterpolator(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ V = _V;
+ F = _F;
+
+ assert(V.rows() > 0);
+ assert(F.rows() > 0);
+
+
+ // Generate topological relations
+ igl::triangle_triangle_adjacency(F,TT,TTi);
+ igl::edge_topology(V,F, EV, FE, EF);
+
+ // Flag border edges
+ isBorderEdge.resize(EV.rows());
+ for(unsigned i=0; i<EV.rows(); ++i)
+ isBorderEdge[i] = (EF(i,0) == -1) || ((EF(i,1) == -1));
+
+ // Generate normals per face
+ igl::per_face_normals(V, F, N);
+
+ // Generate reference frames
+ for(unsigned fid=0; fid<F.rows(); ++fid)
+ {
+ // First edge
+ Vector3d e1 = V.row(F(fid,1)) - V.row(F(fid,0));
+ e1.normalize();
+ Vector3d e2 = N.row(fid);
+ e2 = e2.cross(e1);
+ e2.normalize();
+
+ MatrixXd TP(2,3);
+ TP << e1.transpose(), e2.transpose();
+ TPs.push_back(TP);
+ }
+
+ // Reset the constraints
+ resetConstraints();
+
+ // Compute k, differences between reference frames
+ computek();
+
+ // Alloc internal variables
+ thetas = VectorXd::Zero(F.rows());
+ S = MatrixXd::Zero(F.rows(),3);
+
+ compute_edge_consistency();
+}
+
+FrameInterpolator::~FrameInterpolator()
+{
+
+}
+
+double FrameInterpolator::mod2pi(double d)
+{
+ while(d<0)
+ d = d + (2.0*igl::PI);
+
+ return fmod(d, (2.0*igl::PI));
+}
+
+double FrameInterpolator::modpi2(double d)
+{
+ while(d<0)
+ d = d + (igl::PI/2.0);
+
+ return fmod(d, (igl::PI/2.0));
+}
+
+double FrameInterpolator::modpi(double d)
+{
+ while(d<0)
+ d = d + (igl::PI);
+
+ return fmod(d, (igl::PI));
+}
+
+
+double FrameInterpolator::vector2theta(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v)
+{
+ // Project onto the tangent plane
+ Eigen::Vector2d vp = TP * v.transpose();
+
+ // Convert to angle
+ double theta = atan2(vp(1),vp(0));
+ return theta;
+}
+
+Eigen::RowVectorXd FrameInterpolator::theta2vector(const Eigen::MatrixXd& TP, const double theta)
+{
+ Eigen::Vector2d vp(cos(theta),sin(theta));
+ return vp.transpose() * TP;
+}
+
+void FrameInterpolator::interpolateCross()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ //olga: was
+ // NRosyField nrosy(V,F);
+ // for (unsigned i=0; i<F.rows(); ++i)
+ // if(thetas_c[i])
+ // nrosy.setConstraintHard(i,theta2vector(TPs[i],thetas(i)));
+ // nrosy.solve(4);
+ // MatrixXd R = nrosy.getFieldPerFace();
+
+ //olga: is
+ Eigen::MatrixXd R;
+ Eigen::VectorXd S;
+ Eigen::VectorXi b; b.resize(F.rows(),1);
+ Eigen::MatrixXd bc; bc.resize(F.rows(),3);
+ int num = 0;
+ for (unsigned i=0; i<F.rows(); ++i)
+ if(thetas_c[i])
+ {
+ b[num] = i;
+ bc.row(num) = theta2vector(TPs[i],thetas(i));
+ num++;
+ }
+ b.conservativeResize(num,Eigen::NoChange);
+ bc.conservativeResize(num,Eigen::NoChange);
+
+ igl::copyleft::comiso::nrosy(V, F, b, bc, 4, R, S);
+ //olga:end
+ assert(R.rows() == F.rows());
+
+ for (unsigned i=0; i<F.rows(); ++i)
+ thetas(i) = vector2theta(TPs[i],R.row(i));
+}
+
+void FrameInterpolator::resetConstraints()
+{
+ thetas_c.resize(F.rows());
+ S_c.resize(F.rows());
+
+ for(unsigned i=0; i<F.rows(); ++i)
+ {
+ thetas_c[i] = false;
+ S_c[i] = false;
+ }
+
+}
+
+void FrameInterpolator::compute_edge_consistency()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // Compute per-edge consistency
+ edge_consistency.resize(EF.rows());
+ edge_consistency_TT = MatrixXi::Constant(TT.rows(),3,-1);
+
+ // For every non-border edge
+ for (unsigned eid=0; eid<EF.rows(); ++eid)
+ {
+ if (!isBorderEdge[eid])
+ {
+ int fid0 = EF(eid,0);
+ int fid1 = EF(eid,1);
+
+ double theta0 = thetas(fid0);
+ double theta1 = thetas(fid1);
+
+ theta0 = theta0 + k(eid);
+
+ double r = modpi(theta0-theta1);
+
+ edge_consistency[eid] = r < igl::PI/4.0 || r > 3*(igl::PI/4.0);
+
+ // Copy it into edge_consistency_TT
+ int i1 = -1;
+ int i2 = -1;
+ for (unsigned i=0; i<3; ++i)
+ {
+ if (TT(fid0,i) == fid1)
+ i1 = i;
+ if (TT(fid1,i) == fid0)
+ i2 = i;
+ }
+ assert(i1 != -1);
+ assert(i2 != -1);
+
+ edge_consistency_TT(fid0,i1) = edge_consistency[eid];
+ edge_consistency_TT(fid1,i2) = edge_consistency[eid];
+ }
+ }
+}
+
+void FrameInterpolator::computek()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ k.resize(EF.rows());
+
+ // For every non-border edge
+ for (unsigned eid=0; eid<EF.rows(); ++eid)
+ {
+ if (!isBorderEdge[eid])
+ {
+ int fid0 = EF(eid,0);
+ int fid1 = EF(eid,1);
+
+ Vector3d N0 = N.row(fid0);
+ //Vector3d N1 = N.row(fid1);
+
+ // find common edge on triangle 0 and 1
+ int fid0_vc = -1;
+ int fid1_vc = -1;
+ for (unsigned i=0;i<3;++i)
+ {
+ if (EV(eid,0) == F(fid0,i))
+ fid0_vc = i;
+ if (EV(eid,1) == F(fid1,i))
+ fid1_vc = i;
+ }
+ assert(fid0_vc != -1);
+ assert(fid1_vc != -1);
+
+ Vector3d common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
+ common_edge.normalize();
+
+ // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
+ MatrixXd P(3,3);
+ VectorXd o = V.row(F(fid0,fid0_vc));
+ VectorXd tmp = -N0.cross(common_edge);
+ P << common_edge, tmp, N0;
+ P.transposeInPlace();
+
+
+ MatrixXd V0(3,3);
+ V0.row(0) = V.row(F(fid0,0)).transpose() -o;
+ V0.row(1) = V.row(F(fid0,1)).transpose() -o;
+ V0.row(2) = V.row(F(fid0,2)).transpose() -o;
+
+ V0 = (P*V0.transpose()).transpose();
+
+ assert(V0(0,2) < 10e-10);
+ assert(V0(1,2) < 10e-10);
+ assert(V0(2,2) < 10e-10);
+
+ MatrixXd V1(3,3);
+ V1.row(0) = V.row(F(fid1,0)).transpose() -o;
+ V1.row(1) = V.row(F(fid1,1)).transpose() -o;
+ V1.row(2) = V.row(F(fid1,2)).transpose() -o;
+ V1 = (P*V1.transpose()).transpose();
+
+ assert(V1(fid1_vc,2) < 10e-10);
+ assert(V1((fid1_vc+1)%3,2) < 10e-10);
+
+ // compute rotation R such that R * N1 = N0
+ // i.e. map both triangles to the same plane
+ double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
+
+ MatrixXd R(3,3);
+ R << 1, 0, 0,
+ 0, cos(alpha), -sin(alpha) ,
+ 0, sin(alpha), cos(alpha);
+ V1 = (R*V1.transpose()).transpose();
+
+ assert(V1(0,2) < 10e-10);
+ assert(V1(1,2) < 10e-10);
+ assert(V1(2,2) < 10e-10);
+
+ // measure the angle between the reference frames
+ // k_ij is the angle between the triangle on the left and the one on the right
+ VectorXd ref0 = V0.row(1) - V0.row(0);
+ VectorXd ref1 = V1.row(1) - V1.row(0);
+
+ ref0.normalize();
+ ref1.normalize();
+
+ double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
+
+ // just to be sure, rotate ref0 using angle ktemp...
+ MatrixXd R2(2,2);
+ R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
+
+ tmp = R2*ref0.head<2>();
+
+ assert(tmp(0) - ref1(0) < (0.000001));
+ assert(tmp(1) - ref1(1) < (0.000001));
+
+ k[eid] = ktemp;
+ }
+ }
+
+}
+
+
+ void FrameInterpolator::frame2canonical(const Eigen::MatrixXd& TP, const Eigen::RowVectorXd& v, double& theta, Eigen::VectorXd& S_v)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ RowVectorXd v0 = v.segment<3>(0);
+ RowVectorXd v1 = v.segment<3>(3);
+
+ // Project onto the tangent plane
+ Vector2d vp0 = TP * v0.transpose();
+ Vector2d vp1 = TP * v1.transpose();
+
+ // Assemble matrix
+ MatrixXd M(2,2);
+ M << vp0, vp1;
+
+ if (M.determinant() < 0)
+ M.col(1) = -M.col(1);
+
+ assert(M.determinant() > 0);
+
+ // cerr << "M: " << M << endl;
+
+ MatrixXd R,S;
+ PolarDecomposition(M,R,S);
+
+ // Finally, express the cross field as an angle
+ theta = atan2(R(1,0),R(0,0));
+
+ MatrixXd R2(2,2);
+ R2 << cos(theta), -sin(theta), sin(theta), cos(theta);
+
+ assert((R2-R).norm() < 10e-8);
+
+ // Convert into rotation invariant form
+ S = R * S * R.inverse();
+
+ // Copy in vector form
+ S_v = VectorXd(3);
+ S_v << S(0,0), S(0,1), S(1,1);
+}
+
+ void FrameInterpolator::canonical2frame(const Eigen::MatrixXd& TP, const double theta, const Eigen::VectorXd& S_v, Eigen::RowVectorXd& v)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ assert(S_v.size() == 3);
+
+ MatrixXd S_temp(2,2);
+ S_temp << S_v(0), S_v(1), S_v(1), S_v(2);
+
+ // Convert angle in vector in the tangent plane
+ // Vector2d vp(cos(theta),sin(theta));
+
+ // First reconstruct R
+ MatrixXd R(2,2);
+
+ R << cos(theta), -sin(theta), sin(theta), cos(theta);
+
+ // Rotation invariant reconstruction
+ MatrixXd M = S_temp * R;
+
+ Vector2d vp0(M(0,0),M(1,0));
+ Vector2d vp1(M(0,1),M(1,1));
+
+ // Unproject the vectors
+ RowVectorXd v0 = vp0.transpose() * TP;
+ RowVectorXd v1 = vp1.transpose() * TP;
+
+ v.resize(6);
+ v << v0, v1;
+}
+
+void FrameInterpolator::solve()
+{
+ interpolateCross();
+ interpolateSymmetric();
+}
+
+void FrameInterpolator::interpolateSymmetric()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // Generate uniform Laplacian matrix
+ typedef Eigen::Triplet<double> triplet;
+ std::vector<triplet> triplets;
+
+ // Variables are stacked as x1,y1,z1,x2,y2,z2
+ triplets.reserve(3*4*F.rows());
+
+ MatrixXd b = MatrixXd::Zero(3*F.rows(),1);
+
+ // Build L and b
+ for (unsigned eid=0; eid<EF.rows(); ++eid)
+ {
+ if (!isBorderEdge[eid])
+ {
+ for (int z=0;z<2;++z)
+ {
+ // W = [w_a, w_b
+ // w_b, w_c]
+ //
+
+ // It is not symmetric
+ int i = EF(eid,z==0?0:1);
+ int j = EF(eid,z==0?1:0);
+
+ int w_a_0 = (i*3)+0;
+ int w_b_0 = (i*3)+1;
+ int w_c_0 = (i*3)+2;
+
+ int w_a_1 = (j*3)+0;
+ int w_b_1 = (j*3)+1;
+ int w_c_1 = (j*3)+2;
+
+ // Rotation to change frame
+ double r_a = cos(z==1?k(eid):-k(eid));
+ double r_b = -sin(z==1?k(eid):-k(eid));
+ double r_c = sin(z==1?k(eid):-k(eid));
+ double r_d = cos(z==1?k(eid):-k(eid));
+
+ // First term
+ // w_a_0 = r_a^2 w_a_1 + 2 r_a r_b w_b_1 + r_b^2 w_c_1 = 0
+ triplets.push_back(triplet(w_a_0,w_a_0, -1 ));
+ triplets.push_back(triplet(w_a_0,w_a_1, r_a*r_a ));
+ triplets.push_back(triplet(w_a_0,w_b_1, 2 * r_a*r_b ));
+ triplets.push_back(triplet(w_a_0,w_c_1, r_b*r_b ));
+
+ // Second term
+ // w_b_0 = r_a r_c w_a + (r_b r_c + r_a r_d) w_b + r_b r_d w_c
+ triplets.push_back(triplet(w_b_0,w_b_0, -1 ));
+ triplets.push_back(triplet(w_b_0,w_a_1, r_a*r_c ));
+ triplets.push_back(triplet(w_b_0,w_b_1, r_b*r_c + r_a*r_d ));
+ triplets.push_back(triplet(w_b_0,w_c_1, r_b*r_d ));
+
+ // Third term
+ // w_c_0 = r_c^2 w_a + 2 r_c r_d w_b + r_d^2 w_c
+ triplets.push_back(triplet(w_c_0,w_c_0, -1 ));
+ triplets.push_back(triplet(w_c_0,w_a_1, r_c*r_c ));
+ triplets.push_back(triplet(w_c_0,w_b_1, 2 * r_c*r_d ));
+ triplets.push_back(triplet(w_c_0,w_c_1, r_d*r_d ));
+ }
+ }
+ }
+
+ SparseMatrix<double> L(3*F.rows(),3*F.rows());
+ L.setFromTriplets(triplets.begin(), triplets.end());
+
+ triplets.clear();
+
+ // Add soft constraints
+ double w = 100000;
+ for (unsigned fid=0; fid < F.rows(); ++fid)
+ {
+ if (S_c[fid])
+ {
+ for (unsigned i=0;i<3;++i)
+ {
+ triplets.push_back(triplet(3*fid + i,3*fid + i,w));
+ b(3*fid + i) += w*S(fid,i);
+ }
+ }
+ }
+
+ SparseMatrix<double> soft(3*F.rows(),3*F.rows());
+ soft.setFromTriplets(triplets.begin(), triplets.end());
+
+ SparseMatrix<double> M;
+
+ M = L + soft;
+
+ // Solve Lx = b;
+
+ SparseLU<SparseMatrix<double> > solver;
+
+ solver.compute(M);
+
+ if(solver.info()!=Success)
+ {
+ std::cerr << "LU failed - frame_interpolator.cpp" << std::endl;
+ assert(0);
+ }
+
+ MatrixXd x;
+ x = solver.solve(b);
+
+ if(solver.info()!=Success)
+ {
+ std::cerr << "Linear solve failed - frame_interpolator.cpp" << std::endl;
+ assert(0);
+ }
+
+ S = MatrixXd::Zero(F.rows(),3);
+
+ // Copy back the result
+ for (unsigned i=0;i<F.rows();++i)
+ S.row(i) << x(i*3+0), x(i*3+1), x(i*3+2);
+
+}
+
+void FrameInterpolator::setConstraint(const int fid, const Eigen::VectorXd& v)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ double t_;
+ VectorXd S_;
+
+ frame2canonical(TPs[fid],v,t_,S_);
+
+ Eigen::RowVectorXd v2;
+ canonical2frame(TPs[fid], t_, S_, v2);
+
+ thetas(fid) = t_;
+ thetas_c[fid] = true;
+
+ S.row(fid) = S_;
+ S_c[fid] = true;
+
+}
+
+Eigen::MatrixXd FrameInterpolator::getFieldPerFace()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ MatrixXd R(F.rows(),6);
+ for (unsigned i=0; i<F.rows(); ++i)
+ {
+ RowVectorXd v;
+ canonical2frame(TPs[i],thetas(i),S.row(i),v);
+ R.row(i) = v;
+ }
+ return R;
+}
+
+ void FrameInterpolator::PolarDecomposition(Eigen::MatrixXd V, Eigen::MatrixXd& U, Eigen::MatrixXd& P)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // Polar Decomposition
+ JacobiSVD<MatrixXd> svd(V,Eigen::ComputeFullU | Eigen::ComputeFullV);
+
+ U = svd.matrixU() * svd.matrixV().transpose();
+ P = svd.matrixV() * svd.singularValues().asDiagonal() * svd.matrixV().transpose();
+}
+
+}
+}
+}
+
+IGL_INLINE void igl::copyleft::comiso::frame_field(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc1,
+ const Eigen::MatrixXd& bc2,
+ Eigen::MatrixXd& FF1,
+ Eigen::MatrixXd& FF2
+ )
+
+{
+ using namespace std;
+ using namespace Eigen;
+
+ assert(b.size() > 0);
+
+ // Init Solver
+ FrameInterpolator field(V,F);
+
+ for (unsigned i=0; i<b.size(); ++i)
+ {
+ VectorXd t(6); t << bc1.row(i).transpose(), bc2.row(i).transpose();
+ field.setConstraint(b(i), t);
+ }
+
+ // Solve
+ field.solve();
+
+ // Copy back
+ MatrixXd R = field.getFieldPerFace();
+ FF1 = R.block(0, 0, R.rows(), 3);
+ FF2 = R.block(0, 3, R.rows(), 3);
+}
diff --git a/xs/src/igl/copyleft/comiso/frame_field.h b/xs/src/igl/copyleft/comiso/frame_field.h
new file mode 100644
index 000000000..a43d464c7
--- /dev/null
+++ b/xs/src/igl/copyleft/comiso/frame_field.h
@@ -0,0 +1,57 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COMISO_FRAMEFIELD_H
+#define IGL_COMISO_FRAMEFIELD_H
+
+#include <igl/igl_inline.h>
+#include <igl/PI.h>
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl
+{
+namespace copyleft
+{
+namespace comiso
+{
+// Generate a piecewise-constant frame-field field from a sparse set of constraints on faces
+// using the algorithm proposed in:
+// Frame Fields: Anisotropic and Non-Orthogonal Cross Fields
+// Daniele Panozzo, Enrico Puppo, Marco Tarini, Olga Sorkine-Hornung,
+// ACM Transactions on Graphics (SIGGRAPH, 2014)
+//
+// Inputs:
+// V #V by 3 list of mesh vertex coordinates
+// F #F by 3 list of mesh faces (must be triangles)
+// b #B by 1 list of constrained face indices
+// bc1 #B by 3 list of the constrained first representative vector of the frame field (up to permutation and sign)
+// bc2 #B by 3 list of the constrained second representative vector of the frame field (up to permutation and sign)
+//
+// Outputs:
+// FF1 #F by 3 the first representative vector of the frame field (up to permutation and sign)
+// FF2 #F by 3 the second representative vector of the frame field (up to permutation and sign)
+//
+// TODO: it now supports only soft constraints, should be extended to support both hard and soft constraints
+IGL_INLINE void frame_field(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc1,
+ const Eigen::MatrixXd& bc2,
+ Eigen::MatrixXd& FF1,
+ Eigen::MatrixXd& FF2
+ );
+}
+}
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "frame_field.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/comiso/miq.cpp b/xs/src/igl/copyleft/comiso/miq.cpp
new file mode 100644
index 000000000..ecf3d282b
--- /dev/null
+++ b/xs/src/igl/copyleft/comiso/miq.cpp
@@ -0,0 +1,1534 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>, Kevin Walliman <wkevin@student.ethz.ch>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "miq.h"
+#include "../../local_basis.h"
+#include "../../triangle_triangle_adjacency.h"
+#include "../../cut_mesh.h"
+#include "../../LinSpaced.h"
+
+// includes for VertexIndexing
+#include "../../HalfEdgeIterator.h"
+#include "../../is_border_vertex.h"
+#include "../../vertex_triangle_adjacency.h"
+
+// includes for PoissonSolver
+#include "../../slice_into.h"
+#include "../../grad.h"
+#include "../../cotmatrix.h"
+#include "../../doublearea.h"
+#include <gmm/gmm.h>
+#include <CoMISo/Solver/ConstrainedSolver.hh>
+#include <CoMISo/Solver/MISolver.hh>
+#include <CoMISo/Solver/GMM_Tools.hh>
+
+//
+#include "../../cross_field_missmatch.h"
+#include "../../comb_frame_field.h"
+#include "../../comb_cross_field.h"
+#include "../../cut_mesh_from_singularities.h"
+#include "../../find_cross_field_singularities.h"
+#include "../../compute_frame_field_bisectors.h"
+#include "../../rotate_vectors.h"
+
+#ifndef NDEBUG
+#include <fstream>
+#endif
+#include <iostream>
+#include "../../matlab_format.h"
+
+#define DEBUGPRINT 0
+
+
+namespace igl {
+namespace copyleft {
+namespace comiso {
+ struct SeamInfo
+ {
+ int v0,v0p;
+ int integerVar;
+ unsigned char MMatch;
+
+ IGL_INLINE SeamInfo(int _v0,
+ int _v0p,
+ int _MMatch,
+ int _integerVar);
+
+ IGL_INLINE SeamInfo(const SeamInfo &S1);
+ };
+
+ struct MeshSystemInfo
+ {
+ ////number of vertices variables
+ int num_vert_variables;
+ ///num of integer for cuts
+ int num_integer_cuts;
+ ///this are used for drawing purposes
+ std::vector<SeamInfo> EdgeSeamInfo;
+ };
+
+
+ template <typename DerivedV, typename DerivedF>
+ class VertexIndexing
+ {
+ public:
+ // Input:
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ const Eigen::PlainObjectBase<DerivedV> &Vcut;
+ const Eigen::PlainObjectBase<DerivedF> &Fcut;
+ const Eigen::PlainObjectBase<DerivedF> &TT;
+ const Eigen::PlainObjectBase<DerivedF> &TTi;
+
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_MMatch;
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &Handle_Singular; // bool
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_Seams; // 3 bool
+
+
+ ///this handle for mesh TODO: move with the other global variables
+ MeshSystemInfo Handle_SystemInfo;
+
+ IGL_INLINE VertexIndexing(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_Vcut,
+ const Eigen::PlainObjectBase<DerivedF> &_Fcut,
+ const Eigen::PlainObjectBase<DerivedF> &_TT,
+ const Eigen::PlainObjectBase<DerivedF> &_TTi,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &_Handle_MMatch,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &_Handle_Singular,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &_Handle_Seams
+ );
+
+ // provide information about every vertex per seam
+ IGL_INLINE void InitSeamInfo();
+
+
+ private:
+ struct VertexInfo{
+ int v; // vertex index (according to V)
+ int f0, k0; // face and local edge information of the edge that connects this vertex to the previous vertex (previous in the vector)
+ int f1, k1; // face and local edge information of the other face corresponding to the same edge
+ VertexInfo(int _v, int _f0, int _k0, int _f1, int _k1) :
+ v(_v), f0(_f0), k0(_k0), f1(_f1), k1(_k1){}
+ bool operator==(VertexInfo const& other){
+ return other.v == v;
+ }
+ };
+
+ IGL_INLINE void GetSeamInfo(const int f0,
+ const int f1,
+ const int indexE,
+ int &v0,int &v1,
+ int &v0p,int &v1p,
+ unsigned char &_MMatch);
+
+ IGL_INLINE std::vector<std::vector<VertexInfo> > GetVerticesPerSeam();
+ };
+
+
+ template <typename DerivedV, typename DerivedF>
+ class PoissonSolver
+ {
+
+ public:
+ IGL_INLINE void SolvePoisson(Eigen::VectorXd Stiffness,
+ double vector_field_scale=0.1f,
+ double grid_res=1.f,
+ bool direct_round=true,
+ int localIter=0,
+ bool _integer_rounding=true,
+ bool _singularity_rounding=true,
+ std::vector<int> roundVertices = std::vector<int>(),
+ std::vector<std::vector<int> > hardFeatures = std::vector<std::vector<int> >());
+
+ IGL_INLINE PoissonSolver(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_Vcut,
+ const Eigen::PlainObjectBase<DerivedF> &_Fcut,
+ const Eigen::PlainObjectBase<DerivedF> &_TT,
+ const Eigen::PlainObjectBase<DerivedF> &_TTi,
+ const Eigen::PlainObjectBase<DerivedV> &_PD1,
+ const Eigen::PlainObjectBase<DerivedV> &_PD2,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1>&_Handle_Singular,
+ const MeshSystemInfo &_Handle_SystemInfo
+ );
+
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ const Eigen::PlainObjectBase<DerivedV> &Vcut;
+ const Eigen::PlainObjectBase<DerivedF> &Fcut;
+ const Eigen::PlainObjectBase<DerivedF> &TT;
+ const Eigen::PlainObjectBase<DerivedF> &TTi;
+ const Eigen::PlainObjectBase<DerivedV> &PD1;
+ const Eigen::PlainObjectBase<DerivedV> &PD2;
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &Handle_Singular; // bool
+
+ const MeshSystemInfo &Handle_SystemInfo;
+
+ // Internal:
+ Eigen::VectorXd Handle_Stiffness;
+ std::vector<std::vector<int> > VF;
+ std::vector<std::vector<int> > VFi;
+ Eigen::MatrixXd UV; // this is probably useless
+
+ // Output:
+ // per wedge UV coordinates, 6 coordinates (1 face) per row
+ Eigen::MatrixXd WUV;
+ // per vertex UV coordinates, Vcut.rows() x 2
+ Eigen::MatrixXd UV_out;
+
+ // Matrices
+ Eigen::SparseMatrix<double> Lhs;
+ Eigen::SparseMatrix<double> Constraints;
+ Eigen::VectorXd rhs;
+ Eigen::VectorXd constraints_rhs;
+ ///vector of unknowns
+ std::vector< double > X;
+
+ ////REAL PART
+ ///number of fixed vertex
+ unsigned int n_fixed_vars;
+
+ ///the number of REAL variables for vertices
+ unsigned int n_vert_vars;
+
+ ///total number of variables of the system,
+ ///do not consider constraints, but consider integer vars
+ unsigned int num_total_vars;
+
+ //////INTEGER PART
+ ///the total number of integer variables
+ unsigned int n_integer_vars;
+
+ ///CONSTRAINT PART
+ ///number of cuts constraints
+ unsigned int num_cut_constraint;
+
+ // number of user-defined constraints
+ unsigned int num_userdefined_constraint;
+
+ ///total number of constraints equations
+ unsigned int num_constraint_equations;
+
+ ///vector of blocked vertices
+ std::vector<int> Hard_constraints;
+
+ ///vector of indexes to round
+ std::vector<int> ids_to_round;
+
+ ///vector of indexes to round
+ std::vector<std::vector<int > > userdefined_constraints;
+
+ ///boolean that is true if rounding to integer is needed
+ bool integer_rounding;
+
+ ///START COMMON MATH FUNCTIONS
+ ///return the complex encoding the rotation
+ ///for a given missmatch interval
+ IGL_INLINE std::complex<double> GetRotationComplex(int interval);
+ ///END COMMON MATH FUNCTIONS
+
+ ///START FIXING VERTICES
+ ///set a given vertex as fixed
+ IGL_INLINE void AddFixedVertex(int v);
+
+ ///find vertex to fix in case we're using
+ ///a vector field NB: multiple components not handled
+ IGL_INLINE void FindFixedVertField();
+
+ ///find hard constraint depending if using or not
+ ///a vector field
+ IGL_INLINE void FindFixedVert();
+
+ IGL_INLINE int GetFirstVertexIndex(int v);
+
+ ///fix the vertices which are flagged as fixed
+ IGL_INLINE void FixBlockedVertex();
+ ///END FIXING VERTICES
+
+ ///HANDLING SINGULARITY
+ //set the singularity round to integer location
+ IGL_INLINE void AddSingularityRound();
+
+ IGL_INLINE void AddToRoundVertices(std::vector<int> ids);
+
+ ///START GENERIC SYSTEM FUNCTIONS
+ //build the laplacian matrix cyclyng over all rangemaps
+ //and over all faces
+ IGL_INLINE void BuildLaplacianMatrix(double vfscale=1);
+
+ ///find different sized of the system
+ IGL_INLINE void FindSizes();
+
+ IGL_INLINE void AllocateSystem();
+
+ ///intitialize the whole matrix
+ IGL_INLINE void InitMatrix();
+
+ ///map back coordinates after that
+ ///the system has been solved
+ IGL_INLINE void MapCoords();
+ ///END GENERIC SYSTEM FUNCTIONS
+
+ ///set the constraints for the inter-range cuts
+ IGL_INLINE void BuildSeamConstraintsExplicitTranslation();
+
+ ///set the constraints for the inter-range cuts
+ IGL_INLINE void BuildUserDefinedConstraints();
+
+ ///call of the mixed integer solver
+ IGL_INLINE void MixedIntegerSolve(double cone_grid_res=1,
+ bool direct_round=true,
+ int localIter=0);
+
+ IGL_INLINE void clearUserConstraint();
+
+ IGL_INLINE void addSharpEdgeConstraint(int fid, int vid);
+
+ };
+
+ template <typename DerivedV, typename DerivedF, typename DerivedU>
+ class MIQ_class
+ {
+ private:
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ DerivedV Vcut;
+ DerivedF Fcut;
+ Eigen::MatrixXd UV_out;
+ DerivedF FUV_out;
+
+ // internal
+ DerivedF TT;
+ DerivedF TTi;
+
+ // Stiffness per face
+ Eigen::VectorXd Handle_Stiffness;
+ DerivedV B1, B2, B3;
+
+ public:
+ IGL_INLINE MIQ_class(const Eigen::PlainObjectBase<DerivedV> &V_,
+ const Eigen::PlainObjectBase<DerivedF> &F_,
+ const Eigen::PlainObjectBase<DerivedV> &PD1_combed,
+ const Eigen::PlainObjectBase<DerivedV> &PD2_combed,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_MMatch,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &Handle_Singular,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_Seams,
+ Eigen::PlainObjectBase<DerivedU> &UV,
+ Eigen::PlainObjectBase<DerivedF> &FUV,
+ double GradientSize = 30.0,
+ double Stiffness = 5.0,
+ bool DirectRound = false,
+ int iter = 5,
+ int localIter = 5,
+ bool DoRound = true,
+ bool SingularityRound=true,
+ std::vector<int> roundVertices = std::vector<int>(),
+ std::vector<std::vector<int> > hardFeatures = std::vector<std::vector<int> >());
+
+
+ IGL_INLINE void extractUV(Eigen::PlainObjectBase<DerivedU> &UV_out,
+ Eigen::PlainObjectBase<DerivedF> &FUV_out);
+
+ private:
+ IGL_INLINE int NumFlips(const Eigen::MatrixXd& WUV);
+
+ IGL_INLINE double Distortion(int f, double h, const Eigen::MatrixXd& WUV);
+
+ IGL_INLINE double LaplaceDistortion(const int f, double h, const Eigen::MatrixXd& WUV);
+
+ IGL_INLINE bool updateStiffeningJacobianDistorsion(double grad_size, const Eigen::MatrixXd& WUV);
+
+ IGL_INLINE bool IsFlipped(const Eigen::Vector2d &uv0,
+ const Eigen::Vector2d &uv1,
+ const Eigen::Vector2d &uv2);
+
+ IGL_INLINE bool IsFlipped(const int i, const Eigen::MatrixXd& WUV);
+
+ };
+};
+};
+}
+
+IGL_INLINE igl::copyleft::comiso::SeamInfo::SeamInfo(int _v0,
+ int _v0p,
+ int _MMatch,
+ int _integerVar)
+{
+ v0=_v0;
+ v0p=_v0p;
+ integerVar=_integerVar;
+ MMatch=_MMatch;
+}
+
+IGL_INLINE igl::copyleft::comiso::SeamInfo::SeamInfo(const SeamInfo &S1)
+{
+ v0=S1.v0;
+ v0p=S1.v0p;
+ integerVar=S1.integerVar;
+ MMatch=S1.MMatch;
+}
+
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE igl::copyleft::comiso::VertexIndexing<DerivedV, DerivedF>::VertexIndexing(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_Vcut,
+ const Eigen::PlainObjectBase<DerivedF> &_Fcut,
+ const Eigen::PlainObjectBase<DerivedF> &_TT,
+ const Eigen::PlainObjectBase<DerivedF> &_TTi,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &_Handle_MMatch,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &_Handle_Singular,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &_Handle_Seams
+ ):
+V(_V),
+F(_F),
+Vcut(_Vcut),
+Fcut(_Fcut),
+TT(_TT),
+TTi(_TTi),
+Handle_MMatch(_Handle_MMatch),
+Handle_Singular(_Handle_Singular),
+Handle_Seams(_Handle_Seams)
+{
+ #ifdef DEBUG_PRINT
+ cerr<<igl::matlab_format(Handle_Seams,"Handle_Seams");
+#endif
+
+ Handle_SystemInfo.num_vert_variables=Vcut.rows();
+ Handle_SystemInfo.num_integer_cuts=0;
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::VertexIndexing<DerivedV, DerivedF>::GetSeamInfo(const int f0,
+ const int f1,
+ const int indexE,
+ int &v0,int &v1,
+ int &v0p,int &v1p,
+ unsigned char &_MMatch)
+{
+ int edgef0 = indexE;
+ v0 = Fcut(f0,edgef0);
+ v1 = Fcut(f0,(edgef0+1)%3);
+ ////get the index on opposite side
+ assert(TT(f0,edgef0) == f1);
+ int edgef1 = TTi(f0,edgef0);
+ v1p = Fcut(f1,edgef1);
+ v0p = Fcut(f1,(edgef1+1)%3);
+
+ _MMatch = Handle_MMatch(f0,edgef0);
+ assert(F(f0,edgef0) == F(f1,((edgef1+1)%3)));
+ assert(F(f0,((edgef0+1)%3)) == F(f1,edgef1));
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE std::vector<std::vector<typename igl::copyleft::comiso::VertexIndexing<DerivedV, DerivedF>::VertexInfo> > igl::copyleft::comiso::VertexIndexing<DerivedV, DerivedF>::GetVerticesPerSeam()
+{
+ // Return value
+ std::vector<std::vector<VertexInfo> >verticesPerSeam;
+
+ // for every vertex, keep track of their adjacent vertices on seams.
+ // regular vertices have two neighbors on a seam, start- and endvertices may have any other numbers of neighbors (e.g. 1 or 3)
+ std::vector<std::list<VertexInfo> > VVSeam(V.rows());
+ Eigen::MatrixXi F_hit = Eigen::MatrixXi::Zero(F.rows(), 3);
+ for (unsigned int f=0; f<F.rows();f++)
+ {
+ int f0 = f;
+ for(int k0=0; k0<3; k0++){
+ int f1 = TT(f0,k0);
+ if(f1 == -1)
+ continue;
+
+ bool seam = Handle_Seams(f0,k0);
+ if (seam && F_hit(f0,k0) == 0)
+ {
+ int v0 = F(f0, k0);
+ int v1 = F(f0, (k0+1)%3);
+ int k1 = TTi(f0,k0);
+ VVSeam[v0].push_back(VertexInfo(v1, f0, k0, f1, k1));
+ VVSeam[v1].push_back(VertexInfo(v0, f0, k0, f1, k1));
+ F_hit(f0, k0) = 1;
+ F_hit(f1, k1) = 1;
+ }
+ }
+ }
+
+ // Find start vertices, i.e. vertices that start or end a seam branch
+ std::vector<int> startVertexIndices;
+ std::vector<bool> isStartVertex(V.rows());
+ for (unsigned int i=0;i<V.rows();i++)
+ {
+ isStartVertex[i] = false;
+ // vertices with two neighbors are regular vertices, unless the vertex is a singularity, in which case it qualifies as a start vertex
+ if (VVSeam[i].size() > 0 && VVSeam[i].size() != 2 || Handle_Singular(i) == true)
+ {
+ startVertexIndices.push_back(i);
+ isStartVertex[i] = true;
+ }
+ }
+
+ // For each startVertex, walk along its seam
+ for (unsigned int i=0;i<startVertexIndices.size();i++)
+ {
+ auto startVertexNeighbors = &VVSeam[startVertexIndices[i]];
+ const int neighborSize = startVertexNeighbors->size();
+
+ // explore every seam to which this vertex is a start vertex
+ // note: a vertex can never be a start vertex and a regular vertex simultaneously
+ for (unsigned int j=0;j<neighborSize;j++)
+ {
+ std::vector<VertexInfo> thisSeam; // temporary container
+
+ // Create vertexInfo struct for start vertex
+ auto startVertex = VertexInfo(startVertexIndices[i], -1, -1, -1, -1);// -1 values are arbitrary (will never be used)
+ auto currentVertex = startVertex;
+ // Add start vertex to the seam
+ thisSeam.push_back(currentVertex);
+
+ // advance on the seam
+ auto currentVertexNeighbors = startVertexNeighbors;
+ auto nextVertex = currentVertexNeighbors->front();
+ currentVertexNeighbors->pop_front();
+
+ auto prevVertex = startVertex; // bogus initialization to get the type
+ while (true)
+ {
+ // move to the next vertex
+ prevVertex = currentVertex;
+ currentVertex = nextVertex;
+ currentVertexNeighbors = &VVSeam[nextVertex.v];
+
+ // add current vertex to this seam
+ thisSeam.push_back(currentVertex);
+
+ // remove the previous vertex
+ auto it = std::find(currentVertexNeighbors->begin(), currentVertexNeighbors->end(), prevVertex);
+ assert(it != currentVertexNeighbors->end());
+ currentVertexNeighbors->erase(it);
+
+ if (currentVertexNeighbors->size() == 1 && !isStartVertex[currentVertex.v])
+ {
+ nextVertex = currentVertexNeighbors->front();
+ currentVertexNeighbors->pop_front();
+ }
+ else
+ break;
+ }
+ verticesPerSeam.push_back(thisSeam);
+ }
+ }
+
+ return verticesPerSeam;
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::VertexIndexing<DerivedV, DerivedF>::InitSeamInfo()
+{
+ auto verticesPerSeam = GetVerticesPerSeam();
+ Handle_SystemInfo.EdgeSeamInfo.clear();
+ int integerVar = 0;
+ // Loop over each seam
+ for(auto seam : verticesPerSeam){
+ //choose initial side of the seam such that the start vertex corresponds to Fcut(f, k) and the end vertex corresponds to Fcut(f, (k+1)%3) and not vice versa.
+ int priorVertexIdx;
+ if(seam.size() > 2){
+ auto v1 = seam[1];
+ auto v2 = seam[2];
+ if(Fcut(v1.f0, (v1.k0+1) % 3) == Fcut(v2.f0, v2.k0) || Fcut(v1.f0, (v1.k0+1) % 3) == Fcut(v2.f1, v2.k1)){
+ priorVertexIdx = Fcut(v1.f0, v1.k0);
+ }
+ else{
+ priorVertexIdx = Fcut(v1.f1, v1.k1);
+ assert(Fcut(v1.f1, (v1.k1+1) % 3) == Fcut(v2.f0, v2.k0) || Fcut(v1.f1, (v1.k1+1) % 3) == Fcut(v2.f1, v2.k1));
+ }
+ }
+ else{
+ auto v1 = seam[1];
+ priorVertexIdx = Fcut(v1.f0, v1.k0);
+ }
+
+ // Loop over each vertex of the seam
+ for(auto it=seam.begin()+1; it != seam.end(); ++it){
+ auto vertex = *it;
+ // choose the correct side of the seam
+ int f,k,ff,kk;
+ if(priorVertexIdx == Fcut(vertex.f0, vertex.k0)){
+ f = vertex.f0; ff = vertex.f1;
+ k = vertex.k0; kk = vertex.k1;
+ }
+ else{
+ f = vertex.f1; ff = vertex.f0;
+ k = vertex.k1; kk = vertex.k0;
+ assert(priorVertexIdx == Fcut(vertex.f1, vertex.k1));
+ }
+
+ int vtx0,vtx0p,vtx1,vtx1p;
+ unsigned char MM;
+ GetSeamInfo(f,ff,k,vtx0,vtx1,vtx0p,vtx1p,MM);
+ Handle_SystemInfo.EdgeSeamInfo.push_back(SeamInfo(vtx0,vtx0p,MM,integerVar));
+ if(it == seam.end() -1){
+ Handle_SystemInfo.EdgeSeamInfo.push_back(SeamInfo(vtx1,vtx1p,MM,integerVar));
+ }
+ priorVertexIdx = vtx1;
+ }
+ // use the same integer for each seam
+ integerVar++;
+ }
+ Handle_SystemInfo.num_integer_cuts = integerVar;
+
+#ifndef NDEBUG
+ int totalNVerticesOnSeams = 0;
+ for(auto seam : verticesPerSeam){
+ totalNVerticesOnSeams += seam.size();
+ }
+ assert(Handle_SystemInfo.EdgeSeamInfo.size() == totalNVerticesOnSeams);
+#endif
+}
+
+
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::SolvePoisson(Eigen::VectorXd Stiffness,
+ double vector_field_scale,
+ double grid_res,
+ bool direct_round,
+ int localIter,
+ bool _integer_rounding,
+ bool _singularity_rounding,
+ std::vector<int> roundVertices,
+ std::vector<std::vector<int> > hardFeatures)
+{
+ Handle_Stiffness = Stiffness;
+
+ //initialization of flags and data structures
+ integer_rounding=_integer_rounding;
+
+ ids_to_round.clear();
+
+ clearUserConstraint();
+ // copy the user constraints number
+ for (size_t i = 0; i < hardFeatures.size(); ++i)
+ {
+ addSharpEdgeConstraint(hardFeatures[i][0],hardFeatures[i][1]);
+ }
+
+ ///Initializing Matrix
+
+ int t0=clock();
+
+ ///initialize the matrix ALLOCATING SPACE
+ InitMatrix();
+ if (DEBUGPRINT)
+ printf("\n ALLOCATED THE MATRIX \n");
+
+ ///build the laplacian system
+ BuildLaplacianMatrix(vector_field_scale);
+
+ // add seam constraints
+ BuildSeamConstraintsExplicitTranslation();
+
+ // add user defined constraints
+ BuildUserDefinedConstraints();
+
+ ////add the lagrange multiplier
+ FixBlockedVertex();
+
+ if (DEBUGPRINT)
+ printf("\n BUILT THE MATRIX \n");
+
+ if (integer_rounding)
+ AddToRoundVertices(roundVertices);
+
+ if (_singularity_rounding)
+ AddSingularityRound();
+
+ int t1=clock();
+ if (DEBUGPRINT) printf("\n time:%d \n",t1-t0);
+ if (DEBUGPRINT) printf("\n SOLVING \n");
+
+ MixedIntegerSolve(grid_res,direct_round,localIter);
+
+ int t2=clock();
+ if (DEBUGPRINT) printf("\n time:%d \n",t2-t1);
+ if (DEBUGPRINT) printf("\n ASSIGNING COORDS \n");
+
+ MapCoords();
+
+ int t3=clock();
+ if (DEBUGPRINT) printf("\n time:%d \n",t3-t2);
+ if (DEBUGPRINT) printf("\n FINISHED \n");
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>
+::PoissonSolver(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_Vcut,
+ const Eigen::PlainObjectBase<DerivedF> &_Fcut,
+ const Eigen::PlainObjectBase<DerivedF> &_TT,
+ const Eigen::PlainObjectBase<DerivedF> &_TTi,
+ const Eigen::PlainObjectBase<DerivedV> &_PD1,
+ const Eigen::PlainObjectBase<DerivedV> &_PD2,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1>&_Handle_Singular,
+ const MeshSystemInfo &_Handle_SystemInfo
+):
+V(_V),
+F(_F),
+Vcut(_Vcut),
+Fcut(_Fcut),
+TT(_TT),
+TTi(_TTi),
+PD1(_PD1),
+PD2(_PD2),
+Handle_Singular(_Handle_Singular),
+Handle_SystemInfo(_Handle_SystemInfo)
+{
+ UV = Eigen::MatrixXd(V.rows(),2);
+ WUV = Eigen::MatrixXd(F.rows(),6);
+ UV_out = Eigen::MatrixXd(Vcut.rows(),2);
+ igl::vertex_triangle_adjacency(V,F,VF,VFi);
+}
+
+///START COMMON MATH FUNCTIONS
+///return the complex encoding the rotation
+///for a given missmatch interval
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE std::complex<double> igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::GetRotationComplex(int interval)
+{
+ assert((interval>=0)&&(interval<4));
+
+ switch(interval)
+ {
+ case 0:return std::complex<double>(1,0);
+ case 1:return std::complex<double>(0,1);
+ case 2:return std::complex<double>(-1,0);
+ default:return std::complex<double>(0,-1);
+ }
+}
+
+///END COMMON MATH FUNCTIONS
+
+///START FIXING VERTICES
+///set a given vertex as fixed
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::AddFixedVertex(int v)
+{
+ n_fixed_vars++;
+ Hard_constraints.push_back(v);
+}
+
+///find vertex to fix in case we're using
+///a vector field NB: multiple components not handled
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::FindFixedVertField()
+{
+ Hard_constraints.clear();
+
+ n_fixed_vars=0;
+ //fix the first singularity
+ for (unsigned int v=0;v<V.rows();v++)
+ {
+ if (Handle_Singular(v))
+ {
+ AddFixedVertex(v);
+ UV.row(v) << 0,0;
+ return;
+ }
+ }
+
+ ///if anything fixed fix the first
+ AddFixedVertex(0);
+ UV.row(0) << 0,0;
+ std::cerr << "No vertices to fix, I am fixing the first vertex to the origin!" << std::endl;
+}
+
+///find hard constraint depending if using or not
+///a vector field
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::FindFixedVert()
+{
+ Hard_constraints.clear();
+ FindFixedVertField();
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE int igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::GetFirstVertexIndex(int v)
+{
+ return Fcut(VF[v][0],VFi[v][0]);
+}
+
+///fix the vertices which are flagged as fixed
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::FixBlockedVertex()
+{
+ int offset_row = num_cut_constraint*2;
+
+ unsigned int constr_num = 0;
+ for (unsigned int i=0;i<Hard_constraints.size();i++)
+ {
+ int v = Hard_constraints[i];
+
+ ///get first index of the vertex that must blocked
+ //int index=v->vertex_index[0];
+ int index = GetFirstVertexIndex(v);
+
+ ///multiply times 2 because of uv
+ int indexvert = index*2;
+
+ ///find the first free row to add the constraint
+ int indexRow = (offset_row+constr_num*2);
+ int indexCol = indexRow;
+
+ ///add fixing constraint LHS
+ Constraints.coeffRef(indexRow, indexvert) += 1;
+ Constraints.coeffRef(indexRow+1,indexvert+1) += 1;
+
+ ///add fixing constraint RHS
+ constraints_rhs[indexCol] = UV(v,0);
+ constraints_rhs[indexCol+1] = UV(v,1);
+
+ constr_num++;
+ }
+ assert(constr_num==n_fixed_vars);
+}
+///END FIXING VERTICES
+
+///HANDLING SINGULARITY
+//set the singularity round to integer location
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::AddSingularityRound()
+{
+ for (unsigned int v=0;v<V.rows();v++)
+ {
+ if (Handle_Singular(v))
+ {
+ int index0=GetFirstVertexIndex(v);
+ ids_to_round.push_back( index0*2 );
+ ids_to_round.push_back((index0*2)+1);
+ }
+ }
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::AddToRoundVertices(std::vector<int> ids)
+{
+ for (size_t i = 0; i < ids.size(); ++i)
+ {
+ if (ids[i] < 0 || ids[i] >= V.rows())
+ std::cerr << "WARNING: Ignored round vertex constraint, vertex " << ids[i] << " does not exist in the mesh." << std::endl;
+ int index0 = GetFirstVertexIndex(ids[i]);
+ ids_to_round.push_back( index0*2 );
+ ids_to_round.push_back((index0*2)+1);
+ }
+}
+
+///START GENERIC SYSTEM FUNCTIONS
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::BuildLaplacianMatrix(double vfscale)
+{
+ Eigen::VectorXi idx = igl::LinSpaced<Eigen::VectorXi >(Vcut.rows(), 0, 2*Vcut.rows()-2);
+ Eigen::VectorXi idx2 = igl::LinSpaced<Eigen::VectorXi >(Vcut.rows(), 1, 2*Vcut.rows()-1);
+
+ // get gradient matrix
+ Eigen::SparseMatrix<double> G(Fcut.rows() * 3, Vcut.rows());
+ igl::grad(Vcut, Fcut, G);
+
+ // get triangle weights
+ Eigen::VectorXd dblA(Fcut.rows());
+ igl::doublearea(Vcut, Fcut, dblA);
+
+ // compute intermediate result
+ Eigen::SparseMatrix<double> G2;
+ G2 = G.transpose() * dblA.replicate<3,1>().asDiagonal() * Handle_Stiffness.replicate<3,1>().asDiagonal();
+
+ /// Compute LHS
+ Eigen::SparseMatrix<double> Cotmatrix;
+ Cotmatrix = 0.5 * G2 * G;
+ igl::slice_into(Cotmatrix, idx, idx, Lhs);
+ igl::slice_into(Cotmatrix, idx2, idx2, Lhs);
+
+ /// Compute RHS
+ // reshape nrosy vectors
+ const Eigen::MatrixXd u = Eigen::Map<const Eigen::MatrixXd>(PD1.data(),Fcut.rows()*3,1); // this mimics a reshape at the cost of a copy.
+ const Eigen::MatrixXd v = Eigen::Map<const Eigen::MatrixXd>(PD2.data(),Fcut.rows()*3,1); // this mimics a reshape at the cost of a copy.
+
+ // multiply with weights
+ Eigen::VectorXd rhs1 = G2 * u * 0.5 * vfscale;
+ Eigen::VectorXd rhs2 = -G2 * v * 0.5 * vfscale;
+ igl::slice_into(rhs1, idx, 1, rhs);
+ igl::slice_into(rhs2, idx2, 1, rhs);
+}
+
+///find different sized of the system
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::FindSizes()
+{
+ ///find the vertex that need to be fixed
+ FindFixedVert();
+
+ ///REAL PART
+ n_vert_vars = Handle_SystemInfo.num_vert_variables;
+
+ ///INTEGER PART
+ ///the total number of integer variables
+ n_integer_vars = Handle_SystemInfo.num_integer_cuts;
+
+ ///CONSTRAINT PART
+ num_cut_constraint = Handle_SystemInfo.EdgeSeamInfo.size();
+
+ num_constraint_equations = num_cut_constraint * 2 + n_fixed_vars * 2 + num_userdefined_constraint;
+
+ ///total variable of the system
+ num_total_vars = (n_vert_vars+n_integer_vars) * 2;
+
+ ///initialize matrix size
+
+ if (DEBUGPRINT) printf("\n*** SYSTEM VARIABLES *** \n");
+ if (DEBUGPRINT) printf("* NUM REAL VERTEX VARIABLES %d \n",n_vert_vars);
+
+ if (DEBUGPRINT) printf("\n*** INTEGER VARIABLES *** \n");
+ if (DEBUGPRINT) printf("* NUM INTEGER VARIABLES %d \n",(int)n_integer_vars);
+
+ if (DEBUGPRINT) printf("\n*** CONSTRAINTS *** \n ");
+ if (DEBUGPRINT) printf("* NUM FIXED CONSTRAINTS %d\n",n_fixed_vars);
+ if (DEBUGPRINT) printf("* NUM CUTS CONSTRAINTS %d\n",num_cut_constraint);
+ if (DEBUGPRINT) printf("* NUM USER DEFINED CONSTRAINTS %d\n",num_userdefined_constraint);
+
+ if (DEBUGPRINT) printf("\n*** TOTAL SIZE *** \n");
+ if (DEBUGPRINT) printf("* TOTAL VARIABLE SIZE (WITH INTEGER TRASL) %d \n",num_total_vars);
+ if (DEBUGPRINT) printf("* TOTAL CONSTRAINTS %d \n",num_constraint_equations);
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::AllocateSystem()
+{
+ Lhs.resize(n_vert_vars * 2, n_vert_vars * 2);
+ Constraints.resize(num_constraint_equations, num_total_vars);
+ rhs.resize(n_vert_vars * 2);
+ constraints_rhs.resize(num_constraint_equations);
+
+ printf("\n INITIALIZED SPARSE MATRIX OF %d x %d \n",n_vert_vars*2, n_vert_vars*2);
+ printf("\n INITIALIZED SPARSE MATRIX OF %d x %d \n",num_constraint_equations, num_total_vars);
+ printf("\n INITIALIZED VECTOR OF %d x 1 \n",n_vert_vars*2);
+ printf("\n INITIALIZED VECTOR OF %d x 1 \n",num_constraint_equations);
+}
+
+///intitialize the whole matrix
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::InitMatrix()
+{
+ FindSizes();
+ AllocateSystem();
+}
+
+///map back coordinates after that
+///the system has been solved
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::MapCoords()
+{
+ ///map coords to faces
+ for (unsigned int f=0;f<Fcut.rows();f++)
+ {
+
+ for (int k=0;k<3;k++)
+ {
+ //get the index of the variable in the system
+ int indexUV = Fcut(f,k);
+ ///then get U and V coords
+ double U=X[indexUV*2];
+ double V=X[indexUV*2+1];
+
+ WUV(f,k*2 + 0) = U;
+ WUV(f,k*2 + 1) = V;
+ }
+
+ }
+
+ for(int i = 0; i < Vcut.rows(); i++){
+ UV_out(i,0) = X[i*2];
+ UV_out(i,1) = X[i*2+1];
+ }
+}
+
+///END GENERIC SYSTEM FUNCTIONS
+
+///set the constraints for the inter-range cuts
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::BuildSeamConstraintsExplicitTranslation()
+{
+ ///current constraint row
+ int constr_row = 0;
+
+ for (unsigned int i=0; i<num_cut_constraint; i++)
+ {
+ unsigned char interval = Handle_SystemInfo.EdgeSeamInfo[i].MMatch;
+ if (interval==1)
+ interval=3;
+ else
+ if(interval==3)
+ interval=1;
+
+ int p0 = Handle_SystemInfo.EdgeSeamInfo[i].v0;
+ int p0p = Handle_SystemInfo.EdgeSeamInfo[i].v0p;
+
+ std::complex<double> rot = GetRotationComplex(interval);
+
+ ///get the integer variable
+ int integerVar = n_vert_vars + Handle_SystemInfo.EdgeSeamInfo[i].integerVar;
+
+ if (integer_rounding)
+ {
+ ids_to_round.push_back(integerVar*2);
+ ids_to_round.push_back(integerVar*2+1);
+ }
+
+ // cross boundary compatibility conditions
+ Constraints.coeffRef(constr_row, 2*p0) += rot.real();
+ Constraints.coeffRef(constr_row, 2*p0+1) += -rot.imag();
+ Constraints.coeffRef(constr_row+1, 2*p0) += rot.imag();
+ Constraints.coeffRef(constr_row+1, 2*p0+1) += rot.real();
+
+ Constraints.coeffRef(constr_row, 2*p0p) += -1;
+ Constraints.coeffRef(constr_row+1, 2*p0p+1) += -1;
+
+ Constraints.coeffRef(constr_row, 2*integerVar) += 1;
+ Constraints.coeffRef(constr_row+1, 2*integerVar+1) += 1;
+
+ constraints_rhs[constr_row] = 0;
+ constraints_rhs[constr_row+1] = 0;
+
+ constr_row += 2;
+ }
+
+}
+
+///set the constraints for the inter-range cuts
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::BuildUserDefinedConstraints()
+{
+ /// the user defined constraints are at the end
+ int offset_row = num_cut_constraint*2 + n_fixed_vars*2;
+
+ ///current constraint row
+ int constr_row = offset_row;
+
+ assert(num_userdefined_constraint == userdefined_constraints.size());
+
+ for (unsigned int i=0; i<num_userdefined_constraint; i++)
+ {
+ for (unsigned int j=0; j<userdefined_constraints[i].size()-1; ++j)
+ {
+ Constraints.coeffRef(constr_row, j) = userdefined_constraints[i][j];
+ }
+
+ constraints_rhs[constr_row] = userdefined_constraints[i][userdefined_constraints[i].size()-1];
+ constr_row +=1;
+ }
+}
+
+///call of the mixed integer solver
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::MixedIntegerSolve(double cone_grid_res,
+ bool direct_round,
+ int localIter)
+{
+ X = std::vector<double>((n_vert_vars+n_integer_vars)*2);
+ if (DEBUGPRINT)
+ printf("\n ALLOCATED X \n");
+
+ ///variables part
+ int ScalarSize = n_vert_vars*2;
+ int SizeMatrix = (n_vert_vars+n_integer_vars)*2;
+
+ ///matrix A
+ gmm::col_matrix< gmm::wsvector< double > > A(SizeMatrix,SizeMatrix); // lhs matrix variables
+
+ ///constraints part
+ int CsizeX = num_constraint_equations;
+ int CsizeY = SizeMatrix+1;
+ gmm::row_matrix< gmm::wsvector< double > > C(CsizeX,CsizeY); // constraints
+
+ if (DEBUGPRINT)
+ printf("\n ALLOCATED QMM STRUCTURES \n");
+
+ std::vector<double> B(SizeMatrix,0); // rhs
+
+ if (DEBUGPRINT)
+ printf("\n ALLOCATED RHS STRUCTURES \n");
+
+ //// copy LHS
+ for (int k=0; k < Lhs.outerSize(); ++k){
+ for (Eigen::SparseMatrix<double>::InnerIterator it(Lhs,k); it; ++it){
+ int row = it.row();
+ int col = it.col();
+ A(row, col) += it.value();
+ }
+ }
+ //// copy Constraints
+ for (int k=0; k < Constraints.outerSize(); ++k){
+ for (Eigen::SparseMatrix<double>::InnerIterator it(Constraints,k); it; ++it){
+ int row = it.row();
+ int col = it.col();
+ C(row, col) += it.value();
+ }
+ }
+
+ if (DEBUGPRINT)
+ printf("\n SET %d INTEGER VALUES \n",n_integer_vars);
+
+ ///add penalization term for integer variables
+ double penalization = 0.000001;
+ int offline_index = ScalarSize;
+ for(unsigned int i = 0; i < (n_integer_vars)*2; ++i)
+ {
+ int index=offline_index+i;
+ A(index,index)=penalization;
+ }
+
+ if (DEBUGPRINT)
+ printf("\n SET RHS \n");
+
+ // copy RHS
+ for(int i = 0; i < (int)ScalarSize; ++i)
+ {
+ B[i] = rhs[i] * cone_grid_res;
+ }
+
+ // copy constraint RHS
+ if (DEBUGPRINT)
+ printf("\n SET %d CONSTRAINTS \n",num_constraint_equations);
+
+ for(unsigned int i = 0; i < num_constraint_equations; ++i)
+ {
+ C(i, SizeMatrix) = -constraints_rhs[i] * cone_grid_res;
+ }
+
+ COMISO::ConstrainedSolver solver;
+
+ solver.misolver().set_local_iters(localIter);
+
+ solver.misolver().set_direct_rounding(direct_round);
+
+ std::sort(ids_to_round.begin(),ids_to_round.end());
+ std::vector<int>::iterator new_end=std::unique(ids_to_round.begin(),ids_to_round.end());
+ int dist=distance(ids_to_round.begin(),new_end);
+ ids_to_round.resize(dist);
+
+ solver.solve( C, A, X, B, ids_to_round, 0.0, false, false);
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::clearUserConstraint()
+{
+ num_userdefined_constraint = 0;
+ userdefined_constraints.clear();
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::copyleft::comiso::PoissonSolver<DerivedV, DerivedF>::addSharpEdgeConstraint(int fid, int vid)
+{
+ // prepare constraint
+ std::vector<int> c(Handle_SystemInfo.num_vert_variables*2 + 1);
+
+ for (size_t i = 0; i < c.size(); ++i)
+ {
+ c[i] = 0;
+ }
+
+ int v1 = Fcut(fid,vid);
+ int v2 = Fcut(fid,(vid+1)%3);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> e = Vcut.row(v2) - Vcut.row(v1);
+ e = e.normalized();
+
+ double d1 = fabs(e.dot(PD1.row(fid).normalized()));
+ double d2 = fabs(e.dot(PD2.row(fid).normalized()));
+
+ int offset = 0;
+
+ if (d1>d2)
+ offset = 1;
+
+ ids_to_round.push_back((v1 * 2) + offset);
+ ids_to_round.push_back((v2 * 2) + offset);
+
+ // add constraint
+ c[(v1 * 2) + offset] = 1;
+ c[(v2 * 2) + offset] = -1;
+
+ // add to the user-defined constraints
+ num_userdefined_constraint++;
+ userdefined_constraints.push_back(c);
+
+}
+
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::MIQ_class(const Eigen::PlainObjectBase<DerivedV> &V_,
+ const Eigen::PlainObjectBase<DerivedF> &F_,
+ const Eigen::PlainObjectBase<DerivedV> &PD1_combed,
+ const Eigen::PlainObjectBase<DerivedV> &PD2_combed,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_MMatch,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &Handle_Singular,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_Seams,
+ Eigen::PlainObjectBase<DerivedU> &UV,
+ Eigen::PlainObjectBase<DerivedF> &FUV,
+ double GradientSize,
+ double Stiffness,
+ bool DirectRound,
+ int iter,
+ int localIter,
+ bool DoRound,
+ bool SingularityRound,
+ std::vector<int> roundVertices,
+ std::vector<std::vector<int> > hardFeatures):
+V(V_),
+F(F_)
+{
+ igl::cut_mesh(V, F, Handle_Seams, Vcut, Fcut);
+
+ igl::local_basis(V,F,B1,B2,B3);
+ igl::triangle_triangle_adjacency(F,TT,TTi);
+
+ // Prepare indexing for the linear system
+ VertexIndexing<DerivedV, DerivedF> VInd(V, F, Vcut, Fcut, TT, TTi, Handle_MMatch, Handle_Singular, Handle_Seams);
+
+ VInd.InitSeamInfo();
+
+ // Assemble the system and solve
+ PoissonSolver<DerivedV, DerivedF> PSolver(V,
+ F,
+ Vcut,
+ Fcut,
+ TT,
+ TTi,
+ PD1_combed,
+ PD2_combed,
+ Handle_Singular,
+ VInd.Handle_SystemInfo);
+ Handle_Stiffness = Eigen::VectorXd::Constant(F.rows(),1);
+
+
+ if (iter > 0) // do stiffening
+ {
+ for (int i=0;i<iter;i++)
+ {
+ PSolver.SolvePoisson(Handle_Stiffness, GradientSize,1.f,DirectRound,localIter,DoRound,SingularityRound,roundVertices,hardFeatures);
+ int nflips=NumFlips(PSolver.WUV);
+ bool folded = updateStiffeningJacobianDistorsion(GradientSize,PSolver.WUV);
+ printf("ITERATION %d FLIPS %d \n",i,nflips);
+ if (!folded)break;
+ }
+ }
+ else
+ {
+ PSolver.SolvePoisson(Handle_Stiffness,GradientSize,1.f,DirectRound,localIter,DoRound,SingularityRound,roundVertices,hardFeatures);
+ }
+
+ int nflips=NumFlips(PSolver.WUV);
+ printf("**** END OPTIMIZING #FLIPS %d ****\n",nflips);
+
+ UV_out = PSolver.UV_out;
+ FUV_out = PSolver.Fcut;
+ fflush(stdout);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE void igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::extractUV(Eigen::PlainObjectBase<DerivedU> &UV_out,
+ Eigen::PlainObjectBase<DerivedF> &FUV_out)
+{
+ UV_out = this->UV_out;
+ FUV_out = this->FUV_out;
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE int igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::NumFlips(const Eigen::MatrixXd& WUV)
+{
+ int numFl=0;
+ for (unsigned int i=0;i<F.rows();i++)
+ {
+ if (IsFlipped(i, WUV))
+ numFl++;
+ }
+ return numFl;
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE double igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::Distortion(int f, double h, const Eigen::MatrixXd& WUV)
+{
+ assert(h > 0);
+
+ Eigen::Vector2d uv0,uv1,uv2;
+
+ uv0 << WUV(f,0), WUV(f,1);
+ uv1 << WUV(f,2), WUV(f,3);
+ uv2 << WUV(f,4), WUV(f,5);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> p0 = Vcut.row(Fcut(f,0));
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> p1 = Vcut.row(Fcut(f,1));
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> p2 = Vcut.row(Fcut(f,2));
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> norm = (p1 - p0).cross(p2 - p0);
+ double area2 = norm.norm();
+ double area2_inv = 1.0 / area2;
+ norm *= area2_inv;
+
+ if (area2 > 0)
+ {
+ // Singular values of the Jacobian
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> neg_t0 = norm.cross(p2 - p1);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> neg_t1 = norm.cross(p0 - p2);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> neg_t2 = norm.cross(p1 - p0);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> diffu = (neg_t0 * uv0(0) +neg_t1 *uv1(0) + neg_t2 * uv2(0) )*area2_inv;
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> diffv = (neg_t0 * uv0(1) + neg_t1*uv1(1) + neg_t2*uv2(1) )*area2_inv;
+
+ // first fundamental form
+ double I00 = diffu.dot(diffu); // guaranteed non-neg
+ double I01 = diffu.dot(diffv); // I01 = I10
+ double I11 = diffv.dot(diffv); // guaranteed non-neg
+
+ // eigenvalues of a 2x2 matrix
+ // [a00 a01]
+ // [a10 a11]
+ // 1/2 * [ (a00 + a11) +/- sqrt((a00 - a11)^2 + 4 a01 a10) ]
+ double trI = I00 + I11; // guaranteed non-neg
+ double diffDiag = I00 - I11; // guaranteed non-neg
+ double sqrtDet = sqrt(std::max(0.0, diffDiag*diffDiag +
+ 4 * I01 * I01)); // guaranteed non-neg
+ double sig1 = 0.5 * (trI + sqrtDet); // higher singular value
+ double sig2 = 0.5 * (trI - sqrtDet); // lower singular value
+
+ // Avoid sig2 < 0 due to numerical error
+ if (fabs(sig2) < 1.0e-8)
+ sig2 = 0;
+
+ assert(sig1 >= 0);
+ assert(sig2 >= 0);
+
+ if (sig2 < 0) {
+ printf("Distortion will be NaN! sig1^2 is negative (%lg)\n",
+ sig2);
+ }
+
+ // The singular values of the Jacobian are the sqrts of the
+ // eigenvalues of the first fundamental form.
+ sig1 = sqrt(sig1);
+ sig2 = sqrt(sig2);
+
+ // distortion
+ double tao = IsFlipped(f,WUV) ? -1 : 1;
+ double factor = tao / h;
+ double lam = fabs(factor * sig1 - 1) + fabs(factor * sig2 - 1);
+ return lam;
+ }
+ else {
+ return 10; // something "large"
+ }
+}
+
+////////////////////////////////////////////////////////////////////////////
+// Approximate the distortion laplacian using a uniform laplacian on
+// the dual mesh:
+// ___________
+// \-1 / \-1 /
+// \ / 3 \ /
+// \-----/
+// \-1 /
+// \ /
+//
+// @param[in] f facet on which to compute distortion laplacian
+// @param[in] h scaling factor applied to cross field
+// @return distortion laplacian for f
+///////////////////////////////////////////////////////////////////////////
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE double igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::LaplaceDistortion(const int f, double h, const Eigen::MatrixXd& WUV)
+{
+ double mydist = Distortion(f, h, WUV);
+ double lapl=0;
+ for (int i=0;i<3;i++)
+ {
+ if (TT(f,i) != -1)
+ lapl += (mydist - Distortion(TT(f,i), h, WUV));
+ }
+ return lapl;
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE bool igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::updateStiffeningJacobianDistorsion(double grad_size, const Eigen::MatrixXd& WUV)
+{
+ bool flipped = NumFlips(WUV)>0;
+
+ if (!flipped)
+ return false;
+
+ double maxL=0;
+ double maxD=0;
+
+ if (flipped)
+ {
+ const double c = 1.0;
+ const double d = 5.0;
+
+ for (unsigned int i = 0; i < Fcut.rows(); ++i)
+ {
+ double dist=Distortion(i,grad_size,WUV);
+ if (dist > maxD)
+ maxD=dist;
+
+ double absLap=fabs(LaplaceDistortion(i, grad_size,WUV));
+ if (absLap > maxL)
+ maxL = absLap;
+
+ double stiffDelta = std::min(c * absLap, d);
+
+ Handle_Stiffness[i]+=stiffDelta;
+ }
+ }
+ printf("Maximum Distorsion %4.4f \n",maxD);
+ printf("Maximum Laplacian %4.4f \n",maxL);
+ return flipped;
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE bool igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::IsFlipped(const Eigen::Vector2d &uv0,
+ const Eigen::Vector2d &uv1,
+ const Eigen::Vector2d &uv2)
+{
+ Eigen::Vector2d e0 = (uv1-uv0);
+ Eigen::Vector2d e1 = (uv2-uv0);
+
+ double Area = e0(0)*e1(1) - e0(1)*e1(0);
+ return (Area<=0);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE bool igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU>::IsFlipped(
+ const int i, const Eigen::MatrixXd& WUV)
+{
+ Eigen::Vector2d uv0,uv1,uv2;
+ uv0 << WUV(i,0), WUV(i,1);
+ uv1 << WUV(i,2), WUV(i,3);
+ uv2 << WUV(i,4), WUV(i,5);
+
+ return (IsFlipped(uv0,uv1,uv2));
+}
+
+
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE void igl::copyleft::comiso::miq(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1_combed,
+ const Eigen::PlainObjectBase<DerivedV> &PD2_combed,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_MMatch,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &Handle_Singular,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Handle_Seams,
+ Eigen::PlainObjectBase<DerivedU> &UV,
+ Eigen::PlainObjectBase<DerivedF> &FUV,
+ double GradientSize,
+ double Stiffness,
+ bool DirectRound,
+ int iter,
+ int localIter,
+ bool DoRound,
+ bool SingularityRound,
+ std::vector<int> roundVertices,
+ std::vector<std::vector<int> > hardFeatures)
+{
+ GradientSize = GradientSize/(V.colwise().maxCoeff()-V.colwise().minCoeff()).norm();
+
+ igl::copyleft::comiso::MIQ_class<DerivedV, DerivedF, DerivedU> miq(V,
+ F,
+ PD1_combed,
+ PD2_combed,
+ Handle_MMatch,
+ Handle_Singular,
+ Handle_Seams,
+ UV,
+ FUV,
+ GradientSize,
+ Stiffness,
+ DirectRound,
+ iter,
+ localIter,
+ DoRound,
+ SingularityRound,
+ roundVertices,
+ hardFeatures);
+
+ miq.extractUV(UV,FUV);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE void igl::copyleft::comiso::miq(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const Eigen::PlainObjectBase<DerivedV> &PD2,
+ Eigen::PlainObjectBase<DerivedU> &UV,
+ Eigen::PlainObjectBase<DerivedF> &FUV,
+ double GradientSize,
+ double Stiffness,
+ bool DirectRound,
+ int iter,
+ int localIter,
+ bool DoRound,
+ bool SingularityRound,
+ std::vector<int> roundVertices,
+ std::vector<std::vector<int> > hardFeatures)
+{
+
+ DerivedV BIS1, BIS2;
+ igl::compute_frame_field_bisectors(V, F, PD1, PD2, BIS1, BIS2);
+
+ DerivedV BIS1_combed, BIS2_combed;
+ igl::comb_cross_field(V, F, BIS1, BIS2, BIS1_combed, BIS2_combed);
+
+ DerivedF Handle_MMatch;
+ igl::cross_field_missmatch(V, F, BIS1_combed, BIS2_combed, true, Handle_MMatch);
+
+ Eigen::Matrix<int, Eigen::Dynamic, 1> isSingularity, singularityIndex;
+ igl::find_cross_field_singularities(V, F, Handle_MMatch, isSingularity, singularityIndex);
+
+ Eigen::Matrix<int, Eigen::Dynamic, 3> Handle_Seams;
+ igl::cut_mesh_from_singularities(V, F, Handle_MMatch, Handle_Seams);
+
+ DerivedV PD1_combed, PD2_combed;
+ igl::comb_frame_field(V, F, PD1, PD2, BIS1_combed, BIS2_combed, PD1_combed, PD2_combed);
+
+ igl::copyleft::comiso::miq(V,
+ F,
+ PD1_combed,
+ PD2_combed,
+ Handle_MMatch,
+ isSingularity,
+ Handle_Seams,
+ UV,
+ FUV,
+ GradientSize,
+ Stiffness,
+ DirectRound,
+ iter,
+ localIter,
+ DoRound,
+ SingularityRound,
+ roundVertices,
+ hardFeatures);
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::comiso::miq<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, double, double, bool, int, int, bool, bool, std::vector<int, std::allocator<int> >, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >);
+template void igl::copyleft::comiso::miq<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 3, 0, -1, 3> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 3, 0, -1, 3> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, double, double, bool, int, int, bool, bool, std::vector<int, std::allocator<int> >, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >);
+template void igl::copyleft::comiso::miq<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, double, double, bool, int, int, bool, bool, std::vector<int, std::allocator<int> >, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >);
+#endif
diff --git a/xs/src/igl/copyleft/comiso/miq.h b/xs/src/igl/copyleft/comiso/miq.h
new file mode 100644
index 000000000..f4581f65d
--- /dev/null
+++ b/xs/src/igl/copyleft/comiso/miq.h
@@ -0,0 +1,99 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>, Kevin Walliman <wkevin@student.ethz.ch>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COMISO_MIQ_H
+#define IGL_COMISO_MIQ_H
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace comiso
+ {
+ // Global seamless parametrization aligned with a given per-face jacobian (PD1,PD2).
+ // The algorithm is based on
+ // "Mixed-Integer Quadrangulation" by D. Bommes, H. Zimmer, L. Kobbelt
+ // ACM SIGGRAPH 2009, Article No. 77 (http://dl.acm.org/citation.cfm?id=1531383)
+ // We thank Nico Pietroni for providing a reference implementation of MIQ
+ // on which our code is based.
+
+ // Inputs:
+ // V #V by 3 list of mesh vertex 3D positions
+ // F #F by 3 list of faces indices in V
+ // PD1 #V by 3 first line of the Jacobian per triangle
+ // PD2 #V by 3 second line of the Jacobian per triangle
+ // (optional, if empty it will be a vector in the tangent plane orthogonal to PD1)
+ // scale global scaling for the gradient (controls the quads resolution)
+ // stiffness weight for the stiffness iterations
+ // direct_round greedily round all integer variables at once (greatly improves optimization speed but lowers quality)
+ // iter stiffness iterations (0 = no stiffness)
+ // local_iter number of local iterations for the integer rounding
+ // do_round enables the integer rounding (disabling it could be useful for debugging)
+ // round_vertices id of additional vertices that should be snapped to integer coordinates
+ // hard_features #H by 2 list of pairs of vertices that belongs to edges that should be snapped to integer coordinates
+ //
+ // Output:
+ // UV #UV by 2 list of vertices in 2D
+ // FUV #FUV by 3 list of face indices in UV
+ //
+ // TODO: rename the parameters name in the cpp consistently
+ // improve the handling of hard_features, right now it might fail in difficult cases
+
+ template <typename DerivedV, typename DerivedF, typename DerivedU>
+ IGL_INLINE void miq(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const Eigen::PlainObjectBase<DerivedV> &PD2,
+ Eigen::PlainObjectBase<DerivedU> &UV,
+ Eigen::PlainObjectBase<DerivedF> &FUV,
+ double scale = 30.0,
+ double stiffness = 5.0,
+ bool direct_round = false,
+ int iter = 5,
+ int local_iter = 5,
+ bool DoRound = true,bool SingularityRound=true,
+ std::vector<int> round_vertices = std::vector<int>(),
+ std::vector<std::vector<int> > hard_features = std::vector<std::vector<int> >());
+
+ // Helper function that allows to directly provided pre-combed bisectors for an already cut mesh
+ // Additional input:
+ // PD1_combed, PD2_combed : #F by 3 combed jacobian
+ // BIS1_combed, BIS2_combed: #F by 3 pre combed bi-sectors
+ // MMatch: #F by 3 list of per-corner integer PI/2 rotations
+ // Singular: #V list of flag that denotes if a vertex is singular or not
+ // SingularDegree: #V list of flag that denotes the degree of the singularity
+ // Seams: #F by 3 list of per-corner flag that denotes seams
+
+ template <typename DerivedV, typename DerivedF, typename DerivedU>
+ IGL_INLINE void miq(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1_combed,
+ const Eigen::PlainObjectBase<DerivedV> &PD2_combed,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &MMatch,
+ const Eigen::Matrix<int, Eigen::Dynamic, 1> &Singular,
+ const Eigen::Matrix<int, Eigen::Dynamic, 3> &Seams,
+ Eigen::PlainObjectBase<DerivedU> &UV,
+ Eigen::PlainObjectBase<DerivedF> &FUV,
+ double GradientSize = 30.0,
+ double Stiffness = 5.0,
+ bool DirectRound = false,
+ int iter = 5,
+ int localIter = 5, bool DoRound = true,bool SingularityRound=true,
+ std::vector<int> roundVertices = std::vector<int>(),
+ std::vector<std::vector<int> > hardFeatures = std::vector<std::vector<int> >());
+ };
+};
+};
+#ifndef IGL_STATIC_LIBRARY
+#include "miq.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/comiso/nrosy.cpp b/xs/src/igl/copyleft/comiso/nrosy.cpp
new file mode 100644
index 000000000..0f3ee86bc
--- /dev/null
+++ b/xs/src/igl/copyleft/comiso/nrosy.cpp
@@ -0,0 +1,941 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "nrosy.h"
+
+#include <igl/copyleft/comiso/nrosy.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/edge_topology.h>
+#include <igl/per_face_normals.h>
+
+#include <iostream>
+#include <fstream>
+
+#include <Eigen/Geometry>
+#include <Eigen/Sparse>
+#include <queue>
+
+#include <gmm/gmm.h>
+#include <CoMISo/Solver/ConstrainedSolver.hh>
+#include <CoMISo/Solver/MISolver.hh>
+#include <CoMISo/Solver/GMM_Tools.hh>
+
+namespace igl
+{
+namespace copyleft
+{
+
+namespace comiso
+{
+class NRosyField
+{
+public:
+ // Init
+ IGL_INLINE NRosyField(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F);
+
+ // Generate the N-rosy field
+ // N degree of the rosy field
+ // roundseparately: round the integer variables one at a time, slower but higher quality
+ IGL_INLINE void solve(const int N = 4);
+
+ // Set a hard constraint on fid
+ // fid: face id
+ // v: direction to fix (in 3d)
+ IGL_INLINE void setConstraintHard(const int fid, const Eigen::Vector3d& v);
+
+ // Set a soft constraint on fid
+ // fid: face id
+ // w: weight of the soft constraint, clipped between 0 and 1
+ // v: direction to fix (in 3d)
+ IGL_INLINE void setConstraintSoft(const int fid, const double w, const Eigen::Vector3d& v);
+
+ // Set the ratio between smoothness and soft constraints (0 -> smoothness only, 1 -> soft constr only)
+ IGL_INLINE void setSoftAlpha(double alpha);
+
+ // Reset constraints (at least one constraint must be present or solve will fail)
+ IGL_INLINE void resetConstraints();
+
+ // Return the current field
+ IGL_INLINE Eigen::MatrixXd getFieldPerFace();
+
+ // Return the current field (in Ahish's ffield format)
+ IGL_INLINE Eigen::MatrixXd getFFieldPerFace();
+
+ // Compute singularity indexes
+ IGL_INLINE void findCones(int N);
+
+ // Return the singularities
+ IGL_INLINE Eigen::VectorXd getSingularityIndexPerVertex();
+
+private:
+
+ // Compute angle differences between reference frames
+ IGL_INLINE void computek();
+
+ // Remove useless matchings
+ IGL_INLINE void reduceSpace();
+
+ // Prepare the system matrix
+ IGL_INLINE void prepareSystemMatrix(const int N);
+
+ // Solve without roundings
+ IGL_INLINE void solveNoRoundings();
+
+ // Solve with roundings using CoMIso
+ IGL_INLINE void solveRoundings();
+
+ // Round all p to 0 and fix
+ IGL_INLINE void roundAndFixToZero();
+
+ // Round all p and fix
+ IGL_INLINE void roundAndFix();
+
+ // Convert a vector in 3d to an angle wrt the local reference system
+ IGL_INLINE double convert3DtoLocal(unsigned fid, const Eigen::Vector3d& v);
+
+ // Convert an angle wrt the local reference system to a 3d vector
+ IGL_INLINE Eigen::Vector3d convertLocalto3D(unsigned fid, double a);
+
+ // Compute the per vertex angle defect
+ IGL_INLINE Eigen::VectorXd angleDefect();
+
+ // Temporary variable for the field
+ Eigen::VectorXd angles;
+
+ // Hard constraints
+ Eigen::VectorXd hard;
+ std::vector<bool> isHard;
+
+ // Soft constraints
+ Eigen::VectorXd soft;
+ Eigen::VectorXd wSoft;
+ double softAlpha;
+
+ // Face Topology
+ Eigen::MatrixXi TT, TTi;
+
+ // Edge Topology
+ Eigen::MatrixXi EV, FE, EF;
+ std::vector<bool> isBorderEdge;
+
+ // Per Edge information
+ // Angle between two reference frames
+ Eigen::VectorXd k;
+
+ // Jumps
+ Eigen::VectorXi p;
+ std::vector<bool> pFixed;
+
+ // Mesh
+ Eigen::MatrixXd V;
+ Eigen::MatrixXi F;
+
+ // Normals per face
+ Eigen::MatrixXd N;
+
+ // Singularity index
+ Eigen::VectorXd singularityIndex;
+
+ // Reference frame per triangle
+ std::vector<Eigen::MatrixXd> TPs;
+
+ // System stuff
+ Eigen::SparseMatrix<double> A;
+ Eigen::VectorXd b;
+ Eigen::VectorXi tag_t;
+ Eigen::VectorXi tag_p;
+
+};
+
+} // NAMESPACE COMISO
+} // NAMESPACE COPYLEFT
+} // NAMESPACE IGL
+
+igl::copyleft::comiso::NRosyField::NRosyField(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ V = _V;
+ F = _F;
+
+ assert(V.rows() > 0);
+ assert(F.rows() > 0);
+
+
+ // Generate topological relations
+ igl::triangle_triangle_adjacency(F,TT,TTi);
+ igl::edge_topology(V,F, EV, FE, EF);
+
+ // Flag border edges
+ isBorderEdge.resize(EV.rows());
+ for(unsigned i=0; i<EV.rows(); ++i)
+ isBorderEdge[i] = (EF(i,0) == -1) || ((EF(i,1) == -1));
+
+ // Generate normals per face
+ igl::per_face_normals(V, F, N);
+
+ // Generate reference frames
+ for(unsigned fid=0; fid<F.rows(); ++fid)
+ {
+ // First edge
+ Vector3d e1 = V.row(F(fid,1)) - V.row(F(fid,0));
+ e1.normalize();
+ Vector3d e2 = N.row(fid);
+ e2 = e2.cross(e1);
+ e2.normalize();
+
+ MatrixXd TP(2,3);
+ TP << e1.transpose(), e2.transpose();
+ TPs.push_back(TP);
+ }
+
+ // Alloc internal variables
+ angles = VectorXd::Zero(F.rows());
+ p = VectorXi::Zero(EV.rows());
+ pFixed.resize(EV.rows());
+ k = VectorXd::Zero(EV.rows());
+ singularityIndex = VectorXd::Zero(V.rows());
+
+ // Reset the constraints
+ resetConstraints();
+
+ // Compute k, differences between reference frames
+ computek();
+
+ softAlpha = 0.5;
+}
+
+void igl::copyleft::comiso::NRosyField::setSoftAlpha(double alpha)
+{
+ assert(alpha >= 0 && alpha < 1);
+ softAlpha = alpha;
+}
+
+
+void igl::copyleft::comiso::NRosyField::prepareSystemMatrix(const int N)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ double Nd = N;
+
+ // Minimize the MIQ energy
+ // Energy on edge ij is
+ // (t_i - t_j + kij + pij*(2*pi/N))^2
+ // Partial derivatives:
+ // t_i: 2 ( t_i - t_j + kij + pij*(2*pi/N)) = 0
+ // t_j: 2 (-t_i + t_j - kij - pij*(2*pi/N)) = 0
+ // pij: 4pi/N ( t_i - t_j + kij + pij*(2*pi/N)) = 0
+ //
+ // t_i t_j pij kij
+ // t_i [ 2 -2 4pi/N 2 ]
+ // t_j [ -2 2 -4pi/N -2 ]
+ // pij [ 4pi/N -4pi/N 2*(2pi/N)^2 4pi/N ]
+
+ // Count and tag the variables
+ tag_t = VectorXi::Constant(F.rows(),-1);
+ vector<int> id_t;
+ int count = 0;
+ for(unsigned i=0; i<F.rows(); ++i)
+ if (!isHard[i])
+ {
+ tag_t(i) = count++;
+ id_t.push_back(i);
+ }
+
+ unsigned count_t = id_t.size();
+
+ tag_p = VectorXi::Constant(EF.rows(),-1);
+ vector<int> id_p;
+ for(unsigned i=0; i<EF.rows(); ++i)
+ {
+ if (!pFixed[i])
+ {
+ // if it is not fixed then it is a variable
+ tag_p(i) = count++;
+ }
+
+ // if it is not a border edge,
+ if (!isBorderEdge[i])
+ {
+ // and it is not between two fixed faces
+ if (!(isHard[EF(i,0)] && isHard[EF(i,1)]))
+ {
+ // then it participates in the energy!
+ id_p.push_back(i);
+ }
+ }
+ }
+
+ unsigned count_p = count - count_t;
+ // System sizes: A (count_t + count_p) x (count_t + count_p)
+ // b (count_t + count_p)
+
+ b = VectorXd::Zero(count_t + count_p);
+
+ std::vector<Eigen::Triplet<double> > T;
+ T.reserve(3 * 4 * count_p);
+
+ for(unsigned r=0; r<id_p.size(); ++r)
+ {
+ int eid = id_p[r];
+ int i = EF(eid,0);
+ int j = EF(eid,1);
+ bool isFixed_i = isHard[i];
+ bool isFixed_j = isHard[j];
+ bool isFixed_p = pFixed[eid];
+ int row;
+ // (i)-th row: t_i [ 2 -2 4pi/N 2 ]
+ if (!isFixed_i)
+ {
+ row = tag_t[i];
+ if (isFixed_i) b(row) += -2 * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i] , 2 ));
+ if (isFixed_j) b(row) += 2 * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] ,-2 ));
+ if (isFixed_p) b(row) += -((4 * igl::PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],((4 * igl::PI)/Nd)));
+ b(row) += -2 * k[eid];
+ assert(hard[i] == hard[i]);
+ assert(hard[j] == hard[j]);
+ assert(p[eid] == p[eid]);
+ assert(k[eid] == k[eid]);
+ assert(b(row) == b(row));
+ }
+ // (j)+1 -th row: t_j [ -2 2 -4pi/N -2 ]
+ if (!isFixed_j)
+ {
+ row = tag_t[j];
+ if (isFixed_i) b(row) += 2 * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i] , -2 ));
+ if (isFixed_j) b(row) += -2 * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] , 2 ));
+ if (isFixed_p) b(row) += ((4 * igl::PI)/Nd) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid],-((4 * igl::PI)/Nd)));
+ b(row) += 2 * k[eid];
+ assert(k[eid] == k[eid]);
+ assert(b(row) == b(row));
+ }
+ // (r*3)+2 -th row: pij [ 4pi/N -4pi/N 2*(2pi/N)^2 4pi/N ]
+ if (!isFixed_p)
+ {
+ row = tag_p[eid];
+ if (isFixed_i) b(row) += -(4 * igl::PI)/Nd * hard[i]; else T.push_back(Eigen::Triplet<double>(row,tag_t[i] , (4 * igl::PI)/Nd ));
+ if (isFixed_j) b(row) += (4 * igl::PI)/Nd * hard[j]; else T.push_back(Eigen::Triplet<double>(row,tag_t[j] , -(4 * igl::PI)/Nd ));
+ if (isFixed_p) b(row) += -(2 * pow(((2*igl::PI)/Nd),2)) * p[eid] ; else T.push_back(Eigen::Triplet<double>(row,tag_p[eid], (2 * pow(((2*igl::PI)/Nd),2))));
+ b(row) += - (4 * igl::PI)/Nd * k[eid];
+ assert(k[eid] == k[eid]);
+ assert(b(row) == b(row));
+ }
+
+ }
+
+ A = SparseMatrix<double>(count_t + count_p, count_t + count_p);
+ A.setFromTriplets(T.begin(), T.end());
+
+ // Soft constraints
+ bool addSoft = false;
+
+ for(unsigned i=0; i<wSoft.size();++i)
+ if (wSoft[i] != 0)
+ addSoft = true;
+
+ if (addSoft)
+ {
+ cerr << " Adding soft here: " << endl;
+ cerr << " softAplha: " << softAlpha << endl;
+ VectorXd bSoft = VectorXd::Zero(count_t + count_p);
+
+ std::vector<Eigen::Triplet<double> > TSoft;
+ TSoft.reserve(2 * count_p);
+
+ for(unsigned i=0; i<F.rows(); ++i)
+ {
+ int varid = tag_t[i];
+ if (varid != -1) // if it is a variable in the system
+ {
+ TSoft.push_back(Eigen::Triplet<double>(varid,varid,wSoft[i]));
+ bSoft[varid] += wSoft[i] * soft[i];
+ }
+ }
+ SparseMatrix<double> ASoft(count_t + count_p, count_t + count_p);
+ ASoft.setFromTriplets(TSoft.begin(), TSoft.end());
+
+// ofstream s("/Users/daniele/As.txt");
+// for(unsigned i=0; i<TSoft.size(); ++i)
+// s << TSoft[i].row() << " " << TSoft[i].col() << " " << TSoft[i].value() << endl;
+// s.close();
+
+// ofstream s2("/Users/daniele/bs.txt");
+// for(unsigned i=0; i<bSoft.rows(); ++i)
+// s2 << bSoft(i) << endl;
+// s2.close();
+
+ // Stupid Eigen bug
+ SparseMatrix<double> Atmp (count_t + count_p, count_t + count_p);
+ SparseMatrix<double> Atmp2(count_t + count_p, count_t + count_p);
+ SparseMatrix<double> Atmp3(count_t + count_p, count_t + count_p);
+
+ // Merge the two part of the energy
+ Atmp = (1.0 - softAlpha)*A;
+ Atmp2 = softAlpha * ASoft;
+ Atmp3 = Atmp+Atmp2;
+
+ A = Atmp3;
+ b = b*(1.0 - softAlpha) + bSoft * softAlpha;
+ }
+
+// ofstream s("/Users/daniele/A.txt");
+// for (int k=0; k<A.outerSize(); ++k)
+// for (SparseMatrix<double>::InnerIterator it(A,k); it; ++it)
+// {
+// s << it.row() << " " << it.col() << " " << it.value() << endl;
+// }
+// s.close();
+//
+// ofstream s2("/Users/daniele/b.txt");
+// for(unsigned i=0; i<b.rows(); ++i)
+// s2 << b(i) << endl;
+// s2.close();
+}
+
+void igl::copyleft::comiso::NRosyField::solveNoRoundings()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // Solve the linear system
+ SimplicialLDLT<SparseMatrix<double> > solver;
+ solver.compute(A);
+ VectorXd x = solver.solve(b);
+
+ // Copy the result back
+ for(unsigned i=0; i<F.rows(); ++i)
+ if (tag_t[i] != -1)
+ angles[i] = x(tag_t[i]);
+ else
+ angles[i] = hard[i];
+
+ for(unsigned i=0; i<EF.rows(); ++i)
+ if(tag_p[i] != -1)
+ p[i] = roundl(x[tag_p[i]]);
+}
+
+void igl::copyleft::comiso::NRosyField::solveRoundings()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ unsigned n = A.rows();
+
+ gmm::col_matrix< gmm::wsvector< double > > gmm_A;
+ std::vector<double> gmm_b;
+ std::vector<int> ids_to_round;
+ std::vector<double> x;
+
+ gmm_A.resize(n,n);
+ gmm_b.resize(n);
+ x.resize(n);
+
+ // Copy A
+ for (int k=0; k<A.outerSize(); ++k)
+ for (SparseMatrix<double>::InnerIterator it(A,k); it; ++it)
+ {
+ gmm_A(it.row(),it.col()) += it.value();
+ }
+
+ // Copy b
+ for(unsigned i=0; i<n;++i)
+ gmm_b[i] = b[i];
+
+ // Set variables to round
+ ids_to_round.clear();
+ for(unsigned i=0; i<tag_p.size();++i)
+ if(tag_p[i] != -1)
+ ids_to_round.push_back(tag_p[i]);
+
+ // Empty constraints
+ gmm::row_matrix< gmm::wsvector< double > > gmm_C(0, n);
+
+ COMISO::ConstrainedSolver cs;
+ //print_miso_settings(cs.misolver());
+ cs.solve(gmm_C, gmm_A, x, gmm_b, ids_to_round, 0.0, false, true);
+
+ // Copy the result back
+ for(unsigned i=0; i<F.rows(); ++i)
+ if (tag_t[i] != -1)
+ angles[i] = x[tag_t[i]];
+ else
+ angles[i] = hard[i];
+
+ for(unsigned i=0; i<EF.rows(); ++i)
+ if(tag_p[i] != -1)
+ p[i] = roundl(x[tag_p[i]]);
+
+}
+
+
+void igl::copyleft::comiso::NRosyField::roundAndFix()
+{
+ for(unsigned i=0; i<p.rows(); ++i)
+ pFixed[i] = true;
+}
+
+void igl::copyleft::comiso::NRosyField::roundAndFixToZero()
+{
+ for(unsigned i=0; i<p.rows(); ++i)
+ {
+ pFixed[i] = true;
+ p[i] = 0;
+ }
+}
+
+void igl::copyleft::comiso::NRosyField::solve(const int N)
+{
+ // Reduce the search space by fixing matchings
+ reduceSpace();
+
+ // Build the system
+ prepareSystemMatrix(N);
+
+ // Solve with integer roundings
+ solveRoundings();
+
+ // This is a very greedy solving strategy
+ // // Solve with no roundings
+ // solveNoRoundings();
+ //
+ // // Round all p and fix them
+ // roundAndFix();
+ //
+ // // Build the system
+ // prepareSystemMatrix(N);
+ //
+ // // Solve with no roundings (they are all fixed)
+ // solveNoRoundings();
+
+ // Find the cones
+ findCones(N);
+}
+
+void igl::copyleft::comiso::NRosyField::setConstraintHard(const int fid, const Eigen::Vector3d& v)
+{
+ isHard[fid] = true;
+ hard(fid) = convert3DtoLocal(fid, v);
+}
+
+void igl::copyleft::comiso::NRosyField::setConstraintSoft(const int fid, const double w, const Eigen::Vector3d& v)
+{
+ wSoft(fid) = w;
+ soft(fid) = convert3DtoLocal(fid, v);
+}
+
+void igl::copyleft::comiso::NRosyField::resetConstraints()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ isHard.resize(F.rows());
+ for(unsigned i=0; i<F.rows(); ++i)
+ isHard[i] = false;
+ hard = VectorXd::Zero(F.rows());
+
+ wSoft = VectorXd::Zero(F.rows());
+ soft = VectorXd::Zero(F.rows());
+}
+
+Eigen::MatrixXd igl::copyleft::comiso::NRosyField::getFieldPerFace()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ MatrixXd result(F.rows(),3);
+ for(unsigned i=0; i<F.rows(); ++i)
+ result.row(i) = convertLocalto3D(i, angles(i));
+ return result;
+}
+
+Eigen::MatrixXd igl::copyleft::comiso::NRosyField::getFFieldPerFace()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ MatrixXd result(F.rows(),6);
+ for(unsigned i=0; i<F.rows(); ++i)
+ {
+ Vector3d v1 = convertLocalto3D(i, angles(i));
+ Vector3d n = N.row(i);
+ Vector3d v2 = n.cross(v1);
+ v1.normalize();
+ v2.normalize();
+
+ result.block(i,0,1,3) = v1.transpose();
+ result.block(i,3,1,3) = v2.transpose();
+ }
+ return result;
+}
+
+
+void igl::copyleft::comiso::NRosyField::computek()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // For every non-border edge
+ for (unsigned eid=0; eid<EF.rows(); ++eid)
+ {
+ if (!isBorderEdge[eid])
+ {
+ int fid0 = EF(eid,0);
+ int fid1 = EF(eid,1);
+
+ Vector3d N0 = N.row(fid0);
+ Vector3d N1 = N.row(fid1);
+
+ // find common edge on triangle 0 and 1
+ int fid0_vc = -1;
+ int fid1_vc = -1;
+ for (unsigned i=0;i<3;++i)
+ {
+ if (EV(eid,0) == F(fid0,i))
+ fid0_vc = i;
+ if (EV(eid,1) == F(fid1,i))
+ fid1_vc = i;
+ }
+ assert(fid0_vc != -1);
+ assert(fid1_vc != -1);
+
+ Vector3d common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
+ common_edge.normalize();
+
+ // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
+ MatrixXd P(3,3);
+ VectorXd o = V.row(F(fid0,fid0_vc));
+ VectorXd tmp = -N0.cross(common_edge);
+ P << common_edge, tmp, N0;
+ P.transposeInPlace();
+
+
+ MatrixXd V0(3,3);
+ V0.row(0) = V.row(F(fid0,0)).transpose() -o;
+ V0.row(1) = V.row(F(fid0,1)).transpose() -o;
+ V0.row(2) = V.row(F(fid0,2)).transpose() -o;
+
+ V0 = (P*V0.transpose()).transpose();
+
+ assert(V0(0,2) < 10e-10);
+ assert(V0(1,2) < 10e-10);
+ assert(V0(2,2) < 10e-10);
+
+ MatrixXd V1(3,3);
+ V1.row(0) = V.row(F(fid1,0)).transpose() -o;
+ V1.row(1) = V.row(F(fid1,1)).transpose() -o;
+ V1.row(2) = V.row(F(fid1,2)).transpose() -o;
+ V1 = (P*V1.transpose()).transpose();
+
+ assert(V1(fid1_vc,2) < 10e-10);
+ assert(V1((fid1_vc+1)%3,2) < 10e-10);
+
+ // compute rotation R such that R * N1 = N0
+ // i.e. map both triangles to the same plane
+ double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
+
+ MatrixXd R(3,3);
+ R << 1, 0, 0,
+ 0, cos(alpha), -sin(alpha) ,
+ 0, sin(alpha), cos(alpha);
+ V1 = (R*V1.transpose()).transpose();
+
+ assert(V1(0,2) < 10e-10);
+ assert(V1(1,2) < 10e-10);
+ assert(V1(2,2) < 10e-10);
+
+ // measure the angle between the reference frames
+ // k_ij is the angle between the triangle on the left and the one on the right
+ VectorXd ref0 = V0.row(1) - V0.row(0);
+ VectorXd ref1 = V1.row(1) - V1.row(0);
+
+ ref0.normalize();
+ ref1.normalize();
+
+ double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
+
+ // just to be sure, rotate ref0 using angle ktemp...
+ MatrixXd R2(2,2);
+ R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
+
+ tmp = R2*ref0.head<2>();
+
+ assert(tmp(0) - ref1(0) < 10^10);
+ assert(tmp(1) - ref1(1) < 10^10);
+
+ k[eid] = ktemp;
+ }
+ }
+
+}
+
+void igl::copyleft::comiso::NRosyField::reduceSpace()
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // All variables are free in the beginning
+ for(unsigned i=0; i<EV.rows(); ++i)
+ pFixed[i] = false;
+
+ vector<VectorXd> debug;
+
+ // debug
+// MatrixXd B(F.rows(),3);
+// for(unsigned i=0; i<F.rows(); ++i)
+// B.row(i) = 1./3. * (V.row(F(i,0)) + V.row(F(i,1)) + V.row(F(i,2)));
+
+ vector<bool> visited(EV.rows());
+ for(unsigned i=0; i<EV.rows(); ++i)
+ visited[i] = false;
+
+ vector<bool> starting(EV.rows());
+ for(unsigned i=0; i<EV.rows(); ++i)
+ starting[i] = false;
+
+ queue<int> q;
+ for(unsigned i=0; i<F.rows(); ++i)
+ if (isHard[i] || wSoft[i] != 0)
+ {
+ q.push(i);
+ starting[i] = true;
+ }
+
+ // Reduce the search space (see MI paper)
+ while (!q.empty())
+ {
+ int c = q.front();
+ q.pop();
+
+ visited[c] = true;
+ for(int i=0; i<3; ++i)
+ {
+ int eid = FE(c,i);
+ int fid = TT(c,i);
+
+ // skip borders
+ if (fid != -1)
+ {
+ assert((EF(eid,0) == c && EF(eid,1) == fid) || (EF(eid,1) == c && EF(eid,0) == fid));
+ // for every neighbouring face
+ if (!visited[fid] && !starting[fid])
+ {
+ pFixed[eid] = true;
+ p[eid] = 0;
+ visited[fid] = true;
+ q.push(fid);
+
+ }
+ }
+ else
+ {
+ // fix borders
+ pFixed[eid] = true;
+ p[eid] = 0;
+ }
+ }
+
+ }
+
+ // Force matchings between fixed faces
+ for(unsigned i=0; i<F.rows();++i)
+ {
+ if (isHard[i])
+ {
+ for(unsigned int j=0; j<3; ++j)
+ {
+ int fid = TT(i,j);
+ if ((fid!=-1) && (isHard[fid]))
+ {
+ // i and fid are adjacent and fixed
+ int eid = FE(i,j);
+ int fid0 = EF(eid,0);
+ int fid1 = EF(eid,1);
+
+ pFixed[eid] = true;
+ p[eid] = roundl(2.0/igl::PI*(hard(fid1) - hard(fid0) - k(eid)));
+ }
+ }
+ }
+ }
+
+// std::ofstream s("/Users/daniele/debug.txt");
+// for(unsigned i=0; i<debug.size(); i += 2)
+// s << debug[i].transpose() << " " << debug[i+1].transpose() << endl;
+// s.close();
+
+}
+
+double igl::copyleft::comiso::NRosyField::convert3DtoLocal(unsigned fid, const Eigen::Vector3d& v)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // Project onto the tangent plane
+ Vector2d vp = TPs[fid] * v;
+
+ // Convert to angle
+ return atan2(vp(1),vp(0));
+}
+
+Eigen::Vector3d igl::copyleft::comiso::NRosyField::convertLocalto3D(unsigned fid, double a)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ Vector2d vp(cos(a),sin(a));
+ return vp.transpose() * TPs[fid];
+}
+
+Eigen::VectorXd igl::copyleft::comiso::NRosyField::angleDefect()
+{
+ Eigen::VectorXd A = Eigen::VectorXd::Constant(V.rows(),-2*igl::PI);
+
+ for (unsigned i=0; i < F.rows(); ++i)
+ {
+ for (int j = 0; j < 3; ++j)
+ {
+ Eigen::VectorXd a = V.row(F(i,(j+1)%3)) - V.row(F(i,j));
+ Eigen::VectorXd b = V.row(F(i,(j+2)%3)) - V.row(F(i,j));
+ double t = a.transpose()*b;
+ t /= (a.norm() * b.norm());
+ A(F(i,j)) += acos(t);
+ }
+ }
+
+ return A;
+}
+
+void igl::copyleft::comiso::NRosyField::findCones(int N)
+{
+ // Compute I0, see http://www.graphics.rwth-aachen.de/media/papers/bommes_zimmer_2009_siggraph_011.pdf for details
+
+ Eigen::VectorXd I0 = Eigen::VectorXd::Zero(V.rows());
+
+ // first the k
+ for (unsigned i=0; i < EV.rows(); ++i)
+ {
+ if (!isBorderEdge[i])
+ {
+ I0(EV(i,0)) -= k(i);
+ I0(EV(i,1)) += k(i);
+ }
+ }
+
+ // then the A
+ Eigen::VectorXd A = angleDefect();
+
+ I0 = I0 + A;
+
+ // normalize
+ I0 = I0 / (2*igl::PI);
+
+ // round to integer (remove numerical noise)
+ for (unsigned i=0; i < I0.size(); ++i)
+ I0(i) = round(I0(i));
+
+ // compute I
+ Eigen::VectorXd I = I0;
+
+ for (unsigned i=0; i < EV.rows(); ++i)
+ {
+ if (!isBorderEdge[i])
+ {
+ I(EV(i,0)) -= double(p(i))/double(N);
+ I(EV(i,1)) += double(p(i))/double(N);
+ }
+ }
+
+ // Clear the vertices on the edges
+ for (unsigned i=0; i < EV.rows(); ++i)
+ {
+ if (isBorderEdge[i])
+ {
+ I0(EV(i,0)) = 0;
+ I0(EV(i,1)) = 0;
+ I(EV(i,0)) = 0;
+ I(EV(i,1)) = 0;
+ A(EV(i,0)) = 0;
+ A(EV(i,1)) = 0;
+ }
+ }
+
+ singularityIndex = I;
+}
+
+Eigen::VectorXd igl::copyleft::comiso::NRosyField::getSingularityIndexPerVertex()
+{
+ return singularityIndex;
+}
+
+IGL_INLINE void igl::copyleft::comiso::nrosy(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc,
+ const Eigen::VectorXi& b_soft,
+ const Eigen::VectorXd& w_soft,
+ const Eigen::MatrixXd& bc_soft,
+ const int N,
+ const double soft,
+ Eigen::MatrixXd& R,
+ Eigen::VectorXd& S
+ )
+{
+ // Init solver
+ igl::copyleft::comiso::NRosyField solver(V,F);
+
+ // Add hard constraints
+ for (unsigned i=0; i<b.size();++i)
+ solver.setConstraintHard(b(i),bc.row(i));
+
+ // Add soft constraints
+ for (unsigned i=0; i<b_soft.size();++i)
+ solver.setConstraintSoft(b_soft(i),w_soft(i),bc_soft.row(i));
+
+ // Set the soft constraints global weight
+ solver.setSoftAlpha(soft);
+
+ // Interpolate
+ solver.solve(N);
+
+ // Copy the result back
+ R = solver.getFieldPerFace();
+
+ // Extract singularity indices
+ S = solver.getSingularityIndexPerVertex();
+}
+
+
+IGL_INLINE void igl::copyleft::comiso::nrosy(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc,
+ const int N,
+ Eigen::MatrixXd& R,
+ Eigen::VectorXd& S
+ )
+{
+ // Init solver
+ igl::copyleft::comiso::NRosyField solver(V,F);
+
+ // Add hard constraints
+ for (unsigned i=0; i<b.size();++i)
+ solver.setConstraintHard(b(i),bc.row(i));
+
+ // Interpolate
+ solver.solve(N);
+
+ // Copy the result back
+ R = solver.getFieldPerFace();
+
+ // Extract singularity indices
+ S = solver.getSingularityIndexPerVertex();
+}
diff --git a/xs/src/igl/copyleft/comiso/nrosy.h b/xs/src/igl/copyleft/comiso/nrosy.h
new file mode 100644
index 000000000..61c7f9558
--- /dev/null
+++ b/xs/src/igl/copyleft/comiso/nrosy.h
@@ -0,0 +1,73 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COMISO_NROSY_H
+#define IGL_COMISO_NROSY_H
+
+#include <iostream>
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+#include <vector>
+#include "../../igl_inline.h"
+#include "../../PI.h"
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace comiso
+ {
+ // Generate a N-RoSy field from a sparse set of constraints
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex coordinates
+ // F #F by 3 list of mesh faces (must be triangles)
+ // b #B by 1 list of constrained face indices
+ // bc #B by 3 list of representative vectors for the constrained
+ // faces
+ // b_soft #S by 1 b for soft constraints
+ // w_soft #S by 1 weight for the soft constraints (0-1)
+ // bc_soft #S by 3 bc for soft constraints
+ // N the degree of the N-RoSy vector field
+ // soft the strength of the soft constraints w.r.t. smoothness
+ // (0 -> smoothness only, 1->constraints only)
+ // Outputs:
+ // R #F by 3 the representative vectors of the interpolated field
+ // S #V by 1 the singularity index for each vertex (0 = regular)
+ IGL_INLINE void nrosy(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc,
+ const Eigen::VectorXi& b_soft,
+ const Eigen::VectorXd& w_soft,
+ const Eigen::MatrixXd& bc_soft,
+ const int N,
+ const double soft,
+ Eigen::MatrixXd& R,
+ Eigen::VectorXd& S
+ );
+ //wrapper for the case without soft constraints
+ IGL_INLINE void nrosy(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc,
+ const int N,
+ Eigen::MatrixXd& R,
+ Eigen::VectorXd& S
+ );
+
+ }
+}
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "nrosy.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cork/from_cork_mesh.cpp b/xs/src/igl/copyleft/cork/from_cork_mesh.cpp
new file mode 100644
index 000000000..964263111
--- /dev/null
+++ b/xs/src/igl/copyleft/cork/from_cork_mesh.cpp
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "from_cork_mesh.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE void igl::copyleft::cork::from_cork_mesh(
+ const CorkTriMesh & mesh,
+ Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedF > & F)
+{
+ using namespace std;
+ F.resize(mesh.n_triangles,3);
+ V.resize(mesh.n_vertices,3);
+ for(size_t v = 0;v<mesh.n_vertices;v++)
+ {
+ for(size_t c = 0;c<3;c++)
+ {
+ V(v,c) = mesh.vertices[v*3+c];
+ }
+ }
+ for(size_t f = 0;f<mesh.n_triangles;f++)
+ {
+ for(size_t c = 0;c<3;c++)
+ {
+ F(f,c) = mesh.triangles[f*3+c];
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cork::from_cork_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(CorkTriMesh const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cork::from_cork_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(CorkTriMesh const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/copyleft/cork/from_cork_mesh.h b/xs/src/igl/copyleft/cork/from_cork_mesh.h
new file mode 100644
index 000000000..a2fef28c1
--- /dev/null
+++ b/xs/src/igl/copyleft/cork/from_cork_mesh.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CORK_FROM_CORK_MESH_H
+#define IGL_COPYLEFT_CORK_FROM_CORK_MESH_H
+#include "../../igl_inline.h"
+#include <cork.h>
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cork
+ {
+ // Convert cork's triangle mesh representation to a (V,F) mesh.
+ //
+ // Inputs:
+ // mesh cork representation of mesh
+ // Outputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ template <
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE void from_cork_mesh(
+ const CorkTriMesh & mesh,
+ Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedF > & F);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "from_cork_mesh.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/cork/mesh_boolean.cpp b/xs/src/igl/copyleft/cork/mesh_boolean.cpp
new file mode 100644
index 000000000..61ed4a6ad
--- /dev/null
+++ b/xs/src/igl/copyleft/cork/mesh_boolean.cpp
@@ -0,0 +1,99 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mesh_boolean.h"
+#include "to_cork_mesh.h"
+#include "from_cork_mesh.h"
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC>
+IGL_INLINE void igl::copyleft::cork::mesh_boolean(
+ const Eigen::PlainObjectBase<DerivedVA > & VA,
+ const Eigen::PlainObjectBase<DerivedFA > & FA,
+ const Eigen::PlainObjectBase<DerivedVB > & VB,
+ const Eigen::PlainObjectBase<DerivedFB > & FB,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC)
+{
+ CorkTriMesh A,B,C;
+ // pointer to output so it's easy to redirect on degenerate cases
+ CorkTriMesh *ret = &C;
+ to_cork_mesh(VA,FA,A);
+ to_cork_mesh(VB,FB,B);
+ switch(type)
+ {
+ case MESH_BOOLEAN_TYPE_UNION:
+ if(A.n_triangles == 0)
+ {
+ ret = &B;
+ }else if(B.n_triangles == 0)
+ {
+ ret = &A;
+ }else
+ {
+ computeUnion(A,B,ret);
+ }
+ break;
+ case MESH_BOOLEAN_TYPE_INTERSECT:
+ if(A.n_triangles == 0 || B.n_triangles == 0)
+ {
+ ret->n_triangles = 0;
+ ret->n_vertices = 0;
+ }else
+ {
+ computeIntersection(A,B,ret);
+ }
+ break;
+ case MESH_BOOLEAN_TYPE_MINUS:
+ if(A.n_triangles == 0)
+ {
+ ret->n_triangles = 0;
+ ret->n_vertices = 0;
+ }else if(B.n_triangles == 0)
+ {
+ ret = &A;
+ }else
+ {
+ computeDifference(A,B,ret);
+ }
+ break;
+ case MESH_BOOLEAN_TYPE_XOR:
+ if(A.n_triangles == 0)
+ {
+ ret = &B;
+ }else if(B.n_triangles == 0)
+ {
+ ret = &A;
+ }else
+ {
+ computeSymmetricDifference(A,B,&C);
+ }
+ break;
+ case MESH_BOOLEAN_TYPE_RESOLVE:
+ resolveIntersections(A,B,&C);
+ break;
+ default:
+ assert(false && "Unknown type");
+ return;
+ }
+ from_cork_mesh(*ret,VC,FC);
+ freeCorkTriMesh(&A);
+ freeCorkTriMesh(&B);
+ freeCorkTriMesh(&C);
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cork::mesh_boolean<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::copyleft::cork::mesh_boolean<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::MeshBooleanType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+#endif
+
diff --git a/xs/src/igl/copyleft/cork/mesh_boolean.h b/xs/src/igl/copyleft/cork/mesh_boolean.h
new file mode 100644
index 000000000..db2589284
--- /dev/null
+++ b/xs/src/igl/copyleft/cork/mesh_boolean.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CORK_MESH_BOOLEAN_H
+#define IGL_COPYLEFT_CORK_MESH_BOOLEAN_H
+#include "../../MeshBooleanType.h"
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <cork.h> // for consistent uint
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cork
+ {
+ // Compute a boolean operation on two input meshes using the cork library.
+ //
+ // Inputs:
+ // VA #VA by 3 list of vertex positions of first mesh
+ // FA #FA by 3 list of triangle indices into VA
+ // VB #VB by 3 list of vertex positions of second mesh
+ // FB #FB by 3 list of triangle indices into VB
+ // type of boolean operation see MeshBooleanType.h
+ // Outputs:
+ // VC #VC by 3 list of vertex positions of output mesh
+ // FC #FC by 3 list of triangle indices into VC
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename DerivedVC,
+ typename DerivedFC>
+ IGL_INLINE void mesh_boolean(
+ const Eigen::PlainObjectBase<DerivedVA > & VA,
+ const Eigen::PlainObjectBase<DerivedFA > & FA,
+ const Eigen::PlainObjectBase<DerivedVB > & VB,
+ const Eigen::PlainObjectBase<DerivedFB > & FB,
+ const MeshBooleanType & type,
+ Eigen::PlainObjectBase<DerivedVC > & VC,
+ Eigen::PlainObjectBase<DerivedFC > & FC);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mesh_boolean.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/cork/to_cork_mesh.cpp b/xs/src/igl/copyleft/cork/to_cork_mesh.cpp
new file mode 100644
index 000000000..845f8cb67
--- /dev/null
+++ b/xs/src/igl/copyleft/cork/to_cork_mesh.cpp
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "to_cork_mesh.h"
+template <
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE void igl::copyleft::cork::to_cork_mesh(
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ CorkTriMesh & mesh)
+{
+ using namespace std;
+ assert((F.cols() == 0 || F.cols() == 3) && "Facets should be triangles.");
+ assert((V.cols() == 0 || V.cols() == 3) && "Vertices should be in 3D.");
+ mesh.n_triangles = F.rows();
+ mesh.n_vertices = V.rows();
+ mesh.vertices = new float[mesh.n_vertices*3];
+ mesh.triangles = new uint[mesh.n_triangles*3];
+ for(size_t v = 0;v<mesh.n_vertices;v++)
+ {
+ for(size_t c = 0;c<3;c++)
+ {
+ mesh.vertices[v*3+c] = V(v,c);
+ }
+ }
+ for(size_t f = 0;f<mesh.n_triangles;f++)
+ {
+ for(size_t c = 0;c<3;c++)
+ {
+ mesh.triangles[f*3+c] = F(f,c);
+ }
+ }
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::copyleft::cork::to_cork_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, CorkTriMesh&);
+template void igl::copyleft::cork::to_cork_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, CorkTriMesh&);
+#endif
diff --git a/xs/src/igl/copyleft/cork/to_cork_mesh.h b/xs/src/igl/copyleft/cork/to_cork_mesh.h
new file mode 100644
index 000000000..b034e357f
--- /dev/null
+++ b/xs/src/igl/copyleft/cork/to_cork_mesh.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_CORK_TO_CORK_MESH_H
+#define IGL_COPYLEFT_CORK_TO_CORK_MESH_H
+#include "../../igl_inline.h"
+#include <cork.h>
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace cork
+ {
+ // Convert a (V,F) mesh to a cork's triangle mesh representation.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // Outputs:
+ // mesh cork representation of mesh
+ template <
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE void to_cork_mesh(
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ CorkTriMesh & mesh);
+ }
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "to_cork_mesh.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/marching_cubes.cpp b/xs/src/igl/copyleft/marching_cubes.cpp
new file mode 100644
index 000000000..144a02255
--- /dev/null
+++ b/xs/src/igl/copyleft/marching_cubes.cpp
@@ -0,0 +1,258 @@
+/*===========================================================================*\
+ * *
+ * IsoEx *
+ * Copyright (C) 2002 by Computer Graphics Group, RWTH Aachen *
+ * www.rwth-graphics.de *
+ * *
+ *---------------------------------------------------------------------------*
+ * *
+ * License *
+ * *
+ * This library is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Library General Public License as published *
+ * by the Free Software Foundation, version 2. *
+ * *
+ * This library is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ * *
+ \*===========================================================================*/
+
+#include "marching_cubes.h"
+#include "marching_cubes_tables.h"
+
+#include <unordered_map>
+
+
+extern const int edgeTable[256];
+extern const int triTable[256][2][17];
+extern const int polyTable[8][16];
+
+struct EdgeKey
+{
+ EdgeKey(unsigned i0, unsigned i1) : i0_(i0), i1_(i1) {}
+
+ bool operator==(const EdgeKey& _rhs) const
+ {
+ return i0_ == _rhs.i0_ && i1_ == _rhs.i1_;
+ }
+
+ unsigned i0_, i1_;
+};
+
+struct EdgeHash
+{
+ std::size_t operator()(const EdgeKey& key) const {
+ std::size_t seed = 0;
+ seed ^= key.i0_ + 0x9e3779b9 + (seed<<6) + (seed>>2); // Copied from boost::hash_combine
+ seed ^= key.i1_ + 0x9e3779b9 + (seed<<6) + (seed>>2);
+ return std::hash<std::size_t>()(seed);
+ }
+};
+
+
+template <typename Derivedvalues, typename Derivedpoints,typename Derivedvertices, typename DerivedF>
+class MarchingCubes
+{
+ typedef std::unordered_map<EdgeKey, unsigned, EdgeHash> MyMap;
+ typedef typename MyMap::const_iterator MyMapIterator;
+
+public:
+ MarchingCubes(
+ const Eigen::PlainObjectBase<Derivedvalues> &values,
+ const Eigen::PlainObjectBase<Derivedpoints> &points,
+ const unsigned x_res,
+ const unsigned y_res,
+ const unsigned z_res,
+ Eigen::PlainObjectBase<Derivedvertices> &vertices,
+ Eigen::PlainObjectBase<DerivedF> &faces)
+ {
+ assert(values.cols() == 1);
+ assert(points.cols() == 3);
+
+ if(x_res <2 || y_res<2 ||z_res<2)
+ return;
+ faces.resize(10000,3);
+ int num_faces = 0;
+
+ vertices.resize(10000,3);
+ int num_vertices = 0;
+
+
+ unsigned n_cubes = (x_res-1) * (y_res-1) * (z_res-1);
+ assert(unsigned(points.rows()) == x_res * y_res * z_res);
+
+ unsigned int offsets_[8];
+ offsets_[0] = 0;
+ offsets_[1] = 1;
+ offsets_[2] = 1 + x_res;
+ offsets_[3] = x_res;
+ offsets_[4] = x_res*y_res;
+ offsets_[5] = 1 + x_res*y_res;
+ offsets_[6] = 1 + x_res + x_res*y_res;
+ offsets_[7] = x_res + x_res*y_res;
+
+ for (unsigned cube_it =0 ; cube_it < n_cubes; ++cube_it)
+ {
+
+ unsigned corner[8];
+ typename DerivedF::Scalar samples[12];
+ unsigned char cubetype(0);
+ unsigned int i;
+
+
+ // get point indices of corner vertices
+ for (i=0; i<8; ++i)
+ {
+ // get cube coordinates
+ unsigned int _idx = cube_it;
+ unsigned int X(x_res-1), Y(y_res-1);
+ unsigned int x = _idx % X; _idx /= X;
+ unsigned int y = _idx % Y; _idx /= Y;
+ unsigned int z = _idx;
+
+ // transform to point coordinates
+ _idx = x + y*x_res + z*x_res*y_res;
+
+ // add offset
+ corner[i] = _idx + offsets_[i];
+ }
+
+
+ // determine cube type
+ for (i=0; i<8; ++i)
+ if (values(corner[i]) > 0.0)
+ cubetype |= (1<<i);
+
+
+ // trivial reject ?
+ if (cubetype == 0 || cubetype == 255)
+ continue;
+
+
+ // compute samples on cube's edges
+ if (edgeTable[cubetype]&1)
+ samples[0] = add_vertex(values, points, corner[0], corner[1], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&2)
+ samples[1] = add_vertex(values, points, corner[1], corner[2], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&4)
+ samples[2] = add_vertex(values, points, corner[3], corner[2], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&8)
+ samples[3] = add_vertex(values, points, corner[0], corner[3], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&16)
+ samples[4] = add_vertex(values, points, corner[4], corner[5], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&32)
+ samples[5] = add_vertex(values, points, corner[5], corner[6], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&64)
+ samples[6] = add_vertex(values, points, corner[7], corner[6], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&128)
+ samples[7] = add_vertex(values, points, corner[4], corner[7], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&256)
+ samples[8] = add_vertex(values, points, corner[0], corner[4], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&512)
+ samples[9] = add_vertex(values, points, corner[1], corner[5], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&1024)
+ samples[10] = add_vertex(values, points, corner[2], corner[6], vertices, num_vertices, edge2vertex);
+ if (edgeTable[cubetype]&2048)
+ samples[11] = add_vertex(values, points, corner[3], corner[7], vertices, num_vertices, edge2vertex);
+
+
+
+ // connect samples by triangles
+ for (i=0; triTable[cubetype][0][i] != -1; i+=3 )
+ {
+ num_faces++;
+ if (num_faces > faces.rows())
+ faces.conservativeResize(faces.rows()+10000, Eigen::NoChange);
+
+ faces.row(num_faces-1) <<
+ samples[triTable[cubetype][0][i ]],
+ samples[triTable[cubetype][0][i+1]],
+ samples[triTable[cubetype][0][i+2]];
+
+ }
+
+ }
+
+ vertices.conservativeResize(num_vertices, Eigen::NoChange);
+ faces.conservativeResize(num_faces, Eigen::NoChange);
+
+ };
+
+ static typename DerivedF::Scalar add_vertex(const Eigen::PlainObjectBase<Derivedvalues> &values,
+ const Eigen::PlainObjectBase<Derivedpoints> &points,
+ unsigned int i0,
+ unsigned int i1,
+ Eigen::PlainObjectBase<Derivedvertices> &vertices,
+ int &num_vertices,
+ MyMap &edge2vertex)
+ {
+ // find vertex if it has been computed already
+ MyMapIterator it = edge2vertex.find(EdgeKey(i0, i1));
+ if (it != edge2vertex.end())
+ return it->second;
+ ;
+
+ // generate new vertex
+ const Eigen::Matrix<typename Derivedpoints::Scalar, 1, 3> & p0 = points.row(i0);
+ const Eigen::Matrix<typename Derivedpoints::Scalar, 1, 3> & p1 = points.row(i1);
+
+ typename Derivedvalues::Scalar s0 = fabs(values(i0));
+ typename Derivedvalues::Scalar s1 = fabs(values(i1));
+ typename Derivedvalues::Scalar t = s0 / (s0+s1);
+
+
+ num_vertices++;
+ if (num_vertices > vertices.rows())
+ vertices.conservativeResize(vertices.rows()+10000, Eigen::NoChange);
+
+ // Linear interpolation based on linearly interpolating values
+ vertices.row(num_vertices-1) = ((1.0f-t)*p0 + t*p1).template cast<typename Derivedvertices::Scalar>();
+ edge2vertex[EdgeKey(i0, i1)] = num_vertices-1;
+
+ return num_vertices-1;
+ }
+ ;
+
+ // maps an edge to the sample vertex generated on it
+ MyMap edge2vertex;
+};
+
+
+template <typename Derivedvalues, typename Derivedpoints, typename Derivedvertices, typename DerivedF>
+IGL_INLINE void igl::copyleft::marching_cubes(
+ const Eigen::PlainObjectBase<Derivedvalues> &values,
+ const Eigen::PlainObjectBase<Derivedpoints> &points,
+ const unsigned x_res,
+ const unsigned y_res,
+ const unsigned z_res,
+ Eigen::PlainObjectBase<Derivedvertices> &vertices,
+ Eigen::PlainObjectBase<DerivedF> &faces)
+{
+ MarchingCubes<Derivedvalues, Derivedpoints, Derivedvertices, DerivedF> mc(values,
+ points,
+ x_res,
+ y_res,
+ z_res,
+ vertices,
+ faces);
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::marching_cubes<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::copyleft::marching_cubes<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+template void igl::copyleft::marching_cubes< Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, unsigned int, unsigned int, unsigned int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/marching_cubes.h b/xs/src/igl/copyleft/marching_cubes.h
new file mode 100644
index 000000000..4c9f888e4
--- /dev/null
+++ b/xs/src/igl/copyleft/marching_cubes.h
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_MARCHINGCUBES_H
+#define IGL_COPYLEFT_MARCHINGCUBES_H
+#include "../igl_inline.h"
+
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ // marching_cubes( values, points, x_res, y_res, z_res, vertices, faces )
+ //
+ // performs marching cubes reconstruction on the grid defined by values, and
+ // points, and generates vertices and faces
+ //
+ // Input:
+ // values #number_of_grid_points x 1 array -- the scalar values of an
+ // implicit function defined on the grid points (<0 in the inside of the
+ // surface, 0 on the border, >0 outside)
+ // points #number_of_grid_points x 3 array -- 3-D positions of the grid
+ // points, ordered in x,y,z order:
+ // points[index] = the point at (x,y,z) where :
+ // x = (index % (xres -1),
+ // y = (index / (xres-1)) %(yres-1),
+ // z = index / (xres -1) / (yres -1) ).
+ // where x,y,z index x, y, z dimensions
+ // i.e. index = x + y*xres + z*xres*yres
+ // xres resolutions of the grid in x dimension
+ // yres resolutions of the grid in y dimension
+ // zres resolutions of the grid in z dimension
+ // Output:
+ // vertices #V by 3 list of mesh vertex positions
+ // faces #F by 3 list of mesh triangle indices
+ //
+ template <
+ typename Derivedvalues,
+ typename Derivedpoints,
+ typename Derivedvertices,
+ typename DerivedF>
+ IGL_INLINE void marching_cubes(
+ const Eigen::PlainObjectBase<Derivedvalues> &values,
+ const Eigen::PlainObjectBase<Derivedpoints> &points,
+ const unsigned x_res,
+ const unsigned y_res,
+ const unsigned z_res,
+ Eigen::PlainObjectBase<Derivedvertices> &vertices,
+ Eigen::PlainObjectBase<DerivedF> &faces);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "marching_cubes.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/marching_cubes_tables.h b/xs/src/igl/copyleft/marching_cubes_tables.h
new file mode 100644
index 000000000..4bba533c3
--- /dev/null
+++ b/xs/src/igl/copyleft/marching_cubes_tables.h
@@ -0,0 +1,917 @@
+/*===========================================================================*\
+ * *
+ * IsoEx *
+ * Copyright (C) 2002 by Computer Graphics Group, RWTH Aachen *
+ * www.rwth-graphics.de *
+ * *
+ *---------------------------------------------------------------------------*
+ * *
+ * License *
+ * *
+ * This library is free software; you can redistribute it and/or modify it *
+ * under the terms of the GNU Library General Public License as published *
+ * by the Free Software Foundation, version 2. *
+ * *
+ * This library is distributed in the hope that it will be useful, but *
+ * WITHOUT ANY WARRANTY; without even the implied warranty of *
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
+ * Library General Public License for more details. *
+ * *
+ * You should have received a copy of the GNU Library General Public *
+ * License along with this library; if not, write to the Free Software *
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
+ * *
+ \*===========================================================================*/
+
+//=============================================================================
+#ifndef IGL_ISOEX_MC_TABLES_HH
+#define IGL_ISOEX_MC_TABLES_HH
+//=============================================================================
+
+
+//int edgeTable[256];
+//int triTable[256][2][17];
+//int polyTable[8][16];
+
+const int edgeTable[256]=
+{
+ 0x0 , 0x109, 0x203, 0x30a, 0x406, 0x50f, 0x605, 0x70c,
+ 0x80c, 0x905, 0xa0f, 0xb06, 0xc0a, 0xd03, 0xe09, 0xf00,
+ 0x190, 0x99 , 0x393, 0x29a, 0x596, 0x49f, 0x795, 0x69c,
+ 0x99c, 0x895, 0xb9f, 0xa96, 0xd9a, 0xc93, 0xf99, 0xe90,
+ 0x230, 0x339, 0x33 , 0x13a, 0x636, 0x73f, 0x435, 0x53c,
+ 0xa3c, 0xb35, 0x83f, 0x936, 0xe3a, 0xf33, 0xc39, 0xd30,
+ 0x3a0, 0x2a9, 0x1a3, 0xaa , 0x7a6, 0x6af, 0x5a5, 0x4ac,
+ 0xbac, 0xaa5, 0x9af, 0x8a6, 0xfaa, 0xea3, 0xda9, 0xca0,
+ 0x460, 0x569, 0x663, 0x76a, 0x66 , 0x16f, 0x265, 0x36c,
+ 0xc6c, 0xd65, 0xe6f, 0xf66, 0x86a, 0x963, 0xa69, 0xb60,
+ 0x5f0, 0x4f9, 0x7f3, 0x6fa, 0x1f6, 0xff , 0x3f5, 0x2fc,
+ 0xdfc, 0xcf5, 0xfff, 0xef6, 0x9fa, 0x8f3, 0xbf9, 0xaf0,
+ 0x650, 0x759, 0x453, 0x55a, 0x256, 0x35f, 0x55 , 0x15c,
+ 0xe5c, 0xf55, 0xc5f, 0xd56, 0xa5a, 0xb53, 0x859, 0x950,
+ 0x7c0, 0x6c9, 0x5c3, 0x4ca, 0x3c6, 0x2cf, 0x1c5, 0xcc ,
+ 0xfcc, 0xec5, 0xdcf, 0xcc6, 0xbca, 0xac3, 0x9c9, 0x8c0,
+ 0x8c0, 0x9c9, 0xac3, 0xbca, 0xcc6, 0xdcf, 0xec5, 0xfcc,
+ 0xcc , 0x1c5, 0x2cf, 0x3c6, 0x4ca, 0x5c3, 0x6c9, 0x7c0,
+ 0x950, 0x859, 0xb53, 0xa5a, 0xd56, 0xc5f, 0xf55, 0xe5c,
+ 0x15c, 0x55 , 0x35f, 0x256, 0x55a, 0x453, 0x759, 0x650,
+ 0xaf0, 0xbf9, 0x8f3, 0x9fa, 0xef6, 0xfff, 0xcf5, 0xdfc,
+ 0x2fc, 0x3f5, 0xff , 0x1f6, 0x6fa, 0x7f3, 0x4f9, 0x5f0,
+ 0xb60, 0xa69, 0x963, 0x86a, 0xf66, 0xe6f, 0xd65, 0xc6c,
+ 0x36c, 0x265, 0x16f, 0x66 , 0x76a, 0x663, 0x569, 0x460,
+ 0xca0, 0xda9, 0xea3, 0xfaa, 0x8a6, 0x9af, 0xaa5, 0xbac,
+ 0x4ac, 0x5a5, 0x6af, 0x7a6, 0xaa , 0x1a3, 0x2a9, 0x3a0,
+ 0xd30, 0xc39, 0xf33, 0xe3a, 0x936, 0x83f, 0xb35, 0xa3c,
+ 0x53c, 0x435, 0x73f, 0x636, 0x13a, 0x33 , 0x339, 0x230,
+ 0xe90, 0xf99, 0xc93, 0xd9a, 0xa96, 0xb9f, 0x895, 0x99c,
+ 0x69c, 0x795, 0x49f, 0x596, 0x29a, 0x393, 0x99 , 0x190,
+ 0xf00, 0xe09, 0xd03, 0xc0a, 0xb06, 0xa0f, 0x905, 0x80c,
+ 0x70c, 0x605, 0x50f, 0x406, 0x30a, 0x203, 0x109, 0x0
+};
+
+
+//-----------------------------------------------------------------------------
+
+
+const int triTable[256][2][17] =
+{{{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 8, 3, 9, 8, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 1, 9, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 0, 8, 3, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 2, 10, 0, 2, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 2, 10, 9, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 8, 3, 2, 10, 8, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 10, 9, 8, 3, 2 , -1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 11, 2, 8, 11, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 0, 8, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 10 */
+ {{1, 9, 0, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 1, 9, 0, 2, 3,11, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 11, 2, 1, 9, 11, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 9, 8, 11, 2, 1,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 10, 1, 11, 10, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 3, 11,10, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 10, 1, 0, 8, 10, 8, 11, 10, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 11, 10, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 9, 0, 3, 11, 9, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 11,10, 9, 0, 3, -1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 15 */
+ {{9, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 8, 11, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 3, 0, 7, 3, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 4, 7, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 0, 1, 9, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 1, 9, 4, 7, 1, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 7, 3, 1, 9, 4, -1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 20 */
+ {{1, 2, 10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 1, 2,10, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 4, 7, 3, 0, 4, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 3, 0, 4, 7, 1, 2, 10, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 2, 10, 9, 0, 2, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 2,10, 9, 0, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 10, 9, 2, 9, 7, 2, 7, 3, 7, 9, 4, -1, -1, -1, -1, -1},
+ {1, 6, 7, 3, 2,10, 9, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 8, 4, 7, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 25 */
+ {{11, 4, 7, 11, 2, 4, 2, 0, 4, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 2, 0, 4, 7,11,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 9, 0, 1, 8, 4, 7, 2, 3, 11, -1, -1, -1, -1}},
+
+ {{4, 7, 11, 9, 4, 11, 9, 11, 2, 9, 2, 1, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2, 1, 9, 11, 11,9,4,7, -1, -1, -1, -1, -1 ,-1}},
+
+ {{3, 10, 1, 3, 11, 10, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 3, 11,10, 1, 7, 8, 4, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 11, 10, 1, 4, 11, 1, 0, 4, 7, 11, 4, -1, -1, -1, -1, -1},
+ {1, 6, 1, 0, 4, 7,11,10, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 30 */
+ {{4, 7, 8, 9, 0, 11, 9, 11, 10, 11, 0, 3, -1, -1, -1, -1, -1},
+ {2, 3, 5, 4, 7, 8, 0, 3, 11, 10, 9, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 7, 11, 4, 11, 9, 9, 11, 10, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 4, 7,11,10, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 9, 5, 4, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 5, 4, 1, 5, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 0, 1, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 35 */
+ {{8, 5, 4, 8, 3, 5, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 1, 5, 4, 8,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 2, 10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 1, 2,10, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 3, 0, 8, 1, 2, 10, 4, 9, 5, -1, -1, -1, -1}},
+
+ {{5, 2, 10, 5, 4, 2, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 4, 0, 2,10, 5,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 10, 5, 3, 2, 5, 3, 5, 4, 3, 4, 8, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2, 10, 5, 3, 4, 8, 3, 5, -1, -1, -1, -1, -1, -1}},
+
+ /* 40 */
+ {{9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 9, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 11, 2, 0, 8, 11, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 0, 8, 11, 2, 4, 9, 5, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 5, 4, 0, 1, 5, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 0, 1, 5, 4, 2, 3, 11, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 1, 5, 2, 5, 8, 2, 8, 11, 4, 8, 5, -1, -1, -1, -1, -1},
+ {1, 6, 2, 1, 5, 4, 8,11, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 3, 11, 10, 1, 3, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 4, 3, 3,11,10, 1, 9, 5, 4, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 45 */
+ {{4, 9, 5, 0, 8, 1, 8, 10, 1, 8, 11, 10, -1, -1, -1, -1, -1},
+ {2, 3, 5, 4, 9, 5, 1, 0, 8,11, 10, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 4, 0, 5, 0, 11, 5, 11, 10, 11, 0, 3, -1, -1, -1, -1, -1},
+ {1, 6, 5, 4, 0, 3,11, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 4, 8, 5, 8, 10, 10, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 5, 4, 8, 11, 10,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 7, 8, 5, 7, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 7, 8, 9, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 3, 0, 9, 5, 3, 5, 7, 3, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 5, 7, 3, 0, 9,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 50 */
+ {{0, 7, 8, 0, 1, 7, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 1, 5, 7, 8, 0,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 3, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 7, 8, 9, 5, 7, 10, 1, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 7, 8, 9, 5,10, 1, 2, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 1, 2, 9, 5, 0, 5, 3, 0, 5, 7, 3, -1, -1, -1, -1, -1},
+ { 2, 3, 5,10, 1, 2, 0, 9, 5, 7, 3,-1, -1, -1, -1, -1, -1}},
+
+ {{8, 0, 2, 8, 2, 5, 8, 5, 7, 10, 5, 2, -1, -1, -1, -1, -1},
+ {1, 6, 2,10, 5, 7, 8, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 55 */
+ {{2, 10, 5, 2, 5, 3, 3, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 2,10, 5, 7, 3,-1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 9, 5, 7, 8, 9, 3, 11, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 7, 8, 9, 5, 3,11, 2, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 5, 7, 9, 7, 2, 9, 2, 0, 2, 7, 11, -1, -1, -1, -1, -1},
+ {1, 6, 2, 0, 9, 5, 7,11, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 3, 11, 0, 1, 8, 1, 7, 8, 1, 5, 7, -1, -1, -1, -1, -1},
+ {2, 3, 5, 2, 3,11, 8, 0, 1, 5, 7, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 2, 1, 11, 1, 7, 7, 1, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5,11, 2, 1, 5, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 60 */
+ {{9, 5, 8, 8, 5, 7, 10, 1, 3, 10, 3, 11, -1, -1, -1, -1, -1},
+ {2, 4, 4, 3,11, 10, 1, 5, 7, 8, 9, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 7, 0, 5, 0, 9, 7, 11, 0, 1, 0, 10, 11, 10, 0, -1, -1},
+ {1, 7, 5, 7, 11,10, 1, 0, 9, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 10, 0, 11, 0, 3, 10, 5, 0, 8, 0, 7, 5, 7, 0, -1, -1},
+ {1, 7, 11,10,5, 7, 8, 0,3, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 10, 5, 7, 11, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 4, 5, 7, 11,10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 3,10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 65 */
+ {{0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 0, 8, 3, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 9, 0, 1, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 8, 3, 1, 9, 8, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 1, 9, 8, 3, 5,10, 6, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 6, 5, 2, 6, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 1, 2, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 6, 5, 1, 2, 6, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 1, 2, 6, 5, 3, 0, 8, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 70 */
+ {{9, 6, 5, 9, 0, 6, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 0, 2, 6, 5, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 9, 8, 5, 8, 2, 5, 2, 6, 3, 2, 8, -1, -1, -1, -1, -1},
+ {1, 6, 2, 6, 5, 9, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 3, 11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 2, 3,11, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 0, 8, 11, 2, 0, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 4, 3, 0, 8, 11, 2, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 0, 1, 9, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1}},
+
+ /* 75 */
+ {{5, 10, 6, 1, 9, 2, 9, 11, 2, 9, 8, 11, -1, -1, -1, -1, -1},
+ {2, 3, 5, 5,10, 6, 2, 1, 9, 8,11, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 3, 11, 6, 5, 3, 5, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 5, 1, 3, 11,6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 8, 11, 0, 11, 5, 0, 5, 1, 5, 11, 6, -1, -1, -1, -1, -1},
+ {1, 6, 5, 1, 0, 8,11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 11, 6, 0, 3, 6, 0, 6, 5, 0, 5, 9, -1, -1, -1, -1, -1},
+ {2, 4, 4, 3, 11, 6, 0, 5, 9, 0, 6, -1, -1, -1, -1}},
+
+ {{6, 5, 9, 6, 9, 11, 11, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 6, 5, 9, 8, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 80 */
+ {{5, 10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 5,10, 6, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 3, 0, 4, 7, 3, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 4, 7, 3, 0, 6, 5, 10, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 9, 0, 5, 10, 6, 8, 4, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 1, 9, 0, 5,10, 6, 8, 4, 7, -1, -1, -1, -1}},
+
+ {{10, 6, 5, 1, 9, 7, 1, 7, 3, 7, 9, 4, -1, -1, -1, -1, -1},
+ { 2, 3, 5,10, 6, 5, 9, 4, 7, 3, 1,-1, -1, -1, -1, -1, -1}},
+
+ {{6, 1, 2, 6, 5, 1, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 1, 2, 6, 5, 4, 7, 8, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 85 */
+ {{1, 2, 5, 5, 2, 6, 3, 0, 4, 3, 4, 7, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2, 6, 5, 1, 3, 0, 4, 7, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 4, 7, 9, 0, 5, 0, 6, 5, 0, 2, 6, -1, -1, -1, -1, -1},
+ {2, 3, 5, 8, 4, 7, 5, 9, 0, 2, 6, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 3, 9, 7, 9, 4, 3, 2, 9, 5, 9, 6, 2, 6, 9, -1, -1},
+ {1, 7, 7, 3, 2, 6, 5, 9, 4,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 3,11, 2, 7, 8, 4, 10, 6, 5, -1, -1, -1, -1}},
+
+ {{5, 10, 6, 4, 7, 2, 4, 2, 0, 2, 7, 11, -1, -1, -1, -1, -1},
+ {2, 3, 5, 5,10, 6, 7,11, 2, 0, 4, -1, -1, -1, -1, -1, -1}},
+
+ /* 90 */
+ {{0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6, -1, -1, -1, -1, -1},
+ {4, 3, 3, 3, 3, 0, 1, 9, 4, 7, 8, 2, 3, 11, 5, 10, 6}},
+
+ {{9, 2, 1, 9, 11, 2, 9, 4, 11, 7, 11, 4, 5, 10, 6, -1, -1},
+ {3, 4, 4, 3, 2, 1, 9,11, 4, 7, 11, 9, 5, 10, 6, -1, -1}},
+
+ {{8, 4, 7, 3, 11, 5, 3, 5, 1, 5, 11, 6, -1, -1, -1, -1, -1},
+ {2, 3, 5, 8, 4, 7, 11, 6, 5, 1, 3, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 1, 11, 5, 11, 6, 1, 0, 11, 7, 11, 4, 0, 4, 11, -1, -1},
+ {1, 7, 5, 1, 0, 4, 7,11, 6, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 5, 9, 0, 6, 5, 0, 3, 6, 11, 6, 3, 8, 4, 7, -1, -1},
+ {3, 4, 4, 3, 0, 6, 5, 9, 3, 11, 6, 0, 8, 4, 7, -1, -1}},
+
+ /* 95 */
+ {{6, 5, 9, 6, 9, 11, 4, 7, 9, 7, 11, 9, -1, -1, -1, -1, -1},
+ {2, 4, 4, 9, 4, 7, 11, 6, 5, 9, 11,-1, -1, -1, -1, -1, -1}},
+
+ {{10, 4, 9, 6, 4, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 4, 4, 9, 10, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 10, 6, 4, 9, 10, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 4, 9,10, 6, 0, 8, 3, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 0, 1, 10, 6, 0, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 6, 4, 0, 1, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 3, 1, 8, 1, 6, 8, 6, 4, 6, 1, 10, -1, -1, -1, -1, -1},
+ {1, 6, 1,10, 6, 4, 8, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 100 */
+ {{1, 4, 9, 1, 2, 4, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 2, 6, 4, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 0, 8, 1, 2, 9, 2, 4, 9, 2, 6, 4, -1, -1, -1, -1, -1},
+ {2, 3, 5, 3, 0, 8, 9, 1, 2, 6, 4, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 2, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 3, 2, 8, 2, 4, 4, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 3, 2, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 4, 9, 10, 6, 4, 11, 2, 3, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 4, 3, 10, 6, 4, 9,11, 2, 3, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 105 */
+ {{0, 8, 2, 2, 8, 11, 4, 9, 10, 4, 10, 6, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2, 11, 8, 0, 10, 6, 4, 9, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 11, 2, 0, 1, 6, 0, 6, 4, 6, 1, 10, -1, -1, -1, -1, -1},
+ {2, 3, 5, 3,11, 2, 1, 10,6, 4, 0, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 4, 1, 6, 1, 10, 4, 8, 1, 2, 1, 11, 8, 11, 1, -1, -1},
+ {1, 7, 6, 4, 8,11, 2, 1,10, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 6, 4, 9, 3, 6, 9, 1, 3, 11, 6, 3, -1, -1, -1, -1, -1},
+ {1, 6, 3,11, 6, 4, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 11, 1, 8, 1, 0, 11, 6, 1, 9, 1, 4, 6, 4, 1, -1, -1},
+ {1, 7, 8,11, 6, 4, 9, 1, 0, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 110 */
+ {{3, 11, 6, 3, 6, 0, 0, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3,11, 6, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 4, 8, 11, 6, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 8, 11, 6, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 10, 6, 7, 8, 10, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 9,10, 6, 7,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 7, 3, 0, 10, 7, 0, 9, 10, 6, 7, 10, -1, -1, -1, -1, -1},
+ {1, 6, 0, 9, 10, 6, 7, 3, -1,-1,-1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 6, 7, 1, 10, 7, 1, 7, 8, 1, 8, 0, -1, -1, -1, -1, -1},
+ { 2, 4, 4, 8, 0, 1, 7, 10, 6, 7, 1,-1, -1, -1, -1, -1, -1}},
+
+ /* 115 */
+ {{10, 6, 7, 10, 7, 1, 1, 7, 3, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 10, 6, 7, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 2, 6, 1, 6, 8, 1, 8, 9, 8, 6, 7, -1, -1, -1, -1, -1},
+ {1, 6, 1, 2, 6, 7, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 6, 9, 2, 9, 1, 6, 7, 9, 0, 9, 3, 7, 3, 9, -1, -1},
+ {1, 7, 2, 6, 7, 3, 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 8, 0, 7, 0, 6, 6, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 7, 8, 0, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 3, 2, 6, 7, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 7, 3, 2, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 120 */
+ {{2, 3, 11, 10, 6, 8, 10, 8, 9, 8, 6, 7, -1, -1, -1, -1, -1},
+ {2, 3, 5, 2, 3,11, 6, 7, 8, 9,10, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 0, 7, 2, 7, 11, 0, 9, 7, 6, 7, 10, 9, 10, 7, -1, -1},
+ {1, 7, 2, 0, 9,10,6, 7, 11, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 8, 0, 1, 7, 8, 1, 10, 7, 6, 7, 10, 2, 3, 11, -1, -1},
+ {3, 4, 4, 3, 8, 0, 1, 7, 10, 6, 7, 1, 11, 2, 3, -1, -1}},
+
+ {{11, 2, 1, 11, 1, 7, 10, 6, 1, 6, 7, 1, -1, -1, -1, -1, -1},
+ { 2, 4, 4, 11, 2, 1,7, 1, 10, 6, 7,-1, -1, -1, -1, -1, -1}},
+
+ {{8, 9, 6, 8, 6, 7, 9, 1, 6, 11, 6, 3, 1, 3, 6, -1, -1},
+ {1, 7, 8, 9, 1, 3, 11, 6, 7,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 125 */
+ {{0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 0, 9, 1, 11, 6, 7, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 8, 0, 7, 0, 6, 3, 11, 0, 11, 6, 0, -1, -1, -1, -1, -1},
+ {2, 4, 4, 0, 3,11, 6, 7, 8, 0, 6, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 7, 11, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 3, 0, 8, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 130 */
+ {{0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 0, 1, 9, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 1, 9, 8, 3, 1, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 1, 9, 8, 3,11, 7, 6, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 3, 3,10, 1, 2, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 2, 10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 1, 2,10, 3, 0, 8, 6, 11, 7, -1, -1, -1, -1}},
+
+ {{2, 9, 0, 2, 10, 9, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 2, 10, 9, 0, 6, 11, 7, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 135 */
+ {{6, 11, 7, 2, 10, 3, 10, 8, 3, 10, 9, 8, -1, -1, -1, -1, -1},
+ {2, 3, 5, 6, 11, 7, 3, 2,10, 9, 8, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 2, 3, 6, 2, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 2, 3, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 0, 8, 7, 6, 0, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 6, 2, 0, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 7, 6, 2, 3, 7, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 2, 3, 7, 6, 0, 1, 9, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 6, 2, 1, 8, 6, 1, 9, 8, 8, 7, 6, -1, -1, -1, -1, -1},
+ {1, 6, 6, 2, 1, 9, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 140 */
+ {{10, 7, 6, 10, 1, 7, 1, 3, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 1, 3, 7, 6,10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 7, 6, 1, 7, 10, 1, 8, 7, 1, 0, 8, -1, -1, -1, -1, -1},
+ { 2, 4, 4, 10, 1, 7, 6, 8, 7, 1, 0,-1, -1, -1, -1, -1, -1}},
+
+ {{0, 3, 7, 0, 7, 10, 0, 10, 9, 6, 10, 7, -1, -1, -1, -1, -1},
+ {1, 6,10, 9, 0, 3, 7, 6,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 6, 10, 7, 10, 8, 8, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 7, 6, 10, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 8, 4, 11, 8, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 6, 11, 8, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 145 */
+ {{3, 6, 11, 3, 0, 6, 0, 4, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 0, 4, 6,11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 6, 11, 8, 4, 6, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 6,11, 8, 4, 9, 0, 1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 4, 6, 9, 6, 3, 9, 3, 1, 11, 3, 6, -1, -1, -1, -1, -1},
+ {1, 6, 6,11, 3, 1, 9, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 8, 4, 6, 11, 8, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 6, 11, 8, 4, 2, 10, 1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 2, 10, 3, 0, 11, 0, 6, 11, 0, 4, 6, -1, -1, -1, -1, -1},
+ {2, 3, 5, 1, 2, 10,11, 3,0,4, 6, -1, -1, -1, -1, -1, -1}},
+
+ /* 150 */
+ {{4, 11, 8, 4, 6, 11, 0, 2, 9, 2, 10, 9, -1, -1, -1, -1, -1},
+ {2, 4, 4, 4, 6, 11, 8, 2,10, 9, 0, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 9, 3, 10, 3, 2, 9, 4, 3, 11, 3, 6, 4, 6, 3, -1, -1},
+ {1, 7, 10,9, 4, 6, 11, 3, 2, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 2, 3, 8, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 4, 6, 2, 3, 8,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 4, 2, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 4, 6, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 9, 0, 2, 3, 4, 2, 4, 6, 4, 3, 8, -1, -1, -1, -1, -1},
+ {2, 3, 5, 1, 9, 0, 3, 8, 4, 6, 2, -1, -1, -1, -1, -1, -1}},
+
+ /* 155 */
+ {{1, 9, 4, 1, 4, 2, 2, 4, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 1, 9, 4, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 1, 3, 8, 6, 1, 8, 4, 6, 6, 10, 1, -1, -1, -1, -1, -1},
+ {1, 6, 1, 3, 8, 4, 6,10, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 1, 0, 10, 0, 6, 6, 0, 4, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5,10, 1,0,4,6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 6, 3, 4, 3, 8, 6, 10, 3, 0, 3, 9, 10, 9, 3, -1, -1},
+ {1, 7, 4, 6, 10, 9, 0,3, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 9, 4, 6, 10, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 4, 4, 6, 10, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 160 */
+ {{4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 4, 9, 5, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 0, 8, 3, 4, 9, 5, 11, 7, 6, -1, -1, -1, -1}},
+
+ {{5, 0, 1, 5, 4, 0, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 0, 1, 5, 4, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 7, 6, 8, 3, 4, 3, 5, 4, 3, 1, 5, -1, -1, -1, -1, -1},
+ { 2, 3, 5,11, 7, 6, 4, 8, 3, 1, 5,-1, -1, -1, -1, -1, -1}},
+
+ {{9, 5, 4, 10, 1, 2, 7, 6, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {3, 3, 3, 3, 9, 5, 4,10, 1, 2, 7, 6, 11, -1, -1, -1, -1}},
+
+ /* 165 */
+ {{6, 11, 7, 1, 2, 10, 0, 8, 3, 4, 9, 5, -1, -1, -1, -1, -1},
+ {4, 3, 3, 3, 3, 6,11, 7, 1, 2,10, 0, 8, 3, 4, 9, 5}},
+
+ {{7, 6, 11, 5, 4, 10, 4, 2, 10, 4, 0, 2, -1, -1, -1, -1, -1},
+ {2, 3, 5, 7, 6, 11, 10, 5, 4, 0, 2,-1, -1, -1, -1, -1, -1}},
+
+ {{3, 4, 8, 3, 5, 4, 3, 2, 5, 10, 5, 2, 11, 7, 6, -1, -1},
+ {3, 4, 4, 3, 5, 3, 2,10, 4, 8, 3, 5, 6, 11, 7, 6, -1}},
+
+ {{7, 2, 3, 7, 6, 2, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 4, 3, 2, 3, 7, 6, 5, 4, 9, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 5, 4, 0, 8, 6, 0, 6, 2, 6, 8, 7, -1, -1, -1, -1, -1},
+ {2, 3, 5, 9, 5, 4, 8, 7, 6, 2, 0, -1, -1, -1, -1, -1, -1}},
+
+ /* 170 */
+ {{3, 6, 2, 3, 7, 6, 1, 5, 0, 5, 4, 0, -1, -1, -1, -1, -1},
+ {2, 4, 4, 3, 7, 6, 2, 0, 1, 5, 4, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 2, 8, 6, 8, 7, 2, 1, 8, 4, 8, 5, 1, 5, 8, -1, -1},
+ {1, 7, 6, 2, 1, 5, 4, 8, 7,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 5, 4, 10, 1, 6, 1, 7, 6, 1, 3, 7, -1, -1, -1, -1, -1},
+ {2, 3, 5, 9, 5, 4, 6,10, 1, 3, 7,-1, -1, -1, -1, -1, -1}},
+
+ {{1, 6, 10, 1, 7, 6, 1, 0, 7, 8, 7, 0, 9, 5, 4, -1, -1},
+ {3, 4, 4, 3, 0, 8, 7, 1, 6, 10, 1, 7, 9, 5, 4, -1, -1}},
+
+ {{4, 0, 10, 4, 10, 5, 0, 3, 10, 6, 10, 7, 3, 7, 10, -1, -1},
+ {1, 7, 4, 0, 3, 7, 6, 10, 5, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 175 */
+ {{7, 6, 10, 7, 10, 8, 5, 4, 10, 4, 8, 10, -1, -1, -1, -1, -1},
+ {2, 4, 4, 4, 8, 10, 5, 7, 6,10, 8, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 9, 5, 6, 11, 9, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5,11, 8, 9, 5, 6,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 6, 11, 0, 6, 3, 0, 5, 6, 0, 9, 5, -1, -1, -1, -1, -1},
+ {2, 4, 4, 0, 9, 5, 6, 6,11, 3, 0, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 11, 8, 0, 5, 11, 0, 1, 5, 5, 6, 11, -1, -1, -1, -1, -1},
+ {1, 6, 0, 1, 5, 6,11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 11, 3, 6, 3, 5, 5, 3, 1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 6,11, 3, 1, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /*180 */
+ {{1, 2, 10, 9, 5, 11, 9, 11, 8, 11, 5, 6, -1, -1, -1, -1, -1},
+ {2, 3, 5, 1, 2, 10, 5, 6,11, 8, 9, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 11, 3, 0, 6, 11, 0, 9, 6, 5, 6, 9, 1, 2, 10, -1, -1},
+ {3, 4, 4, 3, 11, 3,0, 6, 9, 5, 6, 0, 2, 10, 1, 2, 10}},
+
+ {{11, 8, 5, 11, 5, 6, 8, 0, 5, 10, 5, 2, 0, 2, 5, -1, -1},
+ { 1, 7,11, 8, 0, 2,10, 5, 6,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{6, 11, 3, 6, 3, 5, 2, 10, 3, 10, 5, 3, -1, -1, -1, -1, -1},
+ {2, 4, 4, 6,11, 3, 5, 10, 5, 3, 2, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 8, 9, 5, 2, 8, 5, 6, 2, 3, 8, 2, -1, -1, -1, -1, -1},
+ {1, 6, 2, 3, 8, 9, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 185 */
+ {{9, 5, 6, 9, 6, 0, 0, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 9, 5, 6, 2, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 5, 8, 1, 8, 0, 5, 6, 8, 3, 8, 2, 6, 2, 8, -1, -1},
+ {1, 7, 1, 5, 6, 2, 3, 8, 0, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 5, 6, 2, 1, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 1, 5, 6, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 3, 6, 1, 6, 10, 3, 8, 6, 5, 6, 9, 8, 9, 6, -1, -1},
+ {1, 7, 1, 3, 8, 9, 5, 6,10, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 1, 0, 10, 0, 6, 9, 5, 0, 5, 6, 0, -1, -1, -1, -1, -1},
+ { 2, 4, 4, 5, 6, 0, 9, 10, 1, 0, 6, -1, -1, -1, -1, -1, -1}},
+
+ /* 190 */
+ {{0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 0, 3, 8, 5, 6, 10, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 3,10, 5, 6, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 5, 10, 7, 5, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 4, 5,10, 11, 7,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 5, 10, 11, 7, 5, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 4, 3, 5,10,11, 7, 8, 3, 0, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 11, 7, 5, 10, 11, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 2, 4, 3, 5, 10, 11, 7, 1, 9, 0, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 195 */
+ {{10, 7, 5, 10, 11, 7, 9, 8, 1, 8, 3, 1, -1, -1, -1, -1, -1},
+ { 2, 4, 4, 10, 11, 7, 5, 1, 9, 8, 3, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 1, 2, 11, 7, 1, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 7, 5, 1, 2,11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 8, 3, 1, 2, 7, 1, 7, 5, 7, 2, 11, -1, -1, -1, -1, -1},
+ {2, 3, 5, 0, 8, 3, 2,11, 7, 5,1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 7, 5, 9, 2, 7, 9, 0, 2, 2, 11, 7, -1, -1, -1, -1, -1},
+ {1, 6, 2,11, 7, 5, 9, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{7, 5, 2, 7, 2, 11, 5, 9, 2, 3, 2, 8, 9, 8, 2, -1, -1},
+ {1, 7, 7, 5, 9, 8, 3, 2,11,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 200 */
+ {{2, 5, 10, 2, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 7, 5,10, 2,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 2, 0, 8, 5, 2, 8, 7, 5, 10, 2, 5, -1, -1, -1, -1, -1},
+ {1, 6, 5,10, 2, 0, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 0, 1, 5, 10, 3, 5, 3, 7, 3, 10, 2, -1, -1, -1, -1, -1},
+ {2, 3, 5, 9, 0, 1, 10, 2, 3, 7, 5, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 8, 2, 9, 2, 1, 8, 7, 2, 10, 2, 5, 7, 5, 2, -1, -1},
+ {1, 7, 9, 8, 7, 5,10, 2, 1,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 3, 5, 3, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 3, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 205 */
+ {{0, 8, 7, 0, 7, 1, 1, 7, 5, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 0, 8, 7, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 0, 3, 9, 3, 5, 5, 3, 7, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 9, 0, 3, 7, 5,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 8, 7, 5, 9, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 7, 5, 9, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 8, 4, 5, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 10,11, 8, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{5, 0, 4, 5, 11, 0, 5, 10, 11, 11, 3, 0, -1, -1, -1, -1, -1},
+ {1, 6, 0, 4, 5,10,11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 210 */
+ {{0, 1, 9, 8, 4, 10, 8, 10, 11, 10, 4, 5, -1, -1, -1, -1, -1},
+ {2, 3, 5, 0, 1, 9, 4, 5, 10, 11, 8, -1, -1, -1, -1, -1, -1}},
+
+ {{10, 11, 4, 10, 4, 5, 11, 3, 4, 9, 4, 1, 3, 1, 4, -1, -1},
+ { 1, 7,10, 11, 3, 1, 9,4, 5,-1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 5, 1, 2, 8, 5, 2, 11, 8, 4, 5, 8, -1, -1, -1, -1, -1},
+ {1, 6, 2,11, 8, 4, 5, 1,-1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 4, 11, 0, 11, 3, 4, 5, 11, 2, 11, 1, 5, 1, 11, -1, -1},
+ {1, 7, 0, 4, 5, 1, 2, 11, 3,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 2, 5, 0, 5, 9, 2, 11, 5, 4, 5, 8, 11, 8, 5, -1, -1},
+ {1, 7, 0, 2,11, 8, 4, 5, 9, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 215 */
+ {{9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 9, 4, 5, 2, 11, 3, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 5, 10, 3, 5, 2, 3, 4, 5, 3, 8, 4, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2, 3, 5, 10, 4, 5, 3, 8,-1, -1, -1, -1, -1, -1}},
+
+ {{5, 10, 2, 5, 2, 4, 4, 2, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 5,10, 2, 0, 4,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 10, 2, 3, 5, 10, 3, 8, 5, 4, 5, 8, 0, 1, 9, -1, -1},
+ {3, 4, 4, 3, 3, 5, 10, 2, 8, 4, 5, 3, 0, 1, 9, -1, -1}},
+
+ {{5, 10, 2, 5, 2, 4, 1, 9, 2, 9, 4, 2, -1, -1, -1, -1, -1},
+ {1, 6,10, 2, 1, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 220 */
+ {{8, 4, 5, 8, 5, 3, 3, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 8, 4, 5, 1, 3,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 4, 5, 1, 0, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 0, 4, 5, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{8, 4, 5, 8, 5, 3, 9, 0, 5, 0, 3, 5, -1, -1, -1, -1, -1},
+ {2, 4, 4, 0, 3, 5, 9, 8, 4, 5, 3, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 9, 4, 5, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 11, 7, 4, 9, 11, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 9,10, 11, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 225 */
+ {{0, 8, 3, 4, 9, 7, 9, 11, 7, 9, 10, 11, -1, -1, -1, -1, -1},
+ {2, 3, 5, 0, 8, 3, 7, 4, 9, 10, 11, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 10, 11, 1, 11, 4, 1, 4, 0, 7, 4, 11, -1, -1, -1, -1, -1},
+ {1, 6, 1, 10,11, 7, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 1, 4, 3, 4, 8, 1, 10, 4, 7, 4, 11, 10, 11, 4, -1, -1},
+ {1, 7, 3, 1,10,11, 7, 4, 8, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 11, 7, 9, 11, 4, 9, 2, 11, 9, 1, 2, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2, 11, 9, 1, 4, 9, 11, 7, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 7, 4, 9, 11, 7, 9, 1, 11, 2, 11, 1, 0, 8, 3, -1, -1},
+ {3, 4, 4, 3, 1, 2, 11, 9, 7, 4, 9,11, 8, 3, 0, 8, 3}},
+
+ /* 230 */
+ {{11, 7, 4, 11, 4, 2, 2, 4, 0, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 1, 5, 11, 7, 4, 0, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{11, 7, 4, 11, 4, 2, 8, 3, 4, 3, 2, 4, -1, -1, -1, -1, -1},
+ { 2, 4, 4, 11, 7, 4, 2, 3, 2, 4, 8,-1, -1, -1, -1, -1, -1}},
+
+ {{2, 9, 10, 2, 7, 9, 2, 3, 7, 7, 4, 9, -1, -1, -1, -1, -1},
+ {1, 6, 2, 3, 7, 4, 9,10, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 10, 7, 9, 7, 4, 10, 2, 7, 8, 7, 0, 2, 0, 7, -1, -1},
+ {1, 7, 9,10, 2, 0, 8, 7, 4,-1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 7, 10, 3, 10, 2, 7, 4, 10, 1, 10, 0, 4, 0, 10, -1, -1},
+ {1, 7, 3, 7, 4, 0, 1,10, 2, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 235 */
+ {{1, 10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {2, 3, 3, 1,10, 2, 8, 7, 4, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 9, 1, 4, 1, 7, 7, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 4, 9, 1, 3, 7,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 9, 1, 4, 1, 7, 0, 8, 1, 8, 7, 1, -1, -1, -1, -1, -1},
+ {2, 4, 4, 8, 7, 1, 0, 4, 9, 1, 7, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 0, 3, 7, 4, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 3, 7, 4, 0,-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 4, 8, 7, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 240 */
+ {{9, 10, 8, 10, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 8, 9, 10,11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 0, 9, 3, 9, 11, 11, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 3, 0, 9, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 1, 10, 0, 10, 8, 8, 10, 11, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 0, 1, 10,11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 1, 10, 11, 3, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 3, 1,10, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 2, 11, 1, 11, 9, 9, 11, 8, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 1, 2, 11, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 245 */
+ {{3, 0, 9, 3, 9, 11, 1, 2, 9, 2, 11, 9, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2,11, 9, 1, 3, 0, 9, 11, -1, -1, -1, -1, -1,-1}},
+
+ {{0, 2, 11, 8, 0, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 0, 2,11, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 3, 2, 11, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{2, 3, 8, 2, 8, 10, 10, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 5, 2, 3, 8, 9, 10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{9, 10, 2, 0, 9, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 2, 0, 9,10, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ /* 250 */
+ {{2, 3, 8, 2, 8, 10, 0, 1, 8, 1, 10, 8, -1, -1, -1, -1, -1},
+ {2, 4, 4, 2, 3, 8, 10, 1, 10, 8, 0, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 1, 10, 2, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{1, 3, 8, 9, 1, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 4, 1, 3, 8, 9, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 0, 9, 1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ {1, 3, 0, 3, 8, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}},
+
+ {{-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1},
+ { 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1}}
+};
+
+
+//-----------------------------------------------------------------------------
+
+
+const int polyTable[8][16] =
+{
+ {-1},
+ {-1},
+ {-1},
+ {0, 1, 2, -1},
+ {0, 1, 2, 2, 3, 0, -1},
+ {0, 1, 2, 0, 2, 4, 4, 2, 3, -1},
+ {0, 1, 2, 2, 3, 4, 4, 5, 0, 0, 2, 4, -1},
+ {0, 1, 5, 0, 5, 6, 1, 2, 5, 4, 5, 3, 2, 3, 5, -1}
+};
+
+
+//=============================================================================
+
+
+//=============================================================================
+#endif // ISOEX_MC_TABLES_HH defined
+//=============================================================================
diff --git a/xs/src/igl/copyleft/offset_surface.cpp b/xs/src/igl/copyleft/offset_surface.cpp
new file mode 100644
index 000000000..c9e90553f
--- /dev/null
+++ b/xs/src/igl/copyleft/offset_surface.cpp
@@ -0,0 +1,64 @@
+#include "offset_surface.h"
+#include "marching_cubes.h"
+#include "../voxel_grid.h"
+#include "../signed_distance.h"
+#include "../flood_fill.h"
+#include <cassert>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename isolevelType,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedGV,
+ typename Derivedside,
+ typename DerivedS>
+void igl::copyleft::offset_surface(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const isolevelType isolevel,
+ const typename Derivedside::Scalar s,
+ const SignedDistanceType & signed_distance_type,
+ Eigen::PlainObjectBase<DerivedSV> & SV,
+ Eigen::PlainObjectBase<DerivedSF> & SF,
+ Eigen::PlainObjectBase<DerivedGV> & GV,
+ Eigen::PlainObjectBase<Derivedside> & side,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ typedef typename DerivedV::Scalar Scalar;
+ typedef typename DerivedF::Scalar Index;
+ {
+ Eigen::AlignedBox<Scalar,3> box;
+ typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
+ assert(V.cols() == 3 && "V must contain positions in 3D");
+ RowVector3S min_ext = V.colwise().minCoeff().array() - isolevel;
+ RowVector3S max_ext = V.colwise().maxCoeff().array() + isolevel;
+ box.extend(min_ext.transpose());
+ box.extend(max_ext.transpose());
+ igl::voxel_grid(box,s,1,GV,side);
+ }
+
+ const Scalar h =
+ (GV.col(0).maxCoeff()-GV.col(0).minCoeff())/((Scalar)(side(0)-1));
+ const Scalar lower_bound = isolevel-sqrt(3.0)*h;
+ const Scalar upper_bound = isolevel+sqrt(3.0)*h;
+ {
+ Eigen::Matrix<Index,Eigen::Dynamic,1> I;
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> C,N;
+ igl::signed_distance(
+ GV,V,F,signed_distance_type,lower_bound,upper_bound,S,I,C,N);
+ }
+ igl::flood_fill(side,S);
+
+ DerivedS SS = S.array()-isolevel;
+ igl::copyleft::marching_cubes(SS,GV,side(0),side(1),side(2),SV,SF);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::offset_surface<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, float, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::copyleft::offset_surface<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::Matrix<int, 1, 3, 1, 1, 3>::Scalar, igl::SignedDistanceType const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/offset_surface.h b/xs/src/igl/copyleft/offset_surface.h
new file mode 100644
index 000000000..7c6307378
--- /dev/null
+++ b/xs/src/igl/copyleft/offset_surface.h
@@ -0,0 +1,54 @@
+#ifndef IGL_COPYLEFT_OFFSET_SURFACE_H
+#define IGL_COPYLEFT_OFFSET_SURFACE_H
+#include "../igl_inline.h"
+#include "../signed_distance.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ // Compute a triangulated offset surface using matching cubes on a grid of
+ // signed distance values from the input triangle mesh.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of mesh triangle indices into V
+ // isolevel iso level to extract (signed distance: negative inside)
+ // s number of grid cells along longest side (controls resolution)
+ // signed_distance_type type of signing to use (see
+ // ../signed_distance.h)
+ // Outputs:
+ // SV #SV by 3 list of output surface mesh vertex positions
+ // SF #SF by 3 list of output mesh triangle indices into SV
+ // GV #GV=side(0)*side(1)*side(2) by 3 list of grid cell centers
+ // side list of number of grid cells in x, y, and z directions
+ // S #GV by 3 list of signed distance values _near_ `isolevel` ("far"
+ // from `isolevel` these values are incorrect)
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename isolevelType,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedGV,
+ typename Derivedside,
+ typename DerivedS>
+ void offset_surface(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const isolevelType isolevel,
+ const typename Derivedside::Scalar s,
+ const SignedDistanceType & signed_distance_type,
+ Eigen::PlainObjectBase<DerivedSV> & SV,
+ Eigen::PlainObjectBase<DerivedSF> & SF,
+ Eigen::PlainObjectBase<DerivedGV> & GV,
+ Eigen::PlainObjectBase<Derivedside> & side,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "offset_surface.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/opengl2/render_to_tga.cpp b/xs/src/igl/copyleft/opengl2/render_to_tga.cpp
new file mode 100644
index 000000000..6d0f97ea1
--- /dev/null
+++ b/xs/src/igl/copyleft/opengl2/render_to_tga.cpp
@@ -0,0 +1,87 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "render_to_tga.h"
+#include "tga.h"
+
+#include "../../opengl2/gl.h"
+
+#include <cstdlib>
+
+IGL_INLINE bool igl::opengl::render_to_tga(
+ const std::string tga_file,
+ const int width,
+ const int height,
+ const bool alpha)
+{
+
+ size_t components = 3;
+ GLenum format = GL_BGR;
+ if(alpha)
+ {
+ format = GL_BGRA;
+ components = 4;
+ }
+ GLubyte * cmap = NULL;
+
+ // OpenGL by default tries to read data in multiples of 4, if our data is
+ // only RGB or BGR and the width is not divible by 4 then we need to alert
+ // opengl
+ if((width % 4) != 0 &&
+ (format == GL_RGB ||
+ format == GL_BGR))
+ {
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ }
+ GLubyte *pixels;
+ pixels = (unsigned char *) malloc (width * height * components);
+ glReadPixels(
+ 0,
+ 0,
+ width,
+ height,
+ format,
+ GL_UNSIGNED_BYTE,
+ pixels);
+
+ // set up generic image struct
+ gliGenericImage * genericImage;
+ genericImage = (gliGenericImage*) malloc(sizeof(gliGenericImage));
+ genericImage->width = width;
+ genericImage->height = height;
+ genericImage->format = format;
+ genericImage->components = components;
+ genericImage->pixels = pixels;
+ // CMAP is not supported, but we need to put something here
+ genericImage->cmapEntries = 0;
+ genericImage->cmapFormat = GL_BGR;
+ genericImage->cmap = cmap;
+
+ // write pixels to tga file
+ FILE * imgFile;
+ // "-" as output file name is code for write to stdout
+ if(tga_file.compare("-") == 0)
+ {
+ imgFile = stdout;
+ }else{
+ imgFile = fopen(tga_file.c_str(),"w");
+ if(NULL==imgFile)
+ {
+ printf("IOError: %s could not be opened...\n",tga_file.c_str());
+ return false;
+ }
+ }
+
+ writeTGA(genericImage,imgFile);
+
+ free(genericImage);
+ return fclose(imgFile) == 0;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/copyleft/opengl2/render_to_tga.h b/xs/src/igl/copyleft/opengl2/render_to_tga.h
new file mode 100644
index 000000000..d792c1e31
--- /dev/null
+++ b/xs/src/igl/copyleft/opengl2/render_to_tga.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_RENDER_TO_TGA_H
+#define IGL_OPENGL_RENDER_TO_TGA_H
+#include "../../igl_inline.h"
+#include <string>
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Render current open GL image to .tga file
+ // Inputs:
+ // tga_file path to output .tga file
+ // width width of scene and resulting image
+ // height height of scene and resulting image
+ /// alpha whether to include alpha channel
+ // Returns true only if no errors occurred
+ //
+ // See also: png/render_to_png which is slower but writes .png files
+ IGL_INLINE bool render_to_tga(
+ const std::string tga_file,
+ const int width,
+ const int height,
+ const bool alpha);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "render_to_tga.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/opengl2/texture_from_tga.cpp b/xs/src/igl/copyleft/opengl2/texture_from_tga.cpp
new file mode 100644
index 000000000..717a6734c
--- /dev/null
+++ b/xs/src/igl/copyleft/opengl2/texture_from_tga.cpp
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "texture_from_tga.h"
+#include "tga.h"
+#include <cstring>
+
+IGL_INLINE bool igl::opengl::texture_from_tga(const std::string tga_file, GLuint & id)
+{
+ using namespace std;
+
+ // read pixels to tga file
+ FILE * imgFile;
+ // "-" as input file name is code for read from stdin
+ imgFile = fopen(tga_file.c_str(),"r");
+ if(NULL==imgFile)
+ {
+ printf("IOError: %s could not be opened...",tga_file.c_str());
+ return false;
+ }
+
+ // gliReadTGA annoyingly uses char * instead of const char *
+ size_t len = tga_file.length();
+ char* tga_file_char = new char [ len + 1 ];
+ strcpy( tga_file_char, tga_file.c_str() );
+ // read image
+ gliGenericImage* img = gliReadTGA(imgFile, tga_file_char, 0, 0);
+ // clean up filename buffer
+ delete[] tga_file_char;
+ fclose( imgFile );
+
+ // set up texture mapping parameters and generate texture id
+ glGenTextures(1,&id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ // Texture parameters
+ float empty[] = {1.0f,1.0f,1.0f,0.0f};
+ glTexParameterfv(GL_TEXTURE_2D,GL_TEXTURE_BORDER_COLOR,empty);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
+ //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
+ // GL_LINEAR_MIPMAP_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
+ GL_LINEAR);
+
+ // OpenGL by default tries to read data in multiples of 4, if our data is
+ // only RGB or BGR and the width is not divible by 4 then we need to alert
+ // opengl
+ if((img->width % 4) != 0 &&
+ (img->format == GL_RGB ||
+ img->format == GL_BGR))
+ {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ }
+
+ // Load texture
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img->width,
+ img->height, 0, img->format, GL_UNSIGNED_BYTE,
+ img->pixels);
+ return id;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/copyleft/opengl2/texture_from_tga.h b/xs/src/igl/copyleft/opengl2/texture_from_tga.h
new file mode 100644
index 000000000..8a5f704c7
--- /dev/null
+++ b/xs/src/igl/copyleft/opengl2/texture_from_tga.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_TEXTURE_FROM_TGA_H
+#define IGL_OPENGL_TEXTURE_FROM_TGA_H
+#include "../../igl_inline.h"
+#include "../../opengl2/gl.h"
+#include <string>
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Read an image from a .tga file and use it as a texture
+ //
+ // Input:
+ // tga_file path to .tga file
+ // Output:
+ // id of generated openGL texture
+ // Returns true on success, false on failure
+ IGL_INLINE bool texture_from_tga(const std::string tga_file, GLuint & id);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "texture_from_tga.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/opengl2/tga.cpp b/xs/src/igl/copyleft/opengl2/tga.cpp
new file mode 100644
index 000000000..2f1f99022
--- /dev/null
+++ b/xs/src/igl/copyleft/opengl2/tga.cpp
@@ -0,0 +1,549 @@
+////////////////////////////////////////////////////////////////////////////////
+//
+// WARNING
+//
+// THIS DOES NOT DEAL WITH VERTICALLY FLIPPED DATA CORRECTLY
+//
+////////////////////////////////////////////////////////////////////////////////
+
+/* This file is derived from (actually an earlier version of)... */
+
+/* The GIMP -- an image manipulation program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * $Id: tga.cpp,v 1.1.2.5 2007-05-10 02:10:07 elif Exp $
+ * TrueVision Targa loading and saving file filter for the Gimp.
+ * Targa code Copyright (C) 1997 Raphael FRANCOIS and Gordon Matzigkeit
+ *
+ * The Targa reading and writing code was written from scratch by
+ * Raphael FRANCOIS <fraph@ibm.net> and Gordon Matzigkeit
+ * <gord@gnu.ai.mit.edu> based on the TrueVision TGA File Format
+ * Specification, Version 2.0:
+ *
+ * <URL:ftp://ftp.truevision.com/pub/TGA.File.Format.Spec/>
+ *
+ * It does not contain any code written for other TGA file loaders.
+ * Not even the RLE handling. ;)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include "tga.h"
+#include "../../opengl2/glext.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+static char error[256];
+static unsigned int _verbose = 0;
+static int totbytes = 0;
+
+typedef struct {
+ unsigned char *statebuf;
+ int statelen;
+ int laststate;
+} RLEstate;
+
+IGL_INLINE static int
+std_fread(RLEstate * /*rleInfo*/, unsigned char *buf, size_t datasize, size_t nelems, FILE *fp)
+{
+ if (_verbose > 1) {
+ totbytes += nelems * datasize;
+ printf("TGA: std_fread %d (total %d)\n",
+ (int)(nelems * datasize), totbytes);
+ }
+ return fread(buf, datasize, nelems, fp);
+}
+
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+
+#define RLE_PACKETSIZE 0x80
+
+/* Decode a bufferful of file. */
+IGL_INLINE static int
+rle_fread(RLEstate *rleInfo, unsigned char *vbuf, size_t datasize, size_t nelems, FILE *fp)
+{
+
+ unsigned char *buf = vbuf;
+ int j, k;
+ int buflen, count, bytes, curbytes;
+ unsigned char *p;
+
+ /* Scale the buffer length. */
+ buflen = nelems * datasize;
+
+ j = 0;
+ curbytes = totbytes;
+ while (j < buflen) {
+ if (rleInfo->laststate < rleInfo->statelen) {
+ /* Copy bytes from our previously decoded buffer. */
+ bytes = MIN(buflen - j, rleInfo->statelen - rleInfo->laststate);
+ memcpy(buf + j, rleInfo->statebuf + rleInfo->laststate, bytes);
+ j += bytes;
+ rleInfo->laststate += bytes;
+
+ /* If we used up all of our state bytes, then reset them. */
+ if (rleInfo->laststate >= rleInfo->statelen) {
+ rleInfo->laststate = 0;
+ rleInfo->statelen = 0;
+ }
+
+ /* If we filled the buffer, then exit the loop. */
+ if (j >= buflen) break;
+ }
+
+ /* Decode the next packet. */
+ count = fgetc(fp);
+ if (count == EOF) {
+ if (_verbose) printf("TGA: hit EOF while looking for count\n");
+ return j / datasize;
+ }
+
+ /* Scale the byte length to the size of the data. */
+ bytes = ((count & ~RLE_PACKETSIZE) + 1) * datasize;
+
+ if (j + bytes <= buflen) {
+ /* We can copy directly into the image buffer. */
+ p = buf + j;
+ } else {
+#ifdef PROFILE
+ printf("TGA: needed to use statebuf for %d bytes\n", buflen - j);
+#endif
+ /* Allocate the state buffer if we haven't already. */
+ if (!rleInfo->statebuf) {
+ rleInfo->statebuf = (unsigned char *) malloc(RLE_PACKETSIZE * datasize);
+ }
+ p = rleInfo->statebuf;
+ }
+
+ if (count & RLE_PACKETSIZE) {
+ /* Fill the buffer with the next value. */
+ if (fread(p, datasize, 1, fp) != 1) {
+ if (_verbose) {
+ printf("TGA: EOF while reading %d/%d element RLE packet\n",
+ bytes, (int)datasize);
+ }
+ return j / datasize;
+ }
+
+ /* Optimized case for single-byte encoded data. */
+ if (datasize == 1) {
+ memset(p + 1, *p, bytes - 1);
+ } else {
+ for (k = datasize; k < bytes; k += datasize) {
+ memcpy(p + k, p, datasize);
+ }
+ }
+ } else {
+ /* Read in the buffer. */
+ if (fread(p, bytes, 1, fp) != 1) {
+ if (_verbose) {
+ printf("TGA: EOF while reading %d/%d element raw packet\n",
+ bytes, (int)datasize);
+ }
+ return j / datasize;
+ }
+ }
+
+ if (_verbose > 1) {
+ totbytes += bytes;
+ if (_verbose > 2) {
+ printf("TGA: %s packet %d/%d\n",
+ (count & RLE_PACKETSIZE) ? "RLE" : "raw",
+ bytes, totbytes);
+ }
+ }
+
+ /* We may need to copy bytes from the state buffer. */
+ if (p == rleInfo->statebuf) {
+ rleInfo->statelen = bytes;
+ } else {
+ j += bytes;
+ }
+ }
+
+ if (_verbose > 1) {
+ printf("TGA: rle_fread %d/%d (total %d)\n",
+ (int) ( nelems * datasize), totbytes - curbytes, totbytes);
+ }
+ return nelems;
+}
+
+IGL_INLINE igl::opengl::gliGenericImage *
+igl::opengl::gliReadTGA(FILE *fp, char *name, int /*hflip*/, int vflip)
+{
+ igl::opengl::TgaHeader tgaHeader;
+ igl::opengl::TgaFooter tgaFooter;
+ char horzrev, vertrev;
+ int width, height, bpp;
+ int start, end, dir;
+ int i, j, k;
+ int pelbytes, wbytes;
+ GLenum format;
+ int components;
+ RLEstate rleRec;
+ RLEstate *rleInfo;
+ int rle;
+ int index, colors, length;
+ GLubyte *cmap, *pixels, *data;
+ int (*myfread)(RLEstate *rleInfo, unsigned char*, size_t, size_t, FILE*);
+ igl::opengl::gliGenericImage *genericImage;
+
+ /* Check the footer. */
+ if (fseek(fp, 0L - sizeof(tgaFooter), SEEK_END)
+ || fread(&tgaFooter, sizeof(tgaFooter), 1, fp) != 1) {
+ sprintf(error, "TGA: Cannot read footer from \"%s\"", name);
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+
+ /* Check the signature. */
+ if (memcmp(tgaFooter.signature, TGA_SIGNATURE,
+ sizeof(tgaFooter.signature)) == 0) {
+ if (_verbose) printf("TGA: found New TGA\n");
+ } else {
+ if (_verbose) printf("TGA: found Original TGA\n");
+ }
+
+ if (fseek(fp, 0, SEEK_SET) ||
+ fread(&tgaHeader, sizeof(tgaHeader), 1, fp) != 1) {
+ sprintf(error, "TGA: Cannot read header from \"%s\"", name);
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+
+ if (_verbose && tgaHeader.idLength) {
+ char *idString = (char*) malloc(tgaHeader.idLength);
+
+ if (fread(idString, tgaHeader.idLength, 1, fp) != 1) {
+ sprintf(error, "TGA: Cannot read ID field in \"%s\"", name);
+ printf("%s\n", error);
+ } else {
+ printf("TGA: ID field: \"%*s\"\n", tgaHeader.idLength, idString);
+ }
+ free(idString);
+ } else {
+ /* Skip the image ID field. */
+ if (tgaHeader.idLength && fseek(fp, tgaHeader.idLength, SEEK_CUR)) {
+ sprintf(error, "TGA: Cannot skip ID field in \"%s\"", name);
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+ }
+
+ /* Reassemble the multi-byte values correctly, regardless of
+ host endianness. */
+ width = (tgaHeader.widthHi << 8) | tgaHeader.widthLo;
+ height = (tgaHeader.heightHi << 8) | tgaHeader.heightLo;
+ bpp = tgaHeader.bpp;
+ if (_verbose) {
+ printf("TGA: width=%d, height=%d, bpp=%d\n", width, height, bpp);
+ }
+
+ horzrev = tgaHeader.descriptor & TGA_DESC_HORIZONTAL;
+ vertrev = tgaHeader.descriptor & TGA_DESC_VERTICAL;
+ //vertrev=0;
+
+// // JASON - we can force this stuff if we want
+// if( hflip )
+// horzrev = 1;
+ if( vflip )
+ vertrev = 1;
+
+ if (_verbose && horzrev) printf("TGA: horizontal reversed\n");
+ if (_verbose && vertrev) printf("TGA: vertical reversed\n");
+
+ rle = 0;
+ switch (tgaHeader.imageType) {
+ case TGA_TYPE_MAPPED_RLE:
+ rle = 1;
+ if (_verbose) printf("TGA: run-length encoded\n");
+ case TGA_TYPE_MAPPED:
+ /* Test for alpha channel. */
+ format = GL_COLOR_INDEX;
+ components = 1;
+ if (_verbose) {
+ printf("TGA: %d bit indexed image (%d bit palette)\n",
+ tgaHeader.colorMapSize, bpp);
+ }
+ break;
+
+ case TGA_TYPE_GRAY_RLE:
+ rle = 1;
+ if (_verbose) printf("TGA: run-length encoded\n");
+ case TGA_TYPE_GRAY:
+ format = GL_LUMINANCE;
+ components = 1;
+ if (_verbose) printf("TGA: %d bit grayscale image\n", bpp);
+ break;
+
+ case TGA_TYPE_COLOR_RLE:
+ rle = 1;
+ if (_verbose) printf("TGA: run-length encoded\n");
+ case TGA_TYPE_COLOR:
+ /* Test for alpha channel. */
+ if (bpp == 32) {
+ format = GL_BGRA_EXT;
+ components = 4;
+ if (_verbose) {
+ printf("TGA: %d bit color image with alpha channel\n", bpp);
+ }
+ } else {
+ format = GL_BGR_EXT;
+ components = 3;
+ if (_verbose) printf("TGA: %d bit color image\n", bpp);
+ }
+ break;
+
+ default:
+ sprintf(error,
+ "TGA: unrecognized image type %d\n", tgaHeader.imageType);
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+
+ if ((format == GL_BGRA_EXT && bpp != 32) ||
+ (format == GL_BGR_EXT && bpp != 24) ||
+ ((format == GL_LUMINANCE || format == GL_COLOR_INDEX) && bpp != 8)) {
+ /* FIXME: We haven't implemented bit-packed fields yet. */
+ fprintf(stderr, "bpp %d, format %x\n", bpp, (unsigned int)format);
+ sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+
+ /* Check that we have a color map only when we need it. */
+ if (format == GL_COLOR_INDEX) {
+ if (tgaHeader.colorMapType != 1) {
+ sprintf(error, "TGA: indexed image has invalid color map type %d\n",
+ tgaHeader.colorMapType);
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+ } else if (tgaHeader.colorMapType != 0) {
+ sprintf(error, "TGA: non-indexed image has invalid color map type %d\n",
+ tgaHeader.colorMapType);
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+
+ if (tgaHeader.colorMapType == 1) {
+ /* We need to read in the colormap. */
+ index = (tgaHeader.colorMapIndexHi << 8) | tgaHeader.colorMapIndexLo;
+ length = (tgaHeader.colorMapLengthHi << 8) | tgaHeader.colorMapLengthLo;
+
+ if (_verbose) {
+ printf("TGA: reading color map (%d + %d) * (%d / 8)\n",
+ index, length, tgaHeader.colorMapSize);
+ }
+ if (length == 0) {
+ sprintf(error, "TGA: invalid color map length %d", length);
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+ if (tgaHeader.colorMapSize != 24) {
+ /* We haven't implemented bit-packed fields yet. */
+ sprintf(error, "TGA: channel sizes other than 8 bits are unimplemented");
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+
+ pelbytes = tgaHeader.colorMapSize / 8;
+ colors = length + index;
+ cmap = (GLubyte*)malloc (colors * pelbytes);
+
+ /* Zero the entries up to the beginning of the map. */
+ memset(cmap, 0, index * pelbytes);
+
+ /* Read in the rest of the colormap. */
+ if (fread(cmap, pelbytes, length, fp) != (size_t) length) {
+ sprintf(error, "TGA: error reading colormap (ftell == %ld)\n",
+ ftell (fp));
+ if (_verbose) printf("%s\n", error);
+ return NULL;
+ }
+
+ if (pelbytes >= 3) {
+ /* Rearrange the colors from BGR to RGB. */
+ int tmp;
+ for (j = index; j < length * pelbytes; j += pelbytes) {
+ tmp = cmap[j];
+ cmap[j] = cmap[j + 2];
+ cmap[j + 2] = tmp;
+ }
+ }
+ } else {
+ colors = 0;
+ cmap = NULL;
+ }
+
+ /* Allocate the data. */
+ pelbytes = bpp / 8;
+ pixels = (unsigned char *) malloc (width * height * pelbytes);
+
+ if (rle) {
+ rleRec.statebuf = 0;
+ rleRec.statelen = 0;
+ rleRec.laststate = 0;
+ rleInfo = &rleRec;
+ myfread = rle_fread;
+ } else {
+ rleInfo = NULL;
+ myfread = std_fread;
+ }
+
+ wbytes = width * pelbytes;
+
+ if (vertrev) {
+ start = 0;
+ end = height;
+ dir = 1;
+ } else {
+ /* We need to reverse loading order of rows. */
+ start = height-1;
+ end = -1;
+ dir = -1;
+ }
+
+ for (i = start; i != end; i += dir) {
+ data = pixels + i*wbytes;
+
+ /* Suck in the data one row at a time. */
+ if (myfread(rleInfo, data, pelbytes, width, fp) != width) {
+ /* Probably premature end of file. */
+ if (_verbose) {
+ printf ("TGA: error reading (ftell == %ld, width=%d)\n",
+ ftell(fp), width);
+ }
+ return NULL;
+ }
+
+ if (horzrev) {
+ /* We need to mirror row horizontally. */
+ for (j = 0; j < width/2; j++) {
+ GLubyte tmp;
+
+ for (k = 0; k < pelbytes; k++) {
+ tmp = data[j*pelbytes+k];
+ data[j*pelbytes+k] = data[(width-j-1)*pelbytes+k];
+ data[(width-j-1)*pelbytes+k] = tmp;
+ }
+ }
+ }
+ }
+
+ if (rle) {
+ free(rleInfo->statebuf);
+ }
+
+ if (fgetc (fp) != EOF) {
+ if (_verbose) printf ("TGA: too much input data, ignoring extra...\n");
+ }
+
+ genericImage = (igl::opengl::gliGenericImage*) malloc(sizeof(igl::opengl::gliGenericImage));
+ genericImage->width = width;
+ genericImage->height = height;
+ genericImage->format = format;
+ genericImage->components = components;
+ genericImage->cmapEntries = colors;
+ genericImage->cmapFormat = GL_BGR_EXT; // XXX fix me
+ genericImage->cmap = cmap;
+ genericImage->pixels = pixels;
+
+ return genericImage;
+}
+
+IGL_INLINE int igl::opengl::gli_verbose(int new_verbose)
+{
+ _verbose = new_verbose;
+ return _verbose;
+}
+
+
+
+// added 10/2005, Denis Zorin
+// a very simple TGA output, supporting
+// uncompressed luminance RGB and RGBA
+// G22.2270 students: this is C (no C++)
+// so this is not the style I would encourage
+// you to use; I used it for consistency
+// with the rest of the code in this file
+
+
+// fixed header values for the subset of TGA we use for writing
+unsigned char TGAHeaderColor[12] =
+ { 0,// 0 ID length = no id
+ 0,// 1 color map type = no color map
+ 2,// 2 image type = uncompressed true color
+ 0, 0, 0, 0, 0,// color map spec = empty
+ 0, 0, // x origin of image
+ 0, 0 // y origin of image
+ };
+
+unsigned char TGAHeaderBW[12] =
+ { 0,// 0 ID length = no id
+ 0,// 1 color map type = no color map
+ 3,// 3 image type = uncompressed black and white
+ 0, 0, 0, 0, 0,// color map spec = empty
+ 0, 0, // x origin of image
+ 0, 0 // y origin of image
+ };
+
+// this makes sure that
+// image size is written in correct format
+// and byte order (least first)
+IGL_INLINE void write16bit(int n, FILE* fp) {
+ unsigned char bytes[] = { static_cast<unsigned char>(n % 256), static_cast<unsigned char>(n / 256) };
+ fwrite(bytes, 2, sizeof(unsigned char),fp);
+}
+
+
+
+IGL_INLINE void igl::opengl::writeTGA( igl::opengl::gliGenericImage* image, FILE *fp) {
+
+ assert(!image->cmap); // we do not deal with color map images
+
+ if(image->components == 3 || image->components == 4)
+ fwrite(TGAHeaderColor, 12, sizeof(unsigned char),fp);
+ else {
+ if(image->components == 1 )
+ fwrite(TGAHeaderBW, 12, sizeof(unsigned char),fp);
+ else { fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1); }
+ }
+
+ write16bit(image->width,fp);
+ write16bit(image->height,fp);
+ switch (image->components ) {
+ case 1:
+ putc(8,fp);
+ break;
+ case 3:
+ putc(24,fp);
+ break;
+ case 4:
+ putc(32,fp);
+ break;
+ default: fprintf(stderr,"Supported component number: 1,3 or 4\n"); exit(1);
+ };
+
+ if(image-> components == 4)
+ putc(0x04,fp); // bottom left image (0x00) + 8 bit alpha (0x4)
+ else
+ putc(0x00,fp);
+
+ fwrite(image->pixels, image->height*image->width*image->components, sizeof(char),fp);
+}
+
diff --git a/xs/src/igl/copyleft/opengl2/tga.h b/xs/src/igl/copyleft/opengl2/tga.h
new file mode 100644
index 000000000..b69f35496
--- /dev/null
+++ b/xs/src/igl/copyleft/opengl2/tga.h
@@ -0,0 +1,106 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_TGA_H
+#define IGL_OPENGL_TGA_H
+#include "../../igl_inline.h"
+
+#include "../../opengl2/gl.h"
+// See license in tga.cpp
+/* tga.h - interface for TrueVision (TGA) image file loader */
+#include <stdio.h>
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+namespace igl
+{
+namespace opengl
+{
+
+typedef struct {
+
+ GLsizei width;
+ GLsizei height;
+ GLint components;
+ GLenum format;
+
+ GLsizei cmapEntries;
+ GLenum cmapFormat;
+ GLubyte *cmap;
+
+ GLubyte *pixels;
+
+} gliGenericImage;
+
+typedef struct {
+ unsigned char idLength;
+ unsigned char colorMapType;
+
+ /* The image type. */
+#define TGA_TYPE_MAPPED 1
+#define TGA_TYPE_COLOR 2
+#define TGA_TYPE_GRAY 3
+#define TGA_TYPE_MAPPED_RLE 9
+#define TGA_TYPE_COLOR_RLE 10
+#define TGA_TYPE_GRAY_RLE 11
+ unsigned char imageType;
+
+ /* Color Map Specification. */
+ /* We need to separately specify high and low bytes to avoid endianness
+ and alignment problems. */
+ unsigned char colorMapIndexLo, colorMapIndexHi;
+ unsigned char colorMapLengthLo, colorMapLengthHi;
+ unsigned char colorMapSize;
+
+ /* Image Specification. */
+ unsigned char xOriginLo, xOriginHi;
+ unsigned char yOriginLo, yOriginHi;
+
+ unsigned char widthLo, widthHi;
+ unsigned char heightLo, heightHi;
+
+ unsigned char bpp;
+
+ /* Image descriptor.
+ 3-0: attribute bpp
+ 4: left-to-right ordering
+ 5: top-to-bottom ordering
+ 7-6: zero
+ */
+#define TGA_DESC_ABITS 0x0f
+#define TGA_DESC_HORIZONTAL 0x10
+#define TGA_DESC_VERTICAL 0x20
+ unsigned char descriptor;
+
+} TgaHeader;
+
+typedef struct {
+ unsigned int extensionAreaOffset;
+ unsigned int developerDirectoryOffset;
+#define TGA_SIGNATURE "TRUEVISION-XFILE"
+ char signature[16];
+ char dot;
+ char null;
+} TgaFooter;
+
+IGL_INLINE extern gliGenericImage *gliReadTGA(FILE *fp, char *name, int hflip, int vflip);
+IGL_INLINE int gli_verbose(int new_verbose);
+IGL_INLINE extern int gliVerbose(int newVerbose);
+
+IGL_INLINE void writeTGA( gliGenericImage* image, FILE *fp);
+
+
+
+} // end of igl namespace
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "tga.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/progressive_hulls.cpp b/xs/src/igl/copyleft/progressive_hulls.cpp
new file mode 100644
index 000000000..44738c8b2
--- /dev/null
+++ b/xs/src/igl/copyleft/progressive_hulls.cpp
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "progressive_hulls.h"
+#include "progressive_hulls_cost_and_placement.h"
+#include "../decimate.h"
+#include "../max_faces_stopping_condition.h"
+IGL_INLINE bool igl::copyleft::progressive_hulls(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J)
+{
+ int m = F.rows();
+ Eigen::VectorXi I;
+ return decimate(
+ V,
+ F,
+ progressive_hulls_cost_and_placement,
+ max_faces_stopping_condition(m,(const int)m,max_m),
+ U,
+ G,
+ J,
+ I);
+}
diff --git a/xs/src/igl/copyleft/progressive_hulls.h b/xs/src/igl/copyleft/progressive_hulls.h
new file mode 100644
index 000000000..54e0580a0
--- /dev/null
+++ b/xs/src/igl/copyleft/progressive_hulls.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_PROGRESSIVE_HULLS_H
+#define IGL_COPYLEFT_PROGRESSIVE_HULLS_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ // Assumes (V,F) is a closed manifold mesh
+ // Collapses edges until desired number of faces is achieved but ensures
+ // that new vertices are placed outside all previous meshes as per
+ // "progressive hulls" in "Silhouette clipping" [Sander et al. 2000].
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // F #F by 3 list of face indices into V.
+ // max_m desired number of output faces
+ // Outputs:
+ // U #U by dim list of output vertex posistions (can be same ref as V)
+ // G #G by 3 list of output face indices into U (can be same ref as G)
+ // J #G list of indices into F of birth faces
+ // Returns true if m was reached (otherwise #G > m)
+ IGL_INLINE bool progressive_hulls(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "progressive_hulls.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/progressive_hulls_cost_and_placement.cpp b/xs/src/igl/copyleft/progressive_hulls_cost_and_placement.cpp
new file mode 100644
index 000000000..c9ab79ced
--- /dev/null
+++ b/xs/src/igl/copyleft/progressive_hulls_cost_and_placement.cpp
@@ -0,0 +1,107 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "progressive_hulls_cost_and_placement.h"
+#include "quadprog.h"
+#include "../unique.h"
+#include "../circulation.h"
+#include <cassert>
+#include <vector>
+#include <limits>
+
+IGL_INLINE void igl::copyleft::progressive_hulls_cost_and_placement(
+ const int e,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ double & cost,
+ Eigen::RowVectorXd & p)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Controls the amount of quadratic energy to add (too small will introduce
+ // instabilities and flaps)
+ const double w = 0.1;
+
+ assert(V.cols() == 3 && "V.cols() should be 3");
+ // Gather list of unique face neighbors
+ vector<int> Nall = circulation(e, true,F,E,EMAP,EF,EI);
+ vector<int> Nother= circulation(e,false,F,E,EMAP,EF,EI);
+ Nall.insert(Nall.end(),Nother.begin(),Nother.end());
+ vector<int> N;
+ igl::unique(Nall,N);
+ // Gather:
+ // A #N by 3 normals scaled by area,
+ // D #N determinants of matrix formed by points as columns
+ // B #N point on plane dot normal
+ MatrixXd A(N.size(),3);
+ VectorXd D(N.size());
+ VectorXd B(N.size());
+ //cout<<"N=[";
+ for(int i = 0;i<N.size();i++)
+ {
+ const int f = N[i];
+ //cout<<(f+1)<<" ";
+ const RowVector3d & v01 = V.row(F(f,1))-V.row(F(f,0));
+ const RowVector3d & v20 = V.row(F(f,2))-V.row(F(f,0));
+ A.row(i) = v01.cross(v20);
+ B(i) = V.row(F(f,0)).dot(A.row(i));
+ D(i) =
+ (Matrix3d()<< V.row(F(f,0)), V.row(F(f,1)), V.row(F(f,2)))
+ .finished().determinant();
+ }
+ //cout<<"];"<<endl;
+ // linear objective
+ Vector3d f = A.colwise().sum().transpose();
+ VectorXd x;
+ //bool success = linprog(f,-A,-B,MatrixXd(0,A.cols()),VectorXd(0,1),x);
+ //VectorXd _;
+ //bool success = mosek_linprog(f,A.sparseView(),B,_,_,_,env,x);
+ //if(success)
+ //{
+ // cost = (1./6.)*(x.dot(f) - D.sum());
+ //}
+ bool success = false;
+ {
+ RowVectorXd mid = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
+ MatrixXd G = w*Matrix3d::Identity(3,3);
+ VectorXd g0 = (1.-w)*f - w*mid.transpose();
+ const int n = A.cols();
+ success = quadprog(
+ G,g0,
+ MatrixXd(n,0),VectorXd(0,1),
+ A.transpose(),-B,x);
+ cost = (1.-w)*(1./6.)*(x.dot(f) - D.sum()) +
+ w*(x.transpose()-mid).squaredNorm() +
+ w*(V.row(E(e,0))-V.row(E(e,1))).norm();
+ }
+
+ // A x >= B
+ // A x - B >=0
+ // This is annoyingly necessary. Seems the solver is letting some garbage
+ // slip by.
+ success = success && ((A*x-B).minCoeff()>-1e-10);
+ if(success)
+ {
+ p = x.transpose();
+ //assert(cost>=0 && "Cost should be positive");
+ }else
+ {
+ cost = std::numeric_limits<double>::infinity();
+ //VectorXi NM;
+ //igl::list_to_matrix(N,NM);
+ //cout<<matlab_format((NM.array()+1).eval(),"N")<<endl;
+ //cout<<matlab_format(f,"f")<<endl;
+ //cout<<matlab_format(A,"A")<<endl;
+ //cout<<matlab_format(B,"B")<<endl;
+ //exit(-1);
+ p = RowVectorXd::Constant(1,3,std::nan("inf-cost"));
+ }
+}
diff --git a/xs/src/igl/copyleft/progressive_hulls_cost_and_placement.h b/xs/src/igl/copyleft/progressive_hulls_cost_and_placement.h
new file mode 100644
index 000000000..bbe4875d8
--- /dev/null
+++ b/xs/src/igl/copyleft/progressive_hulls_cost_and_placement.h
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_PROGRESSIVE_HULLS_COST_AND_PLACEMENT_H
+#define IGL_COPYLEFT_PROGRESSIVE_HULLS_COST_AND_PLACEMENT_H
+#include <Eigen/Core>
+#include "../igl_inline.h"
+namespace igl
+{
+ namespace copyleft
+ {
+ // A "cost and placement" compatible with `igl::decimate` implementing the
+ // "progressive hulls" algorithm in "Silhouette clipping" [Sander et al.
+ // 2000]. This implementation fixes an issue that the original linear
+ // program becomes unstable for flat patches by introducing a small
+ // quadratic energy term pulling the collapsed edge toward its midpoint.
+ // This function is not really meant to be called directly but rather
+ // passed to `igl::decimate` as a handle.
+ //
+ // Inputs:
+ // e index of edge to be collapsed
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of faces indices into V
+ // E #E by 3 list of edges 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).
+ // Outputs:
+ // cost cost of collapsing edge e
+ // p position to place collapsed vertex
+ //
+ IGL_INLINE void progressive_hulls_cost_and_placement(
+ const int e,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ double & cost,
+ Eigen::RowVectorXd & p);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "progressive_hulls_cost_and_placement.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/copyleft/quadprog.cpp b/xs/src/igl/copyleft/quadprog.cpp
new file mode 100644
index 000000000..4c565a0c3
--- /dev/null
+++ b/xs/src/igl/copyleft/quadprog.cpp
@@ -0,0 +1,599 @@
+#include "quadprog.h"
+#include <vector>
+/*
+ FILE eiquadprog.hh
+
+ NOTE: this is a modified of uQuadProg++ package, working with Eigen data structures.
+ uQuadProg++ is itself a port made by Angelo Furfaro of QuadProg++ originally developed by
+ Luca Di Gaspero, working with ublas data structures.
+
+ The quadprog_solve() function implements the algorithm of Goldfarb and Idnani
+ for the solution of a (convex) Quadratic Programming problem
+by means of a dual method.
+
+The problem is in the form:
+
+min 0.5 * x G x + g0 x
+s.t.
+ CE^T x + ce0 = 0
+ CI^T x + ci0 >= 0
+
+ The matrix and vectors dimensions are as follows:
+ G: n * n
+ g0: n
+
+ CE: n * p
+ ce0: p
+
+ CI: n * m
+ ci0: m
+
+ x: n
+
+ The function will return the cost of the solution written in the x vector or
+ std::numeric_limits::infinity() if the problem is infeasible. In the latter case
+ the value of the x vector is not correct.
+
+ References: D. Goldfarb, A. Idnani. A numerically stable dual method for solving
+ strictly convex quadratic programs. Mathematical Programming 27 (1983) pp. 1-33.
+
+ Notes:
+ 1. pay attention in setting up the vectors ce0 and ci0.
+ If the constraints of your problem are specified in the form
+ A^T x = b and C^T x >= d, then you should set ce0 = -b and ci0 = -d.
+ 2. The matrix G is modified within the function since it is used to compute
+ the G = L^T L cholesky factorization for further computations inside the function.
+ If you need the original matrix G you should make a copy of it and pass the copy
+ to the function.
+
+
+ The author will be grateful if the researchers using this software will
+ acknowledge the contribution of this modified function and of Di Gaspero's
+ original version in their research papers.
+
+
+LICENSE
+
+Copyright (2010) Gael Guennebaud
+Copyright (2008) Angelo Furfaro
+Copyright (2006) Luca Di Gaspero
+
+
+This file is a porting of QuadProg++ routine, originally developed
+by Luca Di Gaspero, exploiting uBlas data structures for vectors and
+matrices instead of native C++ array.
+
+uquadprog is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation; either version 2 of the License, or
+(at your option) any later version.
+
+uquadprog is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with uquadprog; if not, write to the Free Software
+Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include <Eigen/Dense>
+
+IGL_INLINE bool igl::copyleft::quadprog(
+ const Eigen::MatrixXd & G,
+ const Eigen::VectorXd & g0,
+ const Eigen::MatrixXd & CE,
+ const Eigen::VectorXd & ce0,
+ const Eigen::MatrixXd & CI,
+ const Eigen::VectorXd & ci0,
+ Eigen::VectorXd& x)
+{
+ using namespace Eigen;
+ typedef double Scalar;
+ const auto distance = [](Scalar a, Scalar b)->Scalar
+ {
+ Scalar a1, b1, t;
+ a1 = std::abs(a);
+ b1 = std::abs(b);
+ if (a1 > b1)
+ {
+ t = (b1 / a1);
+ return a1 * std::sqrt(1.0 + t * t);
+ }
+ else
+ if (b1 > a1)
+ {
+ t = (a1 / b1);
+ return b1 * std::sqrt(1.0 + t * t);
+ }
+ return a1 * std::sqrt(2.0);
+ };
+ const auto compute_d = [](VectorXd &d, const MatrixXd& J, const VectorXd& np)
+ {
+ d = J.adjoint() * np;
+ };
+
+ const auto update_z =
+ [](VectorXd& z, const MatrixXd& J, const VectorXd& d, int iq)
+ {
+ z = J.rightCols(z.size()-iq) * d.tail(d.size()-iq);
+ };
+
+ const auto update_r =
+ [](const MatrixXd& R, VectorXd& r, const VectorXd& d, int iq)
+ {
+ r.head(iq) =
+ R.topLeftCorner(iq,iq).triangularView<Upper>().solve(d.head(iq));
+ };
+
+ const auto add_constraint = [&distance](
+ MatrixXd& R,
+ MatrixXd& J,
+ VectorXd& d,
+ int& iq,
+ double& R_norm)->bool
+ {
+ int n=J.rows();
+#ifdef TRACE_SOLVER
+ std::cerr << "Add constraint " << iq << '/';
+#endif
+ int i, j, k;
+ double cc, ss, h, t1, t2, xny;
+
+ /* we have to find the Givens rotation which will reduce the element
+ d(j) to zero.
+ if it is already zero we don't have to do anything, except of
+ decreasing j */
+ for (j = n - 1; j >= iq + 1; j--)
+ {
+ /* The Givens rotation is done with the matrix (cc cs, cs -cc).
+ If cc is one, then element (j) of d is zero compared with element
+ (j - 1). Hence we don't have to do anything.
+ If cc is zero, then we just have to switch column (j) and column (j - 1)
+ of J. Since we only switch columns in J, we have to be careful how we
+ update d depending on the sign of gs.
+ Otherwise we have to apply the Givens rotation to these columns.
+ The i - 1 element of d has to be updated to h. */
+ cc = d(j - 1);
+ ss = d(j);
+ h = distance(cc, ss);
+ if (h == 0.0)
+ continue;
+ d(j) = 0.0;
+ ss = ss / h;
+ cc = cc / h;
+ if (cc < 0.0)
+ {
+ cc = -cc;
+ ss = -ss;
+ d(j - 1) = -h;
+ }
+ else
+ d(j - 1) = h;
+ xny = ss / (1.0 + cc);
+ for (k = 0; k < n; k++)
+ {
+ t1 = J(k,j - 1);
+ t2 = J(k,j);
+ J(k,j - 1) = t1 * cc + t2 * ss;
+ J(k,j) = xny * (t1 + J(k,j - 1)) - t2;
+ }
+ }
+ /* update the number of constraints added*/
+ iq++;
+ /* To update R we have to put the iq components of the d vector
+ into column iq - 1 of R
+ */
+ R.col(iq-1).head(iq) = d.head(iq);
+#ifdef TRACE_SOLVER
+ std::cerr << iq << std::endl;
+#endif
+
+ if (std::abs(d(iq - 1)) <= std::numeric_limits<double>::epsilon() * R_norm)
+ {
+ // problem degenerate
+ return false;
+ }
+ R_norm = std::max<double>(R_norm, std::abs(d(iq - 1)));
+ return true;
+ };
+
+ const auto delete_constraint = [&distance](
+ MatrixXd& R,
+ MatrixXd& J,
+ VectorXi& A,
+ VectorXd& u,
+ int p,
+ int& iq,
+ int l)
+ {
+ int n = R.rows();
+#ifdef TRACE_SOLVER
+ std::cerr << "Delete constraint " << l << ' ' << iq;
+#endif
+ int i, j, k, qq;
+ double cc, ss, h, xny, t1, t2;
+
+ /* Find the index qq for active constraint l to be removed */
+ for (i = p; i < iq; i++)
+ if (A(i) == l)
+ {
+ qq = i;
+ break;
+ }
+
+ /* remove the constraint from the active set and the duals */
+ for (i = qq; i < iq - 1; i++)
+ {
+ A(i) = A(i + 1);
+ u(i) = u(i + 1);
+ R.col(i) = R.col(i+1);
+ }
+
+ A(iq - 1) = A(iq);
+ u(iq - 1) = u(iq);
+ A(iq) = 0;
+ u(iq) = 0.0;
+ for (j = 0; j < iq; j++)
+ R(j,iq - 1) = 0.0;
+ /* constraint has been fully removed */
+ iq--;
+#ifdef TRACE_SOLVER
+ std::cerr << '/' << iq << std::endl;
+#endif
+
+ if (iq == 0)
+ return;
+
+ for (j = qq; j < iq; j++)
+ {
+ cc = R(j,j);
+ ss = R(j + 1,j);
+ h = distance(cc, ss);
+ if (h == 0.0)
+ continue;
+ cc = cc / h;
+ ss = ss / h;
+ R(j + 1,j) = 0.0;
+ if (cc < 0.0)
+ {
+ R(j,j) = -h;
+ cc = -cc;
+ ss = -ss;
+ }
+ else
+ R(j,j) = h;
+
+ xny = ss / (1.0 + cc);
+ for (k = j + 1; k < iq; k++)
+ {
+ t1 = R(j,k);
+ t2 = R(j + 1,k);
+ R(j,k) = t1 * cc + t2 * ss;
+ R(j + 1,k) = xny * (t1 + R(j,k)) - t2;
+ }
+ for (k = 0; k < n; k++)
+ {
+ t1 = J(k,j);
+ t2 = J(k,j + 1);
+ J(k,j) = t1 * cc + t2 * ss;
+ J(k,j + 1) = xny * (J(k,j) + t1) - t2;
+ }
+ }
+ };
+
+ int i, j, k, l; /* indices */
+ int ip, me, mi;
+ int n=g0.size(); int p=ce0.size(); int m=ci0.size();
+ MatrixXd R(G.rows(),G.cols()), J(G.rows(),G.cols());
+
+ LLT<MatrixXd,Lower> chol(G.cols());
+
+ VectorXd s(m+p), z(n), r(m + p), d(n), np(n), u(m + p);
+ VectorXd x_old(n), u_old(m + p);
+ double f_value, psi, c1, c2, sum, ss, R_norm;
+ const double inf = std::numeric_limits<double>::infinity();
+ double t, t1, t2; /* t is the step length, which is the minimum of the partial step length t1
+ * and the full step length t2 */
+ VectorXi A(m + p), A_old(m + p), iai(m + p);
+ int q;
+ int iq, iter = 0;
+ std::vector<bool> iaexcl(m + p);
+
+ me = p; /* number of equality constraints */
+ mi = m; /* number of inequality constraints */
+ q = 0; /* size of the active set A (containing the indices of the active constraints) */
+
+ /*
+ * Preprocessing phase
+ */
+
+ /* compute the trace of the original matrix G */
+ c1 = G.trace();
+
+ /* decompose the matrix G in the form LL^T */
+ chol.compute(G);
+
+ /* initialize the matrix R */
+ d.setZero();
+ R.setZero();
+ R_norm = 1.0; /* this variable will hold the norm of the matrix R */
+
+ /* compute the inverse of the factorized matrix G^-1, this is the initial value for H */
+ // J = L^-T
+ J.setIdentity();
+ J = chol.matrixU().solve(J);
+ c2 = J.trace();
+#ifdef TRACE_SOLVER
+ print_matrix("J", J, n);
+#endif
+
+ /* c1 * c2 is an estimate for cond(G) */
+
+ /*
+ * Find the unconstrained minimizer of the quadratic form 0.5 * x G x + g0 x
+ * this is a feasible point in the dual space
+ * x = G^-1 * g0
+ */
+ x = chol.solve(g0);
+ x = -x;
+ /* and compute the current solution value */
+ f_value = 0.5 * g0.dot(x);
+#ifdef TRACE_SOLVER
+ std::cerr << "Unconstrained solution: " << f_value << std::endl;
+ print_vector("x", x, n);
+#endif
+
+ /* Add equality constraints to the working set A */
+ iq = 0;
+ for (i = 0; i < me; i++)
+ {
+ np = CE.col(i);
+ compute_d(d, J, np);
+ update_z(z, J, d, iq);
+ update_r(R, r, d, iq);
+#ifdef TRACE_SOLVER
+ print_matrix("R", R, iq);
+ print_vector("z", z, n);
+ print_vector("r", r, iq);
+ print_vector("d", d, n);
+#endif
+
+ /* compute full step length t2: i.e., the minimum step in primal space s.t. the contraint
+ becomes feasible */
+ t2 = 0.0;
+ if (std::abs(z.dot(z)) > std::numeric_limits<double>::epsilon()) // i.e. z != 0
+ t2 = (-np.dot(x) - ce0(i)) / z.dot(np);
+
+ x += t2 * z;
+
+ /* set u = u+ */
+ u(iq) = t2;
+ u.head(iq) -= t2 * r.head(iq);
+
+ /* compute the new solution value */
+ f_value += 0.5 * (t2 * t2) * z.dot(np);
+ A(i) = -i - 1;
+
+ if (!add_constraint(R, J, d, iq, R_norm))
+ {
+ // FIXME: it should raise an error
+ // Equality constraints are linearly dependent
+ return false;
+ }
+ }
+
+ /* set iai = K \ A */
+ for (i = 0; i < mi; i++)
+ iai(i) = i;
+
+l1: iter++;
+#ifdef TRACE_SOLVER
+ print_vector("x", x, n);
+#endif
+ /* step 1: choose a violated constraint */
+ for (i = me; i < iq; i++)
+ {
+ ip = A(i);
+ iai(ip) = -1;
+ }
+
+ /* compute s(x) = ci^T * x + ci0 for all elements of K \ A */
+ ss = 0.0;
+ psi = 0.0; /* this value will contain the sum of all infeasibilities */
+ ip = 0; /* ip will be the index of the chosen violated constraint */
+ for (i = 0; i < mi; i++)
+ {
+ iaexcl[i] = true;
+ sum = CI.col(i).dot(x) + ci0(i);
+ s(i) = sum;
+ psi += std::min(0.0, sum);
+ }
+#ifdef TRACE_SOLVER
+ print_vector("s", s, mi);
+#endif
+
+
+ if (std::abs(psi) <= mi * std::numeric_limits<double>::epsilon() * c1 * c2* 100.0)
+ {
+ /* numerically there are not infeasibilities anymore */
+ q = iq;
+ return true;
+ }
+
+ /* save old values for u, x and A */
+ u_old.head(iq) = u.head(iq);
+ A_old.head(iq) = A.head(iq);
+ x_old = x;
+
+l2: /* Step 2: check for feasibility and determine a new S-pair */
+ for (i = 0; i < mi; i++)
+ {
+ if (s(i) < ss && iai(i) != -1 && iaexcl[i])
+ {
+ ss = s(i);
+ ip = i;
+ }
+ }
+ if (ss >= 0.0)
+ {
+ q = iq;
+ return true;
+ }
+
+ /* set np = n(ip) */
+ np = CI.col(ip);
+ /* set u = (u 0)^T */
+ u(iq) = 0.0;
+ /* add ip to the active set A */
+ A(iq) = ip;
+
+#ifdef TRACE_SOLVER
+ std::cerr << "Trying with constraint " << ip << std::endl;
+ print_vector("np", np, n);
+#endif
+
+l2a:/* Step 2a: determine step direction */
+ /* compute z = H np: the step direction in the primal space (through J, see the paper) */
+ compute_d(d, J, np);
+ update_z(z, J, d, iq);
+ /* compute N* np (if q > 0): the negative of the step direction in the dual space */
+ update_r(R, r, d, iq);
+#ifdef TRACE_SOLVER
+ std::cerr << "Step direction z" << std::endl;
+ print_vector("z", z, n);
+ print_vector("r", r, iq + 1);
+ print_vector("u", u, iq + 1);
+ print_vector("d", d, n);
+ print_ivector("A", A, iq + 1);
+#endif
+
+ /* Step 2b: compute step length */
+ l = 0;
+ /* Compute t1: partial step length (maximum step in dual space without violating dual feasibility */
+ t1 = inf; /* +inf */
+ /* find the index l s.t. it reaches the minimum of u+(x) / r */
+ for (k = me; k < iq; k++)
+ {
+ double tmp;
+ if (r(k) > 0.0 && ((tmp = u(k) / r(k)) < t1) )
+ {
+ t1 = tmp;
+ l = A(k);
+ }
+ }
+ /* Compute t2: full step length (minimum step in primal space such that the constraint ip becomes feasible */
+ if (std::abs(z.dot(z)) > std::numeric_limits<double>::epsilon()) // i.e. z != 0
+ t2 = -s(ip) / z.dot(np);
+ else
+ t2 = inf; /* +inf */
+
+ /* the step is chosen as the minimum of t1 and t2 */
+ t = std::min(t1, t2);
+#ifdef TRACE_SOLVER
+ std::cerr << "Step sizes: " << t << " (t1 = " << t1 << ", t2 = " << t2 << ") ";
+#endif
+
+ /* Step 2c: determine new S-pair and take step: */
+
+ /* case (i): no step in primal or dual space */
+ if (t >= inf)
+ {
+ /* QPP is infeasible */
+ // FIXME: unbounded to raise
+ q = iq;
+ return false;
+ }
+ /* case (ii): step in dual space */
+ if (t2 >= inf)
+ {
+ /* set u = u + t * [-r 1) and drop constraint l from the active set A */
+ u.head(iq) -= t * r.head(iq);
+ u(iq) += t;
+ iai(l) = l;
+ delete_constraint(R, J, A, u, p, iq, l);
+#ifdef TRACE_SOLVER
+ std::cerr << " in dual space: "
+ << f_value << std::endl;
+ print_vector("x", x, n);
+ print_vector("z", z, n);
+ print_ivector("A", A, iq + 1);
+#endif
+ goto l2a;
+ }
+
+ /* case (iii): step in primal and dual space */
+
+ x += t * z;
+ /* update the solution value */
+ f_value += t * z.dot(np) * (0.5 * t + u(iq));
+
+ u.head(iq) -= t * r.head(iq);
+ u(iq) += t;
+#ifdef TRACE_SOLVER
+ std::cerr << " in both spaces: "
+ << f_value << std::endl;
+ print_vector("x", x, n);
+ print_vector("u", u, iq + 1);
+ print_vector("r", r, iq + 1);
+ print_ivector("A", A, iq + 1);
+#endif
+
+ if (t == t2)
+ {
+#ifdef TRACE_SOLVER
+ std::cerr << "Full step has taken " << t << std::endl;
+ print_vector("x", x, n);
+#endif
+ /* full step has taken */
+ /* add constraint ip to the active set*/
+ if (!add_constraint(R, J, d, iq, R_norm))
+ {
+ iaexcl[ip] = false;
+ delete_constraint(R, J, A, u, p, iq, ip);
+#ifdef TRACE_SOLVER
+ print_matrix("R", R, n);
+ print_ivector("A", A, iq);
+#endif
+ for (i = 0; i < m; i++)
+ iai(i) = i;
+ for (i = 0; i < iq; i++)
+ {
+ A(i) = A_old(i);
+ iai(A(i)) = -1;
+ u(i) = u_old(i);
+ }
+ x = x_old;
+ goto l2; /* go to step 2 */
+ }
+ else
+ iai(ip) = -1;
+#ifdef TRACE_SOLVER
+ print_matrix("R", R, n);
+ print_ivector("A", A, iq);
+#endif
+ goto l1;
+ }
+
+ /* a patial step has taken */
+#ifdef TRACE_SOLVER
+ std::cerr << "Partial step has taken " << t << std::endl;
+ print_vector("x", x, n);
+#endif
+ /* drop constraint l */
+ iai(l) = l;
+ delete_constraint(R, J, A, u, p, iq, l);
+#ifdef TRACE_SOLVER
+ print_matrix("R", R, n);
+ print_ivector("A", A, iq);
+#endif
+
+ s(ip) = CI.col(ip).dot(x) + ci0(ip);
+
+#ifdef TRACE_SOLVER
+ print_vector("s", s, mi);
+#endif
+ goto l2a;
+}
diff --git a/xs/src/igl/copyleft/quadprog.h b/xs/src/igl/copyleft/quadprog.h
new file mode 100644
index 000000000..f054bbdba
--- /dev/null
+++ b/xs/src/igl/copyleft/quadprog.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_QUADPROG_H
+#define IGL_COPYLEFT_QUADPROG_H
+
+#include "../igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ namespace copyleft
+ {
+ // Solve a (dense) quadratric program of the form:
+ //
+ // min 0.5 x G x + g0 x
+ // s.t. CE' x + ce0 = 0
+ // and CI' x + ci0 >= 0
+ //
+ // Inputs:
+ // G #x by #x matrix of quadratic coefficients
+ // g0 #x vector of linear coefficients
+ // CE #x by #CE list of linear equality coefficients
+ // ce0 #CE list of linear equality right-hand sides
+ // CI #x by #CI list of linear equality coefficients
+ // ci0 #CI list of linear equality right-hand sides
+ // Outputs:
+ // x #x vector of solution values
+ // Returns true iff success
+ IGL_INLINE bool quadprog(
+ const Eigen::MatrixXd & G,
+ const Eigen::VectorXd & g0,
+ const Eigen::MatrixXd & CE,
+ const Eigen::VectorXd & ce0,
+ const Eigen::MatrixXd & CI,
+ const Eigen::VectorXd & ci0,
+ Eigen::VectorXd& x);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quadprog.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/swept_volume.cpp b/xs/src/igl/copyleft/swept_volume.cpp
new file mode 100644
index 000000000..f21e3aba5
--- /dev/null
+++ b/xs/src/igl/copyleft/swept_volume.cpp
@@ -0,0 +1,49 @@
+#include "swept_volume.h"
+#include "../swept_volume_bounding_box.h"
+#include "../swept_volume_signed_distance.h"
+#include "../voxel_grid.h"
+#include "marching_cubes.h"
+#include <iostream>
+
+IGL_INLINE void igl::copyleft::swept_volume(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<Eigen::Affine3d(const double t)> & transform,
+ const size_t steps,
+ const size_t grid_res,
+ const size_t isolevel_grid,
+ Eigen::MatrixXd & SV,
+ Eigen::MatrixXi & SF)
+{
+ using namespace std;
+ using namespace Eigen;
+ using namespace igl;
+ using namespace igl::copyleft;
+
+ const auto & Vtransform =
+ [&V,&transform](const size_t vi,const double t)->RowVector3d
+ {
+ Vector3d Vvi = V.row(vi).transpose();
+ return (transform(t)*Vvi).transpose();
+ };
+ AlignedBox3d Mbox;
+ swept_volume_bounding_box(V.rows(),Vtransform,steps,Mbox);
+
+ // Amount of padding: pad*h should be >= isolevel
+ const int pad = isolevel_grid+1;
+ // number of vertices on the largest side
+ const int s = grid_res+2*pad;
+ const double h = Mbox.diagonal().maxCoeff()/(double)(s-2.*pad-1.);
+ const double isolevel = isolevel_grid*h;
+
+ // create grid
+ RowVector3i res;
+ MatrixXd GV;
+ voxel_grid(Mbox,s,pad,GV,res);
+
+ // compute values
+ VectorXd S;
+ swept_volume_signed_distance(V,F,transform,steps,GV,res,h,isolevel,S);
+ S.array()-=isolevel;
+ marching_cubes(S,GV,res(0),res(1),res(2),SV,SF);
+}
diff --git a/xs/src/igl/copyleft/swept_volume.h b/xs/src/igl/copyleft/swept_volume.h
new file mode 100644
index 000000000..cc178f78a
--- /dev/null
+++ b/xs/src/igl/copyleft/swept_volume.h
@@ -0,0 +1,41 @@
+#ifndef IGL_COPYLEFT_SWEPT_VOLUME_H
+#define IGL_COPYLEFT_SWEPT_VOLUME_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+namespace igl
+{
+ namespace copyleft
+ {
+ // Compute the surface of the swept volume of a solid object with surface
+ // (V,F) mesh under going rigid motion.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh positions in reference pose
+ // F #F by 3 list of mesh indices into V
+ // transform function handle so that transform(t) returns the rigid
+ // transformation at time t∈[0,1]
+ // steps number of time steps: steps=3 --> t∈{0,0.5,1}
+ // grid_res number of grid cells on the longest side containing the
+ // motion (isolevel+1 cells will also be added on each side as padding)
+ // isolevel distance level to be contoured as swept volume
+ // Outputs:
+ // SV #SV by 3 list of mesh positions of the swept surface
+ // SF #SF by 3 list of mesh faces into SV
+ IGL_INLINE void swept_volume(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<Eigen::Affine3d(const double t)> & transform,
+ const size_t steps,
+ const size_t grid_res,
+ const size_t isolevel,
+ Eigen::MatrixXd & SV,
+ Eigen::MatrixXi & SF);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "swept_volume.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/README b/xs/src/igl/copyleft/tetgen/README
new file mode 100644
index 000000000..0315b6c11
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/README
@@ -0,0 +1,7 @@
+IGL interface to tetgen library
+
+Dependencies:
+ tetgen
+
+Travel to $IGL/external/tetgen and issue:
+ make -f Makefile.igl tetlib
diff --git a/xs/src/igl/copyleft/tetgen/cdt.cpp b/xs/src/igl/copyleft/tetgen/cdt.cpp
new file mode 100644
index 000000000..f2602dd66
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/cdt.cpp
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cdt.h"
+#include "../../bounding_box.h"
+#include "tetrahedralize.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedTV,
+ typename DerivedTT,
+ typename DerivedTF>
+IGL_INLINE bool igl::copyleft::tetgen::cdt(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const CDTParam & param,
+ Eigen::PlainObjectBase<DerivedTV>& TV,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTF>& TF)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Effective input mesh
+ DerivedV U;
+ DerivedF G;
+ if(param.use_bounding_box)
+ {
+ // Construct bounding box mesh
+ DerivedV BV;
+ DerivedF BF;
+ bounding_box(V,BV,BF);
+ // scale bounding box
+ const RowVector3d mid =
+ (BV.colwise().minCoeff() + BV.colwise().maxCoeff()).eval()*0.5;
+ BV.rowwise() -= mid;
+ assert(param.bounding_box_scale >= 1.);
+ BV.array() *= param.bounding_box_scale;
+ BV.rowwise() += mid;
+ // Append bounding box to mesh
+ U.resize(V.rows()+BV.rows(),V.cols());
+ U<<V,BV;
+ BF.array() += V.rows();
+ G.resize(F.rows()+BF.rows(),F.cols());
+ G<<F,BF;
+ }else
+ {
+ // needless copies
+ U = V;
+ G = F;
+ }
+ // effective flags;
+ string flags = param.flags + (param.use_bounding_box ? "" : "c");
+ return tetrahedralize(U,G,flags,TV,TT,TF);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::copyleft::tetgen::cdt<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::copyleft::tetgen::CDTParam const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/cdt.h b/xs/src/igl/copyleft/tetgen/cdt.h
new file mode 100644
index 000000000..e59a28029
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/cdt.h
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_TETGEN_CDT_H
+#define IGL_COPYLEFT_TETGEN_CDT_H
+#include "../../igl_inline.h"
+
+#include <Eigen/Core>
+#include <string>
+#ifndef TETLIBRARY
+# define TETLIBRARY
+#endif
+#include "tetgen.h" // Defined REAL
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace tetgen
+ {
+ struct CDTParam
+ {
+ // Tetgen can compute mesh of convex hull of input (i.e. "c") but often
+ // chokes. One workaround is to force it to mesh the entire bounding box.
+ // {false}
+ bool use_bounding_box = false;
+ // Scale the bounding box a bit so that vertices near it do not give tetgen
+ // problems. {1.01}
+ double bounding_box_scale = 1.01;
+ // Flags to tetgen. Do not include the "c" flag here! {"Y"}
+ std::string flags = "Y";
+ };
+ // Create a constrained delaunay tessellation containing convex hull of the
+ // given **non-selfintersecting** mesh.
+ //
+ // Inputs:
+ // V #V by 3 list of input mesh vertices
+ // F #F by 3 list of input mesh facets
+ // param see above
+ // TV #TV by 3 list of output mesh vertices (V come first)
+ // TT #TT by 3 list of tetrahedra indices into TV.
+ // TF #TF by 3 list of facets from F potentially subdivided.
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedTV,
+ typename DerivedTT,
+ typename DerivedTF>
+ IGL_INLINE bool cdt(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const CDTParam & param,
+ Eigen::PlainObjectBase<DerivedTV>& TV,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTF>& TF);
+ }
+ }
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cdt.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.cpp b/xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.cpp
new file mode 100644
index 000000000..78eaebb5c
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.cpp
@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mesh_to_tetgenio.h"
+
+// IGL includes
+#include "../../matrix_to_list.h"
+
+// STL includes
+#include <cassert>
+
+IGL_INLINE bool igl::copyleft::tetgen::mesh_to_tetgenio(
+ const std::vector<std::vector<REAL > > & V,
+ const std::vector<std::vector<int> > & F,
+ tetgenio & in)
+{
+ using namespace std;
+ // all indices start from 0
+ in.firstnumber = 0;
+
+ in.numberofpoints = V.size();
+ in.pointlist = new REAL[in.numberofpoints * 3];
+ // loop over points
+ for(int i = 0; i < (int)V.size(); i++)
+ {
+ assert(V[i].size() == 3);
+ in.pointlist[i*3+0] = V[i][0];
+ in.pointlist[i*3+1] = V[i][1];
+ in.pointlist[i*3+2] = V[i][2];
+ }
+
+ in.numberoffacets = F.size();
+ in.facetlist = new tetgenio::facet[in.numberoffacets];
+ in.facetmarkerlist = new int[in.numberoffacets];
+
+ // loop over face
+ for(int i = 0;i < (int)F.size(); i++)
+ {
+ in.facetmarkerlist[i] = i;
+ tetgenio::facet * f = &in.facetlist[i];
+ f->numberofpolygons = 1;
+ f->polygonlist = new tetgenio::polygon[f->numberofpolygons];
+ f->numberofholes = 0;
+ f->holelist = NULL;
+ tetgenio::polygon * p = &f->polygonlist[0];
+ p->numberofvertices = F[i].size();
+ p->vertexlist = new int[p->numberofvertices];
+ // loop around face
+ for(int j = 0;j < (int)F[i].size(); j++)
+ {
+ p->vertexlist[j] = F[i][j];
+ }
+ }
+ return true;
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::copyleft::tetgen::mesh_to_tetgenio(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ tetgenio & in)
+{
+ using namespace std;
+ vector<vector<REAL> > vV;
+ vector<vector<int> > vF;
+ matrix_to_list(V,vV);
+ matrix_to_list(F,vF);
+ return mesh_to_tetgenio(vV,vF,in);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::copyleft::tetgen::mesh_to_tetgenio<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, tetgenio&);
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.h b/xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.h
new file mode 100644
index 000000000..3295294fe
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/mesh_to_tetgenio.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_TETGEN_MESH_TO_TETGENIO_H
+#define IGL_COPYLEFT_TETGEN_MESH_TO_TETGENIO_H
+#include "../../igl_inline.h"
+
+#ifndef TETLIBRARY
+# define TETLIBRARY
+#endif
+#include "tetgen.h" // Defined tetgenio, REAL
+#include <vector>
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace tetgen
+ {
+ // Load a vertex list and face list into a tetgenio object
+ // Inputs:
+ // V #V by 3 vertex position list
+ // F #F list of polygon face indices into V (0-indexed)
+ // Outputs:
+ // in tetgenio input object
+ // Returns true on success, false on error
+ IGL_INLINE bool mesh_to_tetgenio(
+ const std::vector<std::vector<REAL > > & V,
+ const std::vector<std::vector<int> > & F,
+ tetgenio & in);
+
+ // Wrapper with Eigen types
+ // Templates:
+ // DerivedV real-value: i.e. from MatrixXd
+ // DerivedF integer-value: i.e. from MatrixXi
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool mesh_to_tetgenio(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ tetgenio & in);
+ }
+ }
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mesh_to_tetgenio.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/mesh_with_skeleton.cpp b/xs/src/igl/copyleft/tetgen/mesh_with_skeleton.cpp
new file mode 100644
index 000000000..5c920b36d
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/mesh_with_skeleton.cpp
@@ -0,0 +1,102 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mesh_with_skeleton.h"
+#include "tetrahedralize.h"
+
+#include "../../sample_edges.h"
+#include "../../cat.h"
+
+#include <iostream>
+// Default settings pq2Y tell tetgen to mesh interior of triangle mesh and
+// to produce a graded tet mesh
+const static std::string DEFAULT_TETGEN_FLAGS = "pq2Y";
+
+IGL_INLINE bool igl::copyleft::tetgen::mesh_with_skeleton(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & C,
+ const Eigen::VectorXi & /*P*/,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXi & CE,
+ const int samples_per_bone,
+ const std::string & tetgen_flags,
+ Eigen::MatrixXd & VV,
+ Eigen::MatrixXi & TT,
+ Eigen::MatrixXi & FF)
+{
+ using namespace Eigen;
+ using namespace std;
+ const string eff_tetgen_flags =
+ (tetgen_flags.length() == 0?DEFAULT_TETGEN_FLAGS:tetgen_flags);
+ // Collect all edges that need samples:
+ MatrixXi BECE = cat(1,BE,CE);
+ MatrixXd S;
+ // Sample each edge with 10 samples. (Choice of 10 doesn't seem to matter so
+ // much, but could under some circumstances)
+ sample_edges(C,BECE,samples_per_bone,S);
+ // Vertices we'll constrain tet mesh to meet
+ MatrixXd VS = cat(1,V,S);
+ // Use tetgen to mesh the interior of surface, this assumes surface:
+ // * has no holes
+ // * has no non-manifold edges or vertices
+ // * has consistent orientation
+ // * has no self-intersections
+ // * has no 0-volume pieces
+ cerr<<"tetgen begin()"<<endl;
+ int status = tetrahedralize( VS,F,eff_tetgen_flags,VV,TT,FF);
+ cerr<<"tetgen end()"<<endl;
+ if(FF.rows() != F.rows())
+ {
+ // Issue a warning if the surface has changed
+ cerr<<"mesh_with_skeleton: Warning: boundary faces != input faces"<<endl;
+ }
+ if(status != 0)
+ {
+ cerr<<
+ "***************************************************************"<<endl<<
+ "***************************************************************"<<endl<<
+ "***************************************************************"<<endl<<
+ "***************************************************************"<<endl<<
+ "* mesh_with_skeleton: tetgen failed. Just meshing convex hull *"<<endl<<
+ "***************************************************************"<<endl<<
+ "***************************************************************"<<endl<<
+ "***************************************************************"<<endl<<
+ "***************************************************************"<<endl;
+ // If meshing convex hull then use more regular mesh
+ status = tetrahedralize(VS,F,"q1.414",VV,TT,FF);
+ // I suppose this will fail if the skeleton is outside the mesh
+ assert(FF.maxCoeff() < VV.rows());
+ if(status != 0)
+ {
+ cerr<<"mesh_with_skeleton: tetgen failed again."<<endl;
+ return false;
+ }
+ }
+
+ return true;
+}
+
+IGL_INLINE bool igl::copyleft::tetgen::mesh_with_skeleton(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & C,
+ const Eigen::VectorXi & P,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXi & CE,
+ const int samples_per_bone,
+ Eigen::MatrixXd & VV,
+ Eigen::MatrixXi & TT,
+ Eigen::MatrixXi & FF)
+{
+ return mesh_with_skeleton(
+ V,F,C,P,BE,CE,samples_per_bone,DEFAULT_TETGEN_FLAGS,VV,TT,FF);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/mesh_with_skeleton.h b/xs/src/igl/copyleft/tetgen/mesh_with_skeleton.h
new file mode 100644
index 000000000..a01bedffb
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/mesh_with_skeleton.h
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_TETGEN_MESH_WITH_SKELETON_H
+#define IGL_COPYLEFT_TETGEN_MESH_WITH_SKELETON_H
+#include "../../igl_inline.h"
+#include <Eigen/Dense>
+#include <string>
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace tetgen
+ {
+ // Mesh the interior of a given surface with tetrahedra which are graded
+ // (tend to be small near the surface and large inside) and conform to the
+ // given handles and samplings thereof.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of triangle indices
+ // C #C by 3 list of vertex positions
+ // P #P list of point handle indices
+ // BE #BE by 2 list of bone-edge indices
+ // CE #CE by 2 list of cage-edge indices
+ // samples_per_bone #samples to add per bone
+ // tetgen_flags flags to pass to tetgen {""-->"pq2Y"} otherwise you're on
+ // your own and it's your funeral if you pass nonsense flags
+ // Outputs:
+ // VV #VV by 3 list of tet-mesh vertex positions
+ // TT #TT by 4 list of tetrahedra indices
+ // FF #FF by 3 list of surface triangle indices
+ // Returns true only on success
+ IGL_INLINE bool mesh_with_skeleton(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & C,
+ const Eigen::VectorXi & /*P*/,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXi & CE,
+ const int samples_per_bone,
+ const std::string & tetgen_flags,
+ Eigen::MatrixXd & VV,
+ Eigen::MatrixXi & TT,
+ Eigen::MatrixXi & FF);
+ // Wrapper using default tetgen_flags
+ IGL_INLINE bool mesh_with_skeleton(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & C,
+ const Eigen::VectorXi & /*P*/,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXi & CE,
+ const int samples_per_bone,
+ Eigen::MatrixXd & VV,
+ Eigen::MatrixXi & TT,
+ Eigen::MatrixXi & FF);
+ }
+ }
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mesh_with_skeleton.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/read_into_tetgenio.cpp b/xs/src/igl/copyleft/tetgen/read_into_tetgenio.cpp
new file mode 100644
index 000000000..506c5e4ba
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/read_into_tetgenio.cpp
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "read_into_tetgenio.h"
+#include "mesh_to_tetgenio.h"
+
+// IGL includes
+#include "../../pathinfo.h"
+#ifndef IGL_NO_EIGEN
+# define IGL_NO_EIGEN_WAS_NOT_ALREADY_DEFINED
+# define IGL_NO_EIGEN
+#endif
+// Include igl headers without including Eigen
+#include "../../readOBJ.h"
+#ifdef IGL_NO_EIGEN_WAS_NOT_ALREADY_DEFINED
+# undef IGL_NO_EIGEN
+#endif
+
+// STL includes
+#include <algorithm>
+#include <iostream>
+#include <vector>
+
+IGL_INLINE bool igl::copyleft::tetgen::read_into_tetgenio(
+ const std::string & path,
+ tetgenio & in)
+{
+ using namespace std;
+ // get file extension
+ string dirname,basename,ext,filename;
+ pathinfo(path,dirname,basename,ext,filename);
+ // convert to lower case for easy comparison
+ transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+ bool success = false;
+
+ char basename_char[1024];
+ strcpy(basename_char,basename.c_str());
+
+ if(ext == "obj")
+ {
+ // read obj into vertex list and face list
+ vector<vector<REAL> > V,TC,N;
+ vector<vector<int> > F,FTC,FN;
+ success = readOBJ(path,V,TC,N,F,FTC,FN);
+ success &= mesh_to_tetgenio(V,F,in);
+ }else if(ext == "off")
+ {
+ success = in.load_off(basename_char);
+ }else if(ext == "node")
+ {
+ success = in.load_node(basename_char);
+ }else
+ {
+ if(ext.length() > 0)
+ {
+ cerr<<"^read_into_tetgenio Warning: Unsupported extension ("<<ext<<
+ "): try to load as basename..."<<endl;
+ }
+ // This changed as of (the so far unreleased) tetgen 1.5
+ //success = in.load_tetmesh(basename_char);
+ //int object = tetgenbehavior::NODES;
+ //if(ext == "mesh")
+ //{
+ // object = tetgenbehavior::MEDIT;
+ //}
+ success = in.load_tetmesh(basename_char,!tetgenbehavior::MEDIT);
+ }
+
+ return success;
+}
diff --git a/xs/src/igl/copyleft/tetgen/read_into_tetgenio.h b/xs/src/igl/copyleft/tetgen/read_into_tetgenio.h
new file mode 100644
index 000000000..dd4b4b998
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/read_into_tetgenio.h
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_TETGEN_READ_INTO_TETGENIO_H
+#define IGL_COPYLEFT_TETGEN_READ_INTO_TETGENIO_H
+#include "../../igl_inline.h"
+
+#include <string>
+#ifndef TETLIBRARY
+#define TETLIBRARY
+#endif
+#include "tetgen.h" // Defined tetgenio, REAL
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace tetgen
+ {
+ // Read a mesh or point set into tetgenio (input object for calling
+ // tetgen). Many file formats are already supported by tetgen:
+ // .off
+ // .ply
+ // .node
+ // .ply
+ // .medit
+ // .vtk
+ // etc.
+ // Notably it does not support .obj which is loaded by hand here (also
+ // demonstrating how to load points/faces programmatically)
+ //
+ // If the file extension is not recognized the filename is assumed to be
+ // the basename of a collection describe a tetmesh, (of which at least
+ // the .node file must exist):
+ // [filename].node
+ // [filename].ele
+ // [filename].face
+ // [filename].edge
+ // [filename].vol
+ //
+ // Inputs:
+ // path path to file or basename to files
+ // Outputs:
+ // in tetgenio input object
+ // Returns true on success, false on error
+ IGL_INLINE bool read_into_tetgenio(
+ const std::string & path,
+ tetgenio & in);
+ }
+ }
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "read_into_tetgenio.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp b/xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp
new file mode 100644
index 000000000..d61153053
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.cpp
@@ -0,0 +1,146 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "tetgenio_to_tetmesh.h"
+
+// IGL includes
+#include "../../list_to_matrix.h"
+
+// STL includes
+#include <iostream>
+
+IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
+ const tetgenio & out,
+ std::vector<std::vector<REAL > > & V,
+ std::vector<std::vector<int> > & T,
+ std::vector<std::vector<int> > & F)
+{
+ using namespace std;
+ // process points
+ if(out.pointlist == NULL)
+ {
+ cerr<<"^tetgenio_to_tetmesh Error: point list is NULL\n"<<endl;
+ return false;
+ }
+ V.resize(out.numberofpoints,vector<REAL>(3));
+ // loop over points
+ for(int i = 0;i < out.numberofpoints; i++)
+ {
+ V[i][0] = out.pointlist[i*3+0];
+ V[i][1] = out.pointlist[i*3+1];
+ V[i][2] = out.pointlist[i*3+2];
+ }
+
+
+ // process tets
+ if(out.tetrahedronlist == NULL)
+ {
+ cerr<<"^tetgenio_to_tetmesh Error: tet list is NULL\n"<<endl;
+ return false;
+ }
+
+ // When would this not be 4?
+ assert(out.numberofcorners == 4);
+ T.resize(out.numberoftetrahedra,vector<int>(out.numberofcorners));
+ int min_index = 1e7;
+ int max_index = -1e7;
+ // loop over tetrahedra
+ for(int i = 0; i < out.numberoftetrahedra; i++)
+ {
+ for(int j = 0; j<out.numberofcorners; j++)
+ {
+ int index = out.tetrahedronlist[i * out.numberofcorners + j];
+ T[i][j] = index;
+ min_index = (min_index > index ? index : min_index);
+ max_index = (max_index < index ? index : max_index);
+ }
+ }
+ assert(min_index >= 0);
+ assert(max_index >= 0);
+ assert(max_index < (int)V.size());
+
+ cout<<out.numberoftrifaces<<endl;
+
+ // When would this not be 4?
+ F.clear();
+ // loop over tetrahedra
+ for(int i = 0; i < out.numberoftrifaces; i++)
+ {
+ if(out.trifacemarkerlist[i]>=0)
+ {
+ vector<int> face(3);
+ for(int j = 0; j<3; j++)
+ {
+ face[j] = out.trifacelist[i * 3 + j];
+ }
+ F.push_back(face);
+ }
+ }
+
+ return true;
+}
+
+IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
+ const tetgenio & out,
+ std::vector<std::vector<REAL > > & V,
+ std::vector<std::vector<int> > & T)
+{
+ std::vector<std::vector<int> > F;
+ return tetgenio_to_tetmesh(out,V,T,F);
+}
+
+template <typename DerivedV, typename DerivedT, typename DerivedF>
+IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
+ const tetgenio & out,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ using namespace std;
+ vector<vector<REAL> > vV;
+ vector<vector<int> > vT;
+ vector<vector<int> > vF;
+ bool success = tetgenio_to_tetmesh(out,vV,vT,vF);
+ if(!success)
+ {
+ return false;
+ }
+ bool V_rect = list_to_matrix(vV,V);
+ if(!V_rect)
+ {
+ // igl::list_to_matrix(vV,V) already printed error message to std err
+ return false;
+ }
+ bool T_rect = list_to_matrix(vT,T);
+ if(!T_rect)
+ {
+ // igl::list_to_matrix(vT,T) already printed error message to std err
+ return false;
+ }
+ bool F_rect = list_to_matrix(vF,F);
+ if(!F_rect)
+ {
+ return false;
+ }
+
+ return true;
+}
+
+template <typename DerivedV, typename DerivedT>
+IGL_INLINE bool igl::copyleft::tetgen::tetgenio_to_tetmesh(
+ const tetgenio & out,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T)
+{
+ Eigen::Matrix<typename DerivedT::Scalar,Eigen::Dynamic,3> F;
+ return tetgenio_to_tetmesh(out,V,T,F);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::copyleft::tetgen::tetgenio_to_tetmesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(tetgenio const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.h b/xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.h
new file mode 100644
index 000000000..2a5575886
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/tetgenio_to_tetmesh.h
@@ -0,0 +1,66 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_TETGEN_TETGENIO_TO_TETMESH_H
+#define IGL_COPYLEFT_TETGEN_TETGENIO_TO_TETMESH_H
+#include "../../igl_inline.h"
+
+#ifndef TETLIBRARY
+#define TETLIBRARY
+#endif
+#include "tetgen.h" // Defined tetgenio, REAL
+#include <vector>
+#include <Eigen/Core>
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace tetgen
+ {
+ // Extract a tetrahedral mesh from a tetgenio object
+ // Inputs:
+ // out tetgenio output object
+ // Outputs:
+ // V #V by 3 vertex position list
+ // T #T by 4 list of tetrahedra indices into V
+ // F #F by 3 list of marked facets
+ // Returns true on success, false on error
+ IGL_INLINE bool tetgenio_to_tetmesh(
+ const tetgenio & out,
+ std::vector<std::vector<REAL > > & V,
+ std::vector<std::vector<int> > & T,
+ std::vector<std::vector<int> > & F);
+ IGL_INLINE bool tetgenio_to_tetmesh(
+ const tetgenio & out,
+ std::vector<std::vector<REAL > > & V,
+ std::vector<std::vector<int> > & T);
+
+ // Wrapper with Eigen types
+ // Templates:
+ // DerivedV real-value: i.e. from MatrixXd
+ // DerivedT integer-value: i.e. from MatrixXi
+ template <typename DerivedV, typename DerivedT, typename DerivedF>
+ IGL_INLINE bool tetgenio_to_tetmesh(
+ const tetgenio & out,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ template <typename DerivedV, typename DerivedT>
+ IGL_INLINE bool tetgenio_to_tetmesh(
+ const tetgenio & out,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T);
+ }
+ }
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "tetgenio_to_tetmesh.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/tetrahedralize.cpp b/xs/src/igl/copyleft/tetgen/tetrahedralize.cpp
new file mode 100644
index 000000000..fa6111410
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/tetrahedralize.cpp
@@ -0,0 +1,220 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "tetrahedralize.h"
+#include "mesh_to_tetgenio.h"
+#include "tetgenio_to_tetmesh.h"
+
+// IGL includes
+#include "../../matrix_to_list.h"
+#include "../../list_to_matrix.h"
+#include "../../boundary_facets.h"
+
+// STL includes
+#include <cassert>
+#include <iostream>
+
+IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
+ const std::vector<std::vector<REAL > > & V,
+ const std::vector<std::vector<int> > & F,
+ const std::string switches,
+ std::vector<std::vector<REAL > > & TV,
+ std::vector<std::vector<int > > & TT,
+ std::vector<std::vector<int> > & TF)
+{
+ using namespace std;
+ tetgenio in,out;
+ bool success;
+ success = mesh_to_tetgenio(V,F,in);
+ if(!success)
+ {
+ return -1;
+ }
+ try
+ {
+ char * cswitches = new char[switches.size() + 1];
+ std::strcpy(cswitches,switches.c_str());
+ ::tetrahedralize(cswitches,&in, &out);
+ delete[] cswitches;
+ }catch(int e)
+ {
+ cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
+ return 1;
+ }
+ if(out.numberoftetrahedra == 0)
+ {
+ cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
+ return 2;
+ }
+ success = tetgenio_to_tetmesh(out,TV,TT,TF);
+ if(!success)
+ {
+ return -1;
+ }
+ //boundary_facets(TT,TF);
+ return 0;
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedTV,
+ typename DerivedTT,
+ typename DerivedTF>
+IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const std::string switches,
+ Eigen::PlainObjectBase<DerivedTV>& TV,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTF>& TF)
+{
+ using namespace std;
+ vector<vector<REAL> > vV,vTV;
+ vector<vector<int> > vF,vTT,vTF;
+ matrix_to_list(V,vV);
+ matrix_to_list(F,vF);
+ int e = tetrahedralize(vV,vF,switches,vTV,vTT,vTF);
+ if(e == 0)
+ {
+ bool TV_rect = list_to_matrix(vTV,TV);
+ if(!TV_rect)
+ {
+ return 3;
+ }
+ bool TT_rect = list_to_matrix(vTT,TT);
+ if(!TT_rect)
+ {
+ return 3;
+ }
+ bool TF_rect = list_to_matrix(vTF,TF);
+ if(!TF_rect)
+ {
+ return 3;
+ }
+ }
+ return e;
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVM,
+ typename DerivedFM,
+ typename DerivedTV,
+ typename DerivedTT,
+ typename DerivedTF,
+ typename DerivedTM>
+IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedVM>& VM,
+ const Eigen::PlainObjectBase<DerivedFM>& FM,
+ const std::string switches,
+ Eigen::PlainObjectBase<DerivedTV>& TV,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTF>& TF,
+ Eigen::PlainObjectBase<DerivedTM>& TM)
+{
+ using namespace std;
+ vector<vector<REAL> > vV,vTV;
+ vector<vector<int> > vF,vTT,vTF;
+ vector<int> vTM;
+
+ matrix_to_list(V,vV);
+ matrix_to_list(F,vF);
+ vector<int> vVM = matrix_to_list(VM);
+ vector<int> vFM = matrix_to_list(FM);
+ int e = tetrahedralize(vV,vF,vVM,vFM,switches,vTV,vTT,vTF,vTM);
+ if(e == 0)
+ {
+ bool TV_rect = list_to_matrix(vTV,TV);
+ if(!TV_rect)
+ {
+ return false;
+ }
+ bool TT_rect = list_to_matrix(vTT,TT);
+ if(!TT_rect)
+ {
+ return false;
+ }
+ bool TF_rect = list_to_matrix(vTF,TF);
+ if(!TF_rect)
+ {
+ return false;
+ }
+ bool TM_rect = list_to_matrix(vTM,TM);
+ if(!TM_rect)
+ {
+ return false;
+ }
+ }
+ return e;
+}
+IGL_INLINE int igl::copyleft::tetgen::tetrahedralize(
+ const std::vector<std::vector<REAL > > & V,
+ const std::vector<std::vector<int> > & F,
+ const std::vector<int> & VM,
+ const std::vector<int> & FM,
+ const std::string switches,
+ std::vector<std::vector<REAL > > & TV,
+ std::vector<std::vector<int > > & TT,
+ std::vector<std::vector<int> > & TF,
+ std::vector<int> & TM)
+{
+ using namespace std;
+ tetgenio in,out;
+ bool success;
+ success = mesh_to_tetgenio(V,F,in);
+ if(!success)
+ {
+ return -1;
+ }
+ in.pointmarkerlist = new int[VM.size()];
+ for (int i = 0; i < VM.size(); ++i) {
+ in.pointmarkerlist[i] = VM[i];
+ }
+ // These have already been created in mesh_to_tetgenio.
+ // Reset them here.
+ for (int i = 0; i < FM.size(); ++i) {
+ in.facetmarkerlist[i] = FM[i];
+ }
+ try
+ {
+ char * cswitches = new char[switches.size() + 1];
+ std::strcpy(cswitches,switches.c_str());
+ ::tetrahedralize(cswitches,&in, &out);
+ delete[] cswitches;
+ }catch(int e)
+ {
+ cerr<<"^"<<__FUNCTION__<<": TETGEN CRASHED... KABOOOM!!!"<<endl;
+ return 1;
+ }
+ if(out.numberoftetrahedra == 0)
+ {
+ cerr<<"^"<<__FUNCTION__<<": Tetgen failed to create tets"<<endl;
+ return 2;
+ }
+ success = tetgenio_to_tetmesh(out,TV,TT,TF);
+ if(!success)
+ {
+ return -1;
+ }
+ TM.resize(out.numberofpoints);
+ for (int i = 0; i < out.numberofpoints; ++i) {
+ TM[i] = out.pointmarkerlist[i];
+ }
+ //boundary_facets(TT,TF);
+ return 0;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<int, -1, 1, 0, -1, 1>,Eigen::Matrix<double, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, -1, 0, -1, -1>,Eigen::Matrix<int, -1, 1, 0, -1, 1> >(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &,const std::basic_string<char, std::char_traits<char>, std::allocator<char> >,Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &,Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > &);
+template int igl::copyleft::tetgen::tetrahedralize<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/copyleft/tetgen/tetrahedralize.h b/xs/src/igl/copyleft/tetgen/tetrahedralize.h
new file mode 100644
index 000000000..170a3f985
--- /dev/null
+++ b/xs/src/igl/copyleft/tetgen/tetrahedralize.h
@@ -0,0 +1,136 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COPYLEFT_TETGEN_TETRAHEDRALIZE_H
+#define IGL_COPYLEFT_TETGEN_TETRAHEDRALIZE_H
+#include "../../igl_inline.h"
+
+#include <vector>
+#include <string>
+#include <Eigen/Core>
+#ifndef TETLIBRARY
+#define TETLIBRARY
+#endif
+#include "tetgen.h" // Defined REAL
+
+namespace igl
+{
+ namespace copyleft
+ {
+ namespace tetgen
+ {
+ // Mesh the interior of a surface mesh (V,F) using tetgen
+ //
+ // Inputs:
+ // V #V by 3 vertex position list
+ // F #F list of polygon face indices into V (0-indexed)
+ // switches string of tetgen options (See tetgen documentation) e.g.
+ // "pq1.414a0.01" tries to mesh the interior of a given surface with
+ // quality and area constraints
+ // "" will mesh the convex hull constrained to pass through V (ignores F)
+ // Outputs:
+ // TV #V by 3 vertex position list
+ // TT #T by 4 list of tet face indices
+ // TF #F by 3 list of triangle face indices
+ // Returns status:
+ // 0 success
+ // 1 tetgen threw exception
+ // 2 tetgen did not crash but could not create any tets (probably there are
+ // holes, duplicate faces etc.)
+ // -1 other error
+ IGL_INLINE int tetrahedralize(
+ const std::vector<std::vector<REAL > > & V,
+ const std::vector<std::vector<int> > & F,
+ const std::string switches,
+ std::vector<std::vector<REAL > > & TV,
+ std::vector<std::vector<int > > & TT,
+ std::vector<std::vector<int> > & TF);
+
+ // Wrapper with Eigen types
+ // Templates:
+ // DerivedV real-value: i.e. from MatrixXd
+ // DerivedF integer-value: i.e. from MatrixXi
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedTV,
+ typename DerivedTT,
+ typename DerivedTF>
+ IGL_INLINE int tetrahedralize(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const std::string switches,
+ Eigen::PlainObjectBase<DerivedTV>& TV,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTF>& TF);
+
+ // Mesh the interior of a surface mesh (V,F) using tetgen
+ //
+ // Inputs:
+ // V #V by 3 vertex position list
+ // F #F list of polygon face indices into V (0-indexed)
+ // M #V list of markers for vertices
+ // switches string of tetgen options (See tetgen documentation) e.g.
+ // "pq1.414a0.01" tries to mesh the interior of a given surface with
+ // quality and area constraints
+ // "" will mesh the convex hull constrained to pass through V (ignores F)
+ // Outputs:
+ // TV #V by 3 vertex position list
+ // TT #T by 4 list of tet face indices
+ // TF #F by 3 list of triangle face indices
+ // TM #V list of markers for vertices
+ // Returns status:
+ // 0 success
+ // 1 tetgen threw exception
+ // 2 tetgen did not crash but could not create any tets (probably there are
+ // holes, duplicate faces etc.)
+ // -1 other error
+ IGL_INLINE int tetrahedralize(
+ const std::vector<std::vector<REAL > > & V,
+ const std::vector<std::vector<int> > & F,
+ const std::vector<int> & VM,
+ const std::vector<int> & FM,
+ const std::string switches,
+ std::vector<std::vector<REAL > > & TV,
+ std::vector<std::vector<int > > & TT,
+ std::vector<std::vector<int> > & TF,
+ std::vector<int> & TM);
+
+ // Wrapper with Eigen types
+ // Templates:
+ // DerivedV real-value: i.e. from MatrixXd
+ // DerivedF integer-value: i.e. from MatrixXi
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVM,
+ typename DerivedFM,
+ typename DerivedTV,
+ typename DerivedTT,
+ typename DerivedTF,
+ typename DerivedTM>
+ IGL_INLINE int tetrahedralize(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedVM>& VM,
+ const Eigen::PlainObjectBase<DerivedFM>& FM,
+ const std::string switches,
+ Eigen::PlainObjectBase<DerivedTV>& TV,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTF>& TF,
+ Eigen::PlainObjectBase<DerivedTM>& TM);
+ }
+ }
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "tetrahedralize.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/cotmatrix.cpp b/xs/src/igl/cotmatrix.cpp
new file mode 100644
index 000000000..b1fd658ac
--- /dev/null
+++ b/xs/src/igl/cotmatrix.cpp
@@ -0,0 +1,88 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cotmatrix.h"
+#include <vector>
+
+// For error printing
+#include <cstdio>
+#include "cotmatrix_entries.h"
+
+// Bug in unsupported/Eigen/SparseExtra needs iostream first
+#include <iostream>
+
+template <typename DerivedV, typename DerivedF, typename Scalar>
+IGL_INLINE void igl::cotmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& L)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ L.resize(V.rows(),V.rows());
+ Matrix<int,Dynamic,2> edges;
+ int simplex_size = F.cols();
+ // 3 for triangles, 4 for tets
+ assert(simplex_size == 3 || simplex_size == 4);
+ if(simplex_size == 3)
+ {
+ // This is important! it could decrease the comptuation time by a factor of 2
+ // Laplacian for a closed 2d manifold mesh will have on average 7 entries per
+ // row
+ L.reserve(10*V.rows());
+ edges.resize(3,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1;
+ }else if(simplex_size == 4)
+ {
+ L.reserve(17*V.rows());
+ edges.resize(6,2);
+ edges <<
+ 1,2,
+ 2,0,
+ 0,1,
+ 3,0,
+ 3,1,
+ 3,2;
+ }else
+ {
+ return;
+ }
+ // Gather cotangents
+ Matrix<Scalar,Dynamic,Dynamic> C;
+ cotmatrix_entries(V,F,C);
+
+ vector<Triplet<Scalar> > IJV;
+ IJV.reserve(F.rows()*edges.rows()*4);
+ // Loop over triangles
+ for(int i = 0; i < F.rows(); i++)
+ {
+ // loop over edges of element
+ for(int e = 0;e<edges.rows();e++)
+ {
+ int source = F(i,edges(e,0));
+ int dest = F(i,edges(e,1));
+ IJV.push_back(Triplet<Scalar>(source,dest,C(i,e)));
+ IJV.push_back(Triplet<Scalar>(dest,source,C(i,e)));
+ IJV.push_back(Triplet<Scalar>(source,source,-C(i,e)));
+ IJV.push_back(Triplet<Scalar>(dest,dest,-C(i,e)));
+ }
+ }
+ L.setFromTriplets(IJV.begin(),IJV.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/cotmatrix.h b/xs/src/igl/cotmatrix.h
new file mode 100644
index 000000000..bb8232f5a
--- /dev/null
+++ b/xs/src/igl/cotmatrix.h
@@ -0,0 +1,57 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COTMATRIX_H
+#define IGL_COTMATRIX_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+// History:
+// Used const references rather than copying the entire mesh
+// Alec 9 October 2011
+// removed cotan (uniform weights) optional parameter it was building a buggy
+// half of the uniform laplacian, please see adjacency_matrix instead
+// Alec 9 October 2011
+
+namespace igl
+{
+ // Constructs the cotangent stiffness matrix (discrete laplacian) for a given
+ // mesh (V,F).
+ //
+ // Templates:
+ // DerivedV derived type of eigen matrix for V (e.g. derived from
+ // MatrixXd)
+ // DerivedF derived type of eigen matrix for F (e.g. derived from
+ // MatrixXi)
+ // Scalar scalar type for eigen sparse matrix (e.g. double)
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by simplex_size list of mesh faces (must be triangles)
+ // Outputs:
+ // L #V by #V cotangent matrix, each row i corresponding to V(i,:)
+ //
+ // See also: adjacency_matrix
+ //
+ // Note: This Laplacian uses the convention that diagonal entries are
+ // **minus** the sum of off-diagonal entries. The diagonal entries are
+ // therefore in general negative and the matrix is **negative** semi-definite
+ // (immediately, -L is **positive** semi-definite)
+ //
+ template <typename DerivedV, typename DerivedF, typename Scalar>
+ IGL_INLINE void cotmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cotmatrix.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/cotmatrix_entries.cpp b/xs/src/igl/cotmatrix_entries.cpp
new file mode 100644
index 000000000..6f7dfbbd3
--- /dev/null
+++ b/xs/src/igl/cotmatrix_entries.cpp
@@ -0,0 +1,110 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cotmatrix_entries.h"
+#include "doublearea.h"
+#include "squared_edge_lengths.h"
+#include "edge_lengths.h"
+#include "face_areas.h"
+#include "volume.h"
+#include "dihedral_angles.h"
+
+#include "verbose.h"
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::cotmatrix_entries(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedC>& C)
+{
+ using namespace std;
+ using namespace Eigen;
+ // simplex size (3: triangles, 4: tetrahedra)
+ int simplex_size = F.cols();
+ // Number of elements
+ int m = F.rows();
+
+ // Law of cosines + law of sines
+ switch(simplex_size)
+ {
+ case 3:
+ {
+ // Triangles
+ //Compute Squared Edge lengths
+ Matrix<typename DerivedC::Scalar,Dynamic,3> l2;
+ igl::squared_edge_lengths(V,F,l2);
+ //Compute Edge lengths
+ Matrix<typename DerivedC::Scalar,Dynamic,3> l;
+ l = l2.array().sqrt();
+
+ // double area
+ Matrix<typename DerivedC::Scalar,Dynamic,1> dblA;
+ doublearea(l,0.,dblA);
+ // cotangents and diagonal entries for element matrices
+ // correctly divided by 4 (alec 2010)
+ C.resize(m,3);
+ for(int i = 0;i<m;i++)
+ {
+ C(i,0) = (l2(i,1) + l2(i,2) - l2(i,0))/dblA(i)/4.0;
+ C(i,1) = (l2(i,2) + l2(i,0) - l2(i,1))/dblA(i)/4.0;
+ C(i,2) = (l2(i,0) + l2(i,1) - l2(i,2))/dblA(i)/4.0;
+ }
+ break;
+ }
+ case 4:
+ {
+
+ // edge lengths numbered same as opposite vertices
+ Matrix<typename DerivedC::Scalar,Dynamic,6> l;
+ edge_lengths(V,F,l);
+ Matrix<typename DerivedC::Scalar,Dynamic,4> s;
+ face_areas(l,s);
+ Matrix<typename DerivedC::Scalar,Dynamic,6> cos_theta,theta;
+ dihedral_angles_intrinsic(l,s,theta,cos_theta);
+
+ // volume
+ Matrix<typename DerivedC::Scalar,Dynamic,1> vol;
+ volume(l,vol);
+
+
+ // Law of sines
+ // http://mathworld.wolfram.com/Tetrahedron.html
+ Matrix<typename DerivedC::Scalar,Dynamic,6> sin_theta(m,6);
+ sin_theta.col(0) = vol.array() / ((2./(3.*l.col(0).array())).array() * s.col(1).array() * s.col(2).array());
+ sin_theta.col(1) = vol.array() / ((2./(3.*l.col(1).array())).array() * s.col(2).array() * s.col(0).array());
+ sin_theta.col(2) = vol.array() / ((2./(3.*l.col(2).array())).array() * s.col(0).array() * s.col(1).array());
+ sin_theta.col(3) = vol.array() / ((2./(3.*l.col(3).array())).array() * s.col(3).array() * s.col(0).array());
+ sin_theta.col(4) = vol.array() / ((2./(3.*l.col(4).array())).array() * s.col(3).array() * s.col(1).array());
+ sin_theta.col(5) = vol.array() / ((2./(3.*l.col(5).array())).array() * s.col(3).array() * s.col(2).array());
+
+
+ // http://arxiv.org/pdf/1208.0354.pdf Page 18
+ C = (1./6.) * l.array() * cos_theta.array() / sin_theta.array();
+
+ break;
+ }
+ default:
+ {
+ fprintf(stderr,
+ "cotmatrix_entries.h: Error: Simplex size (%d) not supported\n", simplex_size);
+ assert(false);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::cotmatrix_entries<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/cotmatrix_entries.h b/xs/src/igl/cotmatrix_entries.h
new file mode 100644
index 000000000..6368c02e8
--- /dev/null
+++ b/xs/src/igl/cotmatrix_entries.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COTMATRIX_ENTRIES_H
+#define IGL_COTMATRIX_ENTRIES_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // COTMATRIX_ENTRIES compute the cotangents of each angle in mesh (V,F)
+ //
+ // Inputs:
+ // V #V by dim list of rest domain positions
+ // F #F by {3|4} list of {triangle|tetrahedra} indices into V
+ // Outputs:
+ // C #F by 3 list of 1/2*cotangents corresponding angles
+ // for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+ // OR
+ // C #F by 6 list of 1/6*cotangents of dihedral angles*edge lengths
+ // for tets, columns along edges [1,2],[2,0],[0,1],[3,0],[3,1],[3,2]
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedC>
+ IGL_INLINE void cotmatrix_entries(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedC>& C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cotmatrix_entries.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/count.cpp b/xs/src/igl/count.cpp
new file mode 100644
index 000000000..bdde79ca7
--- /dev/null
+++ b/xs/src/igl/count.cpp
@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "count.h"
+#include "redux.h"
+
+template <typename XType, typename SType>
+IGL_INLINE void igl::count(
+ const Eigen::SparseMatrix<XType>& X,
+ const int dim,
+ Eigen::SparseVector<SType>& S)
+{
+ // dim must be 2 or 1
+ assert(dim == 1 || dim == 2);
+ // Get size of input
+ int m = X.rows();
+ int n = X.cols();
+ // resize output
+ if(dim==1)
+ {
+ S = Eigen::SparseVector<SType>(n);
+ }else
+ {
+ S = Eigen::SparseVector<SType>(m);
+ }
+
+ // Iterate over outside
+ for(int k=0; k<X.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<XType>::InnerIterator it (X,k); it; ++it)
+ {
+ if(dim == 1)
+ {
+ S.coeffRef(it.col()) += (it.value() == 0? 0: 1);
+ }else
+ {
+ S.coeffRef(it.row()) += (it.value() == 0? 0: 1);
+ }
+ }
+ }
+
+}
+
+template <typename AType, typename DerivedB>
+IGL_INLINE void igl::count(
+ const Eigen::SparseMatrix<AType>& A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB>& B)
+{
+ typedef typename DerivedB::Scalar Scalar;
+ igl::redux(A,dim,[](Scalar a, Scalar b){ return a+(b==0?0:1);},B);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::count<bool, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::count<bool, Eigen::Array<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Array<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/count.h b/xs/src/igl/count.h
new file mode 100644
index 000000000..61aeb94e8
--- /dev/null
+++ b/xs/src/igl/count.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COUNT_H
+#define IGL_COUNT_H
+#include "igl_inline.h"
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Note: If your looking for dense matrix matlab like sum for eigen matrics
+ // just use:
+ // M.colwise().count() or M.rowwise().count()
+ //
+
+ // Count the number of non-zeros in the columns or rows of a sparse matrix
+ //
+ // Inputs:
+ // X m by n sparse matrix
+ // dim dimension along which to sum (1 or 2)
+ // Output:
+ // S n-long sparse vector (if dim == 1)
+ // or
+ // S m-long sparse vector (if dim == 2)
+ template <typename XType, typename SType>
+ IGL_INLINE void count(
+ const Eigen::SparseMatrix<XType>& X,
+ const int dim,
+ Eigen::SparseVector<SType>& S);
+ template <typename XType, typename DerivedS>
+ IGL_INLINE void count(
+ const Eigen::SparseMatrix<XType>& X,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedS>& S);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "count.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/covariance_scatter_matrix.cpp b/xs/src/igl/covariance_scatter_matrix.cpp
new file mode 100644
index 000000000..24fe9f760
--- /dev/null
+++ b/xs/src/igl/covariance_scatter_matrix.cpp
@@ -0,0 +1,76 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "covariance_scatter_matrix.h"
+#include "arap_linear_block.h"
+#include "cotmatrix.h"
+#include "diag.h"
+#include "sum.h"
+#include "edges.h"
+#include "verbose.h"
+#include "cat.h"
+#include "PI.h"
+
+IGL_INLINE void igl::covariance_scatter_matrix(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const ARAPEnergyType energy,
+ Eigen::SparseMatrix<double>& CSM)
+{
+ using namespace Eigen;
+ // number of mesh vertices
+ int n = V.rows();
+ assert(n > F.maxCoeff());
+ // dimension of mesh
+ int dim = V.cols();
+ // Number of mesh elements
+ int m = F.rows();
+
+ // number of rotations
+ int nr;
+ switch(energy)
+ {
+ case ARAP_ENERGY_TYPE_SPOKES:
+ nr = n;
+ break;
+ case ARAP_ENERGY_TYPE_SPOKES_AND_RIMS:
+ nr = n;
+ break;
+ case ARAP_ENERGY_TYPE_ELEMENTS:
+ nr = m;
+ break;
+ default:
+ fprintf(
+ stderr,
+ "covariance_scatter_matrix.h: Error: Unsupported arap energy %d\n",
+ energy);
+ return;
+ }
+
+ SparseMatrix<double> KX,KY,KZ;
+ arap_linear_block(V,F,0,energy,KX);
+ arap_linear_block(V,F,1,energy,KY);
+ SparseMatrix<double> Z(n,nr);
+ if(dim == 2)
+ {
+ CSM = cat(1,cat(2,KX,Z),cat(2,Z,KY)).transpose();
+ }else if(dim == 3)
+ {
+ arap_linear_block(V,F,2,energy,KZ);
+ SparseMatrix<double>ZZ(n,nr*2);
+ CSM =
+ cat(1,cat(1,cat(2,KX,ZZ),cat(2,cat(2,Z,KY),Z)),cat(2,ZZ,KZ)).transpose();
+ }else
+ {
+ fprintf(
+ stderr,
+ "covariance_scatter_matrix.h: Error: Unsupported dimension %d\n",
+ dim);
+ return;
+ }
+
+}
diff --git a/xs/src/igl/covariance_scatter_matrix.h b/xs/src/igl/covariance_scatter_matrix.h
new file mode 100644
index 000000000..e70c77ab1
--- /dev/null
+++ b/xs/src/igl/covariance_scatter_matrix.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_COVARIANCE_SCATTER_MATRIX_H
+#define IGL_COVARIANCE_SCATTER_MATRIX_H
+
+#include "igl_inline.h"
+#include "ARAPEnergyType.h"
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Construct the covariance scatter matrix for a given arap energy
+ // Inputs:
+ // V #V by Vdim list of initial domain positions
+ // F #F by 3 list of triangle indices into V
+ // energy ARAPEnergyType enum value defining which energy is being used.
+ // See ARAPEnergyType.h for valid options and explanations.
+ // Outputs:
+ // CSM dim*#V/#F by dim*#V sparse matrix containing special laplacians along
+ // the diagonal so that when multiplied by V gives covariance matrix
+ // elements, can be used to speed up covariance matrix computation
+ IGL_INLINE void covariance_scatter_matrix(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const ARAPEnergyType energy,
+ Eigen::SparseMatrix<double>& CSM);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "covariance_scatter_matrix.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/cross.cpp b/xs/src/igl/cross.cpp
new file mode 100644
index 000000000..04ee5340b
--- /dev/null
+++ b/xs/src/igl/cross.cpp
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cross.h"
+
+// http://www.antisphere.com/Wiki/tools:anttweakbar
+IGL_INLINE void igl::cross(
+ const double *a,
+ const double *b,
+ double *out)
+{
+ out[0] = a[1]*b[2]-a[2]*b[1];
+ out[1] = a[2]*b[0]-a[0]*b[2];
+ out[2] = a[0]*b[1]-a[1]*b[0];
+}
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC>
+IGL_INLINE void igl::cross(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ const Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ assert(A.cols() == 3 && "#cols should be 3");
+ assert(B.cols() == 3 && "#cols should be 3");
+ assert(A.rows() == B.rows() && "#rows in A and B should be equal");
+ C.resize(A.rows(),3);
+ for(int d = 0;d<3;d++)
+ {
+ C.col(d) =
+ A.col((d+1)%3).array() * B.col((d+2)%3).array() -
+ A.col((d+2)%3).array() * B.col((d+1)%3).array();
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::cross<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::cross<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/cross.h b/xs/src/igl/cross.h
new file mode 100644
index 000000000..cfbe563ed
--- /dev/null
+++ b/xs/src/igl/cross.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CROSS_H
+#define IGL_CROSS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Computes out = cross(a,b)
+ // Inputs:
+ // a left 3d vector
+ // b right 3d vector
+ // Outputs:
+ // out result 3d vector
+ IGL_INLINE void cross( const double *a, const double *b, double *out);
+ // Computes C = cross(A,B,2);
+ //
+ // Inputs:
+ // A #A by 3 list of row-vectors
+ // B #A by 3 list of row-vectors
+ // Outputs:
+ // C #A by 3 list of row-vectors
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC>
+ IGL_INLINE void cross(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ const Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cross.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/cross_field_missmatch.cpp b/xs/src/igl/cross_field_missmatch.cpp
new file mode 100644
index 000000000..7d3caf0a8
--- /dev/null
+++ b/xs/src/igl/cross_field_missmatch.cpp
@@ -0,0 +1,142 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "cross_field_missmatch.h"
+
+#include <cmath>
+#include <vector>
+#include <deque>
+#include <igl/comb_cross_field.h>
+#include <igl/per_face_normals.h>
+#include <igl/is_border_vertex.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/rotation_matrix_from_directions.h>
+#include <igl/PI.h>
+
+namespace igl {
+ template <typename DerivedV, typename DerivedF, typename DerivedM>
+ class MissMatchCalculator
+ {
+ public:
+
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ const Eigen::PlainObjectBase<DerivedV> &PD1;
+ const Eigen::PlainObjectBase<DerivedV> &PD2;
+
+ DerivedV N;
+
+ private:
+ // internal
+ std::vector<bool> V_border; // bool
+ std::vector<std::vector<int> > VF;
+ std::vector<std::vector<int> > VFi;
+
+ DerivedF TT;
+ DerivedF TTi;
+
+
+ private:
+ ///compute the mismatch between 2 faces
+ inline int MissMatchByCross(const int f0,
+ const int f1)
+ {
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1.row(f1);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1Rot = igl::rotation_matrix_from_directions(n1,n0)*dir1;
+ dir1Rot.normalize();
+
+ // TODO: this should be equivalent to the other code below, to check!
+ // Compute the angle between the two vectors
+ // double a0 = atan2(dir0.dot(B2.row(f0)),dir0.dot(B1.row(f0)));
+ // double a1 = atan2(dir1Rot.dot(B2.row(f0)),dir1Rot.dot(B1.row(f0)));
+ //
+ // double angle_diff = a1-a0; //VectToAngle(f0,dir1Rot);
+
+ double angle_diff = atan2(dir1Rot.dot(PD2.row(f0)),dir1Rot.dot(PD1.row(f0)));
+
+ // std::cerr << "Dani: " << dir0(0) << " " << dir0(1) << " " << dir0(2) << " " << dir1Rot(0) << " " << dir1Rot(1) << " " << dir1Rot(2) << " " << angle_diff << std::endl;
+
+ double step=igl::PI/2.0;
+ int i=(int)std::floor((angle_diff/step)+0.5);
+ int k=0;
+ if (i>=0)
+ k=i%4;
+ else
+ k=(-(3*i))%4;
+ return k;
+ }
+
+
+public:
+ inline MissMatchCalculator(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_PD1,
+ const Eigen::PlainObjectBase<DerivedV> &_PD2
+ ):
+ V(_V),
+ F(_F),
+ PD1(_PD1),
+ PD2(_PD2)
+ {
+ igl::per_face_normals(V,F,N);
+ V_border = igl::is_border_vertex(V,F);
+ igl::vertex_triangle_adjacency(V,F,VF,VFi);
+ igl::triangle_triangle_adjacency(F,TT,TTi);
+ }
+
+ inline void calculateMissmatch(Eigen::PlainObjectBase<DerivedM> &Handle_MMatch)
+ {
+ Handle_MMatch.setConstant(F.rows(),3,-1);
+ for (size_t i=0;i<F.rows();i++)
+ {
+ for (int j=0;j<3;j++)
+ {
+ if (((int)i)==TT(i,j) || TT(i,j) == -1)
+ Handle_MMatch(i,j)=0;
+ else
+ Handle_MMatch(i,j) = MissMatchByCross(i,TT(i,j));
+ }
+ }
+ }
+
+};
+}
+template <typename DerivedV, typename DerivedF, typename DerivedM>
+IGL_INLINE void igl::cross_field_missmatch(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const Eigen::PlainObjectBase<DerivedV> &PD2,
+ const bool isCombed,
+ Eigen::PlainObjectBase<DerivedM> &missmatch)
+{
+ DerivedV PD1_combed;
+ DerivedV PD2_combed;
+
+ if (!isCombed)
+ igl::comb_cross_field(V,F,PD1,PD2,PD1_combed,PD2_combed);
+ else
+ {
+ PD1_combed = PD1;
+ PD2_combed = PD2;
+ }
+ igl::MissMatchCalculator<DerivedV, DerivedF, DerivedM> sf(V, F, PD1_combed, PD2_combed);
+ sf.calculateMissmatch(missmatch);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::cross_field_missmatch<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cross_field_missmatch<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cross_field_missmatch<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+
+#endif
diff --git a/xs/src/igl/cross_field_missmatch.h b/xs/src/igl/cross_field_missmatch.h
new file mode 100644
index 000000000..9d7a7599d
--- /dev/null
+++ b/xs/src/igl/cross_field_missmatch.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_CROSS_FIELD_MISSMATCH_H
+#define IGL_CROSS_FIELD_MISSMATCH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Calculates the missmatch (integer), at each face edge, of a cross field defined on the mesh faces.
+ // The integer missmatch is a multiple of pi/2 that transforms the cross on one side of the edge to
+ // the cross on the other side. It represents the deviation from a Lie connection across the edge.
+
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 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
+ // isCombed boolean, specifying whether the field is combed (i.e. matching has been precomputed.
+ // If not, the field is combed first.
+ // Output:
+ // Handle_MMatch #F by 3 eigen Matrix containing the integer missmatch of the cross field
+ // across all face edges
+ //
+
+ template <typename DerivedV, typename DerivedF, typename DerivedM>
+ IGL_INLINE void cross_field_missmatch(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const Eigen::PlainObjectBase<DerivedV> &PD2,
+ const bool isCombed,
+ Eigen::PlainObjectBase<DerivedM> &missmatch);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "cross_field_missmatch.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/crouzeix_raviart_cotmatrix.cpp b/xs/src/igl/crouzeix_raviart_cotmatrix.cpp
new file mode 100644
index 000000000..2fc5f6d4a
--- /dev/null
+++ b/xs/src/igl/crouzeix_raviart_cotmatrix.cpp
@@ -0,0 +1,100 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "crouzeix_raviart_cotmatrix.h"
+#include "unique_simplices.h"
+#include "oriented_facets.h"
+#include "is_edge_manifold.h"
+#include "cotmatrix_entries.h"
+
+template <typename DerivedV, typename DerivedF, typename LT, typename DerivedE, typename DerivedEMAP>
+void igl::crouzeix_raviart_cotmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<LT> & L,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
+{
+ // All occurrences of directed "facets"
+ Eigen::MatrixXi allE;
+ oriented_facets(F,allE);
+ Eigen::VectorXi _1;
+ unique_simplices(allE,E,_1,EMAP);
+ return crouzeix_raviart_cotmatrix(V,F,E,EMAP,L);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP, typename LT>
+void igl::crouzeix_raviart_cotmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ Eigen::SparseMatrix<LT> & L)
+{
+ // number of rows
+ const int m = F.rows();
+ // Element simplex size
+ const int ss = F.cols();
+ // Mesh should be edge-manifold
+ assert(F.cols() != 3 || is_edge_manifold(F));
+ typedef Eigen::Matrix<LT,Eigen::Dynamic,Eigen::Dynamic> MatrixXS;
+ MatrixXS C;
+ cotmatrix_entries(V,F,C);
+ Eigen::MatrixXi F2E(m,ss);
+ {
+ int k =0;
+ for(int c = 0;c<ss;c++)
+ {
+ for(int f = 0;f<m;f++)
+ {
+ F2E(f,c) = k++;
+ }
+ }
+ }
+ // number of entries inserted per facet
+ const int k = ss*(ss-1)*2;
+ std::vector<Eigen::Triplet<LT> > LIJV;LIJV.reserve(k*m);
+ Eigen::VectorXi LI(k),LJ(k),LV(k);
+ // Compensation factor to match scales in matlab version
+ double factor = 2.0;
+
+ switch(ss)
+ {
+ default: assert(false && "unsupported simplex size");
+ case 3:
+ factor = 4.0;
+ LI<<0,1,2,1,2,0,0,1,2,1,2,0;
+ LJ<<1,2,0,0,1,2,0,1,2,1,2,0;
+ LV<<2,0,1,2,0,1,2,0,1,2,0,1;
+ break;
+ case 4:
+ factor *= -1.0;
+ LI<<0,3,3,3,1,2,1,0,1,2,2,0,0,3,3,3,1,2,1,0,1,2,2,0;
+ LJ<<1,0,1,2,2,0,0,3,3,3,1,2,0,3,3,3,1,2,1,0,1,2,2,0;
+ LV<<2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1,2,3,4,5,0,1;
+ break;
+ }
+
+ for(int f=0;f<m;f++)
+ {
+ for(int c = 0;c<k;c++)
+ {
+ LIJV.emplace_back(
+ EMAP(F2E(f,LI(c))),
+ EMAP(F2E(f,LJ(c))),
+ (c<(k/2)?-1.:1.) * factor *C(f,LV(c)));
+ }
+ }
+ L.resize(E.rows(),E.rows());
+ L.setFromTriplets(LIJV.begin(),LIJV.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::crouzeix_raviart_cotmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/crouzeix_raviart_cotmatrix.h b/xs/src/igl/crouzeix_raviart_cotmatrix.h
new file mode 100644
index 000000000..1504ddad0
--- /dev/null
+++ b/xs/src/igl/crouzeix_raviart_cotmatrix.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CROUZEIX_RAVIART_COTMATRIX
+#define IGL_CROUZEIX_RAVIART_COTMATRIX
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // CROUZEIX_RAVIART_COTMATRIX Compute the Crouzeix-Raviart cotangent
+ // stiffness matrix.
+ //
+ // See for example "Discrete Quadratic Curvature Energies" [Wardetzky, Bergou,
+ // Harmon, Zorin, Grinspun 2007]
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // F #F by 3/4 list of triangle/tetrahedron indices
+ // Outputs:
+ // L #E by #E edge/face-based diagonal cotangent matrix
+ // E #E by 2/3 list of edges/faces
+ // EMAP #F*3/4 list of indices mapping allE to E
+ //
+ // See also: crouzeix_raviart_massmatrix
+ template <typename DerivedV, typename DerivedF, typename LT, typename DerivedE, typename DerivedEMAP>
+ void crouzeix_raviart_cotmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<LT> & L,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
+ // wrapper if E and EMAP are already computed (better match!)
+ template <typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP, typename LT>
+ void crouzeix_raviart_cotmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ Eigen::SparseMatrix<LT> & L);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "crouzeix_raviart_cotmatrix.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/crouzeix_raviart_massmatrix.cpp b/xs/src/igl/crouzeix_raviart_massmatrix.cpp
new file mode 100644
index 000000000..0873712d5
--- /dev/null
+++ b/xs/src/igl/crouzeix_raviart_massmatrix.cpp
@@ -0,0 +1,85 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "crouzeix_raviart_massmatrix.h"
+#include "unique_simplices.h"
+#include "oriented_facets.h"
+
+#include "is_edge_manifold.h"
+#include "doublearea.h"
+#include "volume.h"
+
+#include <cassert>
+#include <vector>
+
+template <typename MT, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP>
+void igl::crouzeix_raviart_massmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<MT> & M,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
+{
+ // All occurrences of directed "facets"
+ Eigen::MatrixXi allE;
+ oriented_facets(F,allE);
+ Eigen::VectorXi _1;
+ unique_simplices(allE,E,_1,EMAP);
+ return crouzeix_raviart_massmatrix(V,F,E,EMAP,M);
+}
+
+template <typename MT, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP>
+void igl::crouzeix_raviart_massmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ Eigen::SparseMatrix<MT> & M)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Mesh should be edge-manifold (TODO: replace `is_edge_manifold` with
+ // `is_facet_manifold`)
+ assert(F.cols() != 3 || is_edge_manifold(F));
+ // number of elements (triangles)
+ const int m = F.rows();
+ // Get triangle areas/volumes
+ VectorXd TA;
+ // Element simplex size
+ const int ss = F.cols();
+ switch(ss)
+ {
+ default:
+ assert(false && "Unsupported simplex size");
+ case 3:
+ doublearea(V,F,TA);
+ TA *= 0.5;
+ break;
+ case 4:
+ volume(V,F,TA);
+ break;
+ }
+ vector<Triplet<MT> > MIJV(ss*m);
+ assert(EMAP.size() == m*ss);
+ for(int f = 0;f<m;f++)
+ {
+ for(int c = 0;c<ss;c++)
+ {
+ MIJV[f+m*c] = Triplet<MT>(EMAP(f+m*c),EMAP(f+m*c),TA(f)/(double)(ss));
+ }
+ }
+ M.resize(E.rows(),E.rows());
+ M.setFromTriplets(MIJV.begin(),MIJV.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::crouzeix_raviart_massmatrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::crouzeix_raviart_massmatrix<float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<float, 0, int>&);
+#endif
diff --git a/xs/src/igl/crouzeix_raviart_massmatrix.h b/xs/src/igl/crouzeix_raviart_massmatrix.h
new file mode 100644
index 000000000..256aa2067
--- /dev/null
+++ b/xs/src/igl/crouzeix_raviart_massmatrix.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef CROUZEIX_RAVIART_MASSMATRIX_H
+#define CROUZEIX_RAVIART_MASSMATRIX_H
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // CROUZEIX_RAVIART_MASSMATRIX Compute the Crouzeix-Raviart mass matrix where
+ // M(e,e) is just the sum of the areas of the triangles on either side of an
+ // edge e.
+ //
+ // See for example "Discrete Quadratic Curvature Energies" [Wardetzky, Bergou,
+ // Harmon, Zorin, Grinspun 2007]
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // F #F by 3/4 list of triangle/tetrahedron indices
+ // Outputs:
+ // M #E by #E edge/face-based diagonal mass matrix
+ // E #E by 2/3 list of edges/faces
+ // EMAP #F*3/4 list of indices mapping allE to E
+ //
+ // See also: crouzeix_raviart_cotmatrix
+ template <typename MT, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP>
+ void crouzeix_raviart_massmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<MT> & M,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
+ // wrapper if E and EMAP are already computed (better match!)
+ template <typename MT, typename DerivedV, typename DerivedF, typename DerivedE, typename DerivedEMAP>
+ void crouzeix_raviart_massmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ Eigen::SparseMatrix<MT> & M);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "crouzeix_raviart_massmatrix.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/cumsum.cpp b/xs/src/igl/cumsum.cpp
new file mode 100644
index 000000000..38eb4edd3
--- /dev/null
+++ b/xs/src/igl/cumsum.cpp
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cumsum.h"
+#include <numeric>
+#include <iostream>
+
+template <typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::cumsum(
+ const Eigen::MatrixBase<DerivedX > & X,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY > & Y)
+{
+ using namespace Eigen;
+ using namespace std;
+ Y.resizeLike(X);
+ // get number of columns (or rows)
+ int num_outer = (dim == 1 ? X.cols() : X.rows() );
+ // get number of rows (or columns)
+ int num_inner = (dim == 1 ? X.rows() : X.cols() );
+ // This has been optimized so that dim = 1 or 2 is roughly the same cost.
+ // (Optimizations assume ColMajor order)
+ if(dim == 1)
+ {
+#pragma omp parallel for
+ for(int o = 0;o<num_outer;o++)
+ {
+ typename DerivedX::Scalar sum = 0;
+ for(int i = 0;i<num_inner;i++)
+ {
+ sum += X(i,o);
+ Y(i,o) = sum;
+ }
+ }
+ }else
+ {
+ for(int i = 0;i<num_inner;i++)
+ {
+ // Notice that it is *not* OK to put this above the inner loop
+ // Though here it doesn't seem to pay off...
+//#pragma omp parallel for
+ for(int o = 0;o<num_outer;o++)
+ {
+ if(i == 0)
+ {
+ Y(o,i) = X(o,i);
+ }else
+ {
+ Y(o,i) = Y(o,i-1) + X(o,i);
+ }
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::cumsum<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::cumsum<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::cumsum<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+template void igl::cumsum<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1>, Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> >(Eigen::MatrixBase<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, 2, 1, 0, 2, 1> >&);
+template void igl::cumsum<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1>, Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<unsigned long, -1, 1, 0, -1, 1> >&);
+template void igl::cumsum<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::cumsum<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<unsigned __int64, -1, 1, 0, -1, 1>> &);
+template void igl::cumsum<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>, class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>>(class Eigen::MatrixBase<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<unsigned __int64, 2, 1, 0, 2, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/cumsum.h b/xs/src/igl/cumsum.h
new file mode 100644
index 000000000..c3fa59258
--- /dev/null
+++ b/xs/src/igl/cumsum.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CUMSUM_H
+#define IGL_CUMSUM_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Computes a cumulative sum of the columns of X, like matlab's `cumsum`.
+ //
+ // Templates:
+ // DerivedX Type of matrix X
+ // DerivedY Type of matrix Y
+ // Inputs:
+ // X m by n Matrix to be cumulatively summed.
+ // dim dimension to take cumulative sum (1 or 2)
+ // Output:
+ // Y m by n Matrix containing cumulative sum.
+ //
+ template <typename DerivedX, typename DerivedY>
+ IGL_INLINE void cumsum(
+ const Eigen::MatrixBase<DerivedX > & X,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY > & Y);
+ //template <typename DerivedX, typename DerivedY>
+ //IGL_INLINE void cumsum(
+ // const Eigen::MatrixBase<DerivedX > & X,
+ // Eigen::PlainObjectBase<DerivedY > & Y);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "cumsum.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/cut_mesh.cpp b/xs/src/igl/cut_mesh.cpp
new file mode 100644
index 000000000..33a25ce93
--- /dev/null
+++ b/xs/src/igl/cut_mesh.cpp
@@ -0,0 +1,330 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include <igl/cut_mesh.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/is_border_vertex.h>
+#include <igl/HalfEdgeIterator.h>
+#include <set>
+
+// This file violates many of the libigl style guidelines.
+
+namespace igl {
+
+
+ template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+ class MeshCutterMini
+ {
+ public:
+ // Input
+ //mesh
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ // TT is the same type as TTi? This is likely to break at some point
+ const Eigen::PlainObjectBase<DerivedTT> &TT;
+ const Eigen::PlainObjectBase<DerivedTT> &TTi;
+ const std::vector<std::vector<VFType> >& VF;
+ const std::vector<std::vector<VFType> >& VFi;
+ const std::vector<bool> &V_border; // bool
+ //edges to cut
+ const Eigen::PlainObjectBase<DerivedC> &Handle_Seams; // 3 bool
+
+ // total number of scalar variables
+ int num_scalar_variables;
+
+ // per face indexes of vertex in the solver
+ DerivedF HandleS_Index;
+
+ // per vertex variable indexes
+ std::vector<std::vector<int> > HandleV_Integer;
+
+ IGL_INLINE MeshCutterMini(
+ const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedTT> &_TT,
+ const Eigen::PlainObjectBase<DerivedTT> &_TTi,
+ const std::vector<std::vector<VFType> > &_VF,
+ const std::vector<std::vector<VFType> > &_VFi,
+ const std::vector<bool> &_V_border,
+ const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams);
+
+ // vertex to variable mapping
+ // initialize the mapping for a given sampled mesh
+ IGL_INLINE void InitMappingSeam();
+
+ private:
+
+ IGL_INLINE void FirstPos(const int v, int &f, int &edge);
+
+ IGL_INLINE int AddNewIndex(const int v0);
+
+ IGL_INLINE bool IsSeam(const int f0, const int f1);
+
+ // find initial position of the pos to
+ // assing face to vert inxex correctly
+ IGL_INLINE void FindInitialPos(const int vert, int &edge, int &face);
+
+
+ // initialize the mapping given an initial pos
+ // whih must be initialized with FindInitialPos
+ IGL_INLINE void MapIndexes(const int vert, const int edge_init, const int f_init);
+
+ // initialize the mapping for a given vertex
+ IGL_INLINE void InitMappingSeam(const int vert);
+
+ };
+}
+
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+MeshCutterMini(
+ const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedTT> &_TT,
+ const Eigen::PlainObjectBase<DerivedTT> &_TTi,
+ const std::vector<std::vector<VFType> > &_VF,
+ const std::vector<std::vector<VFType> > &_VFi,
+ const std::vector<bool> &_V_border,
+ const Eigen::PlainObjectBase<DerivedC> &_Handle_Seams):
+ V(_V),
+ F(_F),
+ TT(_TT),
+ TTi(_TTi),
+ VF(_VF),
+ VFi(_VFi),
+ V_border(_V_border),
+ Handle_Seams(_Handle_Seams)
+{
+ num_scalar_variables=0;
+ HandleS_Index.setConstant(F.rows(),3,-1);
+ HandleV_Integer.resize(V.rows());
+}
+
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+FirstPos(const int v, int &f, int &edge)
+{
+ f = VF[v][0]; // f=v->cVFp();
+ edge = VFi[v][0]; // edge=v->cVFi();
+}
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE int igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+AddNewIndex(const int v0)
+{
+ num_scalar_variables++;
+ HandleV_Integer[v0].push_back(num_scalar_variables);
+ return num_scalar_variables;
+}
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE bool igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+IsSeam(const int f0, const int f1)
+{
+ for (int i=0;i<3;i++)
+ {
+ int f_clos = TT(f0,i);
+
+ if (f_clos == -1)
+ continue; ///border
+
+ if (f_clos == f1)
+ return(Handle_Seams(f0,i));
+ }
+ assert(0);
+ return false;
+}
+
+///find initial position of the pos to
+// assing face to vert inxex correctly
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+FindInitialPos(const int vert,
+ int &edge,
+ int &face)
+{
+ int f_init;
+ int edge_init;
+ FirstPos(vert,f_init,edge_init); // todo manually the function
+ igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
+
+ bool vertexB = V_border[vert];
+ bool possible_split=false;
+ bool complete_turn=false;
+ do
+ {
+ int curr_f = VFI.Fi();
+ int curr_edge=VFI.Ei();
+ VFI.NextFE();
+ int next_f=VFI.Fi();
+ ///test if I've just crossed a border
+ bool on_border=(TT(curr_f,curr_edge)==-1);
+ //bool mismatch=false;
+ bool seam=false;
+
+ ///or if I've just crossed a seam
+ ///if I'm on a border I MUST start from the one next t othe border
+ if (!vertexB)
+ //seam=curr_f->IsSeam(next_f);
+ seam=IsSeam(curr_f,next_f);
+ // if (vertexB)
+ // assert(!Handle_Singular(vert));
+ // ;
+ //assert(!vert->IsSingular());
+ possible_split=((on_border)||(seam));
+ complete_turn = next_f == f_init;
+ } while ((!possible_split)&&(!complete_turn));
+ face=VFI.Fi();
+ edge=VFI.Ei();
+}
+
+
+
+///initialize the mapping given an initial pos
+///whih must be initialized with FindInitialPos
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+MapIndexes(const int vert,
+ const int edge_init,
+ const int f_init)
+{
+ ///check that is not on border..
+ ///in such case maybe it's non manyfold
+ ///insert an initial index
+ int curr_index=AddNewIndex(vert);
+ ///and initialize the jumping pos
+ igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,edge_init);
+ bool complete_turn=false;
+ do
+ {
+ int curr_f = VFI.Fi();
+ int curr_edge = VFI.Ei();
+ ///assing the current index
+ HandleS_Index(curr_f,curr_edge) = curr_index;
+ VFI.NextFE();
+ int next_f = VFI.Fi();
+ ///test if I've finiseh with the face exploration
+ complete_turn = (next_f==f_init);
+ ///or if I've just crossed a mismatch
+ if (!complete_turn)
+ {
+ bool seam=false;
+ //seam=curr_f->IsSeam(next_f);
+ seam=IsSeam(curr_f,next_f);
+ if (seam)
+ {
+ ///then add a new index
+ curr_index=AddNewIndex(vert);
+ }
+ }
+ } while (!complete_turn);
+}
+
+///initialize the mapping for a given vertex
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+InitMappingSeam(const int vert)
+{
+ ///first rotate until find the first pos after a mismatch
+ ///or a border or return to the first position...
+ int f_init = VF[vert][0];
+ int indexE = VFi[vert][0];
+
+ igl::HalfEdgeIterator<DerivedF,DerivedTT,DerivedTT> VFI(F,TT,TTi,f_init,indexE);
+
+ int edge_init;
+ int face_init;
+ FindInitialPos(vert,edge_init,face_init);
+ MapIndexes(vert,edge_init,face_init);
+}
+
+///vertex to variable mapping
+///initialize the mapping for a given sampled mesh
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC>::
+InitMappingSeam()
+{
+ num_scalar_variables=-1;
+ for (unsigned int i=0;i<V.rows();i++)
+ InitMappingSeam(i);
+
+ for (unsigned int j=0;j<V.rows();j++)
+ assert(HandleV_Integer[j].size()>0);
+}
+
+
+template <typename DerivedV, typename DerivedF, typename VFType, typename DerivedTT, typename DerivedC>
+IGL_INLINE void igl::cut_mesh(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const std::vector<std::vector<VFType> >& VF,
+ const std::vector<std::vector<VFType> >& VFi,
+ const Eigen::PlainObjectBase<DerivedTT>& TT,
+ const Eigen::PlainObjectBase<DerivedTT>& TTi,
+ const std::vector<bool> &V_border,
+ const Eigen::PlainObjectBase<DerivedC> &cuts,
+ Eigen::PlainObjectBase<DerivedV> &Vcut,
+ Eigen::PlainObjectBase<DerivedF> &Fcut)
+{
+ //finding the cuts is done, now we need to actually generate a cut mesh
+ igl::MeshCutterMini<DerivedV, DerivedF, VFType, DerivedTT, DerivedC> mc(V, F, TT, TTi, VF, VFi, V_border, cuts);
+ mc.InitMappingSeam();
+
+ Fcut = mc.HandleS_Index;
+ //we have the faces, we need the vertices;
+ int newNumV = Fcut.maxCoeff()+1;
+ Vcut.setZero(newNumV,3);
+ for (int vi=0; vi<V.rows(); ++vi)
+ for (int i=0; i<mc.HandleV_Integer[vi].size();++i)
+ Vcut.row(mc.HandleV_Integer[vi][i]) = V.row(vi);
+
+ //ugly hack to fix some problematic cases (border vertex that is also on the boundary of the hole
+ for (int fi =0; fi<Fcut.rows(); ++fi)
+ for (int k=0; k<3; ++k)
+ if (Fcut(fi,k)==-1)
+ {
+ //we need to add a vertex
+ Fcut(fi,k) = newNumV;
+ newNumV ++;
+ Vcut.conservativeResize(newNumV, Eigen::NoChange);
+ Vcut.row(newNumV-1) = V.row(F(fi,k));
+ }
+
+
+}
+
+
+//Wrapper of the above with only vertices and faces as mesh input
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::cut_mesh(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedC> &cuts,
+ Eigen::PlainObjectBase<DerivedV> &Vcut,
+ Eigen::PlainObjectBase<DerivedF> &Fcut)
+{
+ std::vector<std::vector<int> > VF, VFi;
+ igl::vertex_triangle_adjacency(V,F,VF,VFi);
+ // Alec: Cast? Why? This is likely to break.
+ Eigen::MatrixXd Vt = V;
+ Eigen::MatrixXi Ft = F;
+ Eigen::MatrixXi TT, TTi;
+ igl::triangle_triangle_adjacency(Ft,TT,TTi);
+ std::vector<bool> V_border = igl::is_border_vertex(V,F);
+ igl::cut_mesh(V, F, VF, VFi, TT, TTi, V_border, cuts, Vcut, Fcut);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/cut_mesh.h b/xs/src/igl/cut_mesh.h
new file mode 100644
index 000000000..e49a3e38b
--- /dev/null
+++ b/xs/src/igl/cut_mesh.h
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CUT_MESH
+#define IGL_CUT_MESH
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Given a mesh and a list of edges that are to be cut, the function
+ // generates a new disk-topology mesh that has the cuts at its boundary.
+ //
+ // Todo: this combinatorial operation should not depend on the vertex
+ // positions V.
+ //
+ // Known issues: Assumes mesh is edge-manifold.
+ //
+ // Inputs:
+ // V #V by 3 list of the vertex positions
+ // F #F by 3 list of the faces (must be triangles)
+ // VF #V list of lists of incident faces (adjacency list), e.g. as
+ // returned by igl::vertex_triangle_adjacency
+ // VFi #V list of lists of index of incidence within incident faces listed
+ // in VF, e.g. as returned by igl::vertex_triangle_adjacency
+ // TT #F by 3 triangle to triangle adjacent matrix (e.g. computed via
+ // igl:triangle_triangle_adjacency)
+ // TTi #F by 3 adjacent matrix, the element i,j is the id of edge of the
+ // triangle TT(i,j) that is adjacent with triangle i (e.g. computed via
+ // igl:triangle_triangle_adjacency)
+ // V_border #V by 1 list of booleans, indicating if the corresponging
+ // vertex is at the mesh boundary, e.g. as returned by
+ // igl::is_border_vertex
+ // cuts #F by 3 list of boolean flags, indicating the edges that need to
+ // be cut (has 1 at the face edges that are to be cut, 0 otherwise)
+ // Outputs:
+ // Vcut #V by 3 list of the vertex positions of the cut mesh. This matrix
+ // will be similar to the original vertices except some rows will be
+ // duplicated.
+ // Fcut #F by 3 list of the faces of the cut mesh(must be triangles). This
+ // matrix will be similar to the original face matrix except some indices
+ // will be redirected to point to the newly duplicated vertices.
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename VFType,
+ typename DerivedTT,
+ typename DerivedC>
+ IGL_INLINE void cut_mesh(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const std::vector<std::vector<VFType> >& VF,
+ const std::vector<std::vector<VFType> >& VFi,
+ const Eigen::PlainObjectBase<DerivedTT>& TT,
+ const Eigen::PlainObjectBase<DerivedTT>& TTi,
+ const std::vector<bool> &V_border,
+ const Eigen::PlainObjectBase<DerivedC> &cuts,
+ Eigen::PlainObjectBase<DerivedV> &Vcut,
+ Eigen::PlainObjectBase<DerivedF> &Fcut);
+ //Wrapper of the above with only vertices and faces as mesh input
+ template <typename DerivedV, typename DerivedF, typename DerivedC>
+ IGL_INLINE void cut_mesh(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedC> &cuts,
+ Eigen::PlainObjectBase<DerivedV> &Vcut,
+ Eigen::PlainObjectBase<DerivedF> &Fcut);
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "cut_mesh.cpp"
+#endif
+
+
+#endif
diff --git a/xs/src/igl/cut_mesh_from_singularities.cpp b/xs/src/igl/cut_mesh_from_singularities.cpp
new file mode 100644
index 000000000..382f2e063
--- /dev/null
+++ b/xs/src/igl/cut_mesh_from_singularities.cpp
@@ -0,0 +1,205 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "cut_mesh_from_singularities.h"
+
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/edge_topology.h>
+
+#include <vector>
+#include <deque>
+
+
+namespace igl {
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedM,
+ typename DerivedO
+ >
+ class MeshCutter
+ {
+ protected:
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch;
+
+ Eigen::VectorXi F_visited;
+ DerivedF TT;
+ DerivedF TTi;
+
+ Eigen::MatrixXi E, F2E, E2F;
+ protected:
+
+ inline bool IsRotSeam(const int f0,const int edge)
+ {
+ unsigned char MM = Handle_MMatch(f0,edge);
+ return (MM!=0);
+ }
+
+ inline void FloodFill(const int start, Eigen::PlainObjectBase<DerivedO> &Handle_Seams)
+ {
+ std::deque<int> d;
+ ///clean the visited flag
+ F_visited(start) = true;
+ d.push_back(start);
+
+ while (!d.empty())
+ {
+ int f = d.at(0); d.pop_front();
+ for (int s = 0; s<3; s++)
+ {
+ int g = TT(f,s); // f->FFp(s);
+ int j = TTi(f,s); // f->FFi(s);
+
+ if (j == -1)
+ {
+ g = f;
+ j = s;
+ }
+
+ if ((!(IsRotSeam(f,s))) && (!(IsRotSeam(g,j))) && (!F_visited(g)) )
+ {
+ Handle_Seams(f,s)=false;
+ Handle_Seams(g,j)=false;
+ F_visited(g) = true;
+ d.push_back(g);
+ }
+ }
+ }
+ }
+
+ inline void Retract(Eigen::PlainObjectBase<DerivedO> &Handle_Seams)
+ {
+ std::vector<int> e(V.rows(),0); // number of edges per vert
+ // for (unsigned f=0; f<F.rows(); f++)
+ // {
+ // for (int s = 0; s<3; s++)
+ // {
+ // if (Handle_Seams(f,s))
+ // if (TT(f,s)<=f)
+ // {
+ // e[ F(f,s) ] ++;
+ // e[ F(f,(s+1)%3) ] ++;
+ // }
+ // }
+ // }
+ for (int ei=0; ei<E.rows(); ++ei)
+ {
+ //only need one face
+ int f0 = E2F(ei,0);
+ if (f0==-1)
+ f0 = E2F(ei,1);
+ int k=0;
+ for (k=0; k<3; ++k)
+ if (F2E(f0,k)==ei)
+ break;
+ if (Handle_Seams(f0,k))
+ {
+ e[ F(f0,k) ] ++;
+ e[ F(f0,(k+1)%3) ] ++;
+ }
+ }
+
+ bool over=true;
+ int guard = 0;
+ do
+ {
+ over = true;
+ for (int f = 0; f<F.rows(); f++) //if (!f->IsD())
+ {
+ for (int s = 0; s<3; s++)
+ {
+ if (Handle_Seams(f,s))
+ if (!(IsRotSeam(f,s))) // never retract rot seams
+ {
+ if (e[ F(f,s) ] == 1) {
+ // dissolve seam
+ Handle_Seams(f,s)=false;
+ if (TT(f,s) != -1)
+ Handle_Seams(TT(f,s),TTi(f,s))=false;
+
+ e[ F(f,s)] --;
+ e[ F(f,(s+1)%3) ] --;
+ over = false;
+ }
+ }
+ }
+ }
+
+ if (guard++>10000)
+ over = true;
+
+ } while (!over);
+ }
+
+ public:
+
+ inline MeshCutter(const Eigen::PlainObjectBase<DerivedV> &V_,
+ const Eigen::PlainObjectBase<DerivedF> &F_,
+ const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch_):
+ V(V_),
+ F(F_),
+ Handle_MMatch(Handle_MMatch_)
+ {
+ triangle_triangle_adjacency(F,TT,TTi);
+ edge_topology(V,F,E,F2E,E2F);
+ };
+
+ inline void cut(Eigen::PlainObjectBase<DerivedO> &Handle_Seams)
+ {
+ F_visited.setConstant(F.rows(),0);
+ Handle_Seams.setConstant(F.rows(),3,1);
+
+ int index=0;
+ for (unsigned f = 0; f<F.rows(); f++)
+ {
+ if (!F_visited(f))
+ {
+ index++;
+ FloodFill(f, Handle_Seams);
+ }
+ }
+
+ Retract(Handle_Seams);
+
+ for (unsigned int f=0;f<F.rows();f++)
+ for (int j=0;j<3;j++)
+ if (IsRotSeam(f,j))
+ Handle_Seams(f,j)=true;
+
+ }
+
+
+
+
+ };
+}
+template <typename DerivedV,
+ typename DerivedF,
+ typename DerivedM,
+ typename DerivedO>
+IGL_INLINE void igl::cut_mesh_from_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch,
+ Eigen::PlainObjectBase<DerivedO> &Handle_Seams)
+{
+ igl::MeshCutter< DerivedV, DerivedF, DerivedM, DerivedO> mc(V, F, Handle_MMatch);
+ mc.cut(Handle_Seams);
+
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::cut_mesh_from_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/cut_mesh_from_singularities.h b/xs/src/igl/cut_mesh_from_singularities.h
new file mode 100644
index 000000000..13b6a98c4
--- /dev/null
+++ b/xs/src/igl/cut_mesh_from_singularities.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_CUT_MESH_FROM_SINGULARITIES_H
+#define IGL_CUT_MESH_FROM_SINGULARITIES_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Given a mesh (V,F) and the integer mismatch of a cross field per edge
+ // (MMatch), finds the cut_graph connecting the singularities (seams) and the
+ // degree of the singularities singularity_index
+ //
+ // Input:
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of faces
+ // MMatch #F by 3 list of per corner integer mismatch
+ // Outputs:
+ // seams #F by 3 list of per corner booleans that denotes if an edge is a
+ // seam or not
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedM,
+ typename DerivedO>
+ IGL_INLINE void cut_mesh_from_singularities(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedM> &MMatch,
+ Eigen::PlainObjectBase<DerivedO> &seams);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "cut_mesh_from_singularities.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/cylinder.cpp b/xs/src/igl/cylinder.cpp
new file mode 100644
index 000000000..ab0fd4d3d
--- /dev/null
+++ b/xs/src/igl/cylinder.cpp
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "cylinder.h"
+#include "PI.h"
+#include <cassert>
+#include <cmath>
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::cylinder(
+ const int axis_devisions,
+ const int height_devisions,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F)
+{
+ V.resize(axis_devisions*height_devisions,3);
+ F.resize(2*(axis_devisions*(height_devisions-1)),3);
+ int f = 0;
+ typedef typename DerivedV::Scalar Scalar;
+ for(int th = 0;th<axis_devisions;th++)
+ {
+ Scalar x = cos(2.*igl::PI*Scalar(th)/Scalar(axis_devisions));
+ Scalar y = sin(2.*igl::PI*Scalar(th)/Scalar(axis_devisions));
+ for(int h = 0;h<height_devisions;h++)
+ {
+ Scalar z = Scalar(h)/Scalar(height_devisions-1);
+ V(th+h*axis_devisions,0) = x;
+ V(th+h*axis_devisions,1) = y;
+ V(th+h*axis_devisions,2) = z;
+ if(h > 0)
+ {
+ F(f,0) = ((th+0)%axis_devisions)+(h-1)*axis_devisions;
+ F(f,1) = ((th+1)%axis_devisions)+(h-1)*axis_devisions;
+ F(f,2) = ((th+0)%axis_devisions)+(h+0)*axis_devisions;
+ f++;
+ F(f,0) = ((th+1)%axis_devisions)+(h-1)*axis_devisions;
+ F(f,1) = ((th+1)%axis_devisions)+(h+0)*axis_devisions;
+ F(f,2) = ((th+0)%axis_devisions)+(h+0)*axis_devisions;
+ f++;
+ }
+ }
+ }
+ assert(f == F.rows());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::cylinder<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/cylinder.h b/xs/src/igl/cylinder.h
new file mode 100644
index 000000000..4c5ab7e22
--- /dev/null
+++ b/xs/src/igl/cylinder.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_CYLINDER_H
+#define IGL_CYLINDER_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Construct a triangle mesh of a cylinder (without caps)
+ //
+ // Inputs:
+ // axis_devisions number of vertices _around the cylinder_
+ // height_devisions number of vertices _up the cylinder_
+ // Outputs:
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of triangle indices into V
+ //
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void cylinder(
+ const int axis_devisions,
+ const int height_devisions,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "cylinder.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/dated_copy.cpp b/xs/src/igl/dated_copy.cpp
new file mode 100644
index 000000000..735de6fc4
--- /dev/null
+++ b/xs/src/igl/dated_copy.cpp
@@ -0,0 +1,91 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "dated_copy.h"
+#include "dirname.h"
+#include "basename.h"
+
+#include <ctime>
+#include <fstream>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <iostream>
+
+#if !defined(_WIN32)
+#include <unistd.h>
+
+IGL_INLINE bool igl::dated_copy(const std::string & src_path, const std::string & dir)
+{
+ using namespace std;
+ // Get time and date as string
+ char buffer[80];
+ time_t rawtime;
+ struct tm * timeinfo;
+ time (&rawtime);
+ timeinfo = localtime (&rawtime);
+ // ISO 8601 format with hyphens instead of colons and no timezone offset
+ strftime (buffer,80,"%Y-%m-%dT%H-%M-%S",timeinfo);
+ string src_basename = basename(src_path);
+ string dst_basename = src_basename+"-"+buffer;
+ string dst_path = dir+"/"+dst_basename;
+ cerr<<"Saving binary to "<<dst_path;
+ {
+ // http://stackoverflow.com/a/10195497/148668
+ ifstream src(src_path,ios::binary);
+ if (!src.is_open())
+ {
+ cerr<<" failed."<<endl;
+ return false;
+ }
+ ofstream dst(dst_path,ios::binary);
+ if(!dst.is_open())
+ {
+ cerr<<" failed."<<endl;
+ return false;
+ }
+ dst << src.rdbuf();
+ }
+ cerr<<" succeeded."<<endl;
+ cerr<<"Setting permissions of "<<dst_path;
+ {
+ int src_posix = fileno(fopen(src_path.c_str(),"r"));
+ if(src_posix == -1)
+ {
+ cerr<<" failed."<<endl;
+ return false;
+ }
+ struct stat fst;
+ fstat(src_posix,&fst);
+ int dst_posix = fileno(fopen(dst_path.c_str(),"r"));
+ if(dst_posix == -1)
+ {
+ cerr<<" failed."<<endl;
+ return false;
+ }
+ //update to the same uid/gid
+ if(fchown(dst_posix,fst.st_uid,fst.st_gid))
+ {
+ cerr<<" failed."<<endl;
+ return false;
+ }
+ //update the permissions
+ if(fchmod(dst_posix,fst.st_mode) == -1)
+ {
+ cerr<<" failed."<<endl;
+ return false;
+ }
+ cerr<<" succeeded."<<endl;
+ }
+ return true;
+}
+
+IGL_INLINE bool igl::dated_copy(const std::string & src_path)
+{
+ return dated_copy(src_path,dirname(src_path));
+}
+
+#endif
diff --git a/xs/src/igl/dated_copy.h b/xs/src/igl/dated_copy.h
new file mode 100644
index 000000000..9fd9fd3c8
--- /dev/null
+++ b/xs/src/igl/dated_copy.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+// Known issues: This function does not work under windows
+
+#ifndef IGL_DATED_COPY_H
+#define IGL_DATED_COPY_H
+#include "igl_inline.h"
+#include <string>
+namespace igl
+{
+ // Copy the given file to a new file with the same basename in `dir`
+ // directory with the current date and time as a suffix.
+ //
+ // Inputs:
+ // src_path path to source file
+ // dir directory of destination file
+ // Example:
+ // dated_copy("/path/to/foo","/bar/");
+ // // copies /path/to/foo to /bar/foo-2013-12-12T18-10-56
+ IGL_INLINE bool dated_copy(const std::string & src_path, const std::string & dir);
+ // Wrapper using directory of source file
+ IGL_INLINE bool dated_copy(const std::string & src_path);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "dated_copy.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/decimate.cpp b/xs/src/igl/decimate.cpp
new file mode 100644
index 000000000..a531db2c5
--- /dev/null
+++ b/xs/src/igl/decimate.cpp
@@ -0,0 +1,366 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "decimate.h"
+#include "collapse_edge.h"
+#include "edge_flaps.h"
+#include "is_edge_manifold.h"
+#include "remove_unreferenced.h"
+#include "slice_mask.h"
+#include "slice.h"
+#include "connect_boundary_to_infinity.h"
+#include "max_faces_stopping_condition.h"
+#include "shortest_edge_and_midpoint.h"
+
+IGL_INLINE bool igl::decimate(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I)
+{
+ // Original number of faces
+ const int orig_m = F.rows();
+ // Tracking number of faces
+ int m = F.rows();
+ typedef Eigen::MatrixXd DerivedV;
+ typedef Eigen::MatrixXi DerivedF;
+ DerivedV VO;
+ DerivedF FO;
+ igl::connect_boundary_to_infinity(V,F,VO,FO);
+ // decimate will not work correctly on non-edge-manifold meshes. By extension
+ // this includes meshes with non-manifold vertices on the boundary since these
+ // will create a non-manifold edge when connected to infinity.
+ if(!is_edge_manifold(FO))
+ {
+ return false;
+ }
+ bool ret = decimate(
+ VO,
+ FO,
+ shortest_edge_and_midpoint,
+ max_faces_stopping_condition(m,orig_m,max_m),
+ U,
+ G,
+ J,
+ I);
+ const Eigen::Array<bool,Eigen::Dynamic,1> keep = (J.array()<orig_m);
+ igl::slice_mask(Eigen::MatrixXi(G),keep,1,G);
+ igl::slice_mask(Eigen::VectorXi(J),keep,1,J);
+ Eigen::VectorXi _1,I2;
+ igl::remove_unreferenced(Eigen::MatrixXd(U),Eigen::MatrixXi(G),U,G,_1,I2);
+ igl::slice(Eigen::VectorXi(I),I2,1,I);
+ return ret;
+}
+
+IGL_INLINE bool igl::decimate(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J)
+{
+ Eigen::VectorXi I;
+ return igl::decimate(V,F,max_m,U,G,J,I);
+}
+
+IGL_INLINE bool igl::decimate(
+ const Eigen::MatrixXd & OV,
+ const Eigen::MatrixXi & OF,
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> & stopping_condition,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I
+ )
+{
+ const auto always_try = [](
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ ) -> bool { return true;};
+ const auto never_care = [](
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )-> void { };
+ return igl::decimate(
+ OV,OF,cost_and_placement,stopping_condition,always_try,never_care,U,G,J,I);
+}
+
+IGL_INLINE bool igl::decimate(
+ const Eigen::MatrixXd & OV,
+ const Eigen::MatrixXi & OF,
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> & stopping_condition,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I
+ )
+{
+ using namespace Eigen;
+ using namespace std;
+ VectorXi EMAP;
+ MatrixXi E,EF,EI;
+ edge_flaps(OF,E,EMAP,EF,EI);
+ return igl::decimate(
+ OV,OF,
+ cost_and_placement,stopping_condition,pre_collapse,post_collapse,
+ E,EMAP,EF,EI,
+ U,G,J,I);
+}
+
+
+IGL_INLINE bool igl::decimate(
+ const Eigen::MatrixXd & OV,
+ const Eigen::MatrixXi & OF,
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> & stopping_condition,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ const Eigen::MatrixXi & OE,
+ const Eigen::VectorXi & OEMAP,
+ const Eigen::MatrixXi & OEF,
+ const Eigen::MatrixXi & OEI,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I
+ )
+{
+
+ // Decimate 1
+ using namespace Eigen;
+ using namespace std;
+ // Working copies
+ Eigen::MatrixXd V = OV;
+ Eigen::MatrixXi F = OF;
+ Eigen::MatrixXi E = OE;
+ Eigen::VectorXi EMAP = OEMAP;
+ Eigen::MatrixXi EF = OEF;
+ Eigen::MatrixXi EI = OEI;
+ typedef std::set<std::pair<double,int> > PriorityQueue;
+ PriorityQueue Q;
+ std::vector<PriorityQueue::iterator > Qit;
+ Qit.resize(E.rows());
+ // If an edge were collapsed, we'd collapse it to these points:
+ MatrixXd C(E.rows(),V.cols());
+ for(int e = 0;e<E.rows();e++)
+ {
+ double cost = e;
+ RowVectorXd p(1,3);
+ cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
+ C.row(e) = p;
+ Qit[e] = Q.insert(std::pair<double,int>(cost,e)).first;
+ }
+ int prev_e = -1;
+ bool clean_finish = false;
+
+ while(true)
+ {
+ if(Q.empty())
+ {
+ break;
+ }
+ if(Q.begin()->first == std::numeric_limits<double>::infinity())
+ {
+ // min cost edge is infinite cost
+ break;
+ }
+ int e,e1,e2,f1,f2;
+ if(collapse_edge(
+ cost_and_placement, pre_collapse, post_collapse,
+ V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
+ {
+ if(stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2))
+ {
+ clean_finish = true;
+ break;
+ }
+ }else
+ {
+ if(prev_e == e)
+ {
+ assert(false && "Edge collapse no progress... bad stopping condition?");
+ break;
+ }
+ // Edge was not collapsed... must have been invalid. collapse_edge should
+ // have updated its cost to inf... continue
+ }
+ prev_e = e;
+ }
+ // remove all IGL_COLLAPSE_EDGE_NULL faces
+ MatrixXi F2(F.rows(),3);
+ J.resize(F.rows());
+ int m = 0;
+ for(int f = 0;f<F.rows();f++)
+ {
+ if(
+ F(f,0) != IGL_COLLAPSE_EDGE_NULL ||
+ F(f,1) != IGL_COLLAPSE_EDGE_NULL ||
+ F(f,2) != IGL_COLLAPSE_EDGE_NULL)
+ {
+ F2.row(m) = F.row(f);
+ J(m) = f;
+ m++;
+ }
+ }
+ F2.conservativeResize(m,F2.cols());
+ J.conservativeResize(m);
+ VectorXi _1;
+ remove_unreferenced(V,F2,U,G,_1,I);
+ return clean_finish;
+}
diff --git a/xs/src/igl/decimate.h b/xs/src/igl/decimate.h
new file mode 100644
index 000000000..bdb19e81b
--- /dev/null
+++ b/xs/src/igl/decimate.h
@@ -0,0 +1,255 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DECIMATE_H
+#define IGL_DECIMATE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include <set>
+namespace igl
+{
+ // Assumes (V,F) is a manifold mesh (possibly with boundary) Collapses edges
+ // until desired number of faces is achieved. This uses default edge cost and
+ // merged vertex placement functions {edge length, edge midpoint}.
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // F #F by 3 list of face indices into V.
+ // max_m desired number of output faces
+ // Outputs:
+ // U #U by dim list of output vertex posistions (can be same ref as V)
+ // G #G by 3 list of output face indices into U (can be same ref as G)
+ // J #G list of indices into F of birth face
+ // I #U list of indices into V of birth vertices
+ // Returns true if m was reached (otherwise #G > m)
+ IGL_INLINE bool decimate(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I);
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // F #F by 3 list of face indices into V.
+ // max_m desired number of output faces
+ // Outputs:
+ // U #U by dim list of output vertex posistions (can be same ref as V)
+ // G #G by 3 list of output face indices into U (can be same ref as G)
+ // J #G list of indices into F of birth face
+ // Returns true if m was reached (otherwise #G > m)
+ IGL_INLINE bool decimate(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J);
+ // Assumes a **closed** manifold mesh. See igl::connect_boundary_to_infinity
+ // and igl::decimate in decimate.cpp
+ // is handling meshes with boundary by connecting all boundary edges with
+ // dummy facets to infinity **and** modifying the stopping criteria.
+ //
+ // Inputs:
+ // 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);
+ // stopping_condition function returning whether to stop collapsing edges
+ // based on current state. Guaranteed to be called after _successfully_
+ // collapsing edge e removing edges (e,e1,e2) and faces (f1,f2):
+ // bool should_stop =
+ // stopping_condition(V,F,E,EMAP,EF,EI,Q,Qit,C,e,e1,e2,f1,f2);
+ IGL_INLINE bool decimate(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<void(
+ const int /*e*/,
+ const Eigen::MatrixXd &/*V*/,
+ const Eigen::MatrixXi &/*F*/,
+ const Eigen::MatrixXi &/*E*/,
+ const Eigen::VectorXi &/*EMAP*/,
+ const Eigen::MatrixXi &/*EF*/,
+ const Eigen::MatrixXi &/*EI*/,
+ double & /*cost*/,
+ Eigen::RowVectorXd & /*p*/
+ )> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int ,/*e*/
+ const int ,/*e1*/
+ const int ,/*e2*/
+ const int ,/*f1*/
+ const int /*f2*/
+ )> & stopping_condition,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I);
+
+ // Inputs:
+ // pre_collapse callback called with index of edge whose collapse is about
+ // to be attempted (see collapse_edge)
+ // post_collapse callback called with index of edge whose collapse was
+ // just attempted and a flag revealing whether this was successful (see
+ // collapse_edge)
+ IGL_INLINE bool decimate(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<void(
+ const int /*e*/,
+ const Eigen::MatrixXd &/*V*/,
+ const Eigen::MatrixXi &/*F*/,
+ const Eigen::MatrixXi &/*E*/,
+ const Eigen::VectorXi &/*EMAP*/,
+ const Eigen::MatrixXi &/*EF*/,
+ const Eigen::MatrixXi &/*EI*/,
+ double & /*cost*/,
+ Eigen::RowVectorXd & /*p*/
+ )> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int ,/*e*/
+ const int ,/*e1*/
+ const int ,/*e2*/
+ const int ,/*f1*/
+ const int /*f2*/
+ )> & stopping_condition,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I);
+
+ // Inputs:
+ // EMAP #F*3 list of indices into E, mapping each directed edge to unique
+ // unique edge in E
+ // 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).
+
+ IGL_INLINE bool decimate(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<void(
+ const int /*e*/,
+ const Eigen::MatrixXd &/*V*/,
+ const Eigen::MatrixXi &/*F*/,
+ const Eigen::MatrixXi &/*E*/,
+ const Eigen::VectorXi &/*EMAP*/,
+ const Eigen::MatrixXi &/*EF*/,
+ const Eigen::MatrixXi &/*EI*/,
+ double & /*cost*/,
+ Eigen::RowVectorXd & /*p*/
+ )> & cost_and_placement,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int ,/*e*/
+ const int ,/*e1*/
+ const int ,/*e2*/
+ const int ,/*f1*/
+ const int /*f2*/
+ )> & stopping_condition,
+ const std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ const std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "decimate.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/deform_skeleton.cpp b/xs/src/igl/deform_skeleton.cpp
new file mode 100644
index 000000000..b9d120edd
--- /dev/null
+++ b/xs/src/igl/deform_skeleton.cpp
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "deform_skeleton.h"
+void igl::deform_skeleton(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const std::vector<
+ Eigen::Affine3d,Eigen::aligned_allocator<Eigen::Affine3d> > & vA,
+ Eigen::MatrixXd & CT,
+ Eigen::MatrixXi & BET)
+{
+ using namespace Eigen;
+ assert(BE.rows() == (int)vA.size());
+ CT.resize(2*BE.rows(),C.cols());
+ BET.resize(BE.rows(),2);
+ for(int e = 0;e<BE.rows();e++)
+ {
+ BET(e,0) = 2*e;
+ BET(e,1) = 2*e+1;
+ Affine3d a = vA[e];
+ Vector3d c0 = C.row(BE(e,0));
+ Vector3d c1 = C.row(BE(e,1));
+ CT.row(2*e) = a * c0;
+ CT.row(2*e+1) = a * c1;
+ }
+
+}
+
+IGL_INLINE void igl::deform_skeleton(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXd & T,
+ Eigen::MatrixXd & CT,
+ Eigen::MatrixXi & BET)
+{
+ using namespace Eigen;
+ //assert(BE.rows() == (int)vA.size());
+ CT.resize(2*BE.rows(),C.cols());
+ BET.resize(BE.rows(),2);
+ for(int e = 0;e<BE.rows();e++)
+ {
+ BET(e,0) = 2*e;
+ BET(e,1) = 2*e+1;
+ Matrix4d t;
+ t << T.block(e*4,0,4,3).transpose(), 0,0,0,0;
+ Affine3d a;
+ a.matrix() = t;
+ Vector3d c0 = C.row(BE(e,0));
+ Vector3d c1 = C.row(BE(e,1));
+ CT.row(2*e) = a * c0;
+ CT.row(2*e+1) = a * c1;
+ }
+}
diff --git a/xs/src/igl/deform_skeleton.h b/xs/src/igl/deform_skeleton.h
new file mode 100644
index 000000000..340107b2f
--- /dev/null
+++ b/xs/src/igl/deform_skeleton.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DEFORM_SKELETON_H
+#define IGL_DEFORM_SKELETON_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#include <vector>
+namespace igl
+{
+ // Deform a skeleton.
+ //
+ // Inputs:
+ // C #C by 3 list of joint positions
+ // BE #BE by 2 list of bone edge indices
+ // vA #BE list of bone transformations
+ // Outputs
+ // CT #BE*2 by 3 list of deformed joint positions
+ // BET #BE by 2 list of bone edge indices (maintains order)
+ //
+ IGL_INLINE void deform_skeleton(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const std::vector<
+ Eigen::Affine3d,Eigen::aligned_allocator<Eigen::Affine3d> > & vA,
+ Eigen::MatrixXd & CT,
+ Eigen::MatrixXi & BET);
+ // Inputs:
+ // T #BE*4 by 3 list of stacked transformation matrix
+ IGL_INLINE void deform_skeleton(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXd & T,
+ Eigen::MatrixXd & CT,
+ Eigen::MatrixXi & BET);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "deform_skeleton.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/delaunay_triangulation.cpp b/xs/src/igl/delaunay_triangulation.cpp
new file mode 100644
index 000000000..01669966b
--- /dev/null
+++ b/xs/src/igl/delaunay_triangulation.cpp
@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "delaunay_triangulation.h"
+#include "flip_edge.h"
+#include "lexicographic_triangulation.h"
+#include "unique_edge_map.h"
+
+#include <vector>
+#include <sstream>
+
+template<
+ typename DerivedV,
+ typename Orient2D,
+ typename InCircle,
+ typename DerivedF>
+IGL_INLINE void igl::delaunay_triangulation(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ Orient2D orient2D,
+ InCircle incircle,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ assert(V.cols() == 2);
+ typedef typename DerivedF::Scalar Index;
+ typedef typename DerivedV::Scalar Scalar;
+ igl::lexicographic_triangulation(V, orient2D, F);
+ const size_t num_faces = F.rows();
+ if (num_faces == 0) {
+ // Input points are degenerate. No faces will be generated.
+ return;
+ }
+ assert(F.cols() == 3);
+
+ Eigen::MatrixXi E;
+ Eigen::MatrixXi uE;
+ Eigen::VectorXi EMAP;
+ std::vector<std::vector<Index> > uE2E;
+ igl::unique_edge_map(F, E, uE, EMAP, uE2E);
+
+ auto is_delaunay = [&V,&F,&uE2E,num_faces,&incircle](size_t uei) {
+ auto& half_edges = uE2E[uei];
+ if (half_edges.size() != 2) {
+ throw "Cannot flip non-manifold or boundary edge";
+ }
+
+ const size_t f1 = half_edges[0] % num_faces;
+ const size_t f2 = half_edges[1] % num_faces;
+ const size_t c1 = half_edges[0] / num_faces;
+ const size_t c2 = half_edges[1] / num_faces;
+ assert(c1 < 3);
+ assert(c2 < 3);
+ assert(f1 != f2);
+ const size_t v1 = F(f1, (c1+1)%3);
+ const size_t v2 = F(f1, (c1+2)%3);
+ const size_t v4 = F(f1, c1);
+ const size_t v3 = F(f2, c2);
+ const Scalar p1[] = {V(v1, 0), V(v1, 1)};
+ const Scalar p2[] = {V(v2, 0), V(v2, 1)};
+ const Scalar p3[] = {V(v3, 0), V(v3, 1)};
+ const Scalar p4[] = {V(v4, 0), V(v4, 1)};
+ auto orientation = incircle(p1, p2, p4, p3);
+ return orientation <= 0;
+ };
+
+ bool all_delaunay = false;
+ while(!all_delaunay) {
+ all_delaunay = true;
+ for (size_t i=0; i<uE2E.size(); i++) {
+ if (uE2E[i].size() == 2) {
+ if (!is_delaunay(i)) {
+ all_delaunay = false;
+ flip_edge(F, E, uE, EMAP, uE2E, i);
+ }
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::delaunay_triangulation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, short (*)(double const*, double const*, double const*), short (*)(double const*, double const*, double const*, double const*), Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif \ No newline at end of file
diff --git a/xs/src/igl/delaunay_triangulation.h b/xs/src/igl/delaunay_triangulation.h
new file mode 100644
index 000000000..daeec9fad
--- /dev/null
+++ b/xs/src/igl/delaunay_triangulation.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_DELAUNAY_TRIANGULATION_H
+#define IGL_DELAUNAY_TRIANGULATION_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Given a set of points in 2D, return a Delaunay triangulation of these
+ // points.
+ //
+ // Inputs:
+ // V #V by 2 list of vertex positions
+ // orient2D A functor such that orient2D(pa, pb, pc) returns
+ // 1 if pa,pb,pc forms a conterclockwise triangle.
+ // -1 if pa,pb,pc forms a clockwise triangle.
+ // 0 if pa,pb,pc are collinear.
+ // where the argument pa,pb,pc are of type Scalar[2].
+ // incircle A functor such that incircle(pa, pb, pc, pd) returns
+ // 1 if pd is on the positive size of circumcirle of (pa,pb,pc)
+ // -1 if pd is on the positive size of circumcirle of (pa,pb,pc)
+ // 0 if pd is cocircular with pa, pb, pc.
+ // Outputs:
+ // F #F by 3 of faces in Delaunay triangulation.
+ template<
+ typename DerivedV,
+ typename Orient2D,
+ typename InCircle,
+ typename DerivedF
+ >
+ IGL_INLINE void delaunay_triangulation(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ Orient2D orient2D,
+ InCircle incircle,
+ Eigen::PlainObjectBase<DerivedF>& F);
+}
+
+
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "delaunay_triangulation.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/deprecated.h b/xs/src/igl/deprecated.h
new file mode 100644
index 000000000..52c72ba79
--- /dev/null
+++ b/xs/src/igl/deprecated.h
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DEPRECATED_H
+#define IGL_DEPRECATED_H
+// Macro for marking a function as deprecated.
+//
+// http://stackoverflow.com/a/295229/148668
+#ifdef __GNUC__
+#define IGL_DEPRECATED(func) func __attribute__ ((deprecated))
+#elif defined(_MSC_VER)
+#define IGL_DEPRECATED(func) __declspec(deprecated) func
+#else
+#pragma message("WARNING: You need to implement IGL_DEPRECATED for this compiler")
+#define IGL_DEPRECATED(func) func
+#endif
+// Usage:
+//
+// template <typename T> IGL_INLINE void my_func(Arg1 a);
+//
+// becomes
+//
+// template <typename T> IGL_INLINE IGL_DEPRECATED(void my_func(Arg1 a));
+#endif
diff --git a/xs/src/igl/dfs.cpp b/xs/src/igl/dfs.cpp
new file mode 100644
index 000000000..627fbc26d
--- /dev/null
+++ b/xs/src/igl/dfs.cpp
@@ -0,0 +1,60 @@
+#include "dfs.h"
+#include "list_to_matrix.h"
+#include <vector>
+
+template <
+ typename AType,
+ typename DerivedD,
+ typename DerivedP,
+ typename DerivedC>
+IGL_INLINE void igl::dfs(
+ const std::vector<std::vector<AType> > & A,
+ const size_t s,
+ Eigen::PlainObjectBase<DerivedD> & D,
+ Eigen::PlainObjectBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ std::vector<typename DerivedD::Scalar> vD;
+ std::vector<typename DerivedP::Scalar> vP;
+ std::vector<typename DerivedC::Scalar> vC;
+ dfs(A,s,vD,vP,vC);
+ list_to_matrix(vD,D);
+ list_to_matrix(vP,P);
+ list_to_matrix(vC,C);
+}
+
+template <
+ typename AType,
+ typename DType,
+ typename PType,
+ typename CType>
+IGL_INLINE void igl::dfs(
+ const std::vector<std::vector<AType> > & A,
+ const size_t s,
+ std::vector<DType> & D,
+ std::vector<PType> & P,
+ std::vector<CType> & C)
+{
+ // number of nodes
+ int N = s+1;
+ for(const auto & Ai : A) for(const auto & a : Ai) N = std::max(N,a+1);
+ std::vector<bool> seen(N,false);
+ P.resize(N,-1);
+ std::function<void(const size_t, const size_t)> dfs_helper;
+ dfs_helper = [&D,&P,&C,&dfs_helper,&seen,&A](const size_t s, const size_t p)
+ {
+ if(seen[s]) return;
+ seen[s] = true;
+ D.push_back(s);
+ P[s] = p;
+ for(const auto n : A[s]) dfs_helper(n,s);
+ C.push_back(s);
+ };
+ dfs_helper(s,-1);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::dfs<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, const size_t, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/dfs.h b/xs/src/igl/dfs.h
new file mode 100644
index 000000000..5f3bf2ce6
--- /dev/null
+++ b/xs/src/igl/dfs.h
@@ -0,0 +1,49 @@
+#ifndef IGL_DFS_H
+#define IGL_DFS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ // Traverse a **directed** graph represented by an adjacency list using
+ // depth first search
+ //
+ // Inputs:
+ // A #V list of adjacency lists
+ // 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.
+ // C #V list of indices into rows of A in order that nodes are "closed"
+ // (all descendants have been discovered)
+ template <
+ typename AType,
+ typename DerivedD,
+ typename DerivedP,
+ typename DerivedC>
+ IGL_INLINE void dfs(
+ const std::vector<std::vector<AType> > & A,
+ const size_t s,
+ Eigen::PlainObjectBase<DerivedD> & D,
+ Eigen::PlainObjectBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ template <
+ typename AType,
+ typename DType,
+ typename PType,
+ typename CType>
+ IGL_INLINE void dfs(
+ const std::vector<std::vector<AType> > & A,
+ const size_t s,
+ std::vector<DType> & D,
+ std::vector<PType> & P,
+ std::vector<CType> & C);
+
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "dfs.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/diag.cpp b/xs/src/igl/diag.cpp
new file mode 100644
index 000000000..d29382695
--- /dev/null
+++ b/xs/src/igl/diag.cpp
@@ -0,0 +1,108 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "diag.h"
+
+#include "verbose.h"
+
+// Bug in unsupported/Eigen/SparseExtra needs iostream first
+#include <iostream>
+#include <unsupported/Eigen/SparseExtra>
+
+template <typename T>
+IGL_INLINE void igl::diag(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::SparseVector<T>& V)
+{
+ assert(false && "Just call X.diagonal().sparseView() directly");
+ V = X.diagonal().sparseView();
+ //// Get size of input
+ //int m = X.rows();
+ //int n = X.cols();
+ //V = Eigen::SparseVector<T>((m>n?n:m));
+ //V.reserve(V.size());
+
+ //// Iterate over outside
+ //for(int k=0; k<X.outerSize(); ++k)
+ //{
+ // // Iterate over inside
+ // for(typename Eigen::SparseMatrix<T>::InnerIterator it (X,k); it; ++it)
+ // {
+ // if(it.col() == it.row())
+ // {
+ // V.coeffRef(it.col()) += it.value();
+ // }
+ // }
+ //}
+}
+
+template <typename T,typename DerivedV>
+IGL_INLINE void igl::diag(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::MatrixBase<DerivedV> & V)
+{
+ assert(false && "Just call X.diagonal() directly");
+ V = X.diagonal();
+ //// Get size of input
+ //int m = X.rows();
+ //int n = X.cols();
+ //V.derived().resize((m>n?n:m),1);
+
+ //// Iterate over outside
+ //for(int k=0; k<X.outerSize(); ++k)
+ //{
+ // // Iterate over inside
+ // for(typename Eigen::SparseMatrix<T>::InnerIterator it (X,k); it; ++it)
+ // {
+ // if(it.col() == it.row())
+ // {
+ // V(it.col()) = it.value();
+ // }
+ // }
+ //}
+}
+
+template <typename T>
+IGL_INLINE void igl::diag(
+ const Eigen::SparseVector<T>& V,
+ Eigen::SparseMatrix<T>& X)
+{
+ // clear and resize output
+ Eigen::DynamicSparseMatrix<T, Eigen::RowMajor> dyn_X(V.size(),V.size());
+ dyn_X.reserve(V.size());
+ // loop over non-zeros
+ for(typename Eigen::SparseVector<T>::InnerIterator it(V); it; ++it)
+ {
+ dyn_X.coeffRef(it.index(),it.index()) += it.value();
+ }
+ X = Eigen::SparseMatrix<T>(dyn_X);
+}
+
+template <typename T, typename DerivedV>
+IGL_INLINE void igl::diag(
+ const Eigen::MatrixBase<DerivedV> & V,
+ Eigen::SparseMatrix<T>& X)
+{
+ assert(V.rows() == 1 || V.cols() == 1);
+ // clear and resize output
+ Eigen::DynamicSparseMatrix<T, Eigen::RowMajor> dyn_X(V.size(),V.size());
+ dyn_X.reserve(V.size());
+ // loop over non-zeros
+ for(int i = 0;i<V.size();i++)
+ {
+ dyn_X.coeffRef(i,i) += V[i];
+ }
+ X = Eigen::SparseMatrix<T>(dyn_X);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::diag<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::diag<double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseVector<double, 0, int>&);
+template void igl::diag<double, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::diag<double>(Eigen::SparseVector<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/diag.h b/xs/src/igl/diag.h
new file mode 100644
index 000000000..8001f01b6
--- /dev/null
+++ b/xs/src/igl/diag.h
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DIAG_H
+#define IGL_DIAG_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // http://forum.kde.org/viewtopic.php?f=74&t=117476&p=292388#p292388
+ //
+ // This is superceded by
+ // VectorXd V = X.diagonal() and
+ // SparseVector<double> V = X.diagonal().sparseView()
+ // SparseMatrix<double> X = V.asDiagonal().sparseView()
+ //
+ //
+ // Either extracts the main diagonal of a matrix as a vector OR converts a
+ // vector into a matrix with vector along the main diagonal. Like matlab's
+ // diag function
+
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // X an m by n sparse matrix
+ // Outputs:
+ // V a min(m,n) sparse vector
+ template <typename T>
+ IGL_INLINE void diag(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::SparseVector<T>& V);
+ template <typename T,typename DerivedV>
+ IGL_INLINE void diag(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::MatrixBase<DerivedV>& V);
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // V a m sparse vector
+ // Outputs:
+ // X a m by m sparse matrix
+ template <typename T>
+ IGL_INLINE void diag(
+ const Eigen::SparseVector<T>& V,
+ Eigen::SparseMatrix<T>& X);
+ template <typename T, typename DerivedV>
+ IGL_INLINE void diag(
+ const Eigen::MatrixBase<DerivedV>& V,
+ Eigen::SparseMatrix<T>& X);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "diag.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/dihedral_angles.cpp b/xs/src/igl/dihedral_angles.cpp
new file mode 100644
index 000000000..a04e6f840
--- /dev/null
+++ b/xs/src/igl/dihedral_angles.cpp
@@ -0,0 +1,94 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "dihedral_angles.h"
+#include <cassert>
+
+template <
+ typename DerivedV,
+ typename DerivedT,
+ typename Derivedtheta,
+ typename Derivedcos_theta>
+IGL_INLINE void igl::dihedral_angles(
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<Derivedtheta>& theta,
+ Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
+{
+ using namespace Eigen;
+ assert(T.cols() == 4);
+ Matrix<typename Derivedtheta::Scalar,Dynamic,6> l;
+ edge_lengths(V,T,l);
+ Matrix<typename Derivedtheta::Scalar,Dynamic,4> s;
+ face_areas(l,s);
+ return dihedral_angles_intrinsic(l,s,theta,cos_theta);
+}
+
+template <
+ typename DerivedL,
+ typename DerivedA,
+ typename Derivedtheta,
+ typename Derivedcos_theta>
+IGL_INLINE void igl::dihedral_angles_intrinsic(
+ Eigen::PlainObjectBase<DerivedL>& L,
+ Eigen::PlainObjectBase<DerivedA>& A,
+ Eigen::PlainObjectBase<Derivedtheta>& theta,
+ Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta)
+{
+ using namespace Eigen;
+ const int m = L.rows();
+ assert(m == A.rows());
+ // Law of cosines
+ // http://math.stackexchange.com/a/49340/35376
+ Matrix<typename Derivedtheta::Scalar,Dynamic,6> H_sqr(m,6);
+ H_sqr.col(0) = (1./16.) * (4. * L.col(3).array().square() * L.col(0).array().square() -
+ ((L.col(1).array().square() + L.col(4).array().square()) -
+ (L.col(2).array().square() + L.col(5).array().square())).square());
+ H_sqr.col(1) = (1./16.) * (4. * L.col(4).array().square() * L.col(1).array().square() -
+ ((L.col(2).array().square() + L.col(5).array().square()) -
+ (L.col(3).array().square() + L.col(0).array().square())).square());
+ H_sqr.col(2) = (1./16.) * (4. * L.col(5).array().square() * L.col(2).array().square() -
+ ((L.col(3).array().square() + L.col(0).array().square()) -
+ (L.col(4).array().square() + L.col(1).array().square())).square());
+ H_sqr.col(3) = (1./16.) * (4. * L.col(0).array().square() * L.col(3).array().square() -
+ ((L.col(4).array().square() + L.col(1).array().square()) -
+ (L.col(5).array().square() + L.col(2).array().square())).square());
+ H_sqr.col(4) = (1./16.) * (4. * L.col(1).array().square() * L.col(4).array().square() -
+ ((L.col(5).array().square() + L.col(2).array().square()) -
+ (L.col(0).array().square() + L.col(3).array().square())).square());
+ H_sqr.col(5) = (1./16.) * (4. * L.col(2).array().square() * L.col(5).array().square() -
+ ((L.col(0).array().square() + L.col(3).array().square()) -
+ (L.col(1).array().square() + L.col(4).array().square())).square());
+ cos_theta.resize(m,6);
+ cos_theta.col(0) = (H_sqr.col(0).array() -
+ A.col(1).array().square() - A.col(2).array().square()).array() /
+ (-2.*A.col(1).array() * A.col(2).array());
+ cos_theta.col(1) = (H_sqr.col(1).array() -
+ A.col(2).array().square() - A.col(0).array().square()).array() /
+ (-2.*A.col(2).array() * A.col(0).array());
+ cos_theta.col(2) = (H_sqr.col(2).array() -
+ A.col(0).array().square() - A.col(1).array().square()).array() /
+ (-2.*A.col(0).array() * A.col(1).array());
+ cos_theta.col(3) = (H_sqr.col(3).array() -
+ A.col(3).array().square() - A.col(0).array().square()).array() /
+ (-2.*A.col(3).array() * A.col(0).array());
+ cos_theta.col(4) = (H_sqr.col(4).array() -
+ A.col(3).array().square() - A.col(1).array().square()).array() /
+ (-2.*A.col(3).array() * A.col(1).array());
+ cos_theta.col(5) = (H_sqr.col(5).array() -
+ A.col(3).array().square() - A.col(2).array().square()).array() /
+ (-2.*A.col(3).array() * A.col(2).array());
+
+ theta = cos_theta.array().acos();
+
+ cos_theta.resize(m,6);
+
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::dihedral_angles_intrinsic<Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+#endif
diff --git a/xs/src/igl/dihedral_angles.h b/xs/src/igl/dihedral_angles.h
new file mode 100644
index 000000000..92ac0f862
--- /dev/null
+++ b/xs/src/igl/dihedral_angles.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DIHEDRAL_ANGLES_H
+#define IGL_DIHEDRAL_ANGLES_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // DIHEDRAL_ANGLES Compute dihedral angles for all tets of a given tet mesh
+ // (V,T)
+ //
+ // theta = dihedral_angles(V,T)
+ // theta = dihedral_angles(V,T,'ParameterName',parameter_value,...)
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // T #V by 4 list of tet indices
+ // Outputs:
+ // theta #T by 6 list of dihedral angles (in radians)
+ // cos_theta #T by 6 list of cosine of dihedral angles (in radians)
+ //
+ template <
+ typename DerivedV,
+ typename DerivedT,
+ typename Derivedtheta,
+ typename Derivedcos_theta>
+ IGL_INLINE void dihedral_angles(
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<Derivedtheta>& theta,
+ Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
+ template <
+ typename DerivedL,
+ typename DerivedA,
+ typename Derivedtheta,
+ typename Derivedcos_theta>
+ IGL_INLINE void dihedral_angles_intrinsic(
+ Eigen::PlainObjectBase<DerivedL>& L,
+ Eigen::PlainObjectBase<DerivedA>& A,
+ Eigen::PlainObjectBase<Derivedtheta>& theta,
+ Eigen::PlainObjectBase<Derivedcos_theta>& cos_theta);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "dihedral_angles.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/dijkstra.cpp b/xs/src/igl/dijkstra.cpp
new file mode 100644
index 000000000..ad92f1d7f
--- /dev/null
+++ b/xs/src/igl/dijkstra.cpp
@@ -0,0 +1,71 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include <igl/dijkstra.h>
+
+template <typename IndexType, typename DerivedD, typename DerivedP>
+IGL_INLINE int igl::dijkstra_compute_paths(const IndexType &source,
+ const std::set<IndexType> &targets,
+ const std::vector<std::vector<IndexType> >& VV,
+ Eigen::PlainObjectBase<DerivedD> &min_distance,
+ Eigen::PlainObjectBase<DerivedP> &previous)
+{
+ int numV = VV.size();
+ min_distance.setConstant(numV, 1, std::numeric_limits<typename DerivedD::Scalar>::infinity());
+ min_distance[source] = 0;
+ previous.setConstant(numV, 1, -1);
+ std::set<std::pair<typename DerivedD::Scalar, IndexType> > vertex_queue;
+ vertex_queue.insert(std::make_pair(min_distance[source], source));
+
+ while (!vertex_queue.empty())
+ {
+ typename DerivedD::Scalar dist = vertex_queue.begin()->first;
+ IndexType u = vertex_queue.begin()->second;
+ vertex_queue.erase(vertex_queue.begin());
+
+ if (targets.find(u)!= targets.end())
+ return u;
+
+ // Visit each edge exiting u
+ const std::vector<int> &neighbors = VV[u];
+ for (std::vector<int>::const_iterator neighbor_iter = neighbors.begin();
+ neighbor_iter != neighbors.end();
+ neighbor_iter++)
+ {
+ IndexType v = *neighbor_iter;
+ typename DerivedD::Scalar distance_through_u = dist + 1.;
+ if (distance_through_u < min_distance[v]) {
+ vertex_queue.erase(std::make_pair(min_distance[v], v));
+
+ min_distance[v] = distance_through_u;
+ previous[v] = u;
+ vertex_queue.insert(std::make_pair(min_distance[v], v));
+
+ }
+
+ }
+ }
+ //we should never get here
+ return -1;
+}
+
+template <typename IndexType, typename DerivedP>
+IGL_INLINE void igl::dijkstra_get_shortest_path_to(const IndexType &vertex,
+ const Eigen::PlainObjectBase<DerivedP> &previous,
+ std::vector<IndexType> &path)
+{
+ IndexType source = vertex;
+ path.clear();
+ for ( ; source != -1; source = previous[source])
+ path.push_back(source);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template int igl::dijkstra_compute_paths<int, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, std::set<int, std::less<int>, std::allocator<int> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::dijkstra_get_shortest_path_to<int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<int, std::allocator<int> >&);
+#endif
diff --git a/xs/src/igl/dijkstra.h b/xs/src/igl/dijkstra.h
new file mode 100644
index 000000000..33af160bb
--- /dev/null
+++ b/xs/src/igl/dijkstra.h
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_DIJKSTRA
+#define IGL_DIJKSTRA
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+#include <set>
+
+namespace igl {
+
+ // Dijstra's algorithm for shortest paths, with multiple targets.
+ // Adapted from http://rosettacode.org/wiki/Dijkstra%27s_algorithm .
+ //
+ // Inputs:
+ // source index of source vertex
+ // targets target vector set
+ // VV #V list of lists of incident vertices (adjacency list), e.g.
+ // as returned by igl::adjacency_list
+ //
+ // Output:
+ // min_distance #V by 1 list of the minimum distances from source to all vertices
+ // previous #V by 1 list of the previous visited vertices (for each vertex) - used for backtracking
+ //
+ template <typename IndexType, typename DerivedD, typename DerivedP>
+ IGL_INLINE int dijkstra_compute_paths(const IndexType &source,
+ const std::set<IndexType> &targets,
+ const std::vector<std::vector<IndexType> >& VV,
+ Eigen::PlainObjectBase<DerivedD> &min_distance,
+ Eigen::PlainObjectBase<DerivedP> &previous);
+
+ // Backtracking after Dijstra's algorithm, to find shortest path.
+ //
+ // Inputs:
+ // vertex vertex to which we want the shortest path (from same source as above)
+ // previous #V by 1 list of the previous visited vertices (for each vertex) - result of Dijkstra's algorithm
+ //
+ // Output:
+ // path #P by 1 list of vertex indices in the shortest path from source to vertex
+ //
+ template <typename IndexType, typename DerivedP>
+ IGL_INLINE void dijkstra_get_shortest_path_to(const IndexType &vertex,
+ const Eigen::PlainObjectBase<DerivedP> &previous,
+ std::vector<IndexType> &path);
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "dijkstra.cpp"
+#endif
+
+
+#endif /* defined(IGL_DIJKSTRA) */
diff --git a/xs/src/igl/directed_edge_orientations.cpp b/xs/src/igl/directed_edge_orientations.cpp
new file mode 100644
index 000000000..a3308bc98
--- /dev/null
+++ b/xs/src/igl/directed_edge_orientations.cpp
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "directed_edge_orientations.h"
+
+template <typename DerivedC, typename DerivedE>
+IGL_INLINE void igl::directed_edge_orientations(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & Q)
+{
+ using namespace Eigen;
+ Q.resize(E.rows());
+ for(int e = 0;e<E.rows();e++)
+ {
+ const auto & b = C.row(E(e,1)) - C.row(E(e,0));
+ Q[e].setFromTwoVectors( RowVector3d(1,0,0),b);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::directed_edge_orientations<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> > >&);
+#endif
diff --git a/xs/src/igl/directed_edge_orientations.h b/xs/src/igl/directed_edge_orientations.h
new file mode 100644
index 000000000..b6f047147
--- /dev/null
+++ b/xs/src/igl/directed_edge_orientations.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DIRECTED_EDGE_ORIENTATIONS_H
+#define IGL_DIRECTED_EDGE_ORIENTATIONS_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#include <vector>
+
+namespace igl
+{
+ // Determine rotations that take each edge from the x-axis to its given rest
+ // orientation.
+ //
+ // Inputs:
+ // C #C by 3 list of edge vertex positions
+ // E #E by 2 list of directed edges
+ // Outputs:
+ // Q #E list of quaternions
+ //
+ template <typename DerivedC, typename DerivedE>
+ IGL_INLINE void directed_edge_orientations(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & Q);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "directed_edge_orientations.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/directed_edge_parents.cpp b/xs/src/igl/directed_edge_parents.cpp
new file mode 100644
index 000000000..52e6a41a4
--- /dev/null
+++ b/xs/src/igl/directed_edge_parents.cpp
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "directed_edge_parents.h"
+#include "slice_into.h"
+#include "slice.h"
+#include "colon.h"
+#include "setdiff.h"
+#include <algorithm>
+
+template <typename DerivedE, typename DerivedP>
+IGL_INLINE void igl::directed_edge_parents(
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedP> & P)
+{
+ using namespace Eigen;
+ using namespace std;
+ VectorXi I = VectorXi::Constant(E.maxCoeff()+1,1,-1);
+ //I(E.col(1)) = 0:E.rows()-1
+ slice_into(colon<int>(0,E.rows()-1),E.col(1).eval(),I);
+ VectorXi roots,_;
+ setdiff(E.col(0).eval(),E.col(1).eval(),roots,_);
+ std::for_each(roots.data(),roots.data()+roots.size(),[&](int r){I(r)=-1;});
+ slice(I,E.col(0).eval(),P);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::directed_edge_parents<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/directed_edge_parents.h b/xs/src/igl/directed_edge_parents.h
new file mode 100644
index 000000000..bf42ab8f8
--- /dev/null
+++ b/xs/src/igl/directed_edge_parents.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DIRECTED_EDGE_PARENTS_H
+#define IGL_DIRECTED_EDGE_PARENTS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Recover "parents" (preceding edges) in a tree given just directed edges.
+ //
+ // Inputs:
+ // E #E by 2 list of directed edges
+ // Outputs:
+ // P #E list of parent indices into E (-1) means root
+ //
+ template <typename DerivedE, typename DerivedP>
+ IGL_INLINE void directed_edge_parents(
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedP> & P);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "directed_edge_parents.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/dirname.cpp b/xs/src/igl/dirname.cpp
new file mode 100644
index 000000000..5dc49733a
--- /dev/null
+++ b/xs/src/igl/dirname.cpp
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "dirname.h"
+
+#include <algorithm>
+#include "verbose.h"
+
+IGL_INLINE std::string igl::dirname(const std::string & path)
+{
+ if(path == "")
+ {
+ return std::string("");
+ }
+#if defined (WIN32)
+ char del('\\');
+#else
+ char del('/');
+#endif
+ // http://stackoverflow.com/questions/5077693/dirnamephp-similar-function-in-c
+ std::string::const_reverse_iterator last_slash =
+ std::find(
+ path.rbegin(),
+ path.rend(),del);
+ if( last_slash == path.rend() )
+ {
+ // No slashes found
+ return std::string(".");
+ }else if(1 == (last_slash.base() - path.begin()))
+ {
+ // Slash is first char
+ return std::string(&del);
+ }else if(path.end() == last_slash.base() )
+ {
+ // Slash is last char
+ std::string redo = std::string(path.begin(),path.end()-1);
+ return igl::dirname(redo);
+ }
+ return std::string(path.begin(),last_slash.base()-1);
+}
+
+
diff --git a/xs/src/igl/dirname.h b/xs/src/igl/dirname.h
new file mode 100644
index 000000000..bf5a34a20
--- /dev/null
+++ b/xs/src/igl/dirname.h
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DIRNAME_H
+#define IGL_DIRNAME_H
+#include "igl_inline.h"
+
+#include <string>
+
+namespace igl
+{
+ // Function like PHP's dirname: /etc/passwd --> /etc,
+ // Input:
+ // path string containing input path
+ // Returns string containing dirname (see php's dirname)
+ //
+ // See also: basename, pathinfo
+ IGL_INLINE std::string dirname(const std::string & path);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "dirname.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/dot.cpp b/xs/src/igl/dot.cpp
new file mode 100644
index 000000000..38f191546
--- /dev/null
+++ b/xs/src/igl/dot.cpp
@@ -0,0 +1,16 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "dot.h"
+
+// http://www.antisphere.com/Wiki/tools:anttweakbar
+IGL_INLINE double igl::dot(
+ const double *a,
+ const double *b)
+{
+ return a[0]*b[0] + a[1]*b[1] + a[2]*b[2];
+}
diff --git a/xs/src/igl/dot.h b/xs/src/igl/dot.h
new file mode 100644
index 000000000..9494eac7b
--- /dev/null
+++ b/xs/src/igl/dot.h
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DOT_H
+#define IGL_DOT_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Computes out = dot(a,b)
+ // Inputs:
+ // a left 3d vector
+ // b right 3d vector
+ // Returns scalar dot product
+ IGL_INLINE double dot(
+ const double *a,
+ const double *b);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "dot.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/dot_row.cpp b/xs/src/igl/dot_row.cpp
new file mode 100644
index 000000000..6f6d57e06
--- /dev/null
+++ b/xs/src/igl/dot_row.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "igl/dot_row.h"
+
+template <typename DerivedV>
+IGL_INLINE DerivedV igl::dot_row(
+ const Eigen::PlainObjectBase<DerivedV>& A,
+ const Eigen::PlainObjectBase<DerivedV>& B
+ )
+{
+ assert(A.rows() == B.rows());
+ assert(A.cols() == B.cols());
+
+ return (A.array() * B.array()).rowwise().sum();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::dot_row<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/dot_row.h b/xs/src/igl/dot_row.h
new file mode 100644
index 000000000..83d91aada
--- /dev/null
+++ b/xs/src/igl/dot_row.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DOT_ROW_H
+#define IGL_DOT_ROW_H
+
+#include "igl/igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Compute the dot product between each row of A and B
+ // Templates:
+ // DerivedV derived from vertex positions matrix type: i.e. MatrixXd
+ // Inputs:
+ // A eigen matrix r by c
+ // B eigen matrix r by c
+ // Returns:
+ // d a column vector with r entries that contains the dot product of each corresponding row of A and B
+ //
+ template <typename DerivedV>
+ IGL_INLINE DerivedV dot_row(
+ const Eigen::PlainObjectBase<DerivedV>& A,
+ const Eigen::PlainObjectBase<DerivedV>& B);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "dot_row.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/doublearea.cpp b/xs/src/igl/doublearea.cpp
new file mode 100644
index 000000000..3cfc41b86
--- /dev/null
+++ b/xs/src/igl/doublearea.cpp
@@ -0,0 +1,263 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "doublearea.h"
+#include "edge_lengths.h"
+#include "parallel_for.h"
+#include "sort.h"
+#include <cassert>
+#include <iostream>
+#include <limits>
+
+template <typename DerivedV, typename DerivedF, typename DeriveddblA>
+IGL_INLINE void igl::doublearea(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA)
+{
+ // quads are handled by a specialized function
+ if (F.cols() == 4) return doublearea_quad(V,F,dblA);
+
+ const int dim = V.cols();
+ // Only support triangles
+ assert(F.cols() == 3);
+ const size_t m = F.rows();
+ // Compute edge lengths
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 3> l;
+
+ // Projected area helper
+ const auto & proj_doublearea =
+ [&V,&F](const int x, const int y, const int f)
+ ->typename DerivedV::Scalar
+ {
+ auto rx = V(F(f,0),x)-V(F(f,2),x);
+ auto sx = V(F(f,1),x)-V(F(f,2),x);
+ auto ry = V(F(f,0),y)-V(F(f,2),y);
+ auto sy = V(F(f,1),y)-V(F(f,2),y);
+ return rx*sy - ry*sx;
+ };
+
+ switch(dim)
+ {
+ case 3:
+ {
+ dblA = DeriveddblA::Zero(m,1);
+ for(size_t f = 0;f<m;f++)
+ {
+ for(int d = 0;d<3;d++)
+ {
+ const auto dblAd = proj_doublearea(d,(d+1)%3,f);
+ dblA(f) += dblAd*dblAd;
+ }
+ }
+ dblA = dblA.array().sqrt().eval();
+ break;
+ }
+ case 2:
+ {
+ dblA.resize(m,1);
+ for(size_t f = 0;f<m;f++)
+ {
+ dblA(f) = proj_doublearea(0,1,f);
+ }
+ break;
+ }
+ default:
+ {
+ edge_lengths(V,F,l);
+ return doublearea(l,0.,dblA);
+ }
+ }
+}
+
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedD>
+IGL_INLINE void igl::doublearea(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedD> & D)
+{
+ assert((B.cols() == A.cols()) && "dimensions of A and B should match");
+ assert((C.cols() == A.cols()) && "dimensions of A and C should match");
+ assert(A.rows() == B.rows() && "corners should have same length");
+ assert(A.rows() == C.rows() && "corners should have same length");
+ switch(A.cols())
+ {
+ case 2:
+ {
+ // For 2d compute signed area
+ const auto & R = A-C;
+ const auto & S = B-C;
+ D = (R.col(0).array()*S.col(1).array() -
+ R.col(1).array()*S.col(0).array()).template cast<
+ typename DerivedD::Scalar>();
+ break;
+ }
+ default:
+ {
+ Eigen::Matrix<typename DerivedD::Scalar,DerivedD::RowsAtCompileTime,3>
+ uL(A.rows(),3);
+ uL.col(0) = ((B-C).rowwise().norm()).template cast<typename DerivedD::Scalar>();
+ uL.col(1) = ((C-A).rowwise().norm()).template cast<typename DerivedD::Scalar>();
+ uL.col(2) = ((A-B).rowwise().norm()).template cast<typename DerivedD::Scalar>();
+ doublearea(uL,D);
+ }
+ }
+}
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC>
+IGL_INLINE typename DerivedA::Scalar igl::doublearea_single(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C)
+{
+ assert(A.size() == 2 && "Vertices should be 2D");
+ assert(B.size() == 2 && "Vertices should be 2D");
+ assert(C.size() == 2 && "Vertices should be 2D");
+ auto r = A-C;
+ auto s = B-C;
+ return r(0)*s(1) - r(1)*s(0);
+}
+
+template <typename Derivedl, typename DeriveddblA>
+IGL_INLINE void igl::doublearea(
+ const Eigen::MatrixBase<Derivedl> & ul,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA)
+{
+ // Default is to leave NaNs and fire asserts in debug mode
+ return doublearea(
+ ul,std::numeric_limits<typename Derivedl::Scalar>::quiet_NaN(),dblA);
+}
+
+template <typename Derivedl, typename DeriveddblA>
+IGL_INLINE void igl::doublearea(
+ const Eigen::MatrixBase<Derivedl> & ul,
+ const typename Derivedl::Scalar nan_replacement,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef typename Derivedl::Index Index;
+ // Only support triangles
+ assert(ul.cols() == 3);
+ // Number of triangles
+ const Index m = ul.rows();
+ Eigen::Matrix<typename Derivedl::Scalar, Eigen::Dynamic, 3> l;
+ MatrixXi _;
+ //
+ // "Miscalculating Area and Angles of a Needle-like Triangle"
+ // https://people.eecs.berkeley.edu/~wkahan/Triangle.pdf
+ igl::sort(ul,2,false,l,_);
+ // semiperimeters
+ //Matrix<typename Derivedl::Scalar,Dynamic,1> s = l.rowwise().sum()*0.5;
+ //assert((Index)s.rows() == m);
+ // resize output
+ dblA.resize(l.rows(),1);
+ parallel_for(
+ m,
+ [&l,&dblA,&nan_replacement](const int i)
+ {
+ // Kahan's Heron's formula
+ typedef typename Derivedl::Scalar Scalar;
+ const Scalar arg =
+ (l(i,0)+(l(i,1)+l(i,2)))*
+ (l(i,2)-(l(i,0)-l(i,1)))*
+ (l(i,2)+(l(i,0)-l(i,1)))*
+ (l(i,0)+(l(i,1)-l(i,2)));
+ dblA(i) = 2.0*0.25*sqrt(arg);
+ // Alec: If the input edge lengths were computed from floating point
+ // vertex positions then there's no guarantee that they fulfill the
+ // triangle inequality (in their floating point approximations). For
+ // nearly degenerate triangles the round-off error during side-length
+ // computation may be larger than (or rather smaller) than the height of
+ // the triangle. In "Lecture Notes on Geometric Robustness" Shewchuck 09,
+ // Section 3.1 http://www.cs.berkeley.edu/~jrs/meshpapers/robnotes.pdf,
+ // he recommends computing the triangle areas for 2D and 3D using 2D
+ // signed areas computed with determinants.
+ assert(
+ (nan_replacement == nan_replacement ||
+ (l(i,2) - (l(i,0)-l(i,1)))>=0)
+ && "Side lengths do not obey the triangle inequality.");
+ if(dblA(i) != dblA(i))
+ {
+ dblA(i) = nan_replacement;
+ }
+ assert(dblA(i) == dblA(i) && "DOUBLEAREA() PRODUCED NaN");
+ },
+ 1000l);
+}
+
+template <typename DerivedV, typename DerivedF, typename DeriveddblA>
+IGL_INLINE void igl::doublearea_quad(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA)
+{
+ assert(V.cols() == 3); // Only supports points in 3D
+ assert(F.cols() == 4); // Only support quads
+ const size_t m = F.rows();
+
+ // Split the quads into triangles
+ Eigen::MatrixXi Ft(F.rows()*2,3);
+
+ for(size_t i=0; i<m;++i)
+ {
+ Ft.row(i*2 ) << F(i,0), F(i,1), F(i,2);
+ Ft.row(i*2 + 1) << F(i,2), F(i,3), F(i,0);
+ }
+
+ // Compute areas
+ Eigen::VectorXd doublearea_tri;
+ igl::doublearea(V,Ft,doublearea_tri);
+
+ dblA.resize(F.rows(),1);
+ for(unsigned i=0; i<F.rows();++i)
+ {
+ dblA(i) = doublearea_tri(i*2) + doublearea_tri(i*2 + 1);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::doublearea<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::doublearea<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar igl::doublearea_single<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+template Eigen::Matrix<double, 2, 1, 0, 2, 1>::Scalar igl::doublearea_single<Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 1, 0, 2, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&);
+#endif
diff --git a/xs/src/igl/doublearea.h b/xs/src/igl/doublearea.h
new file mode 100644
index 000000000..95c151508
--- /dev/null
+++ b/xs/src/igl/doublearea.h
@@ -0,0 +1,104 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DOUBLEAREA_H
+#define IGL_DOUBLEAREA_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // DOUBLEAREA computes twice the area for each input triangle[quad]
+ //
+ // Templates:
+ // DerivedV derived type of eigen matrix for V (e.g. derived from
+ // MatrixXd)
+ // DerivedF derived type of eigen matrix for F (e.g. derived from
+ // MatrixXi)
+ // DeriveddblA derived type of eigen matrix for dblA (e.g. derived from
+ // MatrixXd)
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by simplex_size list of mesh faces (must be triangles or quads)
+ // Outputs:
+ // dblA #F list of triangle[quad] double areas (SIGNED only for 2D input)
+ //
+ // Known bug: For dim==3 complexity is O(#V + #F)!! Not just O(#F). This is a big deal
+ // if you have 1million unreferenced vertices and 1 face
+ template <typename DerivedV, typename DerivedF, typename DeriveddblA>
+ IGL_INLINE void doublearea(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA);
+ // Stream of triangles, computes signed area...
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedD>
+ IGL_INLINE void doublearea(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedD> & D);
+ // Single triangle in 2D!
+ //
+ // This should handle streams of corners not just single corners
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC>
+ IGL_INLINE typename DerivedA::Scalar doublearea_single(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C);
+ // Same as above but use instrinsic edge lengths rather than (V,F) mesh. This
+ //
+ // Inputs:
+ // l #F by dim list of edge lengths using
+ // for triangles, columns correspond to edges 23,31,12
+ // nan_replacement what value should be used for triangles whose given
+ // edge lengths do not obey the triangle inequality. These may be very
+ // wrong (e.g., [100 1 1]) or may be nearly degenerate triangles whose
+ // floating point side length computation leads to breach of the triangle
+ // inequality. One may wish to set this parameter to 0 if side lengths l
+ // are _known_ to come from a valid embedding (e.g., some mesh (V,F)). In
+ // that case, the only circumstance the triangle inequality is broken is
+ // when the triangle is nearly degenerate and floating point error
+ // dominates: hence replacing with zero is reasonable.
+ // Outputs:
+ // dblA #F list of triangle double areas
+ template <typename Derivedl, typename DeriveddblA>
+ IGL_INLINE void doublearea(
+ const Eigen::MatrixBase<Derivedl> & l,
+ const typename Derivedl::Scalar nan_replacement,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA);
+ // default behavior is to assert on NaNs and leave them in place
+ template <typename Derivedl, typename DeriveddblA>
+ IGL_INLINE void doublearea(
+ const Eigen::MatrixBase<Derivedl> & l,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA);
+ // DOUBLEAREA_QUAD computes twice the area for each input quadrilateral
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by simplex_size list of mesh faces (must be quadrilaterals)
+ // Outputs:
+ // dblA #F list of quadrilateral double areas
+ //
+ template <typename DerivedV, typename DerivedF, typename DeriveddblA>
+ IGL_INLINE void doublearea_quad(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DeriveddblA> & dblA);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "doublearea.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/dqs.cpp b/xs/src/igl/dqs.cpp
new file mode 100644
index 000000000..aab3c6532
--- /dev/null
+++ b/xs/src/igl/dqs.cpp
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "dqs.h"
+#include <Eigen/Geometry>
+template <
+ typename DerivedV,
+ typename DerivedW,
+ typename Q,
+ typename QAlloc,
+ typename T,
+ typename DerivedU>
+IGL_INLINE void igl::dqs(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedW> & W,
+ const std::vector<Q,QAlloc> & vQ,
+ const std::vector<T> & vT,
+ Eigen::PlainObjectBase<DerivedU> & U)
+{
+ using namespace std;
+ assert(V.rows() <= W.rows());
+ assert(W.cols() == (int)vQ.size());
+ assert(W.cols() == (int)vT.size());
+ // resize output
+ U.resizeLike(V);
+
+ // Convert quats + trans into dual parts
+ vector<Q> vD(vQ.size());
+ for(int c = 0;c<W.cols();c++)
+ {
+ const Q & q = vQ[c];
+ vD[c].w() = -0.5*( vT[c](0)*q.x() + vT[c](1)*q.y() + vT[c](2)*q.z());
+ vD[c].x() = 0.5*( vT[c](0)*q.w() + vT[c](1)*q.z() - vT[c](2)*q.y());
+ vD[c].y() = 0.5*(-vT[c](0)*q.z() + vT[c](1)*q.w() + vT[c](2)*q.x());
+ vD[c].z() = 0.5*( vT[c](0)*q.y() - vT[c](1)*q.x() + vT[c](2)*q.w());
+ }
+
+ // Loop over vertices
+ const int nv = V.rows();
+#pragma omp parallel for if (nv>10000)
+ for(int i = 0;i<nv;i++)
+ {
+ Q b0(0,0,0,0);
+ Q be(0,0,0,0);
+ // Loop over handles
+ for(int c = 0;c<W.cols();c++)
+ {
+ b0.coeffs() += W(i,c) * vQ[c].coeffs();
+ be.coeffs() += W(i,c) * vD[c].coeffs();
+ }
+ Q ce = be;
+ ce.coeffs() /= b0.norm();
+ Q c0 = b0;
+ c0.coeffs() /= b0.norm();
+ // See algorithm 1 in "Geometric skinning with approximate dual quaternion
+ // blending" by Kavan et al
+ T v = V.row(i);
+ T d0 = c0.vec();
+ T de = ce.vec();
+ typename Q::Scalar a0 = c0.w();
+ typename Q::Scalar ae = ce.w();
+ U.row(i) = v + 2*d0.cross(d0.cross(v) + a0*v) + 2*(a0*de - ae*d0 + d0.cross(de));
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::dqs<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> >, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Quaternion<double, 0>, Eigen::aligned_allocator<Eigen::Quaternion<double, 0> > > const&, std::vector<Eigen::Matrix<double, 3, 1, 0, 3, 1>, std::allocator<Eigen::Matrix<double, 3, 1, 0, 3, 1> > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/dqs.h b/xs/src/igl/dqs.h
new file mode 100644
index 000000000..9b53ae1c7
--- /dev/null
+++ b/xs/src/igl/dqs.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_DQS_H
+#define IGL_DQS_H
+#include "igl_inline.h"
+#include <vector>
+#include <Eigen/Core>
+namespace igl
+{
+ // Dual quaternion skinning
+ //
+ // Inputs:
+ // V #V by 3 list of rest positions
+ // W #W by #C list of weights
+ // vQ #C list of rotation quaternions
+ // vT #C list of translation vectors
+ // Outputs:
+ // U #V by 3 list of new positions
+ template <
+ typename DerivedV,
+ typename DerivedW,
+ typename Q,
+ typename QAlloc,
+ typename T,
+ typename DerivedU>
+ IGL_INLINE void dqs(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedW> & W,
+ const std::vector<Q,QAlloc> & vQ,
+ const std::vector<T> & vT,
+ Eigen::PlainObjectBase<DerivedU> & U);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "dqs.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/ears.cpp b/xs/src/igl/ears.cpp
new file mode 100644
index 000000000..81576c321
--- /dev/null
+++ b/xs/src/igl/ears.cpp
@@ -0,0 +1,34 @@
+#include "ears.h"
+#include "on_boundary.h"
+#include "find.h"
+#include "slice.h"
+#include "mat_min.h"
+#include <cassert>
+
+template <
+ typename DerivedF,
+ typename Derivedear,
+ typename Derivedear_opp>
+IGL_INLINE void igl::ears(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<Derivedear> & ear,
+ Eigen::PlainObjectBase<Derivedear_opp> & ear_opp)
+{
+ assert(F.cols() == 3 && "F should contain triangles");
+ Eigen::Array<bool,Eigen::Dynamic,3> B;
+ {
+ Eigen::Array<bool,Eigen::Dynamic,1> I;
+ on_boundary(F,I,B);
+ }
+ find(B.rowwise().count() == 2,ear);
+ Eigen::Array<bool,Eigen::Dynamic,3> Bear;
+ slice(B,ear,1,Bear);
+ Eigen::Array<bool,Eigen::Dynamic,1> M;
+ mat_min(Bear,2,M,ear_opp);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::ears<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/ears.h b/xs/src/igl/ears.h
new file mode 100644
index 000000000..b7c51ec66
--- /dev/null
+++ b/xs/src/igl/ears.h
@@ -0,0 +1,30 @@
+#ifndef IGL_EARS_H
+#define IGL_EARS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // FIND_EARS Find all ears (faces with two boundary edges) in a given mesh
+ //
+ // [ears,ear_opp] = find_ears(F)
+ //
+ // Inputs:
+ // F #F by 3 list of triangle mesh indices
+ // Outputs:
+ // ears #ears list of indices into F of ears
+ // ear_opp #ears list of indices indicating which edge is non-boundary
+ // (connecting to flops)
+ //
+ template <
+ typename DerivedF,
+ typename Derivedear,
+ typename Derivedear_opp>
+ IGL_INLINE void ears(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<Derivedear> & ear,
+ Eigen::PlainObjectBase<Derivedear_opp> & ear_opp);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "ears.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/edge_collapse_is_valid.cpp b/xs/src/igl/edge_collapse_is_valid.cpp
new file mode 100644
index 000000000..0c613b7a3
--- /dev/null
+++ b/xs/src/igl/edge_collapse_is_valid.cpp
@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "edge_collapse_is_valid.h"
+#include "collapse_edge.h"
+#include "circulation.h"
+#include "intersect.h"
+#include "unique.h"
+#include "list_to_matrix.h"
+#include <vector>
+
+IGL_INLINE bool igl::edge_collapse_is_valid(
+ const int e,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI)
+{
+ using namespace Eigen;
+ using namespace std;
+ // For consistency with collapse_edge.cpp, let's determine edge flipness
+ // (though not needed to check validity)
+ const int eflip = E(e,0)>E(e,1);
+ // source and destination
+ const int s = eflip?E(e,1):E(e,0);
+ const int d = eflip?E(e,0):E(e,1);
+
+ if(s == IGL_COLLAPSE_EDGE_NULL && d==IGL_COLLAPSE_EDGE_NULL)
+ {
+ return false;
+ }
+ // check if edge collapse is valid: intersection of vertex neighbors of s and
+ // d should be exactly 2+(s,d) = 4
+ // http://stackoverflow.com/a/27049418/148668
+ {
+ // all vertex neighbors around edge, including the two vertices of the edge
+ const auto neighbors = [](
+ const int e,
+ const bool ccw,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI)
+ {
+ vector<int> N,uN;
+ vector<int> V2Fe = circulation(e, ccw,F,E,EMAP,EF,EI);
+ for(auto f : V2Fe)
+ {
+ N.push_back(F(f,0));
+ N.push_back(F(f,1));
+ N.push_back(F(f,2));
+ }
+ vector<size_t> _1,_2;
+ igl::unique(N,uN,_1,_2);
+ VectorXi uNm;
+ list_to_matrix(uN,uNm);
+ return uNm;
+ };
+ VectorXi Ns = neighbors(e, eflip,F,E,EMAP,EF,EI);
+ VectorXi Nd = neighbors(e,!eflip,F,E,EMAP,EF,EI);
+ VectorXi Nint = igl::intersect(Ns,Nd);
+ if(Nint.size() != 4)
+ {
+ return false;
+ }
+ if(Ns.size() == 4 && Nd.size() == 4)
+ {
+ VectorXi NsNd(8);
+ NsNd<<Ns,Nd;
+ VectorXi Nun,_1,_2;
+ igl::unique(NsNd,Nun,_1,_2);
+ // single tet, don't collapse
+ if(Nun.size() == 4)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
diff --git a/xs/src/igl/edge_collapse_is_valid.h b/xs/src/igl/edge_collapse_is_valid.h
new file mode 100644
index 000000000..194aaad6c
--- /dev/null
+++ b/xs/src/igl/edge_collapse_is_valid.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EDGE_COLLAPSE_IS_VALID_H
+#define IGL_EDGE_COLLAPSE_IS_VALID_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Assumes (V,F) is a closed manifold mesh (except for previouslly collapsed
+ // faces which should be set to:
+ // [IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL IGL_COLLAPSE_EDGE_NULL].
+ // Tests whether collapsing exactly two faces and exactly 3 edges from E (e
+ // and one side of each face gets collapsed to the other) will result in a
+ // mesh with the same topology.
+ //
+ // 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.
+ // 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).
+ // Returns true if edge collapse is valid
+ IGL_INLINE bool edge_collapse_is_valid(
+ const int e,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "edge_collapse_is_valid.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/edge_flaps.cpp b/xs/src/igl/edge_flaps.cpp
new file mode 100644
index 000000000..88c515864
--- /dev/null
+++ b/xs/src/igl/edge_flaps.cpp
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "edge_flaps.h"
+#include "unique_edge_map.h"
+#include <vector>
+#include <cassert>
+
+IGL_INLINE void igl::edge_flaps(
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI)
+{
+ // Initialize to boundary value
+ EF.setConstant(E.rows(),2,-1);
+ EI.setConstant(E.rows(),2,-1);
+ // loop over all faces
+ for(int f = 0;f<F.rows();f++)
+ {
+ // loop over edges across from corners
+ for(int v = 0;v<3;v++)
+ {
+ // get edge id
+ const int e = EMAP(v*F.rows()+f);
+ // See if this is left or right flap w.r.t. edge orientation
+ if( F(f,(v+1)%3) == E(e,0) && F(f,(v+2)%3) == E(e,1))
+ {
+ EF(e,0) = f;
+ EI(e,0) = v;
+ }else
+ {
+ assert(F(f,(v+1)%3) == E(e,1) && F(f,(v+2)%3) == E(e,0));
+ EF(e,1) = f;
+ EI(e,1) = v;
+ }
+ }
+ }
+}
+
+IGL_INLINE void igl::edge_flaps(
+ const Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI)
+{
+ Eigen::MatrixXi allE;
+ std::vector<std::vector<int> > uE2E;
+ igl::unique_edge_map(F,allE,E,EMAP,uE2E);
+ // Const-ify to call overload
+ const auto & cE = E;
+ const auto & cEMAP = EMAP;
+ return edge_flaps(F,cE,cEMAP,EF,EI);
+}
diff --git a/xs/src/igl/edge_flaps.h b/xs/src/igl/edge_flaps.h
new file mode 100644
index 000000000..03ad6eb3d
--- /dev/null
+++ b/xs/src/igl/edge_flaps.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EDGE_FLAPS_H
+#define IGL_EDGE_FLAPS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Determine "edge flaps": two faces on either side of a unique edge (assumes
+ // edge-manifold mesh)
+ //
+ // Inputs:
+ // F #F by 3 list of face indices
+ // 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
+ // Outputs:
+ // 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).
+ //
+ // TODO: This seems to be a duplicate of edge_topology.h
+ // igl::edge_topology(V,F,etEV,etFE,etEF);
+ // igl::edge_flaps(F,efE,efEMAP,efEF,efEI);
+ // [~,I] = sort(efE,2)
+ // all( efE(sub2ind(size(efE),repmat(1:size(efE,1),2,1)',I)) == etEV )
+ // all( efEF(sub2ind(size(efE),repmat(1:size(efE,1),2,1)',I)) == etEF )
+ // all(efEMAP(sub2ind(size(F),repmat(1:size(F,1),3,1)',repmat([1 2 3],size(F,1),1))) == etFE(:,[2 3 1]))
+ IGL_INLINE void edge_flaps(
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI);
+ // Only faces as input
+ IGL_INLINE void edge_flaps(
+ const Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & EMAP,
+ Eigen::MatrixXi & EF,
+ Eigen::MatrixXi & EI);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "edge_flaps.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/edge_lengths.cpp b/xs/src/igl/edge_lengths.cpp
new file mode 100644
index 000000000..02dbae768
--- /dev/null
+++ b/xs/src/igl/edge_lengths.cpp
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "edge_lengths.h"
+#include "squared_edge_lengths.h"
+
+template <typename DerivedV, typename DerivedF, typename DerivedL>
+IGL_INLINE void igl::edge_lengths(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedL>& L)
+ {
+ igl::squared_edge_lengths(V,F,L);
+ L=L.array().sqrt().eval();
+ }
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+// generated by autoexplicit.sh
+template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 2, 0, -1, 2>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/edge_lengths.h b/xs/src/igl/edge_lengths.h
new file mode 100644
index 000000000..30dc3474b
--- /dev/null
+++ b/xs/src/igl/edge_lengths.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EDGE_LENGTHS_H
+#define IGL_EDGE_LENGTHS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Constructs a list of lengths of edges opposite each index in a face
+ // (triangle/tet) list
+ //
+ // 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 2 list of mesh edges
+ // or
+ // F #F by 3 list of mesh faces (must be triangles)
+ // or
+ // T #T by 4 list of mesh elements (must be tets)
+ // Outputs:
+ // L #F by {1|3|6} list of edge lengths
+ // for edges, column of lengths
+ // for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+ // for tets, columns correspond to edges
+ // [3 0],[3 1],[3 2],[1 2],[2 0],[0 1]
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedL>
+ IGL_INLINE void edge_lengths(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedL>& L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "edge_lengths.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/edge_topology.cpp b/xs/src/igl/edge_topology.cpp
new file mode 100644
index 000000000..78147d056
--- /dev/null
+++ b/xs/src/igl/edge_topology.cpp
@@ -0,0 +1,110 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "edge_topology.h"
+#include "is_edge_manifold.h"
+#include <algorithm>
+
+template<typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::edge_topology(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::MatrixXi& EV,
+ Eigen::MatrixXi& FE,
+ Eigen::MatrixXi& EF)
+{
+ // Only needs to be edge-manifold
+ if (V.rows() ==0 || F.rows()==0)
+ {
+ EV = Eigen::MatrixXi::Constant(0,2,-1);
+ FE = Eigen::MatrixXi::Constant(0,3,-1);
+ EF = Eigen::MatrixXi::Constant(0,2,-1);
+ return;
+ }
+ assert(igl::is_edge_manifold(F));
+ std::vector<std::vector<int> > ETT;
+ for(int f=0;f<F.rows();++f)
+ for (int i=0;i<3;++i)
+ {
+ // v1 v2 f vi
+ int v1 = F(f,i);
+ int v2 = F(f,(i+1)%3);
+ if (v1 > v2) std::swap(v1,v2);
+ std::vector<int> r(4);
+ r[0] = v1; r[1] = v2;
+ r[2] = f; r[3] = i;
+ ETT.push_back(r);
+ }
+ std::sort(ETT.begin(),ETT.end());
+
+ // count the number of edges (assume manifoldness)
+ int En = 1; // the last is always counted
+ for(int i=0;i<int(ETT.size())-1;++i)
+ if (!((ETT[i][0] == ETT[i+1][0]) && (ETT[i][1] == ETT[i+1][1])))
+ ++En;
+
+ EV = Eigen::MatrixXi::Constant((int)(En),2,-1);
+ FE = Eigen::MatrixXi::Constant((int)(F.rows()),3,-1);
+ EF = Eigen::MatrixXi::Constant((int)(En),2,-1);
+ En = 0;
+
+ for(unsigned i=0;i<ETT.size();++i)
+ {
+ if (i == ETT.size()-1 ||
+ !((ETT[i][0] == ETT[i+1][0]) && (ETT[i][1] == ETT[i+1][1]))
+ )
+ {
+ // Border edge
+ std::vector<int>& r1 = ETT[i];
+ EV(En,0) = r1[0];
+ EV(En,1) = r1[1];
+ EF(En,0) = r1[2];
+ FE(r1[2],r1[3]) = En;
+ }
+ else
+ {
+ std::vector<int>& r1 = ETT[i];
+ std::vector<int>& r2 = ETT[i+1];
+ EV(En,0) = r1[0];
+ EV(En,1) = r1[1];
+ EF(En,0) = r1[2];
+ EF(En,1) = r2[2];
+ FE(r1[2],r1[3]) = En;
+ FE(r2[2],r2[3]) = En;
+ ++i; // skip the next one
+ }
+ ++En;
+ }
+
+ // Sort the relation EF, accordingly to EV
+ // the first one is the face on the left of the edge
+ for(unsigned i=0; i<EF.rows(); ++i)
+ {
+ int fid = EF(i,0);
+ bool flip = true;
+ // search for edge EV.row(i)
+ for (unsigned j=0; j<3; ++j)
+ {
+ if ((F(fid,j) == EV(i,0)) && (F(fid,(j+1)%3) == EV(i,1)))
+ flip = false;
+ }
+
+ if (flip)
+ {
+ int tmp = EF(i,0);
+ EF(i,0) = EF(i,1);
+ EF(i,1) = tmp;
+ }
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::edge_topology<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
+template void igl::edge_topology<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
+#endif
diff --git a/xs/src/igl/edge_topology.h b/xs/src/igl/edge_topology.h
new file mode 100644
index 000000000..b7a41c597
--- /dev/null
+++ b/xs/src/igl/edge_topology.h
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EDGE_TOPOLOGY_H
+#define IGL_EDGE_TOPOLOGY_H
+
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Initialize Edges and their topological relations (assumes an edge-manifold
+ // mesh)
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions (unused)
+ // F #F by 3 list of triangle indices into V
+ // Outputs:
+ // EV #Ex2 matrix storing the edge description as pair of indices to
+ // vertices
+ // FE #Fx3 matrix storing the Triangle-Edge relation
+ // EF #Ex2 matrix storing the Edge-Triangle relation
+ //
+ // TODO: This seems to be a inferior duplicate of edge_flaps.h:
+ // - unused input parameter V
+ // - roughly 2x slower than edge_flaps
+ // - outputs less information: edge_flaps reveals corner opposite edge
+ // - FE uses non-standard and ambiguous order: FE(f,c) is merely an edge
+ // incident on corner c of face f. In contrast, edge_flaps's EMAP(f,c)
+ // reveals the edge _opposite_ corner c of face f
+template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void edge_topology(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::MatrixXi& EV,
+ Eigen::MatrixXi& FE,
+ Eigen::MatrixXi& EF);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "edge_topology.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/edges.cpp b/xs/src/igl/edges.cpp
new file mode 100644
index 000000000..3d762d410
--- /dev/null
+++ b/xs/src/igl/edges.cpp
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "edges.h"
+#include "adjacency_matrix.h"
+#include <iostream>
+
+template <typename DerivedF, typename DerivedE>
+IGL_INLINE void igl::edges(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E)
+{
+ // build adjacency matrix
+ typedef typename DerivedF::Scalar Index;
+ Eigen::SparseMatrix<Index> A;
+ igl::adjacency_matrix(F,A);
+ // Number of non zeros should be twice number of edges
+ assert(A.nonZeros()%2 == 0);
+ // Resize to fit edges
+ E.resize(A.nonZeros()/2,2);
+ int i = 0;
+ // Iterate over outside
+ for(int k=0; k<A.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<Index>::InnerIterator it (A,k); it; ++it)
+ {
+ // only add edge in one direction
+ if(it.row()<it.col())
+ {
+ E(i,0) = it.row();
+ E(i,1) = it.col();
+ i++;
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::edges<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/edges.h b/xs/src/igl/edges.h
new file mode 100644
index 000000000..fa3405263
--- /dev/null
+++ b/xs/src/igl/edges.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EDGES_H
+#define IGL_EDGES_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Constructs a list of unique edges represented in a given mesh (V,F)
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // F #F by 3 list of mesh faces (must be triangles)
+ // or
+ // T #T x 4 matrix of indices of tet corners
+ // Outputs:
+ // E #E by 2 list of edges in no particular order
+ //
+ // See also: adjacency_matrix
+ template <typename DerivedF, typename DerivedE>
+ IGL_INLINE void edges(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "edges.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/edges_to_path.cpp b/xs/src/igl/edges_to_path.cpp
new file mode 100644
index 000000000..14cd895bc
--- /dev/null
+++ b/xs/src/igl/edges_to_path.cpp
@@ -0,0 +1,103 @@
+#include "edges_to_path.h"
+#include "dfs.h"
+#include "sort.h"
+#include "slice.h"
+#include "ismember.h"
+#include "unique.h"
+#include "adjacency_list.h"
+
+template <
+ typename DerivedE,
+ typename DerivedI,
+ typename DerivedJ,
+ typename DerivedK>
+IGL_INLINE void igl::edges_to_path(
+ const Eigen::MatrixBase<DerivedE> & OE,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedK> & K)
+{
+ assert(OE.rows()>=1);
+ if(OE.rows() == 1)
+ {
+ I.resize(2);
+ I(0) = OE(0);
+ I(1) = OE(1);
+ J.resize(1);
+ J(0) = 0;
+ K.resize(1);
+ K(0) = 0;
+ }
+
+ // Compute on reduced graph
+ DerivedI U;
+ Eigen::VectorXi vE;
+ {
+ Eigen::VectorXi IA;
+ unique(OE,U,IA,vE);
+ }
+
+ Eigen::VectorXi V = Eigen::VectorXi::Zero(vE.maxCoeff()+1);
+ for(int e = 0;e<vE.size();e++)
+ {
+ V(vE(e))++;
+ assert(V(vE(e))<=2);
+ }
+ // Try to find a vertex with valence = 1
+ int c = 2;
+ int s = vE(0);
+ for(int v = 0;v<V.size();v++)
+ {
+ if(V(v) == 1)
+ {
+ c = V(v);
+ s = v;
+ break;
+ }
+ }
+ assert(V(s) == c);
+ assert(c == 2 || c == 1);
+
+ // reshape E to be #E by 2
+ DerivedE E = Eigen::Map<DerivedE>(vE.data(),OE.rows(),OE.cols()).eval();
+ {
+ std::vector<std::vector<int> > A;
+ igl::adjacency_list(E,A);
+ Eigen::VectorXi P,C;
+ dfs(A,s,I,P,C);
+ }
+ if(c == 2)
+ {
+ I.conservativeResize(I.size()+1);
+ I(I.size()-1) = I(0);
+ }
+
+ DerivedE sE;
+ Eigen::Matrix<typename DerivedI::Scalar,Eigen::Dynamic,2> sEI;
+ {
+ Eigen::MatrixXi _;
+ sort(E,2,true,sE,_);
+ Eigen::Matrix<typename DerivedI::Scalar,Eigen::Dynamic,2> EI(I.size()-1,2);
+ EI.col(0) = I.head(I.size()-1);
+ EI.col(1) = I.tail(I.size()-1);
+ sort(EI,2,true,sEI,_);
+ }
+ {
+ Eigen::Array<bool,Eigen::Dynamic,1> F;
+ ismember_rows(sEI,sE,F,J);
+ }
+ K.resize(I.size()-1);
+ for(int k = 0;k<K.size();k++)
+ {
+ K(k) = (E(J(k),0) != I(k) ? 1 : 0);
+ }
+
+ // Map vertex indices onto original graph
+ slice(U,DerivedI(I),1,I);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::edges_to_path<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/edges_to_path.h b/xs/src/igl/edges_to_path.h
new file mode 100644
index 000000000..403e7029a
--- /dev/null
+++ b/xs/src/igl/edges_to_path.h
@@ -0,0 +1,36 @@
+#ifndef IGL_EDGES_TO_PATH_H
+#define IGL_EDGES_TO_PATH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // EDGES_TO_PATH Given a set of undirected, unique edges such that all form a
+ // single connected compoent with exactly 0 or 2 nodes with valence =1,
+ // determine the/a path visiting all nodes.
+ //
+ // Inputs:
+ // E #E by 2 list of undirected edges
+ // Outputs:
+ // I #E+1 list of nodes in order tracing the chain (loop), if the output
+ // is a loop then I(1) == I(end)
+ // J #I-1 list of indices into E of edges tracing I
+ // K #I-1 list of indices into columns of E {1,2} so that K(i) means that
+ // E(i,K(i)) comes before the other (i.e., E(i,3-K(i)) ). This means that
+ // I(i) == E(J(i),K(i)) for i<#I, or
+ // I == E(sub2ind(size(E),J([1:end end]),[K;3-K(end)]))))
+ //
+ template <
+ typename DerivedE,
+ typename DerivedI,
+ typename DerivedJ,
+ typename DerivedK>
+ IGL_INLINE void edges_to_path(
+ const Eigen::MatrixBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedK> & K);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "edges_to_path.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/eigs.cpp b/xs/src/igl/eigs.cpp
new file mode 100755
index 000000000..1fd440ddd
--- /dev/null
+++ b/xs/src/igl/eigs.cpp
@@ -0,0 +1,176 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "eigs.h"
+
+#include "cotmatrix.h"
+#include "sort.h"
+#include "slice.h"
+#include "massmatrix.h"
+#include <iostream>
+
+template <
+ typename Atype,
+ typename Btype,
+ typename DerivedU,
+ typename DerivedS>
+IGL_INLINE bool igl::eigs(
+ const Eigen::SparseMatrix<Atype> & A,
+ const Eigen::SparseMatrix<Btype> & iB,
+ const size_t k,
+ const EigsType type,
+ Eigen::PlainObjectBase<DerivedU> & sU,
+ Eigen::PlainObjectBase<DerivedS> & sS)
+{
+ using namespace Eigen;
+ using namespace std;
+ const size_t n = A.rows();
+ assert(A.cols() == n && "A should be square.");
+ assert(iB.rows() == n && "B should be match A's dims.");
+ assert(iB.cols() == n && "B should be square.");
+ assert(type == EIGS_TYPE_SM && "Only low frequencies are supported");
+ DerivedU U(n,k);
+ DerivedS S(k,1);
+ typedef Atype Scalar;
+ typedef Eigen::Matrix<typename DerivedU::Scalar,DerivedU::RowsAtCompileTime,1> VectorXS;
+ // Rescale B for better numerics
+ const Scalar rescale = std::abs(iB.diagonal().maxCoeff());
+ const Eigen::SparseMatrix<Btype> B = iB/rescale;
+
+ Scalar tol = 1e-4;
+ Scalar conv = 1e-14;
+ int max_iter = 100;
+ int i = 0;
+ //std::cout<<"start"<<std::endl;
+ while(true)
+ {
+ //std::cout<<i<<std::endl;
+ // Random initial guess
+ VectorXS y = VectorXS::Random(n,1);
+ Scalar eff_sigma = 0;
+ if(i>0)
+ {
+ eff_sigma = 1e-8+std::abs(S(i-1));
+ }
+ // whether to use rayleigh quotient method
+ bool ray = false;
+ Scalar err = std::numeric_limits<Scalar>::infinity();
+ int iter;
+ Scalar sigma = std::numeric_limits<Scalar>::infinity();
+ VectorXS x;
+ for(iter = 0;iter<max_iter;iter++)
+ {
+ if(i>0 && !ray)
+ {
+ // project-out existing modes
+ for(int j = 0;j<i;j++)
+ {
+ const VectorXS u = U.col(j);
+ y = (y - u*u.dot(B*y)/u.dot(B * u)).eval();
+ }
+ }
+ // normalize
+ x = y/sqrt(y.dot(B*y));
+
+ // current guess at eigen value
+ sigma = x.dot(A*x)/x.dot(B*x);
+ //x *= sigma>0?1.:-1.;
+
+ Scalar err_prev = err;
+ err = (A*x-sigma*B*x).array().abs().maxCoeff();
+ if(err<conv)
+ {
+ break;
+ }
+ if(ray || err<tol)
+ {
+ eff_sigma = sigma;
+ ray = true;
+ }
+
+ Scalar tikhonov = std::abs(eff_sigma)<1e-12?1e-10:0;
+ switch(type)
+ {
+ default:
+ assert(false && "Not supported");
+ break;
+ case EIGS_TYPE_SM:
+ {
+ SimplicialLDLT<SparseMatrix<Scalar> > solver;
+ const SparseMatrix<Scalar> C = A-eff_sigma*B+tikhonov*B;
+ //mw.save(C,"C");
+ //mw.save(eff_sigma,"eff_sigma");
+ //mw.save(tikhonov,"tikhonov");
+ solver.compute(C);
+ switch(solver.info())
+ {
+ case Eigen::Success:
+ break;
+ case Eigen::NumericalIssue:
+ cerr<<"Error: Numerical issue."<<endl;
+ return false;
+ default:
+ cerr<<"Error: Other."<<endl;
+ return false;
+ }
+ const VectorXS rhs = B*x;
+ y = solver.solve(rhs);
+ //mw.save(rhs,"rhs");
+ //mw.save(y,"y");
+ //mw.save(x,"x");
+ //mw.write("eigs.mat");
+ //if(i == 1)
+ //return false;
+ break;
+ }
+ }
+ }
+ if(iter == max_iter)
+ {
+ cerr<<"Failed to converge."<<endl;
+ return false;
+ }
+ if(
+ i==0 ||
+ (S.head(i).array()-sigma).abs().maxCoeff()>1e-14 ||
+ ((U.leftCols(i).transpose()*B*x).array().abs()<=1e-7).all()
+ )
+ {
+ //cout<<"Found "<<i<<"th mode"<<endl;
+ U.col(i) = x;
+ S(i) = sigma;
+ i++;
+ if(i == k)
+ {
+ break;
+ }
+ }else
+ {
+ //std::cout<<"i: "<<i<<std::endl;
+ //std::cout<<" "<<S.head(i).transpose()<<" << "<<sigma<<std::endl;
+ //std::cout<<" "<<(S.head(i).array()-sigma).abs().maxCoeff()<<std::endl;
+ //std::cout<<" "<<(U.leftCols(i).transpose()*B*x).array().abs().transpose()<<std::endl;
+ // restart with new random guess.
+ cout<<"igl::eigs RESTART"<<endl;
+ }
+ }
+ // finally sort
+ VectorXi I;
+ igl::sort(S,1,false,sS,I);
+ igl::slice(U,I,2,sU);
+ sS /= rescale;
+ sU /= sqrt(rescale);
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::eigs<double, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int> const&, const size_t, igl::EigsType, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template bool igl::eigs<double, double, Eigen::Matrix<double,-1,-1,0,-1,-1>, Eigen::Matrix<double,-1,1,0,-1,1> >(Eigen::SparseMatrix<double,0,int> const &,Eigen::SparseMatrix<double,0,int> const &, const size_t, igl::EigsType, Eigen::PlainObjectBase< Eigen::Matrix<double,-1,-1,0,-1,-1> > &, Eigen::PlainObjectBase<Eigen::Matrix<double,-1,1,0,-1,1> > &);
+#endif
+#endif
diff --git a/xs/src/igl/eigs.h b/xs/src/igl/eigs.h
new file mode 100644
index 000000000..3b376379c
--- /dev/null
+++ b/xs/src/igl/eigs.h
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EIGS_H
+#define IGL_EIGS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Act like MATLAB's eigs function. Compute the first/last k eigen pairs of
+ // the generalized eigen value problem:
+ //
+ // A u = s B u
+ //
+ // Solutions are approximate and sorted.
+ //
+ // Ideally one should use ARPACK and the Eigen unsupported ARPACK module.
+ // This implementation does simple, naive power iterations.
+ //
+ // Inputs:
+ // A #A by #A symmetric matrix
+ // B #A by #A symmetric positive-definite matrix
+ // k number of eigen pairs to compute
+ // type whether to extract from the high or low end
+ // Outputs:
+ // sU #A by k list of sorted eigen vectors (descending)
+ // sS k list of sorted eigen values (descending)
+ //
+ // Known issues:
+ // - only the 'sm' small magnitude eigen values are well supported
+ //
+ enum EigsType
+ {
+ EIGS_TYPE_SM = 0,
+ EIGS_TYPE_LM = 1,
+ NUM_EIGS_TYPES = 2
+ };
+ template <
+ typename Atype,
+ typename Btype,
+ typename DerivedU,
+ typename DerivedS>
+ IGL_INLINE bool eigs(
+ const Eigen::SparseMatrix<Atype> & A,
+ const Eigen::SparseMatrix<Btype> & B,
+ const size_t k,
+ const EigsType type,
+ Eigen::PlainObjectBase<DerivedU> & sU,
+ Eigen::PlainObjectBase<DerivedS> & sS);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "eigs.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/embree/EmbreeIntersector.h b/xs/src/igl/embree/EmbreeIntersector.h
new file mode 100644
index 000000000..ec59c0a1a
--- /dev/null
+++ b/xs/src/igl/embree/EmbreeIntersector.h
@@ -0,0 +1,584 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+// 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+// igl function interface for Embree2.2
+//
+// Necessary changes to switch from previous Embree versions:
+// * Use igl:Hit instead of embree:Hit (where id0 -> id)
+// * For Embree2.2
+// * Uncomment #define __USE_RAY_MASK__ in platform.h to enable masking
+
+#ifndef IGL_EMBREE_EMBREE_INTERSECTOR_H
+#define IGL_EMBREE_EMBREE_INTERSECTOR_H
+
+#include "../Hit.h"
+#include <Eigen/Geometry>
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include "embree2/rtcore.h"
+#include "embree2/rtcore_ray.h"
+#include <iostream>
+#include <vector>
+
+namespace igl
+{
+ namespace embree
+ {
+ class EmbreeIntersector
+ {
+ public:
+ // Initialize embree engine. This will be called on instance `init()`
+ // calls. If already inited then this function does nothing: it is harmless
+ // to call more than once.
+ static inline void global_init();
+ private:
+ // Deinitialize the embree engine.
+ static inline void global_deinit();
+ public:
+ typedef Eigen::Matrix<float,Eigen::Dynamic,3> PointMatrixType;
+ typedef Eigen::Matrix<int,Eigen::Dynamic,3> FaceMatrixType;
+ public:
+ inline EmbreeIntersector();
+ private:
+ // Copying and assignment are not allowed.
+ inline EmbreeIntersector(const EmbreeIntersector & that);
+ inline EmbreeIntersector & operator=(const EmbreeIntersector &);
+ public:
+ virtual inline ~EmbreeIntersector();
+
+ // Initialize with a given mesh.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of Oriented triangles
+ // isStatic scene is optimized for static geometry
+ // Side effects:
+ // The first time this is ever called the embree engine is initialized.
+ inline void init(
+ const PointMatrixType& V,
+ const FaceMatrixType& F,
+ bool isStatic = false);
+
+ // Initialize with a given mesh.
+ //
+ // Inputs:
+ // V vector of #V by 3 list of vertex positions for each geometry
+ // F vector of #F by 3 list of Oriented triangles for each geometry
+ // masks a 32 bit mask to identify active geometries.
+ // isStatic scene is optimized for static geometry
+ // Side effects:
+ // The first time this is ever called the embree engine is initialized.
+ inline void init(
+ const std::vector<const PointMatrixType*>& V,
+ const std::vector<const FaceMatrixType*>& F,
+ const std::vector<int>& masks,
+ bool isStatic = false);
+
+ // Deinitialize embree datasctructures for current mesh. Also called on
+ // destruction: no need to call if you just want to init() once and
+ // destroy.
+ inline void deinit();
+
+ // Given a ray find the first hit
+ //
+ // Inputs:
+ // origin 3d origin point of ray
+ // direction 3d (not necessarily normalized) direction vector of ray
+ // tnear start of ray segment
+ // tfar end of ray segment
+ // masks a 32 bit mask to identify active geometries.
+ // Output:
+ // hit information about hit
+ // Returns true if and only if there was a hit
+ inline bool intersectRay(
+ const Eigen::RowVector3f& origin,
+ const Eigen::RowVector3f& direction,
+ Hit& hit,
+ float tnear = 0,
+ float tfar = std::numeric_limits<float>::infinity(),
+ int mask = 0xFFFFFFFF) const;
+
+ // Given a ray find the first hit
+ // This is a conservative hit test where multiple rays within a small radius
+ // will be tested and only the closesest hit is returned.
+ //
+ // Inputs:
+ // origin 3d origin point of ray
+ // direction 3d (not necessarily normalized) direction vector of ray
+ // tnear start of ray segment
+ // tfar end of ray segment
+ // masks a 32 bit mask to identify active geometries.
+ // geoId id of geometry mask (default std::numeric_limits<float>::infinity() if no: no masking)
+ // closestHit true for gets closest hit, false for furthest hit
+ // Output:
+ // hit information about hit
+ // Returns true if and only if there was a hit
+ inline bool intersectBeam(
+ const Eigen::RowVector3f& origin,
+ const Eigen::RowVector3f& direction,
+ Hit& hit,
+ float tnear = 0,
+ float tfar = std::numeric_limits<float>::infinity(),
+ int mask = 0xFFFFFFFF,
+ int geoId = -1,
+ bool closestHit = true,
+ unsigned int samples = 4) const;
+
+ // Given a ray find all hits in order
+ //
+ // Inputs:
+ // origin 3d origin point of ray
+ // direction 3d (not necessarily normalized) direction vector of ray
+ // tnear start of ray segment
+ // tfar end of ray segment
+ // masks a 32 bit mask to identify active geometries.
+ // Output:
+ // hit information about hit
+ // num_rays number of rays shot (at least one)
+ // Returns true if and only if there was a hit
+ inline bool intersectRay(
+ const Eigen::RowVector3f& origin,
+ const Eigen::RowVector3f& direction,
+ std::vector<Hit > &hits,
+ int& num_rays,
+ float tnear = 0,
+ float tfar = std::numeric_limits<float>::infinity(),
+ int mask = 0xFFFFFFFF) const;
+
+ // Given a ray find the first hit
+ //
+ // Inputs:
+ // a 3d first end point of segment
+ // ab 3d vector from a to other endpoint b
+ // Output:
+ // hit information about hit
+ // Returns true if and only if there was a hit
+ inline bool intersectSegment(
+ const Eigen::RowVector3f& a,
+ const Eigen::RowVector3f& ab,
+ Hit &hit,
+ int mask = 0xFFFFFFFF) const;
+
+ private:
+
+ struct Vertex {float x,y,z,a;};
+ struct Triangle {int v0, v1, v2;};
+
+ RTCScene scene;
+ unsigned geomID;
+ Vertex* vertices;
+ Triangle* triangles;
+ bool initialized;
+
+ inline void createRay(
+ RTCRay& ray,
+ const Eigen::RowVector3f& origin,
+ const Eigen::RowVector3f& direction,
+ float tnear,
+ float tfar,
+ int mask) const;
+ };
+ }
+}
+
+// Implementation
+#include <igl/EPS.h>
+// This unfortunately cannot be a static field of EmbreeIntersector because it
+// would depend on the template and then we might end up with initializing
+// embree twice. If only there was a way to ask embree if it's already
+// initialized...
+namespace igl
+{
+ namespace embree
+ {
+ // Keeps track of whether the **Global** Embree intersector has been
+ // initialized. This should never been done at the global scope.
+ static bool EmbreeIntersector_inited = false;
+ }
+}
+
+inline void igl::embree::EmbreeIntersector::global_init()
+{
+ if(!EmbreeIntersector_inited)
+ {
+ rtcInit();
+ if(rtcGetError() != RTC_NO_ERROR)
+ std::cerr << "Embree: An error occurred while initializing embree core!" << std::endl;
+#ifdef IGL_VERBOSE
+ else
+ std::cerr << "Embree: core initialized." << std::endl;
+#endif
+ EmbreeIntersector_inited = true;
+ }
+}
+
+inline void igl::embree::EmbreeIntersector::global_deinit()
+{
+ EmbreeIntersector_inited = false;
+ rtcExit();
+}
+
+inline igl::embree::EmbreeIntersector::EmbreeIntersector()
+ :
+ //scene(NULL),
+ geomID(0),
+ vertices(NULL),
+ triangles(NULL),
+ initialized(false)
+{
+}
+
+inline igl::embree::EmbreeIntersector::EmbreeIntersector(
+ const EmbreeIntersector &)
+ :// To make -Weffc++ happy
+ //scene(NULL),
+ geomID(0),
+ vertices(NULL),
+ triangles(NULL),
+ initialized(false)
+{
+ assert(false && "Embree: Copying EmbreeIntersector is not allowed");
+}
+
+inline igl::embree::EmbreeIntersector & igl::embree::EmbreeIntersector::operator=(
+ const EmbreeIntersector &)
+{
+ assert(false && "Embree: Assigning an EmbreeIntersector is not allowed");
+ return *this;
+}
+
+
+inline void igl::embree::EmbreeIntersector::init(
+ const PointMatrixType& V,
+ const FaceMatrixType& F,
+ bool isStatic)
+{
+ std::vector<const PointMatrixType*> Vtemp;
+ std::vector<const FaceMatrixType*> Ftemp;
+ std::vector<int> masks;
+ Vtemp.push_back(&V);
+ Ftemp.push_back(&F);
+ masks.push_back(0xFFFFFFFF);
+ init(Vtemp,Ftemp,masks,isStatic);
+}
+
+inline void igl::embree::EmbreeIntersector::init(
+ const std::vector<const PointMatrixType*>& V,
+ const std::vector<const FaceMatrixType*>& F,
+ const std::vector<int>& masks,
+ bool isStatic)
+{
+
+ if(initialized)
+ deinit();
+
+ using namespace std;
+ global_init();
+
+ if(V.size() == 0 || F.size() == 0)
+ {
+ std::cerr << "Embree: No geometry specified!";
+ return;
+ }
+
+ // create a scene
+ RTCSceneFlags flags = RTC_SCENE_ROBUST | RTC_SCENE_HIGH_QUALITY;
+ if(isStatic)
+ flags = flags | RTC_SCENE_STATIC;
+ scene = rtcNewScene(flags,RTC_INTERSECT1);
+
+ for(int g=0;g<(int)V.size();g++)
+ {
+ // create triangle mesh geometry in that scene
+ geomID = rtcNewTriangleMesh(scene,RTC_GEOMETRY_STATIC,F[g]->rows(),V[g]->rows(),1);
+
+ // fill vertex buffer
+ vertices = (Vertex*)rtcMapBuffer(scene,geomID,RTC_VERTEX_BUFFER);
+ for(int i=0;i<(int)V[g]->rows();i++)
+ {
+ vertices[i].x = (float)V[g]->coeff(i,0);
+ vertices[i].y = (float)V[g]->coeff(i,1);
+ vertices[i].z = (float)V[g]->coeff(i,2);
+ }
+ rtcUnmapBuffer(scene,geomID,RTC_VERTEX_BUFFER);
+
+ // fill triangle buffer
+ triangles = (Triangle*) rtcMapBuffer(scene,geomID,RTC_INDEX_BUFFER);
+ for(int i=0;i<(int)F[g]->rows();i++)
+ {
+ triangles[i].v0 = (int)F[g]->coeff(i,0);
+ triangles[i].v1 = (int)F[g]->coeff(i,1);
+ triangles[i].v2 = (int)F[g]->coeff(i,2);
+ }
+ rtcUnmapBuffer(scene,geomID,RTC_INDEX_BUFFER);
+
+ rtcSetMask(scene,geomID,masks[g]);
+ }
+
+ rtcCommit(scene);
+
+ if(rtcGetError() != RTC_NO_ERROR)
+ std::cerr << "Embree: An error occurred while initializing the provided geometry!" << endl;
+#ifdef IGL_VERBOSE
+ else
+ std::cerr << "Embree: geometry added." << endl;
+#endif
+
+ initialized = true;
+}
+
+igl::embree::EmbreeIntersector
+::~EmbreeIntersector()
+{
+ if(initialized)
+ deinit();
+}
+
+void igl::embree::EmbreeIntersector::deinit()
+{
+ if(EmbreeIntersector_inited && scene)
+ {
+ rtcDeleteScene(scene);
+
+ if(rtcGetError() != RTC_NO_ERROR)
+ {
+ std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+ }
+#ifdef IGL_VERBOSE
+ else
+ {
+ std::cerr << "Embree: geometry removed." << std::endl;
+ }
+#endif
+ }
+}
+
+inline bool igl::embree::EmbreeIntersector::intersectRay(
+ const Eigen::RowVector3f& origin,
+ const Eigen::RowVector3f& direction,
+ Hit& hit,
+ float tnear,
+ float tfar,
+ int mask) const
+{
+ RTCRay ray;
+ createRay(ray, origin,direction,tnear,tfar,mask);
+
+ // shot ray
+ rtcIntersect(scene,ray);
+#ifdef IGL_VERBOSE
+ if(rtcGetError() != RTC_NO_ERROR)
+ std::cerr << "Embree: An error occurred while resetting!" << std::endl;
+#endif
+
+ if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
+ {
+ hit.id = ray.primID;
+ hit.gid = ray.geomID;
+ hit.u = ray.u;
+ hit.v = ray.v;
+ hit.t = ray.tfar;
+ return true;
+ }
+
+ return false;
+}
+
+inline bool igl::embree::EmbreeIntersector::intersectBeam(
+ const Eigen::RowVector3f& origin,
+ const Eigen::RowVector3f& direction,
+ Hit& hit,
+ float tnear,
+ float tfar,
+ int mask,
+ int geoId,
+ bool closestHit,
+ unsigned int samples) const
+{
+ bool hasHit = false;
+ Hit bestHit;
+
+ if(closestHit)
+ bestHit.t = std::numeric_limits<float>::max();
+ else
+ bestHit.t = 0;
+
+ if((intersectRay(origin,direction,hit,tnear,tfar,mask) && (hit.gid == geoId || geoId == -1)))
+ {
+ bestHit = hit;
+ hasHit = true;
+ }
+
+ // sample points around actual ray (conservative hitcheck)
+ const float eps= 1e-5;
+
+ Eigen::RowVector3f up(0,1,0);
+ Eigen::RowVector3f offset = direction.cross(up).normalized();
+
+ Eigen::Matrix3f rot = Eigen::AngleAxis<float>(2*3.14159265358979/samples,direction).toRotationMatrix();
+
+ for(int r=0;r<(int)samples;r++)
+ {
+ if(intersectRay(origin+offset*eps,direction,hit,tnear,tfar,mask) &&
+ ((closestHit && (hit.t < bestHit.t)) ||
+ (!closestHit && (hit.t > bestHit.t))) &&
+ (hit.gid == geoId || geoId == -1))
+ {
+ bestHit = hit;
+ hasHit = true;
+ }
+ offset = rot*offset.transpose();
+ }
+
+ hit = bestHit;
+ return hasHit;
+}
+
+inline bool
+igl::embree::EmbreeIntersector
+::intersectRay(
+ const Eigen::RowVector3f& origin,
+ const Eigen::RowVector3f& direction,
+ std::vector<Hit > &hits,
+ int& num_rays,
+ float tnear,
+ float tfar,
+ int mask) const
+{
+ using namespace std;
+ num_rays = 0;
+ hits.clear();
+ int last_id0 = -1;
+ double self_hits = 0;
+ // This epsilon is directly correleated to the number of missed hits, smaller
+ // means more accurate and slower
+ //const double eps = DOUBLE_EPS;
+ const double eps = FLOAT_EPS;
+ double min_t = tnear;
+ bool large_hits_warned = false;
+ RTCRay ray;
+ createRay(ray,origin,direction,tnear,tfar,mask);
+
+ while(true)
+ {
+ ray.tnear = min_t;
+ ray.tfar = tfar;
+ ray.geomID = RTC_INVALID_GEOMETRY_ID;
+ ray.primID = RTC_INVALID_GEOMETRY_ID;
+ ray.instID = RTC_INVALID_GEOMETRY_ID;
+ num_rays++;
+ rtcIntersect(scene,ray);
+ if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
+ {
+ // Hit self again, progressively advance
+ if(ray.primID == last_id0 || ray.tfar <= min_t)
+ {
+ // push min_t a bit more
+ //double t_push = pow(2.0,self_hits-4)*(hit.t<eps?eps:hit.t);
+ double t_push = pow(2.0,self_hits)*eps;
+ #ifdef IGL_VERBOSE
+ std::cerr<<" t_push: "<<t_push<<endl;
+ #endif
+ //o = o+t_push*d;
+ min_t += t_push;
+ self_hits++;
+ }
+ else
+ {
+ Hit hit;
+ hit.id = ray.primID;
+ hit.gid = ray.geomID;
+ hit.u = ray.u;
+ hit.v = ray.v;
+ hit.t = ray.tfar;
+ hits.push_back(hit);
+#ifdef IGL_VERBOSE
+ std::cerr<<" t: "<<hit.t<<endl;
+#endif
+ // Instead of moving origin, just change min_t. That way calculations
+ // all use exactly same origin values
+ min_t = ray.tfar;
+
+ // reset t_scale
+ self_hits = 0;
+ }
+ last_id0 = ray.primID;
+ }
+ else
+ break; // no more hits
+
+ if(hits.size()>1000 && !large_hits_warned)
+ {
+ std::cout<<"Warning: Large number of hits..."<<endl;
+ std::cout<<"[ ";
+ for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end();hit++)
+ {
+ std::cout<<(hit->id+1)<<" ";
+ }
+
+ std::cout.precision(std::numeric_limits< double >::digits10);
+ std::cout<<"[ ";
+
+ for(vector<Hit>::iterator hit = hits.begin(); hit != hits.end(); hit++)
+ {
+ std::cout<<(hit->t)<<endl;;
+ }
+
+ std::cout<<"]"<<endl;
+ large_hits_warned = true;
+
+ return hits.empty();
+ }
+ }
+
+ return hits.empty();
+}
+
+inline bool
+igl::embree::EmbreeIntersector
+::intersectSegment(const Eigen::RowVector3f& a, const Eigen::RowVector3f& ab, Hit &hit, int mask) const
+{
+ RTCRay ray;
+ createRay(ray,a,ab,0,1.0,mask);
+
+ rtcIntersect(scene,ray);
+
+ if((unsigned)ray.geomID != RTC_INVALID_GEOMETRY_ID)
+ {
+ hit.id = ray.primID;
+ hit.gid = ray.geomID;
+ hit.u = ray.u;
+ hit.v = ray.v;
+ hit.t = ray.tfar;
+ return true;
+ }
+
+ return false;
+}
+
+inline void
+igl::embree::EmbreeIntersector
+::createRay(RTCRay& ray, const Eigen::RowVector3f& origin, const Eigen::RowVector3f& direction, float tnear, float tfar, int mask) const
+{
+ ray.org[0] = origin[0];
+ ray.org[1] = origin[1];
+ ray.org[2] = origin[2];
+ ray.dir[0] = direction[0];
+ ray.dir[1] = direction[1];
+ ray.dir[2] = direction[2];
+ ray.tnear = tnear;
+ ray.tfar = tfar;
+ ray.geomID = RTC_INVALID_GEOMETRY_ID;
+ ray.primID = RTC_INVALID_GEOMETRY_ID;
+ ray.instID = RTC_INVALID_GEOMETRY_ID;
+ ray.mask = mask;
+ ray.time = 0.0f;
+}
+
+#endif //EMBREE_INTERSECTOR_H
diff --git a/xs/src/igl/embree/Embree_convenience.h b/xs/src/igl/embree/Embree_convenience.h
new file mode 100644
index 000000000..d654fb786
--- /dev/null
+++ b/xs/src/igl/embree/Embree_convenience.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_EMBREE_CONVENIENCE_H
+#define IGL_EMBREE_EMBREE_CONVENIENCE_H
+
+#undef interface
+#undef near
+#undef far
+// Why are these in quotes? isn't that a bad idea?
+#ifdef __GNUC__
+// This is how it should be done
+# if __GNUC__ >= 4
+# if __GNUC_MINOR__ >= 6
+# pragma GCC diagnostic push
+# pragma GCC diagnostic ignored "-Weffc++"
+# endif
+# endif
+// This is a hack
+# pragma GCC system_header
+#endif
+#include <embree/include/embree.h>
+#include <embree/include/intersector1.h>
+#include <embree/common/ray.h>
+#ifdef __GNUC__
+# if __GNUC__ >= 4
+# if __GNUC_MINOR__ >= 6
+# pragma GCC diagnostic pop
+# endif
+# endif
+#endif
+
+#endif
diff --git a/xs/src/igl/embree/ambient_occlusion.cpp b/xs/src/igl/embree/ambient_occlusion.cpp
new file mode 100644
index 000000000..d19aa9c46
--- /dev/null
+++ b/xs/src/igl/embree/ambient_occlusion.cpp
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ambient_occlusion.h"
+#include "../ambient_occlusion.h"
+#include "EmbreeIntersector.h"
+#include "../Hit.h"
+
+template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::embree::ambient_occlusion(
+ const igl::embree::EmbreeIntersector & ei,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ const auto & shoot_ray = [&ei](
+ const Eigen::Vector3f& s,
+ const Eigen::Vector3f& dir)->bool
+ {
+ igl::Hit hit;
+ const float tnear = 1e-4f;
+ return ei.intersectRay(s,dir,hit,tnear);
+ };
+ return igl::ambient_occlusion(shoot_ray,P,N,num_samples,S);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::embree::ambient_occlusion(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ using namespace Eigen;
+ EmbreeIntersector ei;
+ ei.init(V.template cast<float>(),F.template cast<int>());
+ ambient_occlusion(ei,P,N,num_samples,S);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::embree::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::ambient_occlusion<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::ambient_occlusion<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::ambient_occlusion<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/embree/ambient_occlusion.h b/xs/src/igl/embree/ambient_occlusion.h
new file mode 100644
index 000000000..6df3a53ee
--- /dev/null
+++ b/xs/src/igl/embree/ambient_occlusion.h
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_AMBIENT_OCCLUSION_H
+#define IGL_EMBREE_AMBIENT_OCCLUSION_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace embree
+ {
+ // Forward define
+ class EmbreeIntersector;
+ // Compute ambient occlusion per given point
+ //
+ // Inputs:
+ // ei EmbreeIntersector containing (V,F)
+ // 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)
+ //
+ template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void ambient_occlusion(
+ const EmbreeIntersector & ei,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ // Wrapper which builds new EmbreeIntersector for (V,F). That's expensive so
+ // avoid this if repeatedly calling.
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void ambient_occlusion(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ }
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "ambient_occlusion.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/embree/bone_heat.cpp b/xs/src/igl/embree/bone_heat.cpp
new file mode 100644
index 000000000..8a85af98c
--- /dev/null
+++ b/xs/src/igl/embree/bone_heat.cpp
@@ -0,0 +1,116 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bone_heat.h"
+#include "EmbreeIntersector.h"
+#include "bone_visible.h"
+#include "../project_to_line_segment.h"
+#include "../cotmatrix.h"
+#include "../massmatrix.h"
+#include "../mat_min.h"
+#include <Eigen/Sparse>
+
+bool igl::embree::bone_heat(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & C,
+ const Eigen::VectorXi & P,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXi & CE,
+ Eigen::MatrixXd & W)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(CE.rows() == 0 && "Cage edges not supported.");
+ assert(C.cols() == V.cols() && "V and C should have same #cols");
+ assert(BE.cols() == 2 && "BE should have #cols=2");
+ assert(F.cols() == 3 && "F should contain triangles.");
+ assert(V.cols() == 3 && "V should contain 3D positions.");
+
+ const int n = V.rows();
+ const int np = P.rows();
+ const int nb = BE.rows();
+ const int m = np + nb;
+
+ // "double sided lighting"
+ MatrixXi FF;
+ FF.resize(F.rows()*2,F.cols());
+ FF << F, F.rowwise().reverse();
+ // Initialize intersector
+ EmbreeIntersector ei;
+ ei.init(V.cast<float>(),F.cast<int>());
+
+ typedef Matrix<bool,Dynamic,1> VectorXb;
+ typedef Matrix<bool,Dynamic,Dynamic> MatrixXb;
+ MatrixXb vis_mask(n,m);
+ // Distances
+ MatrixXd D(n,m);
+ // loop over points
+ for(int j = 0;j<np;j++)
+ {
+ const Vector3d p = C.row(P(j));
+ D.col(j) = (V.rowwise()-p.transpose()).rowwise().norm();
+ VectorXb vj;
+ bone_visible(V,F,ei,p,p,vj);
+ vis_mask.col(j) = vj;
+ }
+
+ // loop over bones
+ for(int j = 0;j<nb;j++)
+ {
+ const Vector3d s = C.row(BE(j,0));
+ const Vector3d d = C.row(BE(j,1));
+ VectorXd t,sqrD;
+ project_to_line_segment(V,s,d,t,sqrD);
+ D.col(np+j) = sqrD.array().sqrt();
+ VectorXb vj;
+ bone_visible(V,F,ei,s,d,vj);
+ vis_mask.col(np+j) = vj;
+ }
+
+ if(CE.rows() > 0)
+ {
+ cerr<<"Error: Cage edges are not supported. Ignored."<<endl;
+ }
+
+ MatrixXd PP = MatrixXd::Zero(n,m);
+ VectorXd min_D;
+ VectorXd Hdiag = VectorXd::Zero(n);
+ VectorXi J;
+ mat_min(D,2,min_D,J);
+ for(int i = 0;i<n;i++)
+ {
+ PP(i,J(i)) = 1;
+ if(vis_mask(i,J(i)))
+ {
+ double hii = pow(min_D(i),-2.);
+ Hdiag(i) = (hii>1e10?1e10:hii);
+ }
+ }
+ SparseMatrix<double> Q,L,M;
+ cotmatrix(V,F,L);
+ massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
+ const auto & H = Hdiag.asDiagonal();
+ Q = (-L+M*H);
+ SimplicialLLT <SparseMatrix<double > > llt;
+ llt.compute(Q);
+ switch(llt.info())
+ {
+ case Eigen::Success:
+ break;
+ case Eigen::NumericalIssue:
+ cerr<<"Error: Numerical issue."<<endl;
+ return false;
+ default:
+ cerr<<"Error: Other."<<endl;
+ return false;
+ }
+
+ const auto & rhs = M*H*PP;
+ W = llt.solve(rhs);
+ return true;
+}
diff --git a/xs/src/igl/embree/bone_heat.h b/xs/src/igl/embree/bone_heat.h
new file mode 100644
index 000000000..97c6500eb
--- /dev/null
+++ b/xs/src/igl/embree/bone_heat.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_BONE_HEAT_H
+#define IGL_EMBREE_BONE_HEAT_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace embree
+ {
+ // BONE_HEAT Compute skinning weights W given a surface mesh (V,F) and an
+ // internal skeleton (C,BE) according to "Automatic Rigging" [Baran and
+ // Popovic 2007].
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of mesh corner indices into V
+ // C #C by 3 list of joint locations
+ // P #P 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:
+ // W #V by #P+#BE matrix of weights.
+ // Returns true only on success.
+ //
+ IGL_INLINE bool bone_heat(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & C,
+ const Eigen::VectorXi & P,
+ const Eigen::MatrixXi & BE,
+ const Eigen::MatrixXi & CE,
+ Eigen::MatrixXd & W);
+ }
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "bone_heat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/embree/bone_visible.cpp b/xs/src/igl/embree/bone_visible.cpp
new file mode 100644
index 000000000..4f2fe9126
--- /dev/null
+++ b/xs/src/igl/embree/bone_visible.cpp
@@ -0,0 +1,145 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bone_visible.h"
+#include "../project_to_line.h"
+#include "../EPS.h"
+#include "../Hit.h"
+#include "../Timer.h"
+#include <iostream>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedSD,
+ typename Derivedflag>
+IGL_INLINE void igl::embree::bone_visible(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedSD> & s,
+ const Eigen::PlainObjectBase<DerivedSD> & d,
+ Eigen::PlainObjectBase<Derivedflag> & flag)
+{
+ // "double sided lighting"
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic> FF;
+ FF.resize(F.rows()*2,F.cols());
+ FF << F, F.rowwise().reverse();
+ // Initialize intersector
+ EmbreeIntersector ei;
+ ei.init(V.template cast<float>(),FF.template cast<int>());
+ return bone_visible(V,F,ei,s,d,flag);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedSD,
+ typename Derivedflag>
+IGL_INLINE void igl::embree::bone_visible(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const EmbreeIntersector & ei,
+ const Eigen::PlainObjectBase<DerivedSD> & s,
+ const Eigen::PlainObjectBase<DerivedSD> & d,
+ Eigen::PlainObjectBase<Derivedflag> & flag)
+{
+ using namespace std;
+ using namespace Eigen;
+ flag.resize(V.rows());
+ const double sd_norm = (s-d).norm();
+ // Embree seems to be parallel when constructing but not when tracing rays
+#pragma omp parallel for
+ // loop over mesh vertices
+ for(int v = 0;v<V.rows();v++)
+ {
+ const Vector3d Vv = V.row(v);
+ // Project vertex v onto line segment sd
+ //embree.intersectSegment
+ double t,sqrd;
+ Vector3d projv;
+ // degenerate bone, just snap to s
+ if(sd_norm < DOUBLE_EPS)
+ {
+ t = 0;
+ sqrd = (Vv-s).array().pow(2).sum();
+ projv = s;
+ }else
+ {
+ // project onto (infinite) line
+ project_to_line(
+ Vv(0),Vv(1),Vv(2),s(0),s(1),s(2),d(0),d(1),d(2),
+ projv(0),projv(1),projv(2),t,sqrd);
+ // handle projections past endpoints
+ if(t<0)
+ {
+ t = 0;
+ sqrd = (Vv-s).array().pow(2).sum();
+ projv = s;
+ } else if(t>1)
+ {
+ t = 1;
+ sqrd = (Vv-d).array().pow(2).sum();
+ projv = d;
+ }
+ }
+ igl::Hit hit;
+ // perhaps 1.0 should be 1.0-epsilon, or actually since we checking the
+ // incident face, perhaps 1.0 should be 1.0+eps
+ const Vector3d dir = (Vv-projv)*1.0;
+ if(ei.intersectSegment(
+ projv.template cast<float>(),
+ dir.template cast<float>(),
+ hit))
+ {
+ // mod for double sided lighting
+ const int fi = hit.id % F.rows();
+
+ //if(v == 1228-1)
+ //{
+ // Vector3d bc,P;
+ // bc << 1 - hit.u - hit.v, hit.u, hit.v; // barycentric
+ // P = V.row(F(fi,0))*bc(0) +
+ // V.row(F(fi,1))*bc(1) +
+ // V.row(F(fi,2))*bc(2);
+ // cout<<(fi+1)<<endl;
+ // cout<<bc.transpose()<<endl;
+ // cout<<P.transpose()<<endl;
+ // cout<<hit.t<<endl;
+ // cout<<(projv + dir*hit.t).transpose()<<endl;
+ // cout<<Vv.transpose()<<endl;
+ //}
+
+ // Assume hit is valid, so not visible
+ flag(v) = false;
+ // loop around corners of triangle
+ for(int c = 0;c<F.cols();c++)
+ {
+ if(F(fi,c) == v)
+ {
+ // hit self, so no hits before, so vertex v is visible
+ flag(v) = true;
+ break;
+ }
+ }
+ // Hit is actually past v
+ if(!flag(v) && (hit.t*hit.t*dir.squaredNorm())>sqrd)
+ {
+ flag(v) = true;
+ }
+ }else
+ {
+ // no hit so vectex v is visible
+ flag(v) = true;
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::embree::bone_visible<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
+template void igl::embree::bone_visible<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/embree/bone_visible.h b/xs/src/igl/embree/bone_visible.h
new file mode 100644
index 000000000..1e490b51d
--- /dev/null
+++ b/xs/src/igl/embree/bone_visible.h
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_BONE_VISIBLE_H
+#define IGL_EMBREE_BONE_VISIBLE_H
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+#include "EmbreeIntersector.h"
+namespace igl
+{
+ namespace embree
+ {
+ //
+ // BONE_VISIBLE test whether vertices of mesh are "visible" to a given bone,
+ // where "visible" is defined as in [Baran & Popovic 07]. Instead of checking
+ // whether each point can see *any* of the bone, we just check if each point
+ // can see its own projection onto the bone segment. In other words, we project
+ // each vertex v onto the bone, projv. Then we check if there are any
+ // intersections between the line segment (projv-->v) and the mesh.
+ //
+ // [flag] = bone_visible(V,F,s,d);
+ //
+ // Input:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // s row vector of position of start end point of bone
+ // d row vector of position of dest end point of bone
+ // Output:
+ // flag #V by 1 list of bools (true) visible, (false) obstructed
+ //
+ // Note: This checks for hits along the segment which are facing in *any*
+ // direction from the ray.
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedSD,
+ typename Derivedflag>
+ IGL_INLINE void bone_visible(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedSD> & s,
+ const Eigen::PlainObjectBase<DerivedSD> & d,
+ Eigen::PlainObjectBase<Derivedflag> & flag);
+ // Inputs:
+ // ei EmbreeIntersector for mesh (V,F) should be double sided
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedSD,
+ typename Derivedflag>
+ IGL_INLINE void bone_visible(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const EmbreeIntersector & ei,
+ const Eigen::PlainObjectBase<DerivedSD> & s,
+ const Eigen::PlainObjectBase<DerivedSD> & d,
+ Eigen::PlainObjectBase<Derivedflag> & flag);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "bone_visible.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore.h b/xs/src/igl/embree/embree2/rtcore.h
new file mode 100644
index 000000000..fb24757a9
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore.h
@@ -0,0 +1,257 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_H__
+#define __RTCORE_H__
+
+#include <stddef.h>
+#include <sys/types.h>
+
+#if defined(_WIN32)
+#if defined(_M_X64)
+typedef long long ssize_t;
+#else
+typedef int ssize_t;
+#endif
+#endif
+
+#ifndef RTCORE_API
+#if defined(_WIN32) && !defined(ENABLE_STATIC_LIB)
+# define RTCORE_API extern "C" __declspec(dllimport)
+#else
+# define RTCORE_API extern "C"
+#endif
+#endif
+
+#ifdef _WIN32
+# define RTCORE_ALIGN(...) __declspec(align(__VA_ARGS__))
+#else
+# define RTCORE_ALIGN(...) __attribute__((aligned(__VA_ARGS__)))
+#endif
+
+#ifdef __GNUC__
+ #define RTCORE_DEPRECATED __attribute__((deprecated))
+#elif defined(_MSC_VER)
+ #define RTCORE_DEPRECATED __declspec(deprecated)
+#else
+ #define RTCORE_DEPRECATED
+#endif
+
+/*! Embree API version */
+#define RTCORE_VERSION_MAJOR 2
+#define RTCORE_VERSION_MINOR 9
+#define RTCORE_VERSION_PATCH 0
+#define RTCORE_VERSION 20900
+
+/*! \file rtcore.h Defines the Embree Ray Tracing Kernel API for C and C++
+
+ This file defines the Embree ray tracing kernel API for C and
+ C++. The user is supposed to include this file, and alternatively
+ the rtcore_ray.h file, but none of the other .h files in this
+ folder. */
+
+/*! \{ */
+
+/*! Axis aligned bounding box representation */
+struct RTCORE_ALIGN(16) RTCBounds
+{
+ float lower_x, lower_y, lower_z, align0;
+ float upper_x, upper_y, upper_z, align1;
+};
+
+/*! \brief Defines an opaque device type */
+typedef struct __RTCDevice {}* RTCDevice;
+
+/*! \brief Creates a new Embree device.
+
+ Creates a new Embree device to be used by the application. An
+ application typically creates only a single Embree device, but it is
+ valid to use multiple devices inside an application. A configuration
+ string can be passed at construction time, that allows to configure
+ implementation specific parameters. If this string is NULL, a
+ default configuration is used. The following configuration flags are
+ supported by the Embree implementation of the API:
+
+ verbose = num, // sets verbosity level (default is 0)
+
+ If Embree is started on an unsupported CPU, rtcNewDevice will fail and
+ set the RTC_UNSUPPORTED_CPU error code.
+
+*/
+RTCORE_API RTCDevice rtcNewDevice(const char* cfg = NULL);
+
+/*! \brief Deletes an Embree device.
+
+ Deletes the Embree device again. After deletion, all scene handles
+ are invalid. The application should invoke this call before
+ terminating. */
+RTCORE_API void rtcDeleteDevice(RTCDevice device);
+
+/*! \brief Initializes the Embree ray tracing core
+
+ WARNING: This function is deprecated, use rtcNewDevice instead.
+
+ Initializes the ray tracing core and passed some configuration
+ string. The configuration string allows to configure implementation
+ specific parameters. If this string is NULL, a default configuration
+ is used. The following configuration flags are supported by the
+ Embree implementation of the API:
+
+ verbose = num, // sets verbosity level (default is 0)
+
+ If Embree is started on an unsupported CPU, rtcInit will fail and
+ set the RTC_UNSUPPORTED_CPU error code.
+
+*/
+RTCORE_API RTCORE_DEPRECATED void rtcInit(const char* cfg = NULL);
+
+/*! \brief Shuts down Embree
+
+ WARNING: This function is deprecated, use rtcDeleteDevice instead.
+
+ Shuts down the ray tracing core. After shutdown, all scene handles
+ are invalid, and invoking any API call except rtcInit is not
+ allowed. The application should invoke this call before
+ terminating. It is safe to call rtcInit again after an rtcExit
+ call. */
+RTCORE_API RTCORE_DEPRECATED void rtcExit();
+
+/*! \brief Parameters that can get configured using the rtcSetParameter functions. */
+enum RTCParameter {
+ RTC_SOFTWARE_CACHE_SIZE = 0, /*! Configures the software cache size (used
+ to cache subdivision surfaces for
+ instance). The size is specified as an
+ integer number of bytes. The software
+ cache cannot be configured during
+ rendering. (write only) */
+
+ RTC_CONFIG_INTERSECT1 = 1, //!< checks if rtcIntersect1 is supported (read only)
+ RTC_CONFIG_INTERSECT4 = 2, //!< checks if rtcIntersect4 is supported (read only)
+ RTC_CONFIG_INTERSECT8 = 3, //!< checks if rtcIntersect8 is supported (read only)
+ RTC_CONFIG_INTERSECT16 = 4, //!< checks if rtcIntersect16 is supported (read only)
+ RTC_CONFIG_INTERSECTN = 5, //!< checks if rtcIntersectN is supported (read only)
+
+ RTC_CONFIG_RAY_MASK = 6, //!< checks if ray masks are supported (read only)
+ RTC_CONFIG_BACKFACE_CULLING = 7, //!< checks if backface culling is supported (read only)
+ RTC_CONFIG_INTERSECTION_FILTER = 8, //!< checks if intersection filters are enabled (read only)
+ RTC_CONFIG_INTERSECTION_FILTER_RESTORE = 9, //!< checks if intersection filters restores previous hit (read only)
+ RTC_CONFIG_BUFFER_STRIDE = 10, //!< checks if buffer strides are supported (read only)
+ RTC_CONFIG_IGNORE_INVALID_RAYS = 11, //!< checks if invalid rays are ignored (read only)
+ RTC_CONFIG_TASKING_SYSTEM = 12, //!< return used tasking system (0 = INTERNAL, 1 = TBB) (read only)
+
+ RTC_CONFIG_VERSION_MAJOR = 13, //!< returns Embree major version (read only)
+ RTC_CONFIG_VERSION_MINOR = 14, //!< returns Embree minor version (read only)
+ RTC_CONFIG_VERSION_PATCH = 15, //!< returns Embree patch version (read only)
+ RTC_CONFIG_VERSION = 16, //!< returns Embree version as integer (e.g. Embree v2.8.2 -> 20802) (read only)
+};
+
+/*! \brief Configures some parameters.
+ WARNING: This function is deprecated, use rtcDeviceSetParameter1i instead.
+*/
+RTCORE_API RTCORE_DEPRECATED void rtcSetParameter1i(const RTCParameter parm, ssize_t val);
+
+/*! \brief Reads some device parameter.
+ WARNING: This function is deprecated, use rtcDeviceGetParameter1i instead.
+*/
+RTCORE_API RTCORE_DEPRECATED ssize_t rtcGetParameter1i(const RTCParameter parm);
+
+/*! \brief Configures some device parameters. */
+RTCORE_API void rtcDeviceSetParameter1i(RTCDevice device, const RTCParameter parm, ssize_t val);
+
+/*! \brief Reads some device parameter. */
+RTCORE_API ssize_t rtcDeviceGetParameter1i(RTCDevice device, const RTCParameter parm);
+
+/*! \brief Error codes returned by the rtcGetError function. */
+enum RTCError {
+ RTC_NO_ERROR = 0, //!< No error has been recorded.
+ RTC_UNKNOWN_ERROR = 1, //!< An unknown error has occured.
+ RTC_INVALID_ARGUMENT = 2, //!< An invalid argument is specified
+ RTC_INVALID_OPERATION = 3, //!< The operation is not allowed for the specified object.
+ RTC_OUT_OF_MEMORY = 4, //!< There is not enough memory left to execute the command.
+ RTC_UNSUPPORTED_CPU = 5, //!< The CPU is not supported as it does not support SSE2.
+ RTC_CANCELLED = 6, //!< The user has cancelled the operation through the RTC_PROGRESS_MONITOR_FUNCTION callback
+};
+
+/*! \brief Returns the value of the per-thread error flag.
+
+ WARNING: This function is deprecated, use rtcDeviceGetError instead.
+
+ If an error occurs this flag is set to an error code if it stores no
+ previous error. The rtcGetError function reads and returns the
+ currently stored error and clears the error flag again. */
+RTCORE_API RTCORE_DEPRECATED RTCError rtcGetError();
+
+/*! \brief Returns the value of the per-thread error flag.
+
+ If an error occurs this flag is set to an error code if it stores no
+ previous error. The rtcGetError function reads and returns the
+ currently stored error and clears the error flag again. */
+RTCORE_API RTCError rtcDeviceGetError(RTCDevice device);
+
+/*! \brief Type of error callback function. */
+typedef void (*RTCErrorFunc)(const RTCError code, const char* str);
+RTCORE_DEPRECATED typedef RTCErrorFunc RTC_ERROR_FUNCTION;
+
+/*! \brief Sets a callback function that is called whenever an error occurs.
+ WARNING: This function is deprecated, use rtcDeviceSetErrorFunction instead.
+ */
+RTCORE_API RTCORE_DEPRECATED void rtcSetErrorFunction(RTCErrorFunc func);
+
+/*! \brief Sets a callback function that is called whenever an error occurs. */
+RTCORE_API void rtcDeviceSetErrorFunction(RTCDevice device, RTCErrorFunc func);
+
+/*! \brief Type of memory consumption callback function. */
+typedef bool (*RTCMemoryMonitorFunc)(const ssize_t bytes, const bool post);
+RTCORE_DEPRECATED typedef RTCMemoryMonitorFunc RTC_MEMORY_MONITOR_FUNCTION;
+
+/*! \brief Sets the memory consumption callback function which is
+ * called before or after the library allocates or frees memory.
+ WARNING: This function is deprecated, use rtcDeviceSetMemoryMonitorFunction instead.
+*/
+RTCORE_API RTCORE_DEPRECATED void rtcSetMemoryMonitorFunction(RTCMemoryMonitorFunc func);
+
+/*! \brief Sets the memory consumption callback function which is
+ * called before or after the library allocates or frees memory. */
+RTCORE_API void rtcDeviceSetMemoryMonitorFunction(RTCDevice device, RTCMemoryMonitorFunc func);
+
+/*! \brief Implementation specific (do not call).
+
+ This function is implementation specific and only for debugging
+ purposes. Do not call it. */
+RTCORE_API RTCORE_DEPRECATED void rtcDebug(); // FIXME: remove
+
+#include "rtcore_scene.h"
+#include "rtcore_geometry.h"
+#include "rtcore_geometry_user.h"
+
+/*! \brief Helper to easily combing scene flags */
+inline RTCSceneFlags operator|(const RTCSceneFlags a, const RTCSceneFlags b) {
+ return (RTCSceneFlags)((size_t)a | (size_t)b);
+}
+
+/*! \brief Helper to easily combing algorithm flags */
+inline RTCAlgorithmFlags operator|(const RTCAlgorithmFlags a, const RTCAlgorithmFlags b) {
+ return (RTCAlgorithmFlags)((size_t)a | (size_t)b);
+}
+
+/*! \brief Helper to easily combing geometry flags */
+inline RTCGeometryFlags operator|(const RTCGeometryFlags a, const RTCGeometryFlags b) {
+ return (RTCGeometryFlags)((size_t)a | (size_t)b);
+}
+
+/*! \} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore.isph b/xs/src/igl/embree/embree2/rtcore.isph
new file mode 100644
index 000000000..f46f05252
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore.isph
@@ -0,0 +1,220 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_ISPH__
+#define __RTCORE_ISPH__
+
+#ifdef _WIN32
+# define RTCORE_ALIGN(...) // FIXME: need to specify alignment
+#else
+# define RTCORE_ALIGN(...) // FIXME: need to specify alignment
+#endif
+
+#define RTCORE_DEPRECATED // FIXME: deprecation not supported by ISPC
+
+/*! Embree API version */
+#define RTCORE_VERSION_MAJOR 2
+#define RTCORE_VERSION_MINOR 9
+#define RTCORE_VERSION_PATCH 0
+#define RTCORE_VERSION 20900
+
+/*! \file rtcore.isph Defines the Embree Ray Tracing Kernel API for ISPC.
+
+ This file defines the Embree ray tracing kernel API for C and
+ C++. The user is supposed to include this file, and alternatively
+ the rtcore_ray.isph file, but none of the other .isph files in this
+ folder. */
+
+/*! \{ */
+
+/*! Axis aligned bounding box representation */
+RTCORE_ALIGN(16) struct RTCBounds
+{
+ float lower_x, lower_y, lower_z, align0;
+ float upper_x, upper_y, upper_z, align1;
+};
+
+/*! \brief Defines an opaque device type */
+typedef uniform struct __RTCDevice {}* uniform RTCDevice;
+
+/*! \brief Creates a new Embree device.
+
+ Creates a new Embree device to be used by the application. An
+ application typically creates only a single Embree device, but it is
+ valid to use multiple devices inside an application. A configuration
+ string can be passed at construction time, that allows to configure
+ implementation specific parameters. If this string is NULL, a
+ default configuration is used. The following configuration flags are
+ supported by the Embree implementation of the API:
+
+ verbose = num, // sets verbosity level (default is 0)
+
+ If Embree is started on an unsupported CPU, rtcNewDevice will fail and
+ set the RTC_UNSUPPORTED_CPU error code.
+
+*/
+RTCDevice rtcNewDevice(const uniform int8* uniform cfg = NULL);
+
+/*! \brief Deletes an Embree device.
+
+ Deletes the Embree device again. After deletion, all scene handles
+ are invalid. The application should invoke this call before
+ terminating. */
+void rtcDeleteDevice(RTCDevice device);
+
+/*! \brief Initializes the Embree ray tracing core
+
+ WARNING: This function is deprecated, use rtcNewDevice instead.
+
+ Initializes the ray tracing core and passed some configuration
+ string. The configuration string allows to configure implementation
+ specific parameters. If this string is NULL, a default configuration
+ is used. The following configuration flags are supported by the
+ Embree implementation of the API:
+
+ verbose = num, // sets verbosity level (default is 0)
+
+ If Embree is started on an unsupported CPU, rtcInit will fail and
+ set the RTC_UNSUPPORTED_CPU error code.
+
+*/
+RTCORE_DEPRECATED void rtcInit(const uniform int8* uniform cfg = NULL);
+
+/*! \brief Shuts down Embree.
+
+ WARNING: This function is deprecated, use rtcDeleteDevice instead.
+
+ Shuts down the ray tracing core. After shutdown, all scene handles
+ are invalid, and invoking any API call except rtcInit is not
+ allowed. The application should invoke this call before
+ terminating. It is safe to call rtcInit again after an rtcExit
+ call. */
+RTCORE_DEPRECATED void rtcExit();
+
+/*! \brief Parameters that can get configured using the rtcSetParameter functions. */
+enum RTCParameter {
+ RTC_SOFTWARE_CACHE_SIZE = 0, /*! Configures the software cache size (used
+ to cache subdivision surfaces for
+ instance). The size is specified as an
+ integer number of bytes. The software
+ cache cannot be configured during
+ rendering. (write only) */
+
+ RTC_CONFIG_INTERSECT1 = 1, //!< checks if rtcIntersect1 is supported (read only)
+ RTC_CONFIG_INTERSECT4 = 2, //!< checks if rtcIntersect4 is supported (read only)
+ RTC_CONFIG_INTERSECT8 = 3, //!< checks if rtcIntersect8 is supported (read only)
+ RTC_CONFIG_INTERSECT16 = 4, //!< checks if rtcIntersect16 is supported (read only)
+ RTC_CONFIG_INTERSECTN = 5, //!< checks if rtcIntersectN is supported (read only)
+
+ RTC_CONFIG_RAY_MASK = 6, //!< checks if ray masks are supported (read only)
+ RTC_CONFIG_BACKFACE_CULLING = 7, //!< checks if backface culling is supported (read only)
+ RTC_CONFIG_INTERSECTION_FILTER = 8, //!< checks if intersection filters are enabled (read only)
+ RTC_CONFIG_INTERSECTION_FILTER_RESTORE = 9, //!< checks if intersection filters restores previous hit (read only)
+ RTC_CONFIG_BUFFER_STRIDE = 10, //!< checks if buffer strides are supported (read only)
+ RTC_CONFIG_IGNORE_INVALID_RAYS = 11, //!< checks if invalid rays are ignored (read only)
+ RTC_CONFIG_TASKING_SYSTEM = 12, //!< return used tasking system (0 = INTERNAL, 1 = TBB) (read only)
+
+
+ RTC_CONFIG_VERSION_MAJOR = 13, //!< returns Embree major version (read only)
+ RTC_CONFIG_VERSION_MINOR = 14, //!< returns Embree minor version (read only)
+ RTC_CONFIG_VERSION_PATCH = 15, //!< returns Embree patch version (read only)
+ RTC_CONFIG_VERSION = 16, //!< returns Embree version as integer (e.g. Embree v2.8.2 -> 20802) (read only)
+};
+
+/*! \brief Configures some parameters.
+ WARNING: This function is deprecated, use rtcDeviceSetParameter1i instead.
+*/
+RTCORE_DEPRECATED void rtcSetParameter1i(const uniform RTCParameter parm, uniform size_t val); // FIXME: should be ssize_t
+
+/*! \brief Reads some parameters.
+ WARNING: This function is deprecated, use rtcDeviceGetParameter1i instead.
+*/
+uniform size_t rtcGetParameter1i(const uniform RTCParameter parm); // FIXME: should return ssize_t
+
+/*! \brief Configures some device parameters.*/
+void rtcDeviceSetParameter1i(RTCDevice device, const uniform RTCParameter parm, uniform size_t val); // FIXME: should be ssize_t
+
+/*! \brief Reads some device parameters. */
+uniform size_t rtcDeviceGetParameter1i(RTCDevice device, const uniform RTCParameter parm); // FIXME: should return ssize_t
+
+/*! \brief Error codes returned by the rtcGetError function. */
+enum RTCError {
+ RTC_NO_ERROR = 0, //!< No error has been recorded.
+ RTC_UNKNOWN_ERROR = 1, //!< An unknown error has occured.
+ RTC_INVALID_ARGUMENT = 2, //!< An invalid argument is specified
+ RTC_INVALID_OPERATION = 3, //!< The operation is not allowed for the specified object.
+ RTC_OUT_OF_MEMORY = 4, //!< There is not enough memory left to execute the command.
+ RTC_UNSUPPORTED_CPU = 5, //!< The CPU is not supported as it does not support SSE2.
+ RTC_CANCELLED = 6 //!< The user has cancelled the operation through the RTCProgressMonitorFunc callback
+};
+
+/*! \brief Returns the value of the per-thread error flag.
+
+ WARNING: This function is deprecated, use rtcDeviceGetError instead.
+
+ If an error occurs this flag is set to an error code if it stores no
+ previous error. The rtcGetError function reads and returns the
+ currently stored error and clears the error flag again. */
+RTCORE_DEPRECATED uniform RTCError rtcGetError();
+
+/*! \brief Returns the value of the per-thread error flag.
+
+ If an error occurs this flag is set to an error code if it stores no
+ previous error. The rtcGetError function reads and returns the
+ currently stored error and clears the error flag again. */
+uniform RTCError rtcDeviceGetError(RTCDevice device);
+
+/*! \brief Type of error callback function. */
+typedef void (*uniform RTCErrorFunc)(const uniform RTCError code, const uniform int8* uniform str);
+RTCORE_DEPRECATED typedef RTCErrorFunc RTC_ERROR_FUNCTION;
+
+/*! \brief Sets a callback function that is called whenever an error occurs.
+ WARNING: This function is deprecated, use rtcDeviceSetErrorFunction instead.
+*/
+RTCORE_DEPRECATED void rtcSetErrorFunction(uniform RTCErrorFunc func);
+
+/*! \brief Sets a callback function that is called whenever an error occurs. */
+void rtcDeviceSetErrorFunction(RTCDevice device, uniform RTCErrorFunc func);
+
+/*! \brief Type of memory consumption callback function. */
+typedef uniform bool (*uniform RTCMemoryMonitorFunc)(const uniform size_t bytes, const uniform bool post); // FIXME: should be ssize_t
+RTCORE_DEPRECATED typedef RTCMemoryMonitorFunc RTC_MEMORY_MONITOR_FUNCTION;
+
+/*! \brief Sets the memory consumption callback function which is
+ * called before the library allocates or after the library frees
+ * memory.
+ * WARNING: This function is deprecated, use rtcDeviceSetMemoryMonitorFunction instead.
+*/
+RTCORE_DEPRECATED void rtcSetMemoryMonitorFunction(RTCMemoryMonitorFunc func);
+
+/*! \brief Sets the memory consumption callback function which is
+ * called before the library allocates or after the library frees
+ * memory. */
+void rtcDeviceSetMemoryMonitorFunction(RTCDevice device, RTCMemoryMonitorFunc func);
+
+/*! \brief Implementation specific (do not call).
+
+ This function is implementation specific and only for debugging
+ purposes. Do not call it. */
+RTCORE_DEPRECATED void rtcDebug(); // FIXME: remove
+
+#include "rtcore_scene.isph"
+#include "rtcore_geometry.isph"
+#include "rtcore_geometry_user.isph"
+
+/*! \} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_geometry.h b/xs/src/igl/embree/embree2/rtcore_geometry.h
new file mode 100644
index 000000000..5b80130fc
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_geometry.h
@@ -0,0 +1,483 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_GEOMETRY_H__
+#define __RTCORE_GEOMETRY_H__
+
+/*! \ingroup embree_kernel_api */
+/*! \{ */
+
+/*! invalid geometry ID */
+#define RTC_INVALID_GEOMETRY_ID ((unsigned)-1)
+
+/*! \brief Specifies the type of buffers when mapping buffers */
+enum RTCBufferType {
+ RTC_INDEX_BUFFER = 0x01000000,
+
+ RTC_VERTEX_BUFFER = 0x02000000,
+ RTC_VERTEX_BUFFER0 = 0x02000000,
+ RTC_VERTEX_BUFFER1 = 0x02000001,
+
+ RTC_USER_VERTEX_BUFFER = 0x02100000,
+ RTC_USER_VERTEX_BUFFER0 = 0x02100000,
+ RTC_USER_VERTEX_BUFFER1 = 0x02100001,
+
+ RTC_FACE_BUFFER = 0x03000000,
+ RTC_LEVEL_BUFFER = 0x04000001,
+
+ RTC_EDGE_CREASE_INDEX_BUFFER = 0x05000000,
+ RTC_EDGE_CREASE_WEIGHT_BUFFER = 0x06000000,
+
+ RTC_VERTEX_CREASE_INDEX_BUFFER = 0x07000000,
+ RTC_VERTEX_CREASE_WEIGHT_BUFFER = 0x08000000,
+
+ RTC_HOLE_BUFFER = 0x09000001,
+};
+
+/*! \brief Supported types of matrix layout for functions involving matrices */
+enum RTCMatrixType {
+ RTC_MATRIX_ROW_MAJOR = 0,
+ RTC_MATRIX_COLUMN_MAJOR = 1,
+ RTC_MATRIX_COLUMN_MAJOR_ALIGNED16 = 2,
+};
+
+/*! \brief Supported geometry flags to specify handling in dynamic scenes. */
+enum RTCGeometryFlags
+{
+ RTC_GEOMETRY_STATIC = 0, //!< specifies static geometry that will change rarely
+ RTC_GEOMETRY_DEFORMABLE = 1, //!< specifies dynamic geometry with deformable motion (BVH refit possible)
+ RTC_GEOMETRY_DYNAMIC = 2, //!< specifies dynamic geometry with arbitrary motion (BVH refit not possible)
+};
+
+/*! \brief Boundary interpolation mode for subdivision surfaces */
+enum RTCBoundaryMode
+{
+ RTC_BOUNDARY_NONE = 0, //!< ignores border patches
+ RTC_BOUNDARY_EDGE_ONLY = 1, //!< soft boundary (default)
+ RTC_BOUNDARY_EDGE_AND_CORNER = 2 //!< boundary corner vertices are sharp vertices
+};
+
+/*! Intersection filter function for single rays. */
+typedef void (*RTCFilterFunc)(void* ptr, /*!< pointer to user data */
+ RTCRay& ray /*!< intersection to filter */);
+
+/*! Intersection filter function for ray packets of size 4. */
+typedef void (*RTCFilterFunc4)(const void* valid, /*!< pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay4& ray /*!< intersection to filter */);
+
+/*! Intersection filter function for ray packets of size 8. */
+typedef void (*RTCFilterFunc8)(const void* valid, /*!< pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay8& ray /*!< intersection to filter */);
+
+/*! Intersection filter function for ray packets of size 16. */
+typedef void (*RTCFilterFunc16)(const void* valid, /*!< pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay16& ray /*!< intersection to filter */);
+
+/*! Displacement mapping function. */
+typedef void (*RTCDisplacementFunc)(void* ptr, /*!< pointer to user data of geometry */
+ unsigned geomID, /*!< ID of geometry to displace */
+ unsigned primID, /*!< ID of primitive of geometry to displace */
+ const float* u, /*!< u coordinates (source) */
+ const float* v, /*!< v coordinates (source) */
+ const float* nx, /*!< x coordinates of normalized normal at point to displace (source) */
+ const float* ny, /*!< y coordinates of normalized normal at point to displace (source) */
+ const float* nz, /*!< z coordinates of normalized normal at point to displace (source) */
+ float* px, /*!< x coordinates of points to displace (source and target) */
+ float* py, /*!< y coordinates of points to displace (source and target) */
+ float* pz, /*!< z coordinates of points to displace (source and target) */
+ size_t N /*!< number of points to displace */ );
+
+/*! \brief Creates a new scene instance.
+
+ A scene instance contains a reference to a scene to instantiate and
+ the transformation to instantiate the scene with. An implementation
+ will typically transform the ray with the inverse of the provided
+ transformation and continue traversing the ray through the provided
+ scene. If any geometry is hit, the instance ID (instID) member of
+ the ray will get set to the geometry ID of the instance. */
+RTCORE_API unsigned rtcNewInstance (RTCScene target, //!< the scene the instance belongs to
+ RTCScene source //!< the scene to instantiate
+ );
+
+/*! \brief Creates a new scene instance.
+
+ A scene instance contains a reference to a scene to instantiate and
+ the transformation to instantiate the scene with. For motion blurred
+ instances, a number of timesteps can get specified (currently only 1
+ or 2 timesteps are supported). An implementation will typically
+ transform the ray with the inverse of the provided transformation
+ and continue traversing the ray through the provided scene. If any
+ geometry is hit, the instance ID (instID) member of the ray will get
+ set to the geometry ID of the instance. */
+RTCORE_API unsigned rtcNewInstance2 (RTCScene target, //!< the scene the instance belongs to
+ RTCScene source, //!< the scene to instantiate
+ size_t numTimeSteps = 1); //!< number of timesteps, one matrix per timestep
+
+/*! \brief Sets transformation of the instance */
+RTCORE_API void rtcSetTransform (RTCScene scene, //!< scene handle
+ unsigned geomID, //!< ID of geometry
+ RTCMatrixType layout, //!< layout of transformation matrix
+ const float* xfm //!< pointer to transformation matrix
+ );
+
+
+/*! \brief Sets transformation of the instance for specified timestep */
+RTCORE_API void rtcSetTransform2 (RTCScene scene, //!< scene handle
+ unsigned int geomID, //!< ID of geometry
+ RTCMatrixType layout, //!< layout of transformation matrix
+ const float* xfm, //!< pointer to transformation matrix
+ size_t timeStep = 0 //!< timestep to set the matrix for
+ );
+
+/*! \brief Creates a new triangle mesh. The number of triangles
+ (numTriangles), number of vertices (numVertices), and number of time
+ steps (1 for normal meshes, and 2 for linear motion blur), have to
+ get specified. The triangle indices can be set be mapping and
+ writing to the index buffer (RTC_INDEX_BUFFER) and the triangle
+ vertices can be set by mapping and writing into the vertex buffer
+ (RTC_VERTEX_BUFFER). In case of linear motion blur, two vertex
+ buffers have to get filled (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1),
+ one for each time step. The index buffer has the default layout of
+ three 32 bit integer indices for each triangle. An index points to
+ the ith vertex. The vertex buffer stores single precision x,y,z
+ floating point coordinates aligned to 16 bytes. The value of the 4th
+ float used for alignment can be arbitrary. */
+RTCORE_API unsigned rtcNewTriangleMesh (RTCScene scene, //!< the scene the mesh belongs to
+ RTCGeometryFlags flags, //!< geometry flags
+ size_t numTriangles, //!< number of triangles
+ size_t numVertices, //!< number of vertices
+ size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+
+/*! \brief Creates a new quad mesh. The number of quads
+ (numQuads), number of vertices (numVertices), and number of time
+ steps (1 for normal meshes, and 2 for linear motion blur), have to
+ get specified. The quad indices can be set be mapping and
+ writing to the index buffer (RTC_INDEX_BUFFER) and the quad
+ vertices can be set by mapping and writing into the vertex buffer
+ (RTC_VERTEX_BUFFER). In case of linear motion blur, two vertex
+ buffers have to get filled (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1),
+ one for each time step. The index buffer has the default layout of
+ three 32 bit integer indices for each quad. An index points to
+ the ith vertex. The vertex buffer stores single precision x,y,z
+ floating point coordinates aligned to 16 bytes. The value of the 4th
+ float used for alignment can be arbitrary. */
+RTCORE_API unsigned rtcNewQuadMesh (RTCScene scene, //!< the scene the mesh belongs to
+ RTCGeometryFlags flags, //!< geometry flags
+ size_t numQuads, //!< number of quads
+ size_t numVertices, //!< number of vertices
+ size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! \brief Creates a new subdivision mesh. The number of faces
+ (numFaces), edges/indices (numEdges), vertices (numVertices), edge
+ creases (numEdgeCreases), vertex creases (numVertexCreases), holes
+ (numHoles), and time steps (numTimeSteps) have to get speficied at
+ construction time.
+
+ The following buffers have to get filled by the application: the face
+ buffer (RTC_FACE_BUFFER) contains the number edges/indices (3 or 4)
+ of each of the numFaces faces, the index buffer (RTC_INDEX_BUFFER)
+ contains multiple (3 or 4) 32bit vertex indices for each face and
+ numEdges indices in total, the vertex buffer (RTC_VERTEX_BUFFER)
+ stores numVertices vertices as single precision x,y,z floating point
+ coordinates aligned to 16 bytes. The value of the 4th float used for
+ alignment can be arbitrary.
+
+ Optionally, the application can fill the hole buffer
+ (RTC_HOLE_BUFFER) with numHoles many 32 bit indices of faces that
+ should be considered non-existing.
+
+ Optionally, the application can fill the level buffer
+ (RTC_LEVEL_BUFFER) with a tessellation level for each of the numEdges
+ edges. The subdivision level is a positive floating point value, that
+ specifies how many quads along the edge should get generated during
+ tessellation. The tessellation level is a lower bound, thus the
+ implementation is free to choose a larger level. If no level buffer
+ is specified a level of 1 is used.
+
+ Optionally, the application can fill the sparse edge crease buffers
+ to make some edges appear sharper. The edge crease index buffer
+ (RTC_EDGE_CREASE_INDEX_BUFFER) contains numEdgeCreases many pairs of
+ 32 bit vertex indices that specify unoriented edges. The edge crease
+ weight buffer (RTC_EDGE_CREASE_WEIGHT_BUFFER) stores for each of
+ theses crease edges a positive floating point weight. The larger this
+ weight, the sharper the edge. Specifying a weight of infinify is
+ supported and marks an edge as infinitely sharp. Storing an edge
+ multiple times with the same crease weight is allowed, but has lower
+ performance. Storing the an edge multiple times with different
+ crease weights results in undefined behaviour. For a stored edge
+ (i,j), the reverse direction edges (j,i) does not have to get stored,
+ as both are considered the same edge.
+
+ Optionally, the application can fill the sparse vertex crease buffers
+ to make some vertices appear sharper. The vertex crease index buffer
+ (RTC_VERTEX_CREASE_INDEX_BUFFER), contains numVertexCreases many 32
+ bit vertex indices to speficy a set of vertices. The vertex crease
+ weight buffer (RTC_VERTEX_CREASE_WEIGHT_BUFFER) specifies for each of
+ these vertices a positive floating point weight. The larger this
+ weight, the sharper the vertex. Specifying a weight of infinity is
+ supported and makes the vertex infinitely sharp. Storing a vertex
+ multiple times with the same crease weight is allowed, but has lower
+ performance. Storing a vertex multiple times with different crease
+ weights results in undefined behaviour.
+
+*/
+RTCORE_API unsigned rtcNewSubdivisionMesh (RTCScene scene, //!< the scene the mesh belongs to
+ RTCGeometryFlags flags, //!< geometry flags
+ size_t numFaces, //!< number of faces
+ size_t numEdges, //!< number of edges
+ size_t numVertices, //!< number of vertices
+ size_t numEdgeCreases, //!< number of edge creases
+ size_t numVertexCreases, //!< number of vertex creases
+ size_t numHoles, //!< number of holes
+ size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! \brief Creates a new hair geometry, consisting of multiple hairs
+ represented as cubic bezier curves with varying radii. The number of
+ curves (numCurves), number of vertices (numVertices), and number of
+ time steps (1 for normal curves, and 2 for linear motion blur), have
+ to get specified at construction time. Further, the curve index
+ buffer (RTC_INDEX_BUFFER) and the curve vertex buffer
+ (RTC_VERTEX_BUFFER) have to get set by mapping and writing to the
+ appropiate buffers. In case of linear motion blur, two vertex
+ buffers have to get filled (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1),
+ one for each time step. The index buffer has the default layout of a
+ single 32 bit integer index for each curve, that references the
+ start vertex of the curve. The vertex buffer stores 4 control points
+ per curve, each such control point consists of a single precision
+ (x,y,z) position and radius, stored in that order in
+ memory. Individual hairs are considered to be subpixel sized which
+ allows the implementation to approximate the intersection
+ calculation. This in particular means that zooming onto one hair
+ might show geometric artefacts. */
+RTCORE_API unsigned rtcNewHairGeometry (RTCScene scene, //!< the scene the curves belong to
+ RTCGeometryFlags flags, //!< geometry flags
+ size_t numCurves, //!< number of curves
+ size_t numVertices, //!< number of vertices
+ size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! Sets a uniform tessellation rate for subdiv meshes and hair
+ * geometry. For subdivision meshes the RTC_LEVEL_BUFFER can also be used
+ * optionally to set a different tessellation rate per edge.*/
+RTCORE_API void rtcSetTessellationRate (RTCScene scene, unsigned geomID, float tessellationRate);
+
+/*! \brief Creates a new line segment geometry, consisting of multiple
+ segments with varying radii. The number of line segments (numSegments),
+ number of vertices (numVertices), and number of time steps (1 for
+ normal line segments, and 2 for linear motion blur), have to get
+ specified at construction time. Further, the segment index buffer
+ (RTC_INDEX_BUFFER) and the segment vertex buffer (RTC_VERTEX_BUFFER)
+ have to get set by mapping and writing to the appropiate buffers. In
+ case of linear motion blur, two vertex buffers have to get filled
+ (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1), one for each time step. The
+ index buffer has the default layout of a single 32 bit integer index
+ for each line segment, that references the start vertex of the segment.
+ The vertex buffer stores 2 end points per line segment, each such point
+ consists of a single precision (x,y,z) position and radius, stored in
+ that order in memory. Individual segments are considered to be subpixel
+ sized which allows the implementation to approximate the intersection
+ calculation. This in particular means that zooming onto one line segment
+ might show geometric artefacts. */
+RTCORE_API unsigned rtcNewLineSegments (RTCScene scene, //!< the scene the line segments belong to
+ RTCGeometryFlags flags, //!< geometry flags
+ size_t numSegments, //!< number of line segments
+ size_t numVertices, //!< number of vertices
+ size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! \brief Sets 32 bit ray mask. */
+RTCORE_API void rtcSetMask (RTCScene scene, unsigned geomID, int mask);
+
+/*! \brief Sets boundary interpolation mode for subdivision surfaces */
+RTCORE_API void rtcSetBoundaryMode(RTCScene scene, unsigned geomID, RTCBoundaryMode mode);
+
+/*! \brief Maps specified buffer. This function can be used to set index and
+ * vertex buffers of geometries. */
+RTCORE_API void* rtcMapBuffer(RTCScene scene, unsigned geomID, RTCBufferType type);
+
+/*! \brief Unmaps specified buffer.
+
+ A buffer has to be unmapped before the rtcEnable, rtcDisable,
+ rtcUpdate, or rtcDeleteGeometry calls are executed. */
+RTCORE_API void rtcUnmapBuffer(RTCScene scene, unsigned geomID, RTCBufferType type);
+
+/*! \brief Shares a data buffer between the application and
+ * Embree. The passed buffer is used by Embree to store index and
+ * vertex data. It has to remain valid as long as the mesh exists,
+ * and the user is responsible to free the data when the mesh gets
+ * deleted. One can optionally speficy a byte offset and byte stride
+ * of the elements stored inside the buffer. The addresses
+ * ptr+offset+i*stride have to be aligned to 4 bytes on Xeon CPUs and
+ * 16 bytes on Xeon Phi accelerators. For vertex buffers, the 4 bytes
+ * after the z-coordinate of the last vertex have to be readable memory,
+ * thus padding is required for some layouts. If this function is not
+ * called, Embree will allocate and manage buffers of the default
+ * layout. */
+RTCORE_API void rtcSetBuffer(RTCScene scene, unsigned geomID, RTCBufferType type,
+ const void* ptr, size_t byteOffset, size_t byteStride);
+
+/*! \brief Enable geometry. Enabled geometry can be hit by a ray. */
+RTCORE_API void rtcEnable (RTCScene scene, unsigned geomID);
+
+/*! \brief Update all geometry buffers.
+
+ Each time geometry buffers got modified, the user has to call some
+ update function to tell the ray tracing engine which buffers got
+ modified. The rtcUpdate function taggs each geometry buffer of the
+ specified geometry as modified. */
+RTCORE_API void rtcUpdate (RTCScene scene, unsigned geomID);
+
+/*! \brief Update spefific geometry buffer.
+
+ Each time geometry buffers got modified, the user has to call some
+ update function to tell the ray tracing engine which buffers got
+ modified. The rtcUpdateBuffer function taggs a specific buffer of
+ some geometry as modified. */
+RTCORE_API void rtcUpdateBuffer (RTCScene scene, unsigned geomID, RTCBufferType type);
+
+/*! \brief Disable geometry.
+
+ Disabled geometry is not hit by any ray. Disabling and enabling
+ geometry gives higher performance than deleting and recreating
+ geometry. */
+RTCORE_API void rtcDisable (RTCScene scene, unsigned geomID);
+
+/*! \brief Sets the displacement function. */
+RTCORE_API void rtcSetDisplacementFunction (RTCScene scene, unsigned geomID, RTCDisplacementFunc func, RTCBounds* bounds);
+
+/*! \brief Sets the intersection filter function for single rays. */
+RTCORE_API void rtcSetIntersectionFilterFunction (RTCScene scene, unsigned geomID, RTCFilterFunc func);
+
+/*! \brief Sets the intersection filter function for ray packets of size 4. */
+RTCORE_API void rtcSetIntersectionFilterFunction4 (RTCScene scene, unsigned geomID, RTCFilterFunc4 func);
+
+/*! \brief Sets the intersection filter function for ray packets of size 8. */
+RTCORE_API void rtcSetIntersectionFilterFunction8 (RTCScene scene, unsigned geomID, RTCFilterFunc8 func);
+
+/*! \brief Sets the intersection filter function for ray packets of size 16. */
+RTCORE_API void rtcSetIntersectionFilterFunction16 (RTCScene scene, unsigned geomID, RTCFilterFunc16 func);
+
+/*! \brief Sets the occlusion filter function for single rays. */
+RTCORE_API void rtcSetOcclusionFilterFunction (RTCScene scene, unsigned geomID, RTCFilterFunc func);
+
+/*! \brief Sets the occlusion filter function for ray packets of size 4. */
+RTCORE_API void rtcSetOcclusionFilterFunction4 (RTCScene scene, unsigned geomID, RTCFilterFunc4 func);
+
+/*! \brief Sets the occlusion filter function for ray packets of size 8. */
+RTCORE_API void rtcSetOcclusionFilterFunction8 (RTCScene scene, unsigned geomID, RTCFilterFunc8 func);
+
+/*! \brief Sets the occlusion filter function for ray packets of size 16. */
+RTCORE_API void rtcSetOcclusionFilterFunction16 (RTCScene scene, unsigned geomID, RTCFilterFunc16 func);
+
+/*! Set pointer for user defined data per geometry. Invokations
+ * of the various user intersect and occluded functions get passed
+ * this data pointer when called. */
+RTCORE_API void rtcSetUserData (RTCScene scene, unsigned geomID, void* ptr);
+
+/*! Get pointer for user defined data per geometry based on geomID. */
+RTCORE_API void* rtcGetUserData (RTCScene scene, unsigned geomID);
+
+/*! Interpolates user data to some u/v location. The data buffer
+ * specifies per vertex data to interpolate and can be one of the
+ * RTC_VERTEX_BUFFER0/1 or RTC_USER_VERTEX_BUFFER0/1 and has to
+ * contain numFloats floating point values to interpolate for each
+ * vertex of the geometry. The dP array will get filled with the
+ * interpolated data and the dPdu and dPdv arrays with the u and v
+ * derivative of the interpolation. If the pointers dP is NULL, the
+ * value will not get calculated. If dPdu and dPdv are NULL the
+ * derivatives will not get calculated. Both dPdu and dPdv have to be
+ * either valid or NULL. The buffer has to be padded at the end such
+ * that the last element can be read safely using SSE
+ * instructions. */
+RTCORE_API void rtcInterpolate(RTCScene scene, unsigned geomID, unsigned primID, float u, float v, RTCBufferType buffer,
+ float* P, float* dPdu, float* dPdv, size_t numFloats);
+
+/*! Interpolates user data to some u/v location. The data buffer
+ * specifies per vertex data to interpolate and can be one of the
+ * RTC_VERTEX_BUFFER0/1 or RTC_USER_VERTEX_BUFFER0/1 and has to
+ * contain numFloats floating point values to interpolate for each
+ * vertex of the geometry. The P array will get filled with the
+ * interpolated datam the dPdu and dPdv arrays with the u and v
+ * derivative of the interpolation, and the ddPdudu, ddPdvdv, and
+ * ddPdudv arrays with the respective second derivatives. One can
+ * disable 1) the calculation of the interpolated value by setting P
+ * to NULL, 2) the calculation of the 1st order derivatives by
+ * setting dPdu and dPdv to NULL, 3) the calculation of the second
+ * order derivatives by setting ddPdudu, ddPdvdv, and ddPdudv to
+ * NULL. The buffers have to be padded at the end such that the last
+ * element can be read or written safely using SSE instructions. */
+RTCORE_API void rtcInterpolate2(RTCScene scene, unsigned geomID, unsigned primID, float u, float v, RTCBufferType buffer,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, size_t numFloats);
+
+/*! Interpolates user data to an array of u/v locations. The valid
+ * pointer points to an integer array that specified which entries in
+ * the u/v arrays are valid (-1 denotes valid, and 0 invalid). If the
+ * valid pointer is NULL all elements are considers valid. The data
+ * buffer specifies per vertex data to interpolate and can be one of
+ * the RTC_VERTEX_BUFFER0/1 or RTC_USER_VERTEX_BUFFER0/1 and has to
+ * contain numFloats floating point values to interpolate for each
+ * vertex of the geometry. The P array will get filled with the
+ * interpolated data, and the dPdu and dPdv arrays with the u and v
+ * derivative of the interpolation. If the pointers P is NULL, the
+ * value will not get calculated. If dPdu and dPdv are NULL the
+ * derivatives will not get calculated. Both dPdu and dPdv have to be
+ * either valid or NULL. These destination arrays are filled in
+ * structure of array (SoA) layout. The buffer has to be padded at
+ * the end such that the last element can be read safely using SSE
+ * instructions.*/
+RTCORE_API void rtcInterpolateN(RTCScene scene, unsigned geomID,
+ const void* valid, const unsigned* primIDs, const float* u, const float* v, size_t numUVs,
+ RTCBufferType buffer,
+ float* P, float* dPdu, float* dPdv, size_t numFloats);
+
+/*! Interpolates user data to an array of u/v locations. The valid
+ * pointer points to an integer array that specified which entries in
+ * the u/v arrays are valid (-1 denotes valid, and 0 invalid). If the
+ * valid pointer is NULL all elements are considers valid. The data
+ * buffer specifies per vertex data to interpolate and can be one of
+ * the RTC_VERTEX_BUFFER0/1 or RTC_USER_VERTEX_BUFFER0/1 and has to
+ * contain numFloats floating point values to interpolate for each
+ * vertex of the geometry. The P array will get filled with the
+ * interpolated datam the dPdu and dPdv arrays with the u and v
+ * derivative of the interpolation, and the ddPdudu, ddPdvdv, and
+ * ddPdudv arrays with the respective second derivatives. One can
+ * disable 1) the calculation of the interpolated value by setting P
+ * to NULL, 2) the calculation of the 1st order derivatives by
+ * setting dPdu and dPdv to NULL, 3) the calculation of the second
+ * order derivatives by setting ddPdudu, ddPdvdv, and ddPdudv to
+ * NULL. These destination arrays are filled in structure of array
+ * (SoA) layout. The buffer has to be padded at the end such that
+ * the last element can be read safely using SSE
+ * instructions. */
+RTCORE_API void rtcInterpolateN2(RTCScene scene, unsigned geomID,
+ const void* valid, const unsigned* primIDs, const float* u, const float* v, size_t numUVs,
+ RTCBufferType buffer,
+ float* P, float* dPdu, float* dPdv, float* ddPdudu, float* ddPdvdv, float* ddPdudv, size_t numFloats);
+
+/*! \brief Deletes the geometry. */
+RTCORE_API void rtcDeleteGeometry (RTCScene scene, unsigned geomID);
+
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_geometry.isph b/xs/src/igl/embree/embree2/rtcore_geometry.isph
new file mode 100644
index 000000000..b2fa68cfc
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_geometry.isph
@@ -0,0 +1,405 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_GEOMETRY_ISPH__
+#define __RTCORE_GEOMETRY_ISPH__
+
+/*! \ingroup embree_kernel_api_ispc */
+/*! \{ */
+
+/*! invalid geometry ID */
+#define RTC_INVALID_GEOMETRY_ID ((uniform unsigned int)-1)
+
+/*! \brief Specifies the type of buffers when mapping buffers */
+enum RTCBufferType {
+ RTC_INDEX_BUFFER = 0x01000000,
+
+ RTC_VERTEX_BUFFER = 0x02000000,
+ RTC_VERTEX_BUFFER0 = 0x02000000,
+ RTC_VERTEX_BUFFER1 = 0x02000001,
+
+ RTC_USER_VERTEX_BUFFER = 0x02100000,
+ RTC_USER_VERTEX_BUFFER0 = 0x02100000,
+ RTC_USER_VERTEX_BUFFER1 = 0x02100001,
+
+ RTC_FACE_BUFFER = 0x03000000,
+ RTC_LEVEL_BUFFER = 0x04000001,
+
+ RTC_EDGE_CREASE_INDEX_BUFFER = 0x05000000,
+ RTC_EDGE_CREASE_WEIGHT_BUFFER = 0x06000000,
+
+ RTC_VERTEX_CREASE_INDEX_BUFFER = 0x07000000,
+ RTC_VERTEX_CREASE_WEIGHT_BUFFER = 0x08000000,
+
+ RTC_HOLE_BUFFER = 0x09000001,
+};
+
+/*! \brief Supported types of matrix layout for functions involving matrices */
+enum RTCMatrixType {
+ RTC_MATRIX_ROW_MAJOR = 0,
+ RTC_MATRIX_COLUMN_MAJOR = 1,
+ RTC_MATRIX_COLUMN_MAJOR_ALIGNED16 = 2,
+};
+
+/*! \brief Supported geometry flags to specify handling in dynamic scenes. */
+enum RTCGeometryFlags
+{
+ RTC_GEOMETRY_STATIC = 0, //!< specifies static geometry that will change rarely
+ RTC_GEOMETRY_DEFORMABLE = 1, //!< specifies dynamic geometry with deformable motion (BVH refit possible)
+ RTC_GEOMETRY_DYNAMIC = 2, //!< specifies dynamic geometry with arbitrary motion (BVH refit not possible)
+};
+
+/*! \brief Boundary interpolation mode for subdivision surfaces */
+enum RTCBoundaryMode
+{
+ RTC_BOUNDARY_NONE = 0, //!< ignores border patches
+ RTC_BOUNDARY_EDGE_ONLY = 1, //!< soft boundary (default)
+ RTC_BOUNDARY_EDGE_AND_CORNER = 2 //!< boundary corner vertices are sharp vertices
+};
+
+/*! Intersection filter function for uniform rays. */
+typedef void (*uniform RTCFilterFuncUniform)(void* uniform ptr, /*!< pointer to user data */
+ uniform RTCRay1& ray /*!< intersection to filter */);
+
+/*! Intersection filter function for varying rays. */
+typedef void (*uniform RTCFilterFuncVarying)(void* uniform ptr, /*!< pointer to user data */
+ varying RTCRay& ray /*!< intersection to filter */);
+
+
+/*! \brief Creates a new scene instance.
+
+ A scene instance contains a reference to a scene to instantiate and
+ the transformation to instantiate the scene with. An implementation
+ will typically transform the ray with the inverse of the provided
+ transformation and continue traversing the ray through the provided
+ scene. If any geometry is hit, the instance ID (instID) member of
+ the ray will get set to the geometry ID of the instance. */
+uniform unsigned int rtcNewInstance (RTCScene target, //!< the scene the instance belongs to
+ RTCScene source //!< the geometry to instantiate
+ );
+
+/*! \brief Creates a new scene instance.
+
+ A scene instance contains a reference to a scene to instantiate and
+ the transformation to instantiate the scene with. For motion blurred
+ instances, a number of timesteps can get specified (currently only 1
+ or 2 timesteps are supported). An implementation will typically
+ transform the ray with the inverse of the provided transformation
+ and continue traversing the ray through the provided scene. If any
+ geometry is hit, the instance ID (instID) member of the ray will get
+ set to the geometry ID of the instance. */
+uniform unsigned rtcNewInstance2 (RTCScene target, //!< the scene the instance belongs to
+ RTCScene source, //!< the scene to instantiate
+ uniform size_t numTimeSteps = 1); //!< number of timesteps, one matrix per timestep
+
+
+/*! \brief Sets transformation of the instance */
+void rtcSetTransform (RTCScene scene, //!< scene handle
+ uniform unsigned int geomID, //!< ID of geometry
+ uniform RTCMatrixType layout, //!< layout of transformation matrix
+ const uniform float* uniform xfm //!< pointer to transformation matrix
+ );
+
+/*! \brief Sets transformation of the instance for specified timestep */
+void rtcSetTransform2 (RTCScene scene, //!< scene handle
+ uniform unsigned int geomID, //!< ID of geometry
+ uniform RTCMatrixType layout, //!< layout of transformation matrix
+ const uniform float* uniform xfm, //!< pointer to transformation matrix
+ uniform size_t timeStep = 0 //!< timestep to set the matrix for
+ );
+
+/*! \brief Creates a new triangle mesh. The number of triangles
+ (numTriangles), number of vertices (numVertices), and number of time
+ steps (1 for normal meshes, and 2 for linear motion blur), have to
+ get specified. The triangle indices can be set be mapping and
+ writing to the index buffer (RTC_INDEX_BUFFER) and the triangle
+ vertices can be set by mapping and writing into the vertex buffer
+ (RTC_VERTEX_BUFFER). In case of linear motion blur, two vertex
+ buffers have to get filled (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1),
+ one for each time step. The index buffer has the default layout of
+ three 32 bit integer indices for each triangle. An index points to
+ the ith vertex. The vertex buffer stores single precision x,y,z
+ floating point coordinates aligned to 16 bytes. The value of the 4th
+ float used for alignment can be arbitrary. */
+uniform unsigned int rtcNewTriangleMesh (RTCScene scene, //!< the scene the mesh belongs to
+ uniform RTCGeometryFlags flags, //!< geometry flags
+ uniform size_t numTriangles, //!< number of triangles
+ uniform size_t numVertices, //!< number of vertices
+ uniform size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! \brief Creates a new quad mesh. The number of quads
+ (numQuads), number of vertices (numVertices), and number of time
+ steps (1 for normal meshes, and 2 for linear motion blur), have to
+ get specified. The quad indices can be set be mapping and
+ writing to the index buffer (RTC_INDEX_BUFFER) and the quad
+ vertices can be set by mapping and writing into the vertex buffer
+ (RTC_VERTEX_BUFFER). In case of linear motion blur, two vertex
+ buffers have to get filled (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1),
+ one for each time step. The index buffer has the default layout of
+ three 32 bit integer indices for each quad. An index points to
+ the ith vertex. The vertex buffer stores single precision x,y,z
+ floating point coordinates aligned to 16 bytes. The value of the 4th
+ float used for alignment can be arbitrary. */
+uniform unsigned int rtcNewQuadMesh (RTCScene scene, //!< the scene the mesh belongs to
+ uniform RTCGeometryFlags flags, //!< geometry flags
+ uniform size_t numQuads, //!< number of quads
+ uniform size_t numVertices, //!< number of vertices
+ uniform size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! \brief Creates a new subdivision mesh. The number of faces
+ (numFaces), edges/indices (numEdges), vertices (numVertices), edge
+ creases (numEdgeCreases), vertex creases (numVertexCreases), holes
+ (numHoles), and time steps (numTimeSteps) have to get speficied at
+ construction time.
+
+ The following buffers have to get filled by the application: the face
+ buffer (RTC_FACE_BUFFER) contains the number edges/indices (3 or 4)
+ of each of the numFaces faces, the index buffer (RTC_INDEX_BUFFER)
+ contains multiple (3 or 4) 32bit vertex indices for each face and
+ numEdges indices in total, the vertex buffer (RTC_VERTEX_BUFFER)
+ stores numVertices vertices as single precision x,y,z floating point
+ coordinates aligned to 16 bytes. The value of the 4th float used for
+ alignment can be arbitrary.
+
+ Optionally, the application can fill the hole buffer
+ (RTC_HOLE_BUFFER) with numHoles many 32 bit indices of faces that
+ should be considered non-existing.
+
+ Optionally, the application can fill the level buffer
+ (RTC_LEVEL_BUFFER) with a tessellation level for each of the numEdges
+ edges. The subdivision level is a positive floating point value, that
+ specifies how many quads along the edge should get generated during
+ tessellation. The tessellation level is a lower bound, thus the
+ implementation is free to choose a larger level. If no level buffer
+ is specified a level of 1 is used.
+
+ Optionally, the application can fill the sparse edge crease buffers
+ to make some edges appear sharper. The edge crease index buffer
+ (RTC_EDGE_CREASE_INDEX_BUFFER) contains numEdgeCreases many pairs of
+ 32 bit vertex indices that specify unoriented edges. The edge crease
+ weight buffer (RTC_EDGE_CREASE_WEIGHT_BUFFER) stores for each of
+ theses crease edges a positive floating point weight. The larger this
+ weight, the sharper the edge. Specifying a weight of infinify is
+ supported and marks an edge as infinitely sharp. Storing an edge
+ multiple times with the same crease weight is allowed, but has lower
+ performance. Storing the an edge multiple times with different
+ crease weights results in undefined behaviour. For a stored edge
+ (i,j), the reverse direction edges (j,i) does not have to get stored,
+ as both are considered the same edge.
+
+ Optionally, the application can fill the sparse vertex crease buffers
+ to make some vertices appear sharper. The vertex crease index buffer
+ (RTC_VERTEX_CREASE_INDEX_BUFFER), contains numVertexCreases many 32
+ bit vertex indices to speficy a set of vertices. The vertex crease
+ weight buffer (RTC_VERTEX_CREASE_WEIGHT_BUFFER) specifies for each of
+ these vertices a positive floating point weight. The larger this
+ weight, the sharper the vertex. Specifying a weight of infinity is
+ supported and makes the vertex infinitely sharp. Storing a vertex
+ multiple times with the same crease weight is allowed, but has lower
+ performance. Storing a vertex multiple times with different crease
+ weights results in undefined behaviour.
+
+*/
+
+uniform unsigned int rtcNewSubdivisionMesh (RTCScene scene, //!< the scene the mesh belongs to
+ uniform RTCGeometryFlags flags, //!< geometry flags
+ uniform size_t numFaces, //!< number of faces
+ uniform size_t numEdges, //!< number of edges
+ uniform size_t numVertices, //!< number of vertices
+ uniform size_t numEdgeCreases, //!< number of edge creases
+ uniform size_t numVertexCreases, //!< number of vertex creases
+ uniform size_t numHoles, //!< number of holes
+ uniform size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! \brief Creates a new hair geometry, consisting of multiple hairs
+ represented as cubic bezier curves with varying radii. The number of
+ curves (numCurves), number of vertices (numVertices), and number of
+ time steps (1 for normal curves, and 2 for linear motion blur), have
+ to get specified at construction time. Further, the curve index
+ buffer (RTC_INDEX_BUFFER) and the curve vertex buffer
+ (RTC_VERTEX_BUFFER) have to get set by mapping and writing to the
+ appropiate buffers. In case of linear motion blur, two vertex
+ buffers have to get filled (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1),
+ one for each time step. The index buffer has the default layout of a
+ single 32 bit integer index for each curve, that references the
+ start vertex of the curve. The vertex buffer stores 4 control points
+ per curve, each such control point consists of a single precision
+ (x,y,z) position and radius, stored in that order in
+ memory. Individual hairs are considered to be subpixel sized which
+ allows the implementation to approximate the intersection
+ calculation. This in particular means that zooming onto one hair
+ might show geometric artefacts. */
+uniform unsigned int rtcNewHairGeometry (RTCScene scene, //!< the scene the curves belong to
+ uniform RTCGeometryFlags flags, //!< geometry flags
+ uniform size_t numCurves, //!< number of curves
+ uniform size_t numVertices, //!< number of vertices
+ uniform size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! Sets a uniform tessellation rate for subdiv meshes and hair
+ * geometry. For subdivision meshes the RTC_LEVEL_BUFFER can also be used
+ * optionally to set a different tessellation rate per edge.*/
+void rtcSetTessellationRate (RTCScene scene, uniform unsigned geomID, uniform float tessellationRate);
+
+/*! \brief Creates a new line segment geometry, consisting of multiple
+ segments with varying radii. The number of line segments (numSegments),
+ number of vertices (numVertices), and number of time steps (1 for
+ normal line segments, and 2 for linear motion blur), have to get
+ specified at construction time. Further, the segment index buffer
+ (RTC_INDEX_BUFFER) and the segment vertex buffer (RTC_VERTEX_BUFFER)
+ have to get set by mapping and writing to the appropiate buffers. In
+ case of linear motion blur, two vertex buffers have to get filled
+ (RTC_VERTEX_BUFFER0, RTC_VERTEX_BUFFER1), one for each time step. The
+ index buffer has the default layout of a single 32 bit integer index
+ for each line segment, that references the start vertex of the segment.
+ The vertex buffer stores 2 end points per line segment, each such point
+ consists of a single precision (x,y,z) position and radius, stored in
+ that order in memory. Individual segments are considered to be subpixel
+ sized which allows the implementation to approximate the intersection
+ calculation. This in particular means that zooming onto one line segment
+ might show geometric artefacts. */
+uniform unsigned int rtcNewLineSegments (RTCScene scene, //!< the scene the line segments belong to
+ uniform RTCGeometryFlags flags, //!< geometry flags
+ uniform size_t numSegments, //!< number of line segments
+ uniform size_t numVertices, //!< number of vertices
+ uniform size_t numTimeSteps = 1 //!< number of motion blur time steps
+ );
+
+/*! \brief Sets 32 bit ray mask. */
+void rtcSetMask (RTCScene scene, uniform unsigned int geomID, uniform int mask);
+
+/*! \brief Sets boundary interpolation mode for subdivision surfaces */
+void rtcSetBoundaryMode(RTCScene scene, uniform unsigned int geomID, uniform RTCBoundaryMode mode);
+
+/*! \brief Maps specified buffer. This function can be used to set index and
+ * vertex buffers of geometries. */
+void* uniform rtcMapBuffer(RTCScene scene, uniform unsigned int geomID, uniform RTCBufferType type);
+
+/*! \brief Unmaps specified buffer.
+
+ A buffer has to be unmapped before the rtcEnable, rtcDisable,
+ rtcUpdate, or rtcDeleteGeometry calls are executed. */
+void rtcUnmapBuffer(RTCScene scene, uniform unsigned int geomID, uniform RTCBufferType type);
+
+/*! \brief Shares a data buffer between the application and
+ * Embree. The passed buffer is used by Embree to store index and
+ * vertex data. It has to remain valid as long as the mesh exists,
+ * and the user is responsible to free the data when the mesh gets
+ * deleted. One can optionally speficy a byte offset and byte stride
+ * of the elements stored inside the buffer. The addresses
+ * ptr+offset+i*stride have to be aligned to 4 bytes on Xeon CPUs and
+ * 16 bytes on Xeon Phi accelerators. For vertex buffers, the 4 bytes
+ * after the z-coordinate of the last vertex have to be readable memory,
+ * thus padding is required for some layouts. If this function is not
+ * called, Embree will allocate and manage buffers of the default
+ * layout. */
+void rtcSetBuffer(RTCScene scene, uniform unsigned int geomID, uniform RTCBufferType type,
+ const void* uniform ptr, uniform size_t byteOffset, uniform size_t byteStride);
+
+/*! \brief Enable geometry. Enabled geometry can be hit by a ray. */
+void rtcEnable (RTCScene scene, uniform unsigned int geomID);
+
+/*! \brief Update spefific geometry buffer.
+
+ Each time geometry buffers got modified, the user has to call some
+ update function to tell the ray tracing engine which buffers got
+ modified. The rtcUpdateBuffer function taggs a specific buffer of
+ some geometry as modified. */
+void rtcUpdate (RTCScene scene, uniform unsigned int geomID);
+
+/*! \brief Update spefific geometry buffer.
+
+ Each time geometry buffers got modified, the user has to call some
+ update function to tell the ray tracing engine which buffers got
+ modified. The rtcUpdateBuffer function taggs a specific buffer of
+ some geometry as modified. */
+void rtcUpdateBuffer (RTCScene scene, uniform unsigned int geomID, uniform RTCBufferType type);
+
+/*! \brief Disable geometry.
+
+ Disabled geometry is not hit by any ray. Disabling and enabling
+ geometry gives higher performance than deleting and recreating
+ geometry. */
+void rtcDisable (RTCScene scene, uniform unsigned int geomID);
+
+/*! \brief Sets the intersection filter function for uniform rays. */
+void rtcSetIntersectionFilterFunction1 (RTCScene scene, uniform unsigned int geomID, uniform RTCFilterFuncUniform func);
+
+/*! \brief Sets the intersection filter function for varying rays. */
+void rtcSetIntersectionFilterFunction (RTCScene scene, uniform unsigned int geomID, uniform RTCFilterFuncVarying func);
+
+/*! \brief Sets the occlusion filter function for uniform rays. */
+void rtcSetOcclusionFilterFunction1 (RTCScene scene, uniform unsigned int geomID, uniform RTCFilterFuncUniform func);
+
+/*! \brief Sets the occlusion filter function for varying rays. */
+void rtcSetOcclusionFilterFunction (RTCScene scene, uniform unsigned int geomID, uniform RTCFilterFuncVarying func);
+
+/*! Set pointer for user defined data per geometry. Invokations
+ * of the various user intersect and occluded functions get passed
+ * this data pointer when called. */
+void rtcSetUserData (RTCScene scene, uniform unsigned int geomID, void* uniform ptr);
+
+/*! Get pointer for user defined data per geometry based on geomID. */
+void* uniform rtcGetUserData (RTCScene scene, uniform unsigned int geomID);
+
+/*! Interpolates user data to some varying u/v location. The data
+ * buffer specifies per vertex data to interpolate and can be one of
+ * the RTC_VERTEX_BUFFER0/1 or RTC_USER_VERTEX_BUFFER0/1 and has to contain
+ * numFloats floating point values to interpolate for each vertex of
+ * the geometry. The P array will get filled with the interpolated
+ * data, and the dPdu and dPdv arrays with the u and v derivative of
+ * the interpolation. If the pointers P is NULL, the value will not
+ * get calculated. If dPdu and dPdv are NULL the derivatives will not
+ * get calculated. Both dPdu and dPdv have to be either valid or
+ * NULL. These destination arrays are filled in structure of array
+ * (SoA) layout. The buffer has to be padded at the end such
+ * that the last element can be read safely using SSE
+ * instructions. */
+void rtcInterpolate(RTCScene scene, uniform unsigned int geomID, varying unsigned int primIDs, varying float u, varying float v,
+ uniform RTCBufferType buffer,
+ varying float* uniform P, varying float* uniform dPdu, varying float* uniform dPdv, uniform size_t numFloats);
+
+/*! Interpolates user data to some varying u/v location. The data
+ * buffer specifies per vertex data to interpolate and can be one of
+ * the RTC_VERTEX_BUFFER0/1 or RTC_USER_VERTEX_BUFFER0/1 and has to contain
+ * numFloats floating point values to interpolate for each vertex of
+ * the geometry. The P array will get filled with the
+ * interpolated datam the dPdu and dPdv arrays with the u and v
+ * derivative of the interpolation, and the ddPdudu, ddPdvdv, and
+ * ddPdudv arrays with the respective second derivatives. One can
+ * disable 1) the calculation of the interpolated value by setting P
+ * to NULL, 2) the calculation of the 1st order derivatives by
+ * setting dPdu and dPdv to NULL, 3) the calculation of the second
+ * order derivatives by setting ddPdudu, ddPdvdv, and ddPdudv to
+ * NULL. These destination arrays are filled in structure of array
+ * (SoA) layout. The buffer has to be padded at the end such that
+ * the last element can be read safely using SSE
+ * instructions. */
+void rtcInterpolate2(RTCScene scene, uniform unsigned int geomID, varying unsigned int primIDs, varying float u, varying float v,
+ uniform RTCBufferType buffer,
+ varying float* uniform P, varying float* uniform dPdu, varying float* uniform dPdv,
+ varying float* uniform ddPdudu, varying float* uniform ddPdvdv, varying float* uniform ddPdudv,
+ uniform size_t numFloats);
+
+/*! \brief Deletes the geometry. */
+void rtcDeleteGeometry (RTCScene scene, uniform unsigned int geomID);
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_geometry_user.h b/xs/src/igl/embree/embree2/rtcore_geometry_user.h
new file mode 100644
index 000000000..e4b4d4b8a
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_geometry_user.h
@@ -0,0 +1,154 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_USER_GEOMETRY_H__
+#define __RTCORE_USER_GEOMETRY_H__
+
+/*! \ingroup embree_kernel_api */
+/*! \{ */
+
+/*! Type of bounding function. */
+typedef void (*RTCBoundsFunc)(void* ptr, /*!< pointer to user data */
+ size_t item, /*!< item to calculate bounds for */
+ RTCBounds& bounds_o /*!< returns calculated bounds */);
+
+/*! Type of bounding function. */
+typedef void (*RTCBoundsFunc2)(void* userPtr, /*!< pointer to user data */
+ void* geomUserPtr, /*!< pointer to geometry user data */
+ size_t item, /*!< item to calculate bounds for */
+ RTCBounds* bounds_o /*!< returns calculated bounds */);
+
+/*! Type of intersect function pointer for single rays. */
+typedef void (*RTCIntersectFunc)(void* ptr, /*!< pointer to user data */
+ RTCRay& ray, /*!< ray to intersect */
+ size_t item /*!< item to intersect */);
+
+/*! Type of intersect function pointer for ray packets of size 4. */
+typedef void (*RTCIntersectFunc4)(const void* valid, /*!< pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay4& ray, /*!< ray packet to intersect */
+ size_t item /*!< item to intersect */);
+
+/*! Type of intersect function pointer for ray packets of size 8. */
+typedef void (*RTCIntersectFunc8)(const void* valid, /*!< pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay8& ray, /*!< ray packet to intersect */
+ size_t item /*!< item to intersect */);
+
+/*! Type of intersect function pointer for ray packets of size 16. */
+typedef void (*RTCIntersectFunc16)(const void* valid, /*!< pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay16& ray, /*!< ray packet to intersect */
+ size_t item /*!< item to intersect */);
+
+/*! Type of occlusion function pointer for single rays. */
+typedef void (*RTCOccludedFunc) (void* ptr, /*!< pointer to user data */
+ RTCRay& ray, /*!< ray to test occlusion */
+ size_t item /*!< item to test for occlusion */);
+
+/*! Type of occlusion function pointer for ray packets of size 4. */
+typedef void (*RTCOccludedFunc4) (const void* valid, /*! pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay4& ray, /*!< Ray packet to test occlusion. */
+ size_t item /*!< item to test for occlusion */);
+
+/*! Type of occlusion function pointer for ray packets of size 8. */
+typedef void (*RTCOccludedFunc8) (const void* valid, /*! pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay8& ray, /*!< Ray packet to test occlusion. */
+ size_t item /*!< item to test for occlusion */);
+
+/*! Type of occlusion function pointer for ray packets of size 16. */
+typedef void (*RTCOccludedFunc16) (const void* valid, /*! pointer to valid mask */
+ void* ptr, /*!< pointer to user data */
+ RTCRay16& ray, /*!< Ray packet to test occlusion. */
+ size_t item /*!< item to test for occlusion */);
+
+/*! Creates a new user geometry object. This feature makes it possible
+ * to add arbitrary types of geometry to the scene by providing
+ * appropiate bounding, intersect and occluded functions. A user
+ * geometry object is a set of user geometries. As the rtcIntersect
+ * and rtcOccluded functions support different ray packet sizes, the
+ * user also has to provide different versions of intersect and
+ * occluded function pointers for these packet sizes. However, the
+ * ray packet size of the called function pointer always matches the
+ * packet size of the originally invoked rtcIntersect and rtcOccluded
+ * functions. A user data pointer, that points to a user specified
+ * representation of the geometry, is passed to each intersect and
+ * occluded function invokation, as well as the index of the geometry
+ * of the set to intersect. */
+RTCORE_API unsigned rtcNewUserGeometry (RTCScene scene, /*!< the scene the user geometry set is created in */
+ size_t numGeometries /*!< the number of geometries contained in the set */);
+
+RTCORE_API unsigned rtcNewUserGeometry2 (RTCScene scene, /*!< the scene the user geometry set is created in */
+ size_t numGeometries, /*!< the number of geometries contained in the set */
+ size_t numTimeSteps = 1 /*!< number of motion blur time steps */);
+
+/*! Sets the bounding function to calculate bounding boxes of the user
+ * geometry items when building spatial index structures. The
+ * calculated bounding box have to be conservative and should be
+ * tight. */
+RTCORE_API void rtcSetBoundsFunction (RTCScene scene, unsigned geomID, RTCBoundsFunc bounds);
+
+/*! Sets the bounding function to calculate bounding boxes of the user
+ * geometry items when building spatial index structures. The
+ * calculated bounding box have to be conservative and should be
+ * tight. */
+RTCORE_API void rtcSetBoundsFunction2 (RTCScene scene, unsigned geomID, RTCBoundsFunc2 bounds, void* userPtr);
+
+/*! Set intersect function for single rays. The rtcIntersect function
+ * will call the passed function for intersecting the user
+ * geometry. */
+RTCORE_API void rtcSetIntersectFunction (RTCScene scene, unsigned geomID, RTCIntersectFunc intersect);
+
+/*! Set intersect function for ray packets of size 4. The
+ * rtcIntersect4 function will call the passed function for
+ * intersecting the user geometry. */
+RTCORE_API void rtcSetIntersectFunction4 (RTCScene scene, unsigned geomID, RTCIntersectFunc4 intersect4);
+
+/*! Set intersect function for ray packets of size 8. The
+ * rtcIntersect8 function will call the passed function for
+ * intersecting the user geometry.*/
+RTCORE_API void rtcSetIntersectFunction8 (RTCScene scene, unsigned geomID, RTCIntersectFunc8 intersect8);
+
+/*! Set intersect function for ray packets of size 16. The
+ * rtcIntersect16 function will call the passed function for
+ * intersecting the user geometry. */
+RTCORE_API void rtcSetIntersectFunction16 (RTCScene scene, unsigned geomID, RTCIntersectFunc16 intersect16);
+
+/*! Set occlusion function for single rays. The rtcOccluded function
+ * will call the passed function for intersecting the user
+ * geometry. */
+RTCORE_API void rtcSetOccludedFunction (RTCScene scene, unsigned geomID, RTCOccludedFunc occluded);
+
+/*! Set occlusion function for ray packets of size 4. The rtcOccluded4
+ * function will call the passed function for intersecting the user
+ * geometry. */
+RTCORE_API void rtcSetOccludedFunction4 (RTCScene scene, unsigned geomID, RTCOccludedFunc4 occluded4);
+
+/*! Set occlusion function for ray packets of size 8. The rtcOccluded8
+ * function will call the passed function for intersecting the user
+ * geometry. */
+RTCORE_API void rtcSetOccludedFunction8 (RTCScene scene, unsigned geomID, RTCOccludedFunc8 occluded8);
+
+/*! Set occlusion function for ray packets of size 16. The
+ * rtcOccluded16 function will call the passed function for
+ * intersecting the user geometry. */
+RTCORE_API void rtcSetOccludedFunction16 (RTCScene scene, unsigned geomID, RTCOccludedFunc16 occluded16);
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_geometry_user.isph b/xs/src/igl/embree/embree2/rtcore_geometry_user.isph
new file mode 100644
index 000000000..d89ec1b91
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_geometry_user.isph
@@ -0,0 +1,128 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_USER_GEOMETRY_ISPH__
+#define __RTCORE_USER_GEOMETRY_ISPH__
+
+/*! \ingroup embree_kernel_api_ispc */
+/*! \{ */
+
+/*! Type of bounding function. */
+typedef void (*RTCBoundsFunc)(void* uniform ptr, /*!< pointer to user data */
+ uniform size_t item, /*!< item to calculate bounds for */
+ uniform RTCBounds& bounds_o /*!< returns calculated bounds */);
+
+/*! Type of bounding function. */
+typedef void (*RTCBoundsFunc2)(void* uniform userPtr, /*!< pointer to user data */
+ void* uniform geomUserPtr, /*!< pointer to geometry user data */
+ uniform size_t item, /*!< item to calculate bounds for */
+ RTCBounds* uniform bounds_o /*!< returns calculated bounds */);
+
+/*! Type of intersect function pointer for uniform rays. */
+typedef void (*RTCIntersectFuncUniform)(void* uniform ptr, /*!< pointer to user data */
+ uniform RTCRay1& ray, /*!< ray to intersect */
+ uniform size_t item /*< item to intersect */);
+
+/*! Type of intersect function pointer for varying rays. */
+typedef void (*RTCIntersectFuncVarying)(void* uniform ptr, /*!< pointer to user data */
+ varying RTCRay& ray, /*!< ray to intersect */
+ uniform size_t item /*< item to intersect */);
+
+/*! Type of occlusion function pointer for uniform rays. */
+typedef void (*RTCOccludedFuncUniform) (void* uniform ptr, /*!< pointer to user data */
+ uniform RTCRay1& ray, /*!< ray to test occlusion */
+ uniform size_t item /*< item to test for occlusion */);
+
+
+/*! Type of occlusion function pointer for varying rays. */
+typedef void (*RTCOccludedFuncVarying) (void* uniform ptr, /*!< pointer to user data */
+ varying RTCRay& ray, /*!< ray to test occlusion */
+ uniform size_t item /*< item to test for occlusion */);
+
+
+typedef void (*RTCDisplacementFunc)(void* uniform ptr, /*!< pointer to user data of geometry */
+ uniform unsigned int geomID, /*!< ID of geometry to displace */
+ uniform unsigned int primID, /*!< ID of primitive of geometry to displace */
+ uniform const float* uniform u, /*!< u coordinates (source) */
+ uniform const float* uniform v, /*!< v coordinates (source) */
+ uniform const float* uniform nx, /*!< x coordinates of normal at point to displace (source) */
+ uniform const float* uniform ny, /*!< y coordinates of normal at point to displace (source) */
+ uniform const float* uniform nz, /*!< z coordinates of normal at point to displace (source) */
+ uniform float* uniform px, /*!< x coordinates of points to displace (source and target) */
+ uniform float* uniform py, /*!< y coordinates of points to displace (source and target) */
+ uniform float* uniform pz, /*!< z coordinates of points to displace (source and target) */
+ uniform size_t N /*!< number of points to displace */ );
+
+
+/*! Creates a new user geometry object. This feature makes it possible
+ * to add arbitrary types of geometry to the scene by providing
+ * appropiate intersect and occluded functions, as well as a bounding
+ * box of the implemented geometry. As the rtcIntersect and
+ * rtcOccluded functions support different ray packet sizes, the user
+ * also has to provide different versions of intersect and occluded
+ * function pointers for the different packet sized. However, only
+ * rtcIntersect and rtcOccluded functions of specific packet sizes
+ * are called, it is sufficient to provide only the corresponding
+ * function pointer for the user geometry. However, the functions
+ * provided have to intersect the same geometry. A user data pointer,
+ * that points to a user specified representation of the geometry, is
+ * passed to each intersect and occluded function invokation. */
+uniform unsigned int rtcNewUserGeometry (RTCScene scene, /*!< the scene the user geometry set is created in */
+ uniform size_t numGeometries /*!< the number of geometries contained in the set */);
+
+uniform unsigned int rtcNewUserGeometry2 (RTCScene scene, /*!< the scene the user geometry set is created in */
+ uniform size_t numGeometries, /*!< the number of geometries contained in the set */
+ uniform size_t numTimeSteps = 1 /*!< number of motion blur time steps */);
+
+/*! Sets the bounding function to calculate bounding boxes of the user
+ * geometry items when building spatial index structures. The
+ * calculated bounding box have to be conservative and should be
+ * tight.*/
+void rtcSetBoundsFunction (RTCScene scene, uniform unsigned int geomID, uniform RTCBoundsFunc bounds);
+
+/*! Sets the bounding function to calculate bounding boxes of the user
+ * geometry items when building spatial index structures. The
+ * calculated bounding box have to be conservative and should be
+ * tight.*/
+void rtcSetBoundsFunction2 (RTCScene scene, uniform unsigned int geomID, uniform RTCBoundsFunc2 bounds, void* uniform userPtr);
+
+/*! Set intersect function for uniform rays. The rtcIntersect1
+ * function will call the passed function for intersecting the user
+ * geometry. */
+void rtcSetIntersectFunction1 (RTCScene scene, uniform unsigned int geomID, uniform RTCIntersectFuncUniform intersect);
+
+/*! Set intersect function for varying rays. The rtcIntersect function
+ * will call the passed function for intersecting the user
+ * geometry. */
+void rtcSetIntersectFunction (RTCScene scene, uniform unsigned int geomID, uniform RTCIntersectFuncVarying intersect);
+
+/*! Set occlusion function for uniform rays. The rtcOccluded1 function
+ * will call the passed function for intersecting the user
+ * geometry. */
+void rtcSetOccludedFunction1 (RTCScene scene, uniform unsigned int geomID, uniform RTCOccludedFuncUniform occluded);
+
+/*! Set occlusion function for varying rays. The rtcOccluded function
+ * will call the passed function for intersecting the user
+ * geometry. */
+void rtcSetOccludedFunction (RTCScene scene, uniform unsigned int geomID, uniform RTCOccludedFuncVarying occluded);
+
+
+/*! \brief Sets the displacement function. */
+void rtcSetDisplacementFunction (RTCScene scene, uniform unsigned int geomID, uniform RTCDisplacementFunc func, uniform RTCBounds *uniform bounds);
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_ray.h b/xs/src/igl/embree/embree2/rtcore_ray.h
new file mode 100644
index 000000000..f20b11b5f
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_ray.h
@@ -0,0 +1,195 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_RAY_H__
+#define __RTCORE_RAY_H__
+
+/*! \ingroup embree_kernel_api */
+/*! \{ */
+
+/*! \brief Ray structure for an individual ray */
+struct RTCORE_ALIGN(16) RTCRay
+{
+ /* ray data */
+public:
+ float org[3]; //!< Ray origin
+ float align0;
+
+ float dir[3]; //!< Ray direction
+ float align1;
+
+ float tnear; //!< Start of ray segment
+ float tfar; //!< End of ray segment (set to hit distance)
+
+ float time; //!< Time of this ray for motion blur
+ unsigned mask; //!< Used to mask out objects during traversal
+
+ /* hit data */
+public:
+ float Ng[3]; //!< Unnormalized geometry normal
+ float align2;
+
+ float u; //!< Barycentric u coordinate of hit
+ float v; //!< Barycentric v coordinate of hit
+
+ unsigned geomID; //!< geometry ID
+ unsigned primID; //!< primitive ID
+ unsigned instID; //!< instance ID
+};
+
+/*! Ray structure for packets of 4 rays. */
+struct RTCORE_ALIGN(16) RTCRay4
+{
+ /* ray data */
+public:
+ float orgx[4]; //!< x coordinate of ray origin
+ float orgy[4]; //!< y coordinate of ray origin
+ float orgz[4]; //!< z coordinate of ray origin
+
+ float dirx[4]; //!< x coordinate of ray direction
+ float diry[4]; //!< y coordinate of ray direction
+ float dirz[4]; //!< z coordinate of ray direction
+
+ float tnear[4]; //!< Start of ray segment
+ float tfar[4]; //!< End of ray segment (set to hit distance)
+
+ float time[4]; //!< Time of this ray for motion blur
+ unsigned mask[4]; //!< Used to mask out objects during traversal
+
+ /* hit data */
+public:
+ float Ngx[4]; //!< x coordinate of geometry normal
+ float Ngy[4]; //!< y coordinate of geometry normal
+ float Ngz[4]; //!< z coordinate of geometry normal
+
+ float u[4]; //!< Barycentric u coordinate of hit
+ float v[4]; //!< Barycentric v coordinate of hit
+
+ unsigned geomID[4]; //!< geometry ID
+ unsigned primID[4]; //!< primitive ID
+ unsigned instID[4]; //!< instance ID
+};
+
+/*! Ray structure for packets of 8 rays. */
+struct RTCORE_ALIGN(32) RTCRay8
+{
+ /* ray data */
+public:
+ float orgx[8]; //!< x coordinate of ray origin
+ float orgy[8]; //!< y coordinate of ray origin
+ float orgz[8]; //!< z coordinate of ray origin
+
+ float dirx[8]; //!< x coordinate of ray direction
+ float diry[8]; //!< y coordinate of ray direction
+ float dirz[8]; //!< z coordinate of ray direction
+
+ float tnear[8]; //!< Start of ray segment
+ float tfar[8]; //!< End of ray segment (set to hit distance)
+
+ float time[8]; //!< Time of this ray for motion blur
+ unsigned mask[8]; //!< Used to mask out objects during traversal
+
+ /* hit data */
+public:
+ float Ngx[8]; //!< x coordinate of geometry normal
+ float Ngy[8]; //!< y coordinate of geometry normal
+ float Ngz[8]; //!< z coordinate of geometry normal
+
+ float u[8]; //!< Barycentric u coordinate of hit
+ float v[8]; //!< Barycentric v coordinate of hit
+
+ unsigned geomID[8]; //!< geometry ID
+ unsigned primID[8]; //!< primitive ID
+ unsigned instID[8]; //!< instance ID
+};
+
+/*! \brief Ray structure for packets of 16 rays. */
+struct RTCORE_ALIGN(64) RTCRay16
+{
+ /* ray data */
+public:
+ float orgx[16]; //!< x coordinate of ray origin
+ float orgy[16]; //!< y coordinate of ray origin
+ float orgz[16]; //!< z coordinate of ray origin
+
+ float dirx[16]; //!< x coordinate of ray direction
+ float diry[16]; //!< y coordinate of ray direction
+ float dirz[16]; //!< z coordinate of ray direction
+
+ float tnear[16]; //!< Start of ray segment
+ float tfar[16]; //!< End of ray segment (set to hit distance)
+
+ float time[16]; //!< Time of this ray for motion blur
+ unsigned mask[16]; //!< Used to mask out objects during traversal
+
+ /* hit data */
+public:
+ float Ngx[16]; //!< x coordinate of geometry normal
+ float Ngy[16]; //!< y coordinate of geometry normal
+ float Ngz[16]; //!< z coordinate of geometry normal
+
+ float u[16]; //!< Barycentric u coordinate of hit
+ float v[16]; //!< Barycentric v coordinate of hit
+
+ unsigned geomID[16]; //!< geometry ID
+ unsigned primID[16]; //!< primitive ID
+ unsigned instID[16]; //!< instance ID
+};
+
+
+/*! \brief Ray structure template for packets of N rays in SOA layout. */
+struct RTCRaySOA
+{
+ /* ray data */
+public:
+
+ float* orgx; //!< x coordinate of ray origin
+ float* orgy; //!< y coordinate of ray origin
+ float* orgz; //!< z coordinate of ray origin
+
+ float* dirx; //!< x coordinate of ray direction
+ float* diry; //!< y coordinate of ray direction
+ float* dirz; //!< z coordinate of ray direction
+
+ float* tnear; //!< Start of ray segment (optional)
+ float* tfar; //!< End of ray segment (set to hit distance)
+
+
+ float* time; //!< Time of this ray for motion blur (optional)
+ unsigned* mask; //!< Used to mask out objects during traversal (optional)
+
+ /* hit data */
+
+public:
+
+ float* Ngx; //!< x coordinate of geometry normal (optional)
+ float* Ngy; //!< y coordinate of geometry normal (optional)
+ float* Ngz; //!< z coordinate of geometry normal (optional)
+
+
+
+ float* u; //!< Barycentric u coordinate of hit
+ float* v; //!< Barycentric v coordinate of hit
+
+
+ unsigned* geomID; //!< geometry ID
+ unsigned* primID; //!< primitive ID
+ unsigned* instID; //!< instance ID (optional)
+};
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_ray.isph b/xs/src/igl/embree/embree2/rtcore_ray.isph
new file mode 100644
index 000000000..f1bf4d268
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_ray.isph
@@ -0,0 +1,117 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_RAY_ISPH__
+#define __RTCORE_RAY_ISPH__
+
+/*! \ingroup embree_kernel_api_ispc */
+/*! \{ */
+
+/*! Ray structure for uniform (single) rays. */
+struct RTCRay1
+{
+ /* ray data */
+ float org[3]; //!< Ray origin
+ float align0; //!< unused member to force alignment of following members
+
+ float dir[3]; //!< Ray direction
+ float align1; //!< unused member to force alignment of following members
+
+ float tnear; //!< Start of ray segment
+ float tfar; //!< End of ray segment (set to hit distance)
+ float time; //!< Time of this ray for motion blur
+ unsigned mask; //!< Used to mask out objects during traversal
+
+ /* hit data */
+ float Ng[3]; //!< Unnormalized geometry normal
+ float align2;
+
+ float u; //!< Barycentric u coordinate of hit
+ float v; //!< Barycentric v coordinate of hit
+
+ unsigned geomID; //!< geometry ID
+ unsigned primID; //!< primitive ID
+ unsigned instID; //!< instance ID
+ varying unsigned align[0]; //!< aligns ray on stack to at least 16 bytes
+};
+
+/*! Ray structure for packets of 4 rays. */
+struct RTCRay
+{
+ /* ray data */
+ float orgx; //!< x coordinate of ray origin
+ float orgy; //!< y coordinate of ray origin
+ float orgz; //!< z coordinate of ray origin
+
+ float dirx; //!< x coordinate of ray direction
+ float diry; //!< y coordinate of ray direction
+ float dirz; //!< z coordinate of ray direction
+
+ float tnear; //!< Start of ray segment
+ float tfar; //!< End of ray segment
+ float time; //!< Time of this ray for motion blur
+ unsigned mask; //!< Used to mask out objects during traversal
+
+ /* hit data */
+ float Ngx; //!< x coordinate of geometry normal
+ float Ngy; //!< y coordinate of geometry normal
+ float Ngz; //!< z coordinate of geometry normal
+
+ float u; //!< Barycentric u coordinate of hit
+ float v; //!< Barycentric v coordinate of hit
+
+ unsigned geomID; //!< geometry ID
+ unsigned primID; //!< primitive ID
+ unsigned instID; //!< instance ID
+};
+
+
+struct RTCRaySOA
+{
+ /* ray data */
+
+ uniform float* uniform orgx; //!< x coordinate of ray origin
+ uniform float* uniform orgy; //!< y coordinate of ray origin
+ uniform float* uniform orgz; //!< z coordinate of ray origin
+
+ uniform float* uniform dirx; //!< x coordinate of ray direction
+ uniform float* uniform diry; //!< y coordinate of ray direction
+ uniform float* uniform dirz; //!< z coordinate of ray direction
+
+ uniform float* uniform tnear; //!< Start of ray segment (optional)
+ uniform float* uniform tfar; //!< End of ray segment (set to hit distance)
+
+ uniform float* uniform time; //!< Time of this ray for motion blur (optional)
+ uniform unsigned* uniform mask; //!< Used to mask out objects during traversal (optional)
+
+ /* hit data */
+
+ uniform float* uniform Ngx; //!< x coordinate of geometry normal (optional)
+ uniform float* uniform Ngy; //!< y coordinate of geometry normal (optional)
+ uniform float* uniform Ngz; //!< z coordinate of geometry normal (optional)
+
+ uniform float* uniform u; //!< Barycentric u coordinate of hit
+ uniform float* uniform v; //!< Barycentric v coordinate of hit
+
+ uniform unsigned* uniform geomID; //!< geometry ID
+ uniform unsigned* uniform primID; //!< primitive ID
+ uniform unsigned* uniform instID; //!< instance ID (optional)
+};
+
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_scene.h b/xs/src/igl/embree/embree2/rtcore_scene.h
new file mode 100644
index 000000000..df04e0a2b
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_scene.h
@@ -0,0 +1,187 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_SCENE_H__
+#define __RTCORE_SCENE_H__
+
+/*! \ingroup embree_kernel_api */
+/*! \{ */
+
+/*! forward declarations for ray structures */
+struct RTCRay;
+struct RTCRay4;
+struct RTCRay8;
+struct RTCRay16;
+struct RTCRaySOA;
+
+/*! scene flags */
+enum RTCSceneFlags
+{
+ /* dynamic type flags */
+ RTC_SCENE_STATIC = (0 << 0), //!< specifies static scene
+ RTC_SCENE_DYNAMIC = (1 << 0), //!< specifies dynamic scene
+
+ /* acceleration structure flags */
+ RTC_SCENE_COMPACT = (1 << 8), //!< use memory conservative data structures
+ RTC_SCENE_COHERENT = (1 << 9), //!< optimize data structures for coherent rays
+ RTC_SCENE_INCOHERENT = (1 << 10), //!< optimize data structures for in-coherent rays (enabled by default)
+ RTC_SCENE_HIGH_QUALITY = (1 << 11), //!< create higher quality data structures
+
+ /* traversal algorithm flags */
+ RTC_SCENE_ROBUST = (1 << 16) //!< use more robust traversal algorithms
+};
+
+/*! enabled algorithm flags */
+enum RTCAlgorithmFlags
+{
+ RTC_INTERSECT1 = (1 << 0), //!< enables the rtcIntersect1 and rtcOccluded1 functions for this scene
+ RTC_INTERSECT4 = (1 << 1), //!< enables the rtcIntersect4 and rtcOccluded4 functions for this scene
+ RTC_INTERSECT8 = (1 << 2), //!< enables the rtcIntersect8 and rtcOccluded8 functions for this scene
+ RTC_INTERSECT16 = (1 << 3), //!< enables the rtcIntersect16 and rtcOccluded16 functions for this scene
+ RTC_INTERPOLATE = (1 << 4), //!< enables the rtcInterpolate function for this scene
+
+ RTC_INTERSECTN = (1 << 5), //!< enables the rtcIntersectN and rtcOccludedN functions for this scene
+};
+
+/*! layout flags for ray streams */
+enum RTCRayNFlags
+{
+ RTC_RAYN_DEFAULT = (1 << 0)
+};
+
+
+/*! \brief Defines an opaque scene type */
+typedef struct __RTCScene {}* RTCScene;
+
+/*! Creates a new scene.
+ WARNING: This function is deprecated, use rtcDeviceNewScene instead.
+*/
+RTCORE_API RTCORE_DEPRECATED RTCScene rtcNewScene (RTCSceneFlags flags, RTCAlgorithmFlags aflags);
+
+/*! Creates a new scene. */
+RTCORE_API RTCScene rtcDeviceNewScene (RTCDevice device, RTCSceneFlags flags, RTCAlgorithmFlags aflags);
+
+/*! \brief Type of progress callback function. */
+typedef bool (*RTCProgressMonitorFunc)(void* ptr, const double n);
+RTCORE_DEPRECATED typedef RTCProgressMonitorFunc RTC_PROGRESS_MONITOR_FUNCTION;
+
+/*! \brief Sets the progress callback function which is called during hierarchy build of this scene. */
+RTCORE_API void rtcSetProgressMonitorFunction(RTCScene scene, RTCProgressMonitorFunc func, void* ptr);
+
+/*! Commits the geometry of the scene. After initializing or modifying
+ * geometries, commit has to get called before tracing
+ * rays. */
+RTCORE_API void rtcCommit (RTCScene scene);
+
+/*! Commits the geometry of the scene. The calling threads will be
+ * used internally as a worker threads on some implementations. The
+ * function will wait until 'numThreads' threads have called this
+ * function and all threads return from the function after the scene
+ * commit is finished. The application threads will not be used as
+ * worker threads when the TBB tasking system is enabled (which is
+ * the default). On CPUs, we recommend also using TBB inside your
+ * application to share threads. We recommend using the
+ * rtcCommitThread feature to share threads on the Xeon Phi
+ * coprocessor. */
+RTCORE_API void rtcCommitThread(RTCScene scene, unsigned int threadID, unsigned int numThreads);
+
+/*! Returns to AABB of the scene. rtcCommit has to get called
+ * previously to this function. */
+RTCORE_API void rtcGetBounds(RTCScene scene, RTCBounds& bounds_o);
+
+/*! Intersects a single ray with the scene. The ray has to be aligned
+ * to 16 bytes. This function can only be called for scenes with the
+ * RTC_INTERSECT1 flag set. */
+RTCORE_API void rtcIntersect (RTCScene scene, RTCRay& ray);
+
+/*! Intersects a packet of 4 rays with the scene. The valid mask and
+ * ray have both to be aligned to 16 bytes. This function can only be
+ * called for scenes with the RTC_INTERSECT4 flag set. */
+RTCORE_API void rtcIntersect4 (const void* valid, RTCScene scene, RTCRay4& ray);
+
+/*! Intersects a packet of 8 rays with the scene. The valid mask and
+ * ray have both to be aligned to 32 bytes. This function can only be
+ * called for scenes with the RTC_INTERSECT8 flag set. For performance
+ * reasons, the rtcIntersect8 function should only get called if the
+ * CPU supports AVX. */
+RTCORE_API void rtcIntersect8 (const void* valid, RTCScene scene, RTCRay8& ray);
+
+/*! Intersects a packet of 16 rays with the scene. The valid mask and
+ * ray have both to be aligned to 64 bytes. This function can only be
+ * called for scenes with the RTC_INTERSECT16 flag set. For
+ * performance reasons, the rtcIntersect16 function should only get
+ * called if the CPU supports the 16-wide SIMD instructions. */
+RTCORE_API void rtcIntersect16 (const void* valid, RTCScene scene, RTCRay16& ray);
+
+/*! Intersects a stream of N rays in AOS layout with the scene. This
+ * function can only be called for scenes with the RTC_INTERSECTN
+ * flag set. The stride specifies the offset between rays in
+ * bytes. */
+RTCORE_API void rtcIntersectN (RTCScene scene, RTCRay* rayN, const size_t N, const size_t stride, const size_t flags = RTC_RAYN_DEFAULT);
+
+/*! Intersects one or multiple streams of N rays in compact SOA layout
+ * with the scene. This function can only be called for scenes with
+ * the RTC_INTERSECTN flag set. 'streams' specifies the number of
+ * dense SOA ray streams, and 'stride' the offset in bytes between
+ * those. */
+RTCORE_API void rtcIntersectN_SOA (RTCScene scene, RTCRaySOA& rayN, const size_t N, const size_t streams, const size_t stride, const size_t flags = RTC_RAYN_DEFAULT);
+
+
+/*! Tests if a single ray is occluded by the scene. The ray has to be
+ * aligned to 16 bytes. This function can only be called for scenes
+ * with the RTC_INTERSECT1 flag set. */
+RTCORE_API void rtcOccluded (RTCScene scene, RTCRay& ray);
+
+/*! Tests if a packet of 4 rays is occluded by the scene. This
+ * function can only be called for scenes with the RTC_INTERSECT4
+ * flag set. The valid mask and ray have both to be aligned to 16
+ * bytes. */
+RTCORE_API void rtcOccluded4 (const void* valid, RTCScene scene, RTCRay4& ray);
+
+/*! Tests if a packet of 8 rays is occluded by the scene. The valid
+ * mask and ray have both to be aligned to 32 bytes. This function
+ * can only be called for scenes with the RTC_INTERSECT8 flag
+ * set. For performance reasons, the rtcOccluded8 function should
+ * only get called if the CPU supports AVX. */
+RTCORE_API void rtcOccluded8 (const void* valid, RTCScene scene, RTCRay8& ray);
+
+/*! Tests if a packet of 16 rays is occluded by the scene. The valid
+ * mask and ray have both to be aligned to 64 bytes. This function
+ * can only be called for scenes with the RTC_INTERSECT16 flag
+ * set. For performance reasons, the rtcOccluded16 function should
+ * only get called if the CPU supports the 16-wide SIMD
+ * instructions. */
+RTCORE_API void rtcOccluded16 (const void* valid, RTCScene scene, RTCRay16& ray);
+
+/*! Tests if a stream of N rays on AOS layout is occluded by the
+ * scene. This function can only be called for scenes with the
+ * RTC_INTERSECTN flag set. The stride specifies the offset between
+ * rays in bytes.*/
+RTCORE_API void rtcOccludedN (RTCScene scene, RTCRay* rayN, const size_t N, const size_t stride, const size_t flags = RTC_RAYN_DEFAULT);
+
+/*! Intersects one or multiple streams of N rays in compact SOA layout
+ * with the scene. This function can only be called for scenes with
+ * the RTC_INTERSECTN flag set. 'streams' specifies the number of
+ * dense SOA ray streams, and 'stride' the offset in bytes between
+ * those. */
+RTCORE_API void rtcOccludedN_SOA (RTCScene scene, RTCRaySOA& rayN, const size_t N, const size_t streams, const size_t stride, const size_t flags = RTC_RAYN_DEFAULT);
+
+/*! Deletes the scene. All contained geometry get also destroyed. */
+RTCORE_API void rtcDeleteScene (RTCScene scene);
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/embree2/rtcore_scene.isph b/xs/src/igl/embree/embree2/rtcore_scene.isph
new file mode 100644
index 000000000..a85eee219
--- /dev/null
+++ b/xs/src/igl/embree/embree2/rtcore_scene.isph
@@ -0,0 +1,152 @@
+// ======================================================================== //
+// Copyright 2009-2015 Intel Corporation //
+// //
+// Licensed under the Apache License, Version 2.0 (the "License"); //
+// you may not use this file except in compliance with the License. //
+// You may obtain a copy of the License at //
+// //
+// http://www.apache.org/licenses/LICENSE-2.0 //
+// //
+// Unless required by applicable law or agreed to in writing, software //
+// distributed under the License is distributed on an "AS IS" BASIS, //
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. //
+// See the License for the specific language governing permissions and //
+// limitations under the License. //
+// ======================================================================== //
+
+#ifndef __RTCORE_SCENE_ISPH__
+#define __RTCORE_SCENE_ISPH__
+
+/*! \ingroup embree_kernel_api */
+/*! \{ */
+
+/*! forward declarations for ray structures */
+struct RTCRay1;
+struct RTCRay;
+struct RTCRaySOA;
+
+/*! scene flags */
+enum RTCSceneFlags
+{
+ /* dynamic type flags */
+ RTC_SCENE_STATIC = (0 << 0), //!< specifies static scene
+ RTC_SCENE_DYNAMIC = (1 << 0), //!< specifies dynamic scene
+
+ /* acceleration structure flags */
+ RTC_SCENE_COMPACT = (1 << 8), //!< use memory conservative data structures
+ RTC_SCENE_COHERENT = (1 << 9), //!< optimize data structures for coherent rays (enabled by default)
+ RTC_SCENE_INCOHERENT = (1 << 10), //!< optimize data structures for in-coherent rays
+ RTC_SCENE_HIGH_QUALITY = (1 << 11), //!< create higher quality data structures
+
+ /* traversal algorithm flags */
+ RTC_SCENE_ROBUST = (1 << 16) //!< use more robust traversal algorithms
+};
+
+/*! enabled algorithm flags */
+enum RTCAlgorithmFlags
+{
+ RTC_INTERSECT_UNIFORM = (1 << 0), //!< enables the uniform rtcIntersect1 and uniform rtcOccluded1 functions for this scene
+ RTC_INTERSECT_VARYING = (1 << 1), //!< enables the varying rtcIntersect and varying rtcOccluded functions for this scene
+ RTC_INTERPOLATE = (1 << 4) //!< enables the rtcInterpolate function for this scene
+};
+
+/*! layout flags for ray streams */
+enum RTCRayNFlags
+{
+ RTC_RAYN_DEFAULT = (1 << 0)
+};
+
+
+/*! \brief Defines an opaque scene type */
+typedef uniform struct __RTCScene {}* uniform RTCScene;
+
+/*! Creates a new scene.
+ WARNING: This function is deprecated, use rtcDeviceNewScene instead.
+*/
+RTCORE_DEPRECATED RTCScene rtcNewScene (uniform RTCSceneFlags flags, uniform RTCAlgorithmFlags aflags);
+
+/*! Creates a new scene. */
+RTCScene rtcDeviceNewScene (RTCDevice device, uniform RTCSceneFlags flags, uniform RTCAlgorithmFlags aflags);
+
+/*! \brief Type of progress callback function. */
+typedef uniform bool (*uniform RTC_PROGRESS_MONITOR_FUNCTION)(void* uniform ptr, const uniform double n);
+
+/*! \brief Sets the progress callback function which is called during hierarchy build. */
+void rtcSetProgressMonitorFunction(RTCScene scene, RTC_PROGRESS_MONITOR_FUNCTION func, void* uniform ptr);
+
+/*! Commits the geometry of the scene. After initializing or modifying
+ * geometries, commit has to get called before tracing
+ * rays. */
+void rtcCommit (RTCScene scene);
+
+/*! Commits the geometry of the scene. The calling threads will be
+ * used internally as a worker threads on some implementations. The
+ * function will wait until 'numThreads' threads have called this
+ * function and all threads return from the function after the scene
+ * commit is finished. The application threads will not be used as
+ * worker threads when the TBB tasking system is enabled (which is
+ * the default). On CPUs, we recommend also using TBB inside your
+ * application to share threads. We recommend using the
+ * rtcCommitThread feature to share threads on the Xeon Phi
+ * coprocessor. */
+void rtcCommitThread(RTCScene scene, uniform unsigned int threadID, uniform unsigned int numThreads);
+
+/*! Returns to AABB of the scene. rtcCommit has to get called
+ * previously to this function. */
+void rtcGetBounds(RTCScene scene, uniform RTCBounds& bounds_o);
+
+/*! Intersects a uniform ray with the scene. This function can only be
+ * called for scenes with the RTC_INTERSECT_UNIFORM flag set. The ray
+ * has to be aligned to 16 bytes. */
+void rtcIntersect1 (RTCScene scene, uniform RTCRay1& ray);
+
+/*! Intersects a varying ray with the scene. This function can only be
+ * called for scenes with the RTC_INTERSECT_VARYING flag set. The
+ * valid mask and ray have both to be aligned to sizeof(varing float)
+ * bytes. */
+void rtcIntersect (RTCScene scene, varying RTCRay& ray);
+
+
+/*! Intersects a stream of N rays in AOS layout with the scene. This
+ * function can only be called for scenes with the RTC_INTERSECTN
+ * flag set. The stride specifies the offset between rays in
+ * bytes. */
+void rtcIntersectN (RTCScene scene, uniform RTCRay* uniform rayN, const uniform size_t N, const uniform size_t stride, const uniform size_t flags);
+
+/*! Intersects one or multiple streams of N rays in compact SOA layout with the scene. This
+ * function can only be called for scenes with the RTC_INTERSECTN
+ * flag set. 'streams' specifies the number of dense SOA ray
+ * streams, and 'stride' the offset in bytes between those. */
+void rtcIntersectN_SOA (RTCScene scene, uniform RTCRaySOA& rayN, const uniform size_t N, const uniform size_t streams, const uniform size_t offset, const uniform size_t flags);
+
+
+/*! Tests if a uniform ray is occluded by the scene. This function can
+ * only be called for scenes with the RTC_INTERSECT_UNIFORM flag
+ * set. The ray has to be aligned to 16 bytes. */
+void rtcOccluded1 (RTCScene scene, uniform RTCRay1& ray);
+
+/*! Tests if a varying ray is occluded by the scene. This function can
+ * only be called for scenes with the RTC_INTERSECT_VARYING flag
+ * set. The valid mask and ray have both to be aligned to
+ * sizeof(varing float) bytes. */
+void rtcOccluded (RTCScene scene, varying RTCRay& ray);
+
+
+/*! Tests if a stream of N rays on AOS layout is occluded by the
+ * scene. This function can only be called for scenes with the
+ * RTC_INTERSECTN flag set. The stride specifies the offset between
+ * rays in bytes.*/
+void rtcOccludedN (RTCScene scene, uniform RTCRay* uniform rayN, const uniform size_t N, const uniform size_t stride, const uniform size_t flags);
+
+/*! Intersects one or multiple streams of N rays in compact SOA layout with the scene. This
+ * function can only be called for scenes with the RTC_INTERSECTN
+ * flag set. 'streams' specifies the number of dense SOA ray
+ * streams, and 'stride' the offset in bytes between those. */
+void rtcOccludedN_SOA (RTCScene scene, uniform RTCRaySOA& rayN, const uniform size_t N, const uniform size_t streams, const uniform size_t offset, const uniform size_t flags);
+
+/*! Deletes the geometry again. */
+void rtcDeleteScene (RTCScene scene);
+
+/*! @} */
+
+#endif
diff --git a/xs/src/igl/embree/line_mesh_intersection.cpp b/xs/src/igl/embree/line_mesh_intersection.cpp
new file mode 100644
index 000000000..0f6e02b8c
--- /dev/null
+++ b/xs/src/igl/embree/line_mesh_intersection.cpp
@@ -0,0 +1,85 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "line_mesh_intersection.h"
+#include "../Hit.h"
+
+// For error printing
+#include <cstdio>
+#include <vector>
+
+#include <igl/per_vertex_normals.h>
+#include <igl/embree/EmbreeIntersector.h>
+
+template <typename ScalarMatrix, typename IndexMatrix>
+IGL_INLINE ScalarMatrix igl::embree::line_mesh_intersection
+(
+ const ScalarMatrix & V_source,
+ const ScalarMatrix & N_source,
+ const ScalarMatrix & V_target,
+ const IndexMatrix & F_target
+)
+{
+
+ double tol = 0.00001;
+
+ Eigen::MatrixXd ray_pos = V_source;
+ Eigen::MatrixXd ray_dir = N_source;
+
+ // Allocate matrix for the result
+ ScalarMatrix R;
+ R.resize(V_source.rows(), 3);
+
+ // Initialize embree
+ EmbreeIntersector embree;
+ embree.init(V_target.template cast<float>(),F_target.template cast<int>());
+
+ // Shoot rays from the source to the target
+ for (unsigned i=0; i<ray_pos.rows(); ++i)
+ {
+ igl::Hit A,B;
+ // Shoot ray A
+ Eigen::RowVector3d A_pos = ray_pos.row(i) + tol * ray_dir.row(i);
+ Eigen::RowVector3d A_dir = -ray_dir.row(i);
+
+ bool A_hit = embree.intersectBeam(A_pos.cast<float>(), A_dir.cast<float>(),A);
+
+ Eigen::RowVector3d B_pos = ray_pos.row(i) - tol * ray_dir.row(i);
+ Eigen::RowVector3d B_dir = ray_dir.row(i);
+
+ bool B_hit = embree.intersectBeam(B_pos.cast<float>(), B_dir.cast<float>(),B);
+
+
+ int choice = -1;
+
+ if (A_hit && ! B_hit)
+ choice = 0;
+ else if (!A_hit && B_hit)
+ choice = 1;
+ else if (A_hit && B_hit)
+ choice = A.t > B.t;
+
+ Eigen::RowVector3d temp;
+
+ if (choice == -1)
+ temp << -1, 0, 0;
+ else if (choice == 0)
+ temp << A.id, A.u, A.v;
+ else if (choice == 1)
+ temp << B.id, B.u, B.v;
+
+ R.row(i) = temp;
+
+ }
+
+ return R;
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::embree::line_mesh_intersection<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&);
+#endif
diff --git a/xs/src/igl/embree/line_mesh_intersection.h b/xs/src/igl/embree/line_mesh_intersection.h
new file mode 100644
index 000000000..b7b849c8a
--- /dev/null
+++ b/xs/src/igl/embree/line_mesh_intersection.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_LINE_MESH_INTERSECTION_H
+#define IGL_EMBREE_LINE_MESH_INTERSECTION_H
+#include <igl/igl_inline.h>
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+#include <vector>
+
+namespace igl
+{
+ namespace embree
+ {
+ // Project the point cloud V_source onto the triangle mesh
+ // V_target,F_target.
+ // A ray is casted for every vertex in the direction specified by
+ // N_source and its opposite.
+ //
+ // Input:
+ // V_source: #Vx3 Vertices of the source mesh
+ // N_source: #Vx3 Normals of the point cloud
+ // V_target: #V2x3 Vertices of the target mesh
+ // F_target: #F2x3 Faces of the target mesh
+ //
+ // Output:
+ // #Vx3 matrix of baricentric coordinate. Each row corresponds to
+ // a vertex of the projected mesh and it has the following format:
+ // id b1 b2. id is the id of a face of the source mesh. b1 and b2 are
+ // the barycentric coordinates wrt the first two edges of the triangle
+ // To convert to standard global coordinates, see barycentric_to_global.h
+ template <typename ScalarMatrix, typename IndexMatrix>
+ IGL_INLINE ScalarMatrix line_mesh_intersection
+ (
+ const ScalarMatrix & V_source,
+ const ScalarMatrix & N_source,
+ const ScalarMatrix & V_target,
+ const IndexMatrix & F_target
+ );
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "line_mesh_intersection.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/embree/reorient_facets_raycast.cpp b/xs/src/igl/embree/reorient_facets_raycast.cpp
new file mode 100644
index 000000000..fabc021d9
--- /dev/null
+++ b/xs/src/igl/embree/reorient_facets_raycast.cpp
@@ -0,0 +1,259 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "reorient_facets_raycast.h"
+#include "../per_face_normals.h"
+#include "../doublearea.h"
+#include "../random_dir.h"
+#include "../bfs_orient.h"
+#include "EmbreeIntersector.h"
+#include <iostream>
+#include <random>
+#include <ctime>
+#include <limits>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedC>
+IGL_INLINE void igl::embree::reorient_facets_raycast(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ int rays_total,
+ int rays_minimum,
+ bool facet_wise,
+ bool use_parity,
+ bool is_verbose,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(F.cols() == 3);
+ assert(V.cols() == 3);
+
+ // number of faces
+ const int m = F.rows();
+
+ MatrixXi FF = F;
+ if (facet_wise) {
+ C.resize(m);
+ for (int i = 0; i < m; ++i) C(i) = i;
+
+ } else {
+ if (is_verbose) cout << "extracting patches... ";
+ bfs_orient(F,FF,C);
+ }
+ if (is_verbose) cout << (C.maxCoeff() + 1) << " components. ";
+
+ // number of patches
+ const int num_cc = C.maxCoeff()+1;
+
+ // Init Embree
+ EmbreeIntersector ei;
+ ei.init(V.template cast<float>(),FF);
+
+ // face normal
+ MatrixXd N;
+ per_face_normals(V,FF,N);
+
+ // face area
+ Matrix<typename DerivedV::Scalar,Dynamic,1> A;
+ doublearea(V,FF,A);
+ double area_total = A.sum();
+
+ // determine number of rays per component according to its area
+ VectorXd area_per_component;
+ area_per_component.setZero(num_cc);
+ for (int f = 0; f < m; ++f)
+ {
+ area_per_component(C(f)) += A(f);
+ }
+ VectorXi num_rays_per_component(num_cc);
+ for (int c = 0; c < num_cc; ++c)
+ {
+ num_rays_per_component(c) = max<int>(static_cast<int>(rays_total * area_per_component(c) / area_total), rays_minimum);
+ }
+ rays_total = num_rays_per_component.sum();
+
+ // generate all the rays
+ if (is_verbose) cout << "generating rays... ";
+ uniform_real_distribution<float> rdist;
+ mt19937 prng;
+ prng.seed(time(nullptr));
+ vector<int > ray_face;
+ vector<Vector3f> ray_ori;
+ vector<Vector3f> ray_dir;
+ ray_face.reserve(rays_total);
+ ray_ori .reserve(rays_total);
+ ray_dir .reserve(rays_total);
+ for (int c = 0; c < num_cc; ++c)
+ {
+ if (area_per_component[c] == 0)
+ {
+ continue;
+ }
+ vector<int> CF; // set of faces per component
+ vector<double> CF_area;
+ for (int f = 0; f < m; ++f)
+ {
+ if (C(f)==c)
+ {
+ CF.push_back(f);
+ CF_area.push_back(A(f));
+ }
+ }
+ // discrete distribution for random selection of faces with probability proportional to their areas
+ discrete_distribution<int> ddist(CF.size(), 0, CF.size(), [&](double i){ return CF_area[static_cast<int>(i)]; }); // simple ctor of (Iter, Iter) not provided by the stupid VC11/12
+ for (int i = 0; i < num_rays_per_component[c]; ++i)
+ {
+ int f = CF[ddist(prng)]; // select face with probability proportional to face area
+ float s = rdist(prng); // random barycentric coordinate (reference: Generating Random Points in Triangles [Turk, Graphics Gems I 1990])
+ float t = rdist(prng);
+ float sqrt_t = sqrtf(t);
+ float a = 1 - sqrt_t;
+ float b = (1 - s) * sqrt_t;
+ float c = s * sqrt_t;
+ Vector3f p = a * V.row(FF(f,0)).template cast<float>().eval() // be careful with the index!!!
+ + b * V.row(FF(f,1)).template cast<float>().eval()
+ + c * V.row(FF(f,2)).template cast<float>().eval();
+ Vector3f n = N.row(f).cast<float>();
+ if (n.isZero()) continue;
+ // random direction in hemisphere around n (avoid too grazing angle)
+ Vector3f d;
+ while (true) {
+ d = random_dir().cast<float>();
+ float ndotd = n.dot(d);
+ if (fabsf(ndotd) < 0.1f)
+ {
+ continue;
+ }
+ if (ndotd < 0)
+ {
+ d *= -1.0f;
+ }
+ break;
+ }
+ ray_face.push_back(f);
+ ray_ori .push_back(p);
+ ray_dir .push_back(d);
+
+ if (is_verbose && ray_face.size() % (rays_total / 10) == 0) cout << ".";
+ }
+ }
+ if (is_verbose) cout << ray_face.size() << " rays. ";
+
+ // per component voting: first=front, second=back
+ vector<pair<float, float>> C_vote_distance(num_cc, make_pair(0, 0)); // sum of distance between ray origin and intersection
+ vector<pair<int , int >> C_vote_infinity(num_cc, make_pair(0, 0)); // number of rays reaching infinity
+ vector<pair<int , int >> C_vote_parity(num_cc, make_pair(0, 0)); // sum of parity count for each ray
+
+ if (is_verbose) cout << "shooting rays... ";
+#pragma omp parallel for
+ for (int i = 0; i < (int)ray_face.size(); ++i)
+ {
+ int f = ray_face[i];
+ Vector3f o = ray_ori [i];
+ Vector3f d = ray_dir [i];
+ int c = C(f);
+
+ // shoot ray toward front & back
+ vector<Hit> hits_front;
+ vector<Hit> hits_back;
+ int num_rays_front;
+ int num_rays_back;
+ ei.intersectRay(o, d, hits_front, num_rays_front);
+ ei.intersectRay(o, -d, hits_back , num_rays_back );
+ if (!hits_front.empty() && hits_front[0].id == f) hits_front.erase(hits_front.begin());
+ if (!hits_back .empty() && hits_back [0].id == f) hits_back .erase(hits_back .begin());
+
+ if (use_parity) {
+#pragma omp atomic
+ C_vote_parity[c].first += hits_front.size() % 2;
+#pragma omp atomic
+ C_vote_parity[c].second += hits_back .size() % 2;
+
+ } else {
+ if (hits_front.empty())
+ {
+#pragma omp atomic
+ C_vote_infinity[c].first++;
+ } else {
+#pragma omp atomic
+ C_vote_distance[c].first += hits_front[0].t;
+ }
+
+ if (hits_back.empty())
+ {
+#pragma omp atomic
+ C_vote_infinity[c].second++;
+ } else {
+#pragma omp atomic
+ C_vote_distance[c].second += hits_back[0].t;
+ }
+ }
+ }
+
+ I.resize(m);
+ for(int f = 0; f < m; ++f)
+ {
+ int c = C(f);
+ if (use_parity) {
+ I(f) = C_vote_parity[c].first > C_vote_parity[c].second ? 1 : 0; // Ideally, parity for the front/back side should be 1/0 (i.e., parity sum for all rays should be smaller on the front side)
+
+ } else {
+ I(f) = (C_vote_infinity[c].first == C_vote_infinity[c].second && C_vote_distance[c].first < C_vote_distance[c].second) ||
+ C_vote_infinity[c].first < C_vote_infinity[c].second
+ ? 1 : 0;
+ }
+ // To account for the effect of bfs_orient
+ if (F.row(f) != FF.row(f))
+ I(f) = 1 - I(f);
+ }
+ if (is_verbose) cout << "done!" << endl;
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedI>
+IGL_INLINE void igl::embree::reorient_facets_raycast(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ const int rays_total = F.rows()*100;
+ const int rays_minimum = 10;
+ const bool facet_wise = false;
+ const bool use_parity = false;
+ const bool is_verbose = false;
+ Eigen::VectorXi C;
+ reorient_facets_raycast(
+ V,F,rays_total,rays_minimum,facet_wise,use_parity,is_verbose,I,C);
+ // Conservative in case FF = F
+ FF.conservativeResize(F.rows(),F.cols());
+ for(int i = 0;i<I.rows();i++)
+ {
+ if(I(i))
+ {
+ FF.row(i) = (F.row(i).reverse()).eval();
+ }else
+ {
+ FF.row(i) = F.row(i);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::embree::reorient_facets_raycast<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::embree::reorient_facets_raycast<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool, bool, bool, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::embree::reorient_facets_raycast<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, int, bool, bool, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/embree/reorient_facets_raycast.h b/xs/src/igl/embree/reorient_facets_raycast.h
new file mode 100644
index 000000000..a43efac94
--- /dev/null
+++ b/xs/src/igl/embree/reorient_facets_raycast.h
@@ -0,0 +1,73 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_REORIENT_FACETS_RAYCAST_H
+#define IGL_EMBREE_REORIENT_FACETS_RAYCAST_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace embree
+ {
+ // Orient each component (identified by C) of a mesh (V,F) using ambient
+ // occlusion such that the front side is less occluded than back side, as
+ // described in "A Simple Method for Correcting Facet Orientations in
+ // Polygon Meshes Based on Ray Casting" [Takayama et al. 2014].
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // rays_total Total number of rays that will be shot
+ // rays_minimum Minimum number of rays that each patch should receive
+ // facet_wise Decision made for each face independently, no use of patches
+ // (i.e., each face is treated as a patch)
+ // use_parity Use parity mode
+ // is_verbose Verbose output to cout
+ // Outputs:
+ // I #F list of whether face has been flipped
+ // C #F list of patch ID (output of bfs_orient > manifold patches)
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedC>
+ IGL_INLINE void reorient_facets_raycast(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ int rays_total,
+ int rays_minimum,
+ bool facet_wise,
+ bool use_parity,
+ bool is_verbose,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ // Outputs:
+ // FF #F by 3 list of reoriented faces
+ // Defaults:
+ // rays_total = F.rows()*100;
+ // rays_minimum = 10;
+ // facet_wise = false;
+ // use_parity = false;
+ // is_verbose = false;
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedI>
+ IGL_INLINE void reorient_facets_raycast(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I);
+ }
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "reorient_facets_raycast.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/embree/shape_diameter_function.cpp b/xs/src/igl/embree/shape_diameter_function.cpp
new file mode 100644
index 000000000..3b0be489e
--- /dev/null
+++ b/xs/src/igl/embree/shape_diameter_function.cpp
@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "shape_diameter_function.h"
+#include "../shape_diameter_function.h"
+#include "EmbreeIntersector.h"
+#include "../Hit.h"
+
+template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::embree::shape_diameter_function(
+ const igl::embree::EmbreeIntersector & ei,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ const auto & shoot_ray = [&ei](
+ const Eigen::Vector3f& s,
+ const Eigen::Vector3f& dir)->double
+ {
+ igl::Hit hit;
+ const float tnear = 1e-4f;
+ if(ei.intersectRay(s,dir,hit,tnear))
+ {
+ return hit.t;
+ }else
+ {
+ return std::numeric_limits<double>::infinity();
+ }
+ };
+ return igl::shape_diameter_function(shoot_ray,P,N,num_samples,S);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::embree::shape_diameter_function(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ using namespace Eigen;
+ EmbreeIntersector ei;
+ ei.init(V.template cast<float>(),F.template cast<int>());
+ shape_diameter_function(ei,P,N,num_samples,S);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::embree::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::shape_diameter_function<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::shape_diameter_function<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::embree::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
+
diff --git a/xs/src/igl/embree/shape_diameter_function.h b/xs/src/igl/embree/shape_diameter_function.h
new file mode 100644
index 000000000..c18922d28
--- /dev/null
+++ b/xs/src/igl/embree/shape_diameter_function.h
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_SHAPE_DIAMETER_FUNCTION_H
+#define IGL_EMBREE_SHAPE_DIAMETER_FUNCTION_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace embree
+ {
+ // Forward define
+ class EmbreeIntersector;
+ // Compute shape diamter function per given point
+ //
+ // Inputs:
+ // ei EmbreeIntersector containing (V,F)
+ // P #P by 3 list of origin points
+ // N #P by 3 list of origin normals
+ // Outputs:
+ // S #P list of shape diamater function values between bounding box
+ // diagonal (perfect sphere) and 0 (perfect needle hook)
+ //
+ template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void shape_diameter_function(
+ const EmbreeIntersector & ei,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ // Wrapper which builds new EmbreeIntersector for (V,F). That's expensive so
+ // avoid this if repeatedly calling.
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void shape_diameter_function(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ }
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "shape_diameter_function.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/embree/unproject_in_mesh.cpp b/xs/src/igl/embree/unproject_in_mesh.cpp
new file mode 100644
index 000000000..79a24a0ab
--- /dev/null
+++ b/xs/src/igl/embree/unproject_in_mesh.cpp
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject_in_mesh.h"
+#include "EmbreeIntersector.h"
+#include "../unproject_ray.h"
+#include "../unproject_in_mesh.h"
+#include <vector>
+
+template <typename Derivedobj>
+IGL_INLINE int igl::embree::unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ Eigen::PlainObjectBase<Derivedobj> & obj,
+ std::vector<igl::Hit > & hits)
+{
+ using namespace std;
+ using namespace Eigen;
+ const auto & shoot_ray = [&ei](
+ const Eigen::Vector3f& s,
+ const Eigen::Vector3f& dir,
+ std::vector<igl::Hit> & hits)
+ {
+ int num_rays_shot;
+ ei.intersectRay(s,dir,hits,num_rays_shot);
+ };
+ return igl::unproject_in_mesh(pos,model,proj,viewport,shoot_ray,obj,hits);
+}
+
+template <typename Derivedobj>
+IGL_INLINE int igl::embree::unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ Eigen::PlainObjectBase<Derivedobj> & obj)
+{
+ std::vector<igl::Hit> hits;
+ return unproject_in_mesh(pos,model,proj,viewport,ei,obj,hits);
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+template int igl::embree::unproject_in_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+template int igl::embree::unproject_in_mesh<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+template int igl::embree::unproject_in_mesh<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, igl::embree::EmbreeIntersector const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+#endif
diff --git a/xs/src/igl/embree/unproject_in_mesh.h b/xs/src/igl/embree/unproject_in_mesh.h
new file mode 100644
index 000000000..707c1e625
--- /dev/null
+++ b/xs/src/igl/embree/unproject_in_mesh.h
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_UNPROJECT_IN_MESH
+#define IGL_EMBREE_UNPROJECT_IN_MESH
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+
+#include <vector>
+#include "../Hit.h"
+
+namespace igl
+{
+ namespace embree
+ {
+ // Forward define
+ class EmbreeIntersector;
+
+ // Unproject a screen location (using current opengl viewport, projection, and
+ // model view) to a 3D position _inside_ a given mesh. If the ray through the
+ // given screen location (x,y) _hits_ the mesh more than twice then the 3D
+ // midpoint between the first two hits is return. If it hits once, then that
+ // point is return. If it does not hit the mesh then obj is not set.
+ //
+ //
+ // Inputs:
+ // pos screen space coordinates
+ // model model matrix
+ // proj projection matrix
+ // viewport vieweport vector
+ // ei EmbreeIntersector containing (V,F)
+ // Outputs:
+ // obj 3d unprojected mouse point in mesh
+ // hits vector of embree hits
+ // Returns number of hits
+ //
+ // Note: Previous prototype did not require model, proj, and viewport. This
+ // has been removed. Instead replace with:
+ //
+ // Eigen::Matrix4f model,proj;
+ // Eigen::Vector4f viewport;
+ // igl::opengl2::model_proj_viewport(model,proj,viewport);
+ // igl::embree::unproject_in_mesh(Vector2f(x,y),model,proj,viewport,ei,obj,hits);
+ //
+ template < typename Derivedobj>
+ IGL_INLINE int unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ Eigen::PlainObjectBase<Derivedobj> & obj,
+ std::vector<igl::Hit > & hits);
+ template < typename Derivedobj>
+ IGL_INLINE int unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ Eigen::PlainObjectBase<Derivedobj> & obj);
+
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject_in_mesh.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/embree/unproject_onto_mesh.cpp b/xs/src/igl/embree/unproject_onto_mesh.cpp
new file mode 100644
index 000000000..a9d336690
--- /dev/null
+++ b/xs/src/igl/embree/unproject_onto_mesh.cpp
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject_onto_mesh.h"
+#include "EmbreeIntersector.h"
+#include "../unproject_onto_mesh.h"
+#include <vector>
+
+IGL_INLINE bool igl::embree::unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::MatrixXi& F,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ int& fid,
+ Eigen::Vector3f& bc)
+{
+ using namespace std;
+ using namespace Eigen;
+ const auto & shoot_ray = [&ei](
+ const Eigen::Vector3f& s,
+ const Eigen::Vector3f& dir,
+ igl::Hit & hit)->bool
+ {
+ return ei.intersectRay(s,dir,hit);
+ };
+ return igl::unproject_onto_mesh(pos,model,proj,viewport,shoot_ray,fid,bc);
+}
+
+IGL_INLINE bool igl::embree::unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::MatrixXi& F,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ int& fid,
+ int& vid)
+{
+ Eigen::Vector3f bc;
+ if(!igl::embree::unproject_onto_mesh(pos,F,model,proj,viewport,ei,fid,bc))
+ {
+ return false;
+ }
+ int i;
+ bc.maxCoeff(&i);
+ vid = F(fid,i);
+ return true;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/embree/unproject_onto_mesh.h b/xs/src/igl/embree/unproject_onto_mesh.h
new file mode 100644
index 000000000..db0a2e0cb
--- /dev/null
+++ b/xs/src/igl/embree/unproject_onto_mesh.h
@@ -0,0 +1,73 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EMBREE_UNPROJECT_ONTO_MESH_H
+#define IGL_EMBREE_UNPROJECT_ONTO_MESH_H
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+
+#include <vector>
+
+namespace igl
+{
+ namespace embree
+ {
+ // Forward define
+ class EmbreeIntersector;
+ // Unproject a screen location (using the given model, proj and viewport) to find
+ // the first hit on a mesh.
+ //
+ // Inputs:
+ // pos screen space coordinates
+ // F #F by 3 face matrix
+ // model model matrix
+ // proj projection matrix
+ // viewport vieweport vector
+ // ei EmbreeIntersector containing (V,F)
+ // Outputs:
+ // fid id of the first face hit
+ // bc barycentric coordinates of hit
+ // Returns true if there is a hit
+ IGL_INLINE bool unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::MatrixXi& F,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ int& fid,
+ Eigen::Vector3f& bc);
+
+ // Unproject a screen location (using the given model, proj and viewport) to find
+ // the first face on the mesh and the closest vertex
+ //
+ // Inputs:
+ // pos screen space coordinates
+ // F #F by 3 face matrix
+ // model model matrix
+ // proj projection matrix
+ // viewport vieweport vector
+ // ei EmbreeIntersector containing (V,F)
+ // Outputs:
+ // fid id of the first face hit
+ // vid vertex id of the closest vertex hit
+ // Returns true if there is a hit
+ IGL_INLINE bool unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::MatrixXi& F,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const EmbreeIntersector & ei,
+ int& fid,
+ int& vid);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject_onto_mesh.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/euler_characteristic.cpp b/xs/src/igl/euler_characteristic.cpp
new file mode 100644
index 000000000..ab7eba22b
--- /dev/null
+++ b/xs/src/igl/euler_characteristic.cpp
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich <michaelrabinovich27@gmail.com@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "euler_characteristic.h"
+
+#include "edge_topology.h"
+#include "edges.h"
+
+template <typename Scalar, typename Index>
+IGL_INLINE int igl::euler_characteristic(
+ const Eigen::PlainObjectBase<Scalar> & V,
+ const Eigen::PlainObjectBase<Index> & F)
+{
+
+ int euler_v = V.rows();
+ Eigen::MatrixXi EV, FE, EF;
+ igl::edge_topology(V, F, EV, FE, EF);
+ int euler_e = EV.rows();
+ int euler_f = F.rows();
+
+ int euler_char = euler_v - euler_e + euler_f;
+ return euler_char;
+
+}
+
+template <typename DerivedF>
+IGL_INLINE int igl::euler_characteristic(
+ const Eigen::MatrixBase<DerivedF> & F)
+{
+ const int nf = F.rows();
+ const int nv = F.maxCoeff()+1;
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,2> E;
+ edges(F,E);
+ const int ne = E.rows();
+ return nv - ne + nf;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template int igl::euler_characteristic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template int igl::euler_characteristic<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/euler_characteristic.h b/xs/src/igl/euler_characteristic.h
new file mode 100644
index 000000000..f4c0c0a0f
--- /dev/null
+++ b/xs/src/igl/euler_characteristic.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich <michaelrabinovich27@gmail.com>
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EULER_CHARACTERISTIC_H
+#define IGL_EULER_CHARACTERISTIC_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+#include <vector>
+namespace igl
+{
+ // Computes the Euler characteristic of a given mesh (V,F)
+ //
+ // Inputs:
+ // F #F by dim list of mesh faces (must be triangles)
+ // Returns An int containing the Euler characteristic
+ template <typename DerivedF>
+ IGL_INLINE int euler_characteristic(
+ const Eigen::MatrixBase<DerivedF> & F);
+
+ // Computes the Euler characteristic of a given mesh (V,F)
+ // Templates:
+ // Scalar should be a floating point number type
+ // Index should be an integer type
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by dim list of mesh faces (must be triangles)
+ // Returns An int containing the Euler characteristic
+ template <typename Scalar, typename Index>
+ IGL_INLINE int euler_characteristic(
+ const Eigen::PlainObjectBase<Scalar> & V,
+ const Eigen::PlainObjectBase<Index> & F);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "euler_characteristic.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/exact_geodesic.cpp b/xs/src/igl/exact_geodesic.cpp
new file mode 100644
index 000000000..e20783b88
--- /dev/null
+++ b/xs/src/igl/exact_geodesic.cpp
@@ -0,0 +1,3225 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Zhongshi Jiang <jiangzs@nyu.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "exact_geodesic.h"
+
+//Copyright (C) 2008 Danil Kirsanov, MIT License
+//Code from https://code.google.com/archive/p/geodesic/
+// Compiled into a single file by Zhongshi Jiang
+
+#include <igl/PI.h>
+#include <algorithm>
+#include <cassert>
+#include <cmath>
+#include <cstddef>
+#include <ctime>
+#include <fstream>
+#include <iostream>
+#include <set>
+#include <vector>
+#include <memory>
+namespace igl{
+namespace geodesic{
+
+//#include "geodesic_constants_and_simple_functions.h"
+
+//double const GEODESIC_INF = std::numeric_limits<double>::max();
+double const GEODESIC_INF = 1e100;
+
+//in order to avoid numerical problems with "infinitely small" intervals,
+//we drop all the intervals smaller than SMALLEST_INTERVAL_RATIO*edge_length
+double const SMALLEST_INTERVAL_RATIO = 1e-6;
+//double const SMALL_EPSILON = 1e-10;
+
+
+inline double cos_from_edges(double const a, //compute the cosine of the angle given the lengths of the edges
+ double const b,
+ double const c)
+{
+ assert(a>1e-50);
+ assert(b>1e-50);
+ assert(c>1e-50);
+
+ double result = (b*b + c*c - a*a)/(2.0*b*c);
+ result = std::max(result, -1.0);
+ return std::min(result, 1.0);
+}
+
+inline double angle_from_edges(double const a, //compute the cosine of the angle given the lengths of the edges
+ double const b,
+ double const c)
+{
+ return acos(cos_from_edges(a,b,c));
+}
+
+template<class Points, class Faces>
+inline bool read_mesh_from_file(char* filename,
+ Points& points,
+ Faces& faces)
+{
+ std::ifstream file(filename);
+ assert(file.is_open());
+ if(!file.is_open()) return false;
+
+ unsigned num_points;
+ file >> num_points;
+ assert(num_points>=3);
+
+ unsigned num_faces;
+ file >> num_faces;
+
+ points.resize(num_points*3);
+ for(typename Points::iterator i=points.begin(); i!=points.end(); ++i)
+ {
+ file >> *i;
+ }
+
+ faces.resize(num_faces*3);
+ for(typename Faces::iterator i=faces.begin(); i!=faces.end(); ++i)
+ {
+ file >> *i;
+ }
+ file.close();
+
+ return true;
+}
+
+// #include "geodesic_memory"
+template<class T> //quickly allocates multiple elements of a given type; no deallocation
+class SimlpeMemoryAllocator
+{
+public:
+ typedef T* pointer;
+
+ SimlpeMemoryAllocator(unsigned block_size = 0,
+ unsigned max_number_of_blocks = 0)
+ {
+ reset(block_size,
+ max_number_of_blocks);
+ };
+
+ ~SimlpeMemoryAllocator(){};
+
+ void reset(unsigned block_size,
+ unsigned max_number_of_blocks)
+ {
+ m_block_size = block_size;
+ m_max_number_of_blocks = max_number_of_blocks;
+
+
+ m_current_position = 0;
+
+ m_storage.reserve(max_number_of_blocks);
+ m_storage.resize(1);
+ m_storage[0].resize(block_size);
+ };
+
+ pointer allocate(unsigned const n) //allocate n units
+ {
+ assert(n < m_block_size);
+
+ if(m_current_position + n >= m_block_size)
+ {
+ m_storage.push_back( std::vector<T>() );
+ m_storage.back().resize(m_block_size);
+ m_current_position = 0;
+ }
+ pointer result = & m_storage.back()[m_current_position];
+ m_current_position += n;
+
+ return result;
+ };
+private:
+ std::vector<std::vector<T> > m_storage;
+ unsigned m_block_size; //size of a single block
+ unsigned m_max_number_of_blocks; //maximum allowed number of blocks
+ unsigned m_current_position; //first unused element inside the current block
+};
+
+
+template<class T> //quickly allocates and deallocates single elements of a given type
+class MemoryAllocator
+{
+public:
+ typedef T* pointer;
+
+ MemoryAllocator(unsigned block_size = 1024,
+ unsigned max_number_of_blocks = 1024)
+ {
+ reset(block_size,
+ max_number_of_blocks);
+ };
+
+ ~MemoryAllocator(){};
+
+ void clear()
+ {
+ reset(m_block_size,
+ m_max_number_of_blocks);
+ }
+
+ void reset(unsigned block_size,
+ unsigned max_number_of_blocks)
+ {
+ m_block_size = block_size;
+ m_max_number_of_blocks = max_number_of_blocks;
+
+ assert(m_block_size > 0);
+ assert(m_max_number_of_blocks > 0);
+
+ m_current_position = 0;
+
+ m_storage.reserve(max_number_of_blocks);
+ m_storage.resize(1);
+ m_storage[0].resize(block_size);
+
+ m_deleted.clear();
+ m_deleted.reserve(2*block_size);
+ };
+
+ pointer allocate() //allocates single unit of memory
+ {
+ pointer result;
+ if(m_deleted.empty())
+ {
+ if(m_current_position + 1 >= m_block_size)
+ {
+ m_storage.push_back( std::vector<T>() );
+ m_storage.back().resize(m_block_size);
+ m_current_position = 0;
+ }
+ result = & m_storage.back()[m_current_position];
+ ++m_current_position;
+ }
+ else
+ {
+ result = m_deleted.back();
+ m_deleted.pop_back();
+ }
+
+ return result;
+ };
+
+ void deallocate(pointer p) //allocate n units
+ {
+ if(m_deleted.size() < m_deleted.capacity())
+ {
+ m_deleted.push_back(p);
+ }
+ };
+
+private:
+ std::vector<std::vector<T> > m_storage;
+ unsigned m_block_size; //size of a single block
+ unsigned m_max_number_of_blocks; //maximum allowed number of blocks
+ unsigned m_current_position; //first unused element inside the current block
+
+ std::vector<pointer> m_deleted; //pointers to deleted elemets
+};
+
+
+class OutputBuffer
+{
+public:
+ OutputBuffer():
+ m_num_bytes(0)
+ {}
+
+ void clear()
+ {
+ m_num_bytes = 0;
+ m_buffer = std::shared_ptr<double>();
+ }
+
+ template<class T>
+ T* allocate(unsigned n)
+ {
+ double wanted = n*sizeof(T);
+ if(wanted > m_num_bytes)
+ {
+ unsigned new_size = (unsigned) ceil(wanted / (double)sizeof(double));
+ m_buffer = std::shared_ptr<double>(new double[new_size]);
+ m_num_bytes = new_size*sizeof(double);
+ }
+
+ return (T*)m_buffer.get();
+ }
+
+ template <class T>
+ T* get()
+ {
+ return (T*)m_buffer.get();
+ }
+
+ template<class T>
+ unsigned capacity()
+ {
+ return (unsigned)floor((double)m_num_bytes/(double)sizeof(T));
+ };
+
+private:
+
+ std::shared_ptr<double> m_buffer;
+ unsigned m_num_bytes;
+};
+
+
+
+
+class Vertex;
+class Edge;
+class Face;
+class Mesh;
+class MeshElementBase;
+
+typedef Vertex* vertex_pointer;
+typedef Edge* edge_pointer;
+typedef Face* face_pointer;
+typedef Mesh* mesh_pointer;
+typedef MeshElementBase* base_pointer;
+
+template <class Data> //simple vector that stores info about mesh references
+class SimpleVector //for efficiency, it uses an outside memory allocator
+{
+public:
+ SimpleVector():
+ m_size(0),
+ m_begin(NULL)
+ {};
+
+ typedef Data* iterator;
+
+ unsigned size(){return m_size;};
+ iterator begin(){return m_begin;};
+ iterator end(){return m_begin + m_size;};
+
+ template<class DataPointer>
+ void set_allocation(DataPointer begin, unsigned size)
+ {
+ assert(begin != NULL || size == 0);
+ m_size = size;
+ m_begin = (iterator)begin;
+ }
+
+ Data& operator[](unsigned i)
+ {
+ assert(i < m_size);
+ return *(m_begin + i);
+ }
+
+ void clear()
+ {
+ m_size = 0;
+ m_begin = NULL;
+ }
+
+private:
+ unsigned m_size;
+ Data* m_begin;
+};
+
+enum PointType
+{
+ VERTEX,
+ EDGE,
+ FACE,
+ UNDEFINED_POINT
+};
+
+class MeshElementBase //prototype of vertices, edges and faces
+{
+public:
+ typedef SimpleVector<vertex_pointer> vertex_pointer_vector;
+ typedef SimpleVector<edge_pointer> edge_pointer_vector;
+ typedef SimpleVector<face_pointer> face_pointer_vector;
+
+ MeshElementBase():
+ m_id(0),
+ m_type(UNDEFINED_POINT)
+ {};
+
+ vertex_pointer_vector& adjacent_vertices(){return m_adjacent_vertices;};
+ edge_pointer_vector& adjacent_edges(){return m_adjacent_edges;};
+ face_pointer_vector& adjacent_faces(){return m_adjacent_faces;};
+
+ unsigned& id(){return m_id;};
+ PointType type(){return m_type;};
+
+protected:
+ vertex_pointer_vector m_adjacent_vertices; //list of the adjacent vertices
+ edge_pointer_vector m_adjacent_edges; //list of the adjacent edges
+ face_pointer_vector m_adjacent_faces; //list of the adjacent faces
+
+ unsigned m_id; //unique id
+ PointType m_type; //vertex, edge or face
+};
+
+class Point3D //point in 3D and corresponding operations
+{
+public:
+ Point3D(){};
+ Point3D(Point3D* p)
+ {
+ x() = p->x();
+ y() = p->y();
+ z() = p->z();
+ };
+
+ double* xyz(){return m_coordinates;};
+ double& x(){return *m_coordinates;};
+ double& y(){return *(m_coordinates+1);};
+ double& z(){return *(m_coordinates+2);};
+
+ void set(double new_x, double new_y, double new_z)
+ {
+ x() = new_x;
+ y() = new_y;
+ z() = new_z;
+ }
+
+ void set(double* data)
+ {
+ x() = *data;
+ y() = *(data+1);
+ z() = *(data+2);
+ }
+
+ double distance(double* v)
+ {
+ double dx = m_coordinates[0] - v[0];
+ double dy = m_coordinates[1] - v[1];
+ double dz = m_coordinates[2] - v[2];
+
+ return sqrt(dx*dx + dy*dy + dz*dz);
+ };
+
+ double distance(Point3D* v)
+ {
+ return distance(v->xyz());
+ };
+
+ void add(Point3D* v)
+ {
+ x() += v->x();
+ y() += v->y();
+ z() += v->z();
+ };
+
+ void multiply(double v)
+ {
+ x() *= v;
+ y() *= v;
+ z() *= v;
+ };
+
+private:
+ double m_coordinates[3]; //xyz
+};
+
+class Vertex: public MeshElementBase, public Point3D
+{
+public:
+ Vertex()
+ {
+ m_type = VERTEX;
+ };
+
+ ~Vertex(){};
+
+ bool& saddle_or_boundary(){return m_saddle_or_boundary;};
+private:
+ //this flag speeds up exact geodesic algorithm
+ bool m_saddle_or_boundary; //it is true if total adjacent angle is larger than 2*PI or this vertex belongs to the mesh boundary
+};
+
+
+class Face: public MeshElementBase
+{
+public:
+ Face()
+ {
+ m_type = FACE;
+ };
+
+ ~Face(){};
+
+ edge_pointer opposite_edge(vertex_pointer v);
+ vertex_pointer opposite_vertex(edge_pointer e);
+ edge_pointer next_edge(edge_pointer e, vertex_pointer v);
+
+ double vertex_angle(vertex_pointer v)
+ {
+ for(unsigned i=0; i<3; ++i)
+ {
+ if(adjacent_vertices()[i]->id() == v->id())
+ {
+ return m_corner_angles[i];
+ }
+ }
+ assert(0);
+ return 0;
+ }
+
+ double* corner_angles(){return m_corner_angles;};
+
+private:
+ double m_corner_angles[3]; //triangle angles in radians; angles correspond to vertices in m_adjacent_vertices
+};
+
+class Edge: public MeshElementBase
+{
+public:
+ Edge()
+ {
+ m_type = EDGE;
+ };
+
+ ~Edge(){};
+
+ double& length(){return m_length;};
+
+ face_pointer opposite_face(face_pointer f)
+ {
+ if(adjacent_faces().size() == 1)
+ {
+ assert(adjacent_faces()[0]->id() == f->id());
+ return NULL;
+ }
+
+ assert(adjacent_faces()[0]->id() == f->id() ||
+ adjacent_faces()[1]->id() == f->id());
+
+ return adjacent_faces()[0]->id() == f->id() ?
+ adjacent_faces()[1] : adjacent_faces()[0];
+ };
+
+ vertex_pointer opposite_vertex(vertex_pointer v)
+ {
+ assert(belongs(v));
+
+ return adjacent_vertices()[0]->id() == v->id() ?
+ adjacent_vertices()[1] : adjacent_vertices()[0];
+ };
+
+ bool belongs(vertex_pointer v)
+ {
+ return adjacent_vertices()[0]->id() == v->id() ||
+ adjacent_vertices()[1]->id() == v->id();
+ }
+
+ bool is_boundary(){return adjacent_faces().size() == 1;};
+
+ vertex_pointer v0(){return adjacent_vertices()[0];};
+ vertex_pointer v1(){return adjacent_vertices()[1];};
+
+ void local_coordinates(Point3D* point,
+ double& x,
+ double& y)
+ {
+ double d0 = point->distance(v0());
+ if(d0 < 1e-50)
+ {
+ x = 0.0;
+ y = 0.0;
+ return;
+ }
+
+ double d1 = point->distance(v1());
+ if(d1 < 1e-50)
+ {
+ x = m_length;
+ y = 0.0;
+ return;
+ }
+
+ x = m_length/2.0 + (d0*d0 - d1*d1)/(2.0*m_length);
+ y = sqrt(std::max(0.0, d0*d0 - x*x));
+ return;
+ }
+
+private:
+ double m_length; //length of the edge
+};
+
+class SurfacePoint:public Point3D //point on the surface of the mesh
+{
+public:
+ SurfacePoint():
+ m_p(NULL)
+ {};
+
+ SurfacePoint(vertex_pointer v): //set the surface point in the vertex
+ SurfacePoint::Point3D(v),
+ m_p(v)
+ {};
+
+ SurfacePoint(face_pointer f): //set the surface point in the center of the face
+ m_p(f)
+ {
+ set(0,0,0);
+ add(f->adjacent_vertices()[0]);
+ add(f->adjacent_vertices()[1]);
+ add(f->adjacent_vertices()[2]);
+ multiply(1./3.);
+ };
+
+ SurfacePoint(edge_pointer e, //set the surface point in the middle of the edge
+ double a = 0.5):
+ m_p(e)
+ {
+ double b = 1 - a;
+
+ vertex_pointer v0 = e->adjacent_vertices()[0];
+ vertex_pointer v1 = e->adjacent_vertices()[1];
+
+ x() = b*v0->x() + a*v1->x();
+ y() = b*v0->y() + a*v1->y();
+ z() = b*v0->z() + a*v1->z();
+ };
+
+ SurfacePoint(base_pointer g,
+ double x,
+ double y,
+ double z,
+ PointType t = UNDEFINED_POINT):
+ m_p(g)
+ {
+ set(x,y,z);
+ };
+
+ void initialize(SurfacePoint const& p)
+ {
+ *this = p;
+ }
+
+ ~SurfacePoint(){};
+
+ PointType type(){return m_p ? m_p->type() : UNDEFINED_POINT;};
+ base_pointer& base_element(){return m_p;};
+protected:
+ base_pointer m_p; //could be face, vertex or edge pointer
+};
+
+inline edge_pointer Face::opposite_edge(vertex_pointer v)
+{
+ for(unsigned i=0; i<3; ++i)
+ {
+ edge_pointer e = adjacent_edges()[i];
+ if(!e->belongs(v))
+ {
+ return e;
+ }
+ }
+ assert(0);
+ return NULL;
+}
+
+inline vertex_pointer Face::opposite_vertex(edge_pointer e)
+{
+ for(unsigned i=0; i<3; ++i)
+ {
+ vertex_pointer v = adjacent_vertices()[i];
+ if(!e->belongs(v))
+ {
+ return v;
+ }
+ }
+ assert(0);
+ return NULL;
+}
+
+inline edge_pointer Face::next_edge(edge_pointer e, vertex_pointer v)
+{
+ assert(e->belongs(v));
+
+ for(unsigned i=0; i<3; ++i)
+ {
+ edge_pointer next = adjacent_edges()[i];
+ if(e->id() != next->id() && next->belongs(v))
+ {
+ return next;
+ }
+ }
+ assert(0);
+ return NULL;
+}
+
+struct HalfEdge //prototype of the edge; used for mesh construction
+{
+ unsigned face_id;
+ unsigned vertex_0; //adjacent vertices sorted by id value
+ unsigned vertex_1; //they are sorted, vertex_0 < vertex_1
+};
+
+inline bool operator < (const HalfEdge &x, const HalfEdge &y)
+{
+ if(x.vertex_0 == y.vertex_0)
+ {
+ return x.vertex_1 < y.vertex_1;
+ }
+ else
+ {
+ return x.vertex_0 < y.vertex_0;
+ }
+}
+
+inline bool operator != (const HalfEdge &x, const HalfEdge &y)
+{
+ return x.vertex_0 != y.vertex_0 || x.vertex_1 != y.vertex_1;
+}
+
+inline bool operator == (const HalfEdge &x, const HalfEdge &y)
+{
+ return x.vertex_0 == y.vertex_0 && x.vertex_1 == y.vertex_1;
+}
+
+struct edge_visible_from_source
+{
+ unsigned source;
+ edge_pointer edge;
+};
+
+class Mesh
+{
+public:
+ Mesh()
+ {};
+
+ ~Mesh(){};
+
+ template<class Points, class Faces>
+ void initialize_mesh_data(unsigned num_vertices,
+ Points& p,
+ unsigned num_faces,
+ Faces& tri); //build mesh from regular point-triangle representation
+
+ template<class Points, class Faces>
+ void initialize_mesh_data(Points& p, Faces& tri); //build mesh from regular point-triangle representation
+
+ std::vector<Vertex>& vertices(){return m_vertices;};
+ std::vector<Edge>& edges(){return m_edges;};
+ std::vector<Face>& faces(){return m_faces;};
+
+ unsigned closest_vertices(SurfacePoint* p,
+ std::vector<vertex_pointer>* storage = NULL); //list vertices closest to the point
+
+private:
+
+ void build_adjacencies(); //build internal structure of the mesh
+ bool verify(); //verifies connectivity of the mesh and prints some debug info
+
+ typedef void* void_pointer;
+ void_pointer allocate_pointers(unsigned n)
+ {
+ return m_pointer_allocator.allocate(n);
+ }
+
+ std::vector<Vertex> m_vertices;
+ std::vector<Edge> m_edges;
+ std::vector<Face> m_faces;
+
+ SimlpeMemoryAllocator<void_pointer> m_pointer_allocator; //fast memory allocating for Face/Vertex/Edge cross-references
+};
+
+inline unsigned Mesh::closest_vertices(SurfacePoint* p,
+ std::vector<vertex_pointer>* storage)
+{
+ assert(p->type() != UNDEFINED_POINT);
+
+ if(p->type() == VERTEX)
+ {
+ if(storage)
+ {
+ storage->push_back(static_cast<vertex_pointer>(p->base_element()));
+ }
+ return 1;
+ }
+ else if(p->type() == FACE)
+ {
+ if(storage)
+ {
+ vertex_pointer* vp= p->base_element()->adjacent_vertices().begin();
+ storage->push_back(*vp);
+ storage->push_back(*(vp+1));
+ storage->push_back(*(vp+2));
+ }
+ return 2;
+ }
+ else if(p->type() == EDGE) //for edge include all 4 adjacent vertices
+ {
+ edge_pointer edge = static_cast<edge_pointer>(p->base_element());
+
+ if(storage)
+ {
+ storage->push_back(edge->adjacent_vertices()[0]);
+ storage->push_back(edge->adjacent_vertices()[1]);
+
+ for(unsigned i = 0; i < edge->adjacent_faces().size(); ++i)
+ {
+ face_pointer face = edge->adjacent_faces()[i];
+ storage->push_back(face->opposite_vertex(edge));
+ }
+ }
+ return 2 + edge->adjacent_faces().size();
+ }
+
+ assert(0);
+ return 0;
+}
+
+template<class Points, class Faces>
+void Mesh::initialize_mesh_data(Points& p, Faces& tri) //build mesh from regular point-triangle representation
+{
+ assert(p.size() % 3 == 0);
+ unsigned const num_vertices = p.size() / 3;
+ assert(tri.size() % 3 == 0);
+ unsigned const num_faces = tri.size() / 3;
+
+ initialize_mesh_data(num_vertices, p, num_faces, tri);
+}
+
+template<class Points, class Faces>
+void Mesh::initialize_mesh_data(unsigned num_vertices,
+ Points& p,
+ unsigned num_faces,
+ Faces& tri)
+{
+ unsigned const approximate_number_of_internal_pointers = (num_vertices + num_faces)*4;
+ unsigned const max_number_of_pointer_blocks = 100;
+ m_pointer_allocator.reset(approximate_number_of_internal_pointers,
+ max_number_of_pointer_blocks);
+
+ m_vertices.resize(num_vertices);
+ for(unsigned i=0; i<num_vertices; ++i) //copy coordinates to vertices
+ {
+ Vertex& v = m_vertices[i];
+ v.id() = i;
+
+ unsigned shift = 3*i;
+ v.x() = p[shift];
+ v.y() = p[shift + 1];
+ v.z() = p[shift + 2];
+ }
+
+ m_faces.resize(num_faces);
+ for(unsigned i=0; i<num_faces; ++i) //copy adjacent vertices to polygons/faces
+ {
+ Face& f = m_faces[i];
+ f.id() = i;
+ f.adjacent_vertices().set_allocation(allocate_pointers(3),3); //allocate three units of memory
+
+ unsigned shift = 3*i;
+ for(unsigned j=0; j<3; ++j)
+ {
+ unsigned vertex_index = tri[shift + j];
+ assert(vertex_index < num_vertices);
+ f.adjacent_vertices()[j] = &m_vertices[vertex_index];
+ }
+ }
+
+ build_adjacencies(); //build the structure of the mesh
+}
+
+inline void Mesh::build_adjacencies()
+{
+ // Vertex->adjacent Faces
+ std::vector<unsigned> count(m_vertices.size()); //count adjacent vertices
+ for(unsigned i=0; i<m_faces.size(); ++i)
+ {
+ Face& f = m_faces[i];
+ for(unsigned j=0; j<3; ++j)
+ {
+ unsigned vertex_id = f.adjacent_vertices()[j]->id();
+ assert(vertex_id < m_vertices.size());
+ count[vertex_id]++;
+ }
+ }
+
+ for(unsigned i=0; i<m_vertices.size(); ++i) //reserve space
+ {
+ Vertex& v = m_vertices[i];
+ unsigned num_adjacent_faces = count[i];
+
+ v.adjacent_faces().set_allocation(allocate_pointers(num_adjacent_faces), //allocate three units of memory
+ num_adjacent_faces);
+ }
+
+ std::fill(count.begin(), count.end(), 0);
+ for(unsigned i=0; i<m_faces.size(); ++i)
+ {
+ Face& f = m_faces[i];
+ for(unsigned j=0; j<3; ++j)
+ {
+ vertex_pointer v = f.adjacent_vertices()[j];
+ v->adjacent_faces()[count[v->id()]++] = &f;
+ }
+ }
+
+ //find all edges
+ //i.e. find all half-edges, sort and combine them into edges
+ std::vector<HalfEdge> half_edges(m_faces.size()*3);
+ unsigned k = 0;
+ for(unsigned i=0; i<m_faces.size(); ++i)
+ {
+ Face& f = m_faces[i];
+ for(unsigned j=0; j<3; ++j)
+ {
+ half_edges[k].face_id = i;
+ unsigned vertex_id_1 = f.adjacent_vertices()[j]->id();
+ unsigned vertex_id_2 = f.adjacent_vertices()[(j+1) % 3]->id();
+ half_edges[k].vertex_0 = std::min(vertex_id_1, vertex_id_2);
+ half_edges[k].vertex_1 = std::max(vertex_id_1, vertex_id_2);
+
+ k++;
+ }
+ }
+ std::sort(half_edges.begin(), half_edges.end());
+
+ unsigned number_of_edges = 1;
+ for(unsigned i=1; i<half_edges.size(); ++i)
+ {
+ if(half_edges[i] != half_edges[i-1])
+ {
+ ++number_of_edges;
+ }
+ else
+ {
+ if(i<half_edges.size()-1) //sanity check: there should be at most two equal half-edges
+ { //if it fails, most likely the input data are messed up
+ assert(half_edges[i] != half_edges[i+1]);
+ }
+ }
+ }
+
+ // Edges->adjacent Vertices and Faces
+ m_edges.resize(number_of_edges);
+ unsigned edge_id = 0;
+ for(unsigned i=0; i<half_edges.size();)
+ {
+ Edge& e = m_edges[edge_id];
+ e.id() = edge_id++;
+
+ e.adjacent_vertices().set_allocation(allocate_pointers(2),2); //allocate two units of memory
+
+ e.adjacent_vertices()[0] = &m_vertices[half_edges[i].vertex_0];
+ e.adjacent_vertices()[1] = &m_vertices[half_edges[i].vertex_1];
+
+ e.length() = e.adjacent_vertices()[0]->distance(e.adjacent_vertices()[1]);
+ assert(e.length() > 1e-100); //algorithm works well with non-degenerate meshes only
+
+ if(i != half_edges.size()-1 && half_edges[i] == half_edges[i+1]) //double edge
+ {
+ e.adjacent_faces().set_allocation(allocate_pointers(2),2);
+ e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
+ e.adjacent_faces()[1] = &m_faces[half_edges[i+1].face_id];
+ i += 2;
+ }
+ else //single edge
+ {
+ e.adjacent_faces().set_allocation(allocate_pointers(1),1); //one adjucent faces
+ e.adjacent_faces()[0] = &m_faces[half_edges[i].face_id];
+ i += 1;
+ }
+ }
+
+ // Vertices->adjacent Edges
+ std::fill(count.begin(), count.end(), 0);
+ for(unsigned i=0; i<m_edges.size(); ++i)
+ {
+ Edge& e = m_edges[i];
+ assert(e.adjacent_vertices().size()==2);
+ count[e.adjacent_vertices()[0]->id()]++;
+ count[e.adjacent_vertices()[1]->id()]++;
+ }
+ for(unsigned i=0; i<m_vertices.size(); ++i)
+ {
+ m_vertices[i].adjacent_edges().set_allocation(allocate_pointers(count[i]),
+ count[i]);
+ }
+ std::fill(count.begin(), count.end(), 0);
+ for(unsigned i=0; i<m_edges.size(); ++i)
+ {
+ Edge& e = m_edges[i];
+ for(unsigned j=0; j<2; ++j)
+ {
+ vertex_pointer v = e.adjacent_vertices()[j];
+ v->adjacent_edges()[count[v->id()]++] = &e;
+ }
+ }
+
+ // Faces->adjacent Edges
+ for(unsigned i=0; i<m_faces.size(); ++i)
+ {
+ m_faces[i].adjacent_edges().set_allocation(allocate_pointers(3),3);
+ }
+
+ count.resize(m_faces.size());
+ std::fill(count.begin(), count.end(), 0);
+ for(unsigned i=0; i<m_edges.size(); ++i)
+ {
+ Edge& e = m_edges[i];
+ for(unsigned j=0; j<e.adjacent_faces().size(); ++j)
+ {
+ face_pointer f = e.adjacent_faces()[j];
+ assert(count[f->id()]<3);
+ f->adjacent_edges()[count[f->id()]++] = &e;
+ }
+ }
+
+ //compute angles for the faces
+ for(unsigned i=0; i<m_faces.size(); ++i)
+ {
+ Face& f = m_faces[i];
+ double abc[3];
+ double sum = 0;
+ for(unsigned j=0; j<3; ++j) //compute angle adjacent to the vertex j
+ {
+ for(unsigned k=0; k<3; ++k)
+ {
+ vertex_pointer v = f.adjacent_vertices()[(j + k)%3];
+ abc[k] = f.opposite_edge(v)->length();
+ }
+
+ double angle = angle_from_edges(abc[0], abc[1], abc[2]);
+ assert(angle>1e-5); //algorithm works well with non-degenerate meshes only
+
+ f.corner_angles()[j] = angle;
+ sum += angle;
+ }
+ assert(std::abs(sum - igl::PI) < 1e-5); //algorithm works well with non-degenerate meshes only
+ }
+
+ //define m_turn_around_flag for vertices
+ std::vector<double> total_vertex_angle(m_vertices.size());
+ for(unsigned i=0; i<m_faces.size(); ++i)
+ {
+ Face& f = m_faces[i];
+ for(unsigned j=0; j<3; ++j)
+ {
+ vertex_pointer v = f.adjacent_vertices()[j];
+ total_vertex_angle[v->id()] += f.corner_angles()[j];
+ }
+ }
+
+ for(unsigned i=0; i<m_vertices.size(); ++i)
+ {
+ Vertex& v = m_vertices[i];
+ v.saddle_or_boundary() = (total_vertex_angle[v.id()] > 2.0*igl::PI - 1e-5);
+ }
+
+ for(unsigned i=0; i<m_edges.size(); ++i)
+ {
+ Edge& e = m_edges[i];
+ if(e.is_boundary())
+ {
+ e.adjacent_vertices()[0]->saddle_or_boundary() = true;
+ e.adjacent_vertices()[1]->saddle_or_boundary() = true;
+ }
+ }
+
+ assert(verify());
+}
+
+inline bool Mesh::verify() //verifies connectivity of the mesh and prints some debug info
+{
+ std::cout << std::endl;
+ // make sure that all vertices are mentioned at least once.
+ // though the loose vertex is not a bug, it most likely indicates that something is wrong with the mesh
+ std::vector<bool> map(m_vertices.size(), false);
+ for(unsigned i=0; i<m_edges.size(); ++i)
+ {
+ edge_pointer e = &m_edges[i];
+ map[e->adjacent_vertices()[0]->id()] = true;
+ map[e->adjacent_vertices()[1]->id()] = true;
+ }
+ assert(std::find(map.begin(), map.end(), false) == map.end());
+
+ //make sure that the mesh is connected trough its edges
+ //if mesh has more than one connected component, it is most likely a bug
+ std::vector<face_pointer> stack(1,&m_faces[0]);
+ stack.reserve(m_faces.size());
+
+ map.resize(m_faces.size());
+ std::fill(map.begin(), map.end(), false);
+ map[0] = true;
+
+ while(!stack.empty())
+ {
+ face_pointer f = stack.back();
+ stack.pop_back();
+
+ for(unsigned i=0; i<3; ++i)
+ {
+ edge_pointer e = f->adjacent_edges()[i];
+ face_pointer f_adjacent = e->opposite_face(f);
+ if(f_adjacent && !map[f_adjacent->id()])
+ {
+ map[f_adjacent->id()] = true;
+ stack.push_back(f_adjacent);
+ }
+ }
+ }
+ assert(std::find(map.begin(), map.end(), false) == map.end());
+
+ //print some mesh statistics that can be useful in debugging
+ // std::cout << "mesh has " << m_vertices.size()
+ // << " vertices, " << m_faces.size()
+ // << " faces, " << m_edges.size()
+ // << " edges\n";
+
+ unsigned total_boundary_edges = 0;
+ double longest_edge = 0;
+ double shortest_edge = 1e100;
+ for(unsigned i=0; i<m_edges.size(); ++i)
+ {
+ Edge& e = m_edges[i];
+ total_boundary_edges += e.is_boundary() ? 1 : 0;
+ longest_edge = std::max(longest_edge, e.length());
+ shortest_edge = std::min(shortest_edge, e.length());
+ }
+ // std::cout << total_boundary_edges << " edges are boundary edges\n";
+ // std::cout << "shortest/longest edges are "
+ // << shortest_edge << "/"
+ // << longest_edge << " = "
+ // << shortest_edge/longest_edge
+ // << std::endl;
+
+ double minx = 1e100;
+ double maxx = -1e100;
+ double miny = 1e100;
+ double maxy = -1e100;
+ double minz = 1e100;
+ double maxz = -1e100;
+ for(unsigned i=0; i<m_vertices.size(); ++i)
+ {
+ Vertex& v = m_vertices[i];
+ minx = std::min(minx, v.x());
+ maxx = std::max(maxx, v.x());
+ miny = std::min(miny, v.y());
+ maxy = std::max(maxy, v.y());
+ minz = std::min(minz, v.z());
+ maxz = std::max(maxz, v.z());
+ }
+ // std::cout << "enclosing XYZ box:"
+ // <<" X[" << minx << "," << maxx << "]"
+ // <<" Y[" << miny << "," << maxy << "]"
+ // <<" Z[" << minz << "," << maxz << "]"
+ // << std::endl;
+
+ double dx = maxx - minx;
+ double dy = maxy - miny;
+ double dz = maxz - minz;
+ // std::cout << "approximate diameter of the mesh is "
+ // << sqrt(dx*dx + dy*dy + dz*dz)
+ // << std::endl;
+
+ double min_angle = 1e100;
+ double max_angle = -1e100;
+ for(unsigned i=0; i<m_faces.size(); ++i)
+ {
+ Face& f = m_faces[i];
+ for(unsigned j=0; j<3; ++j)
+ {
+ double angle = f.corner_angles()[j];
+ min_angle = std::min(min_angle, angle);
+ max_angle = std::max(max_angle, angle);
+ }
+ }
+ // std::cout << "min/max face angles are "
+ // << min_angle/igl::PI*180.0 << "/"
+ // << max_angle/igl::PI*180.0
+ // << " degrees\n";
+
+ // std::cout << std::endl;
+ return true;
+}
+
+inline void fill_surface_point_structure(geodesic::SurfacePoint* point,
+ double* data,
+ Mesh* mesh)
+{
+ point->set(data);
+ unsigned type = (unsigned) data[3];
+ unsigned id = (unsigned) data[4];
+
+
+ if(type == 0) //vertex
+ {
+ point->base_element() = &mesh->vertices()[id];
+ }
+ else if(type == 1) //edge
+ {
+ point->base_element() = &mesh->edges()[id];
+ }
+ else //face
+ {
+ point->base_element() = &mesh->faces()[id];
+ }
+}
+
+inline void fill_surface_point_double(geodesic::SurfacePoint* point,
+ double* data,
+ long mesh_id)
+{
+ data[0] = point->x();
+ data[1] = point->y();
+ data[2] = point->z();
+ data[4] = point->base_element()->id();
+
+ if(point->type() == VERTEX) //vertex
+ {
+ data[3] = 0;
+ }
+ else if(point->type() == EDGE) //edge
+ {
+ data[3] = 1;
+ }
+ else //face
+ {
+ data[3] = 2;
+ }
+}
+
+class Interval;
+class IntervalList;
+typedef Interval* interval_pointer;
+typedef IntervalList* list_pointer;
+
+class Interval //interval of the edge
+{
+public:
+
+ Interval(){};
+ ~Interval(){};
+
+ enum DirectionType
+ {
+ FROM_FACE_0,
+ FROM_FACE_1,
+ FROM_SOURCE,
+ UNDEFINED_DIRECTION
+ };
+
+ double signal(double x) //geodesic distance function at point x
+ {
+ assert(x>=0.0 && x <= m_edge->length());
+
+ if(m_d == GEODESIC_INF)
+ {
+ return GEODESIC_INF;
+ }
+ else
+ {
+ double dx = x - m_pseudo_x;
+ if(m_pseudo_y == 0.0)
+ {
+ return m_d + std::abs(dx);
+ }
+ else
+ {
+ return m_d + sqrt(dx*dx + m_pseudo_y*m_pseudo_y);
+ }
+ }
+ }
+
+ double max_distance(double end)
+ {
+ if(m_d == GEODESIC_INF)
+ {
+ return GEODESIC_INF;
+ }
+ else
+ {
+ double a = std::abs(m_start - m_pseudo_x);
+ double b = std::abs(end - m_pseudo_x);
+
+ return a > b ? m_d + sqrt(a*a + m_pseudo_y*m_pseudo_y):
+ m_d + sqrt(b*b + m_pseudo_y*m_pseudo_y);
+ }
+ }
+
+ void compute_min_distance(double stop) //compute min, given c,d theta, start, end.
+ {
+ assert(stop > m_start);
+
+ if(m_d == GEODESIC_INF)
+ {
+ m_min = GEODESIC_INF;
+ }
+ else if(m_start > m_pseudo_x)
+ {
+ m_min = signal(m_start);
+ }
+ else if(stop < m_pseudo_x)
+ {
+ m_min = signal(stop);
+ }
+ else
+ {
+ assert(m_pseudo_y<=0);
+ m_min = m_d - m_pseudo_y;
+ }
+ }
+ //compare two intervals in the queue
+ bool operator()(interval_pointer const x, interval_pointer const y) const
+ {
+ if(x->min() != y->min())
+ {
+ return x->min() < y->min();
+ }
+ else if(x->start() != y->start())
+ {
+ return x->start() < y->start();
+ }
+ else
+ {
+ return x->edge()->id() < y->edge()->id();
+ }
+ }
+
+ double stop() //return the endpoint of the interval
+ {
+ return m_next ? m_next->start() : m_edge->length();
+ }
+
+ double hypotenuse(double a, double b)
+ {
+ return sqrt(a*a + b*b);
+ }
+
+ void find_closest_point(double const x,
+ double const y,
+ double& offset,
+ double& distance); //find the point on the interval that is closest to the point (alpha, s)
+
+ double& start(){return m_start;};
+ double& d(){return m_d;};
+ double& pseudo_x(){return m_pseudo_x;};
+ double& pseudo_y(){return m_pseudo_y;};
+ double& min(){return m_min;};
+ interval_pointer& next(){return m_next;};
+ edge_pointer& edge(){return m_edge;};
+ DirectionType& direction(){return m_direction;};
+ bool visible_from_source(){return m_direction == FROM_SOURCE;};
+ unsigned& source_index(){return m_source_index;};
+
+ void initialize(edge_pointer edge,
+ SurfacePoint* point = NULL,
+ unsigned source_index = 0);
+
+protected:
+ double m_start; //initial point of the interval on the edge
+ double m_d; //distance from the source to the pseudo-source
+ double m_pseudo_x; //coordinates of the pseudo-source in the local coordinate system
+ double m_pseudo_y; //y-coordinate should be always negative
+ double m_min; //minimum distance on the interval
+
+ interval_pointer m_next; //pointer to the next interval in the list
+ edge_pointer m_edge; //edge that the interval belongs to
+ unsigned m_source_index; //the source it belongs to
+ DirectionType m_direction; //where the interval is coming from
+};
+
+struct IntervalWithStop : public Interval
+{
+public:
+ double& stop(){return m_stop;};
+protected:
+ double m_stop;
+};
+
+class IntervalList //list of the of intervals of the given edge
+{
+public:
+ IntervalList(){m_first = NULL;};
+ ~IntervalList(){};
+
+ void clear()
+ {
+ m_first = NULL;
+ };
+
+ void initialize(edge_pointer e)
+ {
+ m_edge = e;
+ m_first = NULL;
+ };
+
+ interval_pointer covering_interval(double offset) //returns the interval that covers the offset
+ {
+ assert(offset >= 0.0 && offset <= m_edge->length());
+
+ interval_pointer p = m_first;
+ while(p && p->stop() < offset)
+ {
+ p = p->next();
+ }
+
+ return p;// && p->start() <= offset ? p : NULL;
+ };
+
+ void find_closest_point(SurfacePoint* point,
+ double& offset,
+ double& distance,
+ interval_pointer& interval)
+ {
+ interval_pointer p = m_first;
+ distance = GEODESIC_INF;
+ interval = NULL;
+
+ double x,y;
+ m_edge->local_coordinates(point, x, y);
+
+ while(p)
+ {
+ if(p->min()<GEODESIC_INF)
+ {
+ double o, d;
+ p->find_closest_point(x, y, o, d);
+ if(d < distance)
+ {
+ distance = d;
+ offset = o;
+ interval = p;
+ }
+ }
+ p = p->next();
+ }
+ };
+
+ unsigned number_of_intervals()
+ {
+ interval_pointer p = m_first;
+ unsigned count = 0;
+ while(p)
+ {
+ ++count;
+ p = p->next();
+ }
+ return count;
+ }
+
+ interval_pointer last()
+ {
+ interval_pointer p = m_first;
+ if(p)
+ {
+ while(p->next())
+ {
+ p = p->next();
+ }
+ }
+ return p;
+ }
+
+ double signal(double x)
+ {
+ interval_pointer interval = covering_interval(x);
+
+ return interval ? interval->signal(x) : GEODESIC_INF;
+ }
+
+ interval_pointer& first(){return m_first;};
+ edge_pointer& edge(){return m_edge;};
+private:
+ interval_pointer m_first; //pointer to the first member of the list
+ edge_pointer m_edge; //edge that owns this list
+};
+
+class SurfacePointWithIndex : public SurfacePoint
+{
+public:
+ unsigned index(){return m_index;};
+
+ void initialize(SurfacePoint& p, unsigned index)
+ {
+ SurfacePoint::initialize(p);
+ m_index = index;
+ }
+
+ bool operator()(SurfacePointWithIndex* x, SurfacePointWithIndex* y) const //used for sorting
+ {
+ assert(x->type() != UNDEFINED_POINT && y->type() !=UNDEFINED_POINT);
+
+ if(x->type() != y->type())
+ {
+ return x->type() < y->type();
+ }
+ else
+ {
+ return x->base_element()->id() < y->base_element()->id();
+ }
+ }
+
+private:
+ unsigned m_index;
+};
+
+class SortedSources : public std::vector<SurfacePointWithIndex>
+{
+private:
+ typedef std::vector<SurfacePointWithIndex*> sorted_vector_type;
+public:
+ typedef sorted_vector_type::iterator sorted_iterator;
+ typedef std::pair<sorted_iterator, sorted_iterator> sorted_iterator_pair;
+
+ sorted_iterator_pair sources(base_pointer mesh_element)
+ {
+ m_search_dummy.base_element() = mesh_element;
+
+ return equal_range(m_sorted.begin(),
+ m_sorted.end(),
+ &m_search_dummy,
+ m_compare_less);
+ }
+
+ void initialize(std::vector<SurfacePoint>& sources) //we initialize the sources by copie
+ {
+ resize(sources.size());
+ m_sorted.resize(sources.size());
+ for(unsigned i=0; i<sources.size(); ++i)
+ {
+ SurfacePointWithIndex& p = *(begin() + i);
+
+ p.initialize(sources[i],i);
+ m_sorted[i] = &p;
+ }
+
+ std::sort(m_sorted.begin(), m_sorted.end(), m_compare_less);
+ };
+
+ SurfacePointWithIndex& operator[](unsigned i)
+ {
+ assert(i < size());
+ return *(begin() + i);
+ }
+
+private:
+ sorted_vector_type m_sorted;
+ SurfacePointWithIndex m_search_dummy; //used as a search template
+ SurfacePointWithIndex m_compare_less; //used as a compare functor
+};
+
+
+inline void Interval::find_closest_point(double const rs,
+ double const hs,
+ double& r,
+ double& d_out) //find the point on the interval that is closest to the point (alpha, s)
+ {
+ if(m_d == GEODESIC_INF)
+ {
+ r = GEODESIC_INF;
+ d_out = GEODESIC_INF;
+ return;
+ }
+
+ double hc = -m_pseudo_y;
+ double rc = m_pseudo_x;
+ double end = stop();
+
+ double local_epsilon = SMALLEST_INTERVAL_RATIO*m_edge->length();
+ if(std::abs(hs+hc) < local_epsilon)
+ {
+ if(rs<=m_start)
+ {
+ r = m_start;
+ d_out = signal(m_start) + std::abs(rs - m_start);
+ }
+ else if(rs>=end)
+ {
+ r = end;
+ d_out = signal(end) + fabs(end - rs);
+ }
+ else
+ {
+ r = rs;
+ d_out = signal(rs);
+ }
+ }
+ else
+ {
+ double ri = (rs*hc + hs*rc)/(hs+hc);
+
+ if(ri<m_start)
+ {
+ r = m_start;
+ d_out = signal(m_start) + hypotenuse(m_start - rs, hs);
+ }
+ else if(ri>end)
+ {
+ r = end;
+ d_out = signal(end) + hypotenuse(end - rs, hs);
+ }
+ else
+ {
+ r = ri;
+ d_out = m_d + hypotenuse(rc - rs, hc + hs);
+ }
+ }
+ }
+
+
+inline void Interval::initialize(edge_pointer edge,
+ SurfacePoint* source,
+ unsigned source_index)
+{
+ m_next = NULL;
+ //m_geodesic_previous = NULL;
+ m_direction = UNDEFINED_DIRECTION;
+ m_edge = edge;
+ m_source_index = source_index;
+
+ m_start = 0.0;
+ //m_stop = edge->length();
+ if(!source)
+ {
+ m_d = GEODESIC_INF;
+ m_min = GEODESIC_INF;
+ return;
+ }
+ m_d = 0;
+
+ if(source->base_element()->type() == VERTEX)
+ {
+ if(source->base_element()->id() == edge->v0()->id())
+ {
+ m_pseudo_x = 0.0;
+ m_pseudo_y = 0.0;
+ m_min = 0.0;
+ return;
+ }
+ else if(source->base_element()->id() == edge->v1()->id())
+ {
+ m_pseudo_x = stop();
+ m_pseudo_y = 0.0;
+ m_min = 0.0;
+ return;
+ }
+ }
+
+ edge->local_coordinates(source, m_pseudo_x, m_pseudo_y);
+ m_pseudo_y = -m_pseudo_y;
+
+ compute_min_distance(stop());
+}
+
+
+
+// #include "geodesic_algorithm_base.h"
+class GeodesicAlgorithmBase
+{
+public:
+ enum AlgorithmType
+ {
+ EXACT,
+ DIJKSTRA,
+ SUBDIVISION,
+ UNDEFINED_ALGORITHM
+ };
+
+ GeodesicAlgorithmBase(geodesic::Mesh* mesh):
+ m_type(UNDEFINED_ALGORITHM),
+ m_max_propagation_distance(1e100),
+ m_mesh(mesh)
+ {};
+
+ virtual ~GeodesicAlgorithmBase(){};
+
+ virtual void propagate(std::vector<SurfacePoint>& sources,
+ double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source
+ std::vector<SurfacePoint>* stop_points = NULL) = 0; //or after ensuring that all the stop_points are covered
+
+ virtual void trace_back(SurfacePoint& destination, //trace back piecewise-linear path
+ std::vector<SurfacePoint>& path) = 0;
+
+ void geodesic(SurfacePoint& source,
+ SurfacePoint& destination,
+ std::vector<SurfacePoint>& path); //lazy people can find geodesic path with one function call
+
+ void geodesic(std::vector<SurfacePoint>& sources,
+ std::vector<SurfacePoint>& destinations,
+ std::vector<std::vector<SurfacePoint> >& paths); //lazy people can find geodesic paths with one function call
+
+ virtual unsigned best_source(SurfacePoint& point, //after propagation step is done, quickly find what source this point belongs to and what is the distance to this source
+ double& best_source_distance) = 0;
+
+ virtual void print_statistics() //print info about timing and memory usage in the propagation step of the algorithm
+ {
+ std::cout << "propagation step took " << m_time_consumed << " seconds " << std::endl;
+ };
+
+ AlgorithmType type(){return m_type;};
+
+ virtual std::string name();
+
+ geodesic::Mesh* mesh(){return m_mesh;};
+protected:
+
+ void set_stop_conditions(std::vector<SurfacePoint>* stop_points,
+ double stop_distance);
+ double stop_distance()
+ {
+ return m_max_propagation_distance;
+ }
+
+ AlgorithmType m_type; // type of the algorithm
+
+ typedef std::pair<vertex_pointer, double> stop_vertex_with_distace_type;
+ std::vector<stop_vertex_with_distace_type> m_stop_vertices; // algorithm stops propagation after covering certain vertices
+ double m_max_propagation_distance; // or reaching the certain distance
+
+ geodesic::Mesh* m_mesh;
+
+ double m_time_consumed; //how much time does the propagation step takes
+ double m_propagation_distance_stopped; //at what distance (if any) the propagation algorithm stopped
+};
+
+inline double length(std::vector<SurfacePoint>& path)
+{
+ double length = 0;
+ if(!path.empty())
+ {
+ for(unsigned i=0; i<path.size()-1; ++i)
+ {
+ length += path[i].distance(&path[i+1]);
+ }
+ }
+ return length;
+}
+
+inline void print_info_about_path(std::vector<SurfacePoint>& path)
+{
+ std::cout << "number of the points in the path = " << path.size()
+ << ", length of the path = " << length(path)
+ << std::endl;
+}
+
+inline std::string GeodesicAlgorithmBase::name()
+{
+ switch(m_type)
+ {
+ case EXACT:
+ return "exact";
+ case DIJKSTRA:
+ return "dijkstra";
+ case SUBDIVISION:
+ return "subdivision";
+ default:
+ case UNDEFINED_ALGORITHM:
+ return "undefined";
+ }
+}
+
+inline void GeodesicAlgorithmBase::geodesic(SurfacePoint& source,
+ SurfacePoint& destination,
+ std::vector<SurfacePoint>& path) //lazy people can find geodesic path with one function call
+{
+ std::vector<SurfacePoint> sources(1, source);
+ std::vector<SurfacePoint> stop_points(1, destination);
+ double const max_propagation_distance = GEODESIC_INF;
+
+ propagate(sources,
+ max_propagation_distance,
+ &stop_points);
+
+ trace_back(destination, path);
+}
+
+inline void GeodesicAlgorithmBase::geodesic(std::vector<SurfacePoint>& sources,
+ std::vector<SurfacePoint>& destinations,
+ std::vector<std::vector<SurfacePoint> >& paths) //lazy people can find geodesic paths with one function call
+{
+ double const max_propagation_distance = GEODESIC_INF;
+
+ propagate(sources,
+ max_propagation_distance,
+ &destinations); //we use desinations as stop points
+
+ paths.resize(destinations.size());
+
+ for(unsigned i=0; i<paths.size(); ++i)
+ {
+ trace_back(destinations[i], paths[i]);
+ }
+}
+
+inline void GeodesicAlgorithmBase::set_stop_conditions(std::vector<SurfacePoint>* stop_points,
+ double stop_distance)
+{
+ m_max_propagation_distance = stop_distance;
+
+ if(!stop_points)
+ {
+ m_stop_vertices.clear();
+ return;
+ }
+
+ m_stop_vertices.resize(stop_points->size());
+
+ std::vector<vertex_pointer> possible_vertices;
+ for(unsigned i = 0; i < stop_points->size(); ++i)
+ {
+ SurfacePoint* point = &(*stop_points)[i];
+
+ possible_vertices.clear();
+ m_mesh->closest_vertices(point, &possible_vertices);
+
+ vertex_pointer closest_vertex = NULL;
+ double min_distance = 1e100;
+ for(unsigned j = 0; j < possible_vertices.size(); ++j)
+ {
+ double distance = point->distance(possible_vertices[j]);
+ if(distance < min_distance)
+ {
+ min_distance = distance;
+ closest_vertex = possible_vertices[j];
+ }
+ }
+ assert(closest_vertex);
+
+ m_stop_vertices[i].first = closest_vertex;
+ m_stop_vertices[i].second = min_distance;
+ }
+}
+
+
+
+class GeodesicAlgorithmExact : public GeodesicAlgorithmBase
+{
+public:
+ GeodesicAlgorithmExact(geodesic::Mesh* mesh):
+ GeodesicAlgorithmBase(mesh),
+ m_memory_allocator(mesh->edges().size(), mesh->edges().size()),
+ m_edge_interval_lists(mesh->edges().size())
+ {
+ m_type = EXACT;
+
+ for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
+ {
+ m_edge_interval_lists[i].initialize(&mesh->edges()[i]);
+ }
+ };
+
+ ~GeodesicAlgorithmExact(){};
+
+ void propagate(std::vector<SurfacePoint>& sources,
+ double max_propagation_distance = GEODESIC_INF, //propagation algorithm stops after reaching the certain distance from the source
+ std::vector<SurfacePoint>* stop_points = NULL); //or after ensuring that all the stop_points are covered
+
+ void trace_back(SurfacePoint& destination, //trace back piecewise-linear path
+ std::vector<SurfacePoint>& path);
+
+ unsigned best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
+ double& best_source_distance);
+
+ void print_statistics();
+
+private:
+ typedef std::set<interval_pointer, Interval> IntervalQueue;
+
+ void update_list_and_queue(list_pointer list,
+ IntervalWithStop* candidates, //up to two candidates
+ unsigned num_candidates);
+
+ unsigned compute_propagated_parameters(double pseudo_x,
+ double pseudo_y,
+ double d, //parameters of the interval
+ double start,
+ double end, //start/end of the interval
+ double alpha, //corner angle
+ double L, //length of the new edge
+ bool first_interval, //if it is the first interval on the edge
+ bool last_interval,
+ bool turn_left,
+ bool turn_right,
+ IntervalWithStop* candidates); //if it is the last interval on the edge
+
+ void construct_propagated_intervals(bool invert,
+ edge_pointer edge,
+ face_pointer face, //constructs iNew from the rest of the data
+ IntervalWithStop* candidates,
+ unsigned& num_candidates,
+ interval_pointer source_interval);
+
+ double compute_positive_intersection(double start,
+ double pseudo_x,
+ double pseudo_y,
+ double sin_alpha,
+ double cos_alpha); //used in construct_propagated_intervals
+
+ unsigned intersect_intervals(interval_pointer zero,
+ IntervalWithStop* one); //intersecting two intervals with up to three intervals in the end
+
+ interval_pointer best_first_interval(SurfacePoint& point,
+ double& best_total_distance,
+ double& best_interval_position,
+ unsigned& best_source_index);
+
+ bool check_stop_conditions(unsigned& index);
+
+ void clear()
+ {
+ m_memory_allocator.clear();
+ m_queue.clear();
+ for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
+ {
+ m_edge_interval_lists[i].clear();
+ }
+ m_propagation_distance_stopped = GEODESIC_INF;
+ };
+
+ list_pointer interval_list(edge_pointer e)
+ {
+ return &m_edge_interval_lists[e->id()];
+ };
+
+ void set_sources(std::vector<SurfacePoint>& sources)
+ {
+ m_sources.initialize(sources);
+ }
+
+ void initialize_propagation_data();
+
+ void list_edges_visible_from_source(MeshElementBase* p,
+ std::vector<edge_pointer>& storage); //used in initialization
+
+ long visible_from_source(SurfacePoint& point); //used in backtracing
+
+ void best_point_on_the_edge_set(SurfacePoint& point,
+ std::vector<edge_pointer> const& storage,
+ interval_pointer& best_interval,
+ double& best_total_distance,
+ double& best_interval_position);
+
+ void possible_traceback_edges(SurfacePoint& point,
+ std::vector<edge_pointer>& storage);
+
+ bool erase_from_queue(interval_pointer p);
+
+ IntervalQueue m_queue; //interval queue
+
+ MemoryAllocator<Interval> m_memory_allocator; //quickly allocate and deallocate intervals
+ std::vector<IntervalList> m_edge_interval_lists; //every edge has its interval data
+
+ enum MapType {OLD, NEW}; //used for interval intersection
+ MapType map[5];
+ double start[6];
+ interval_pointer i_new[5];
+
+ unsigned m_queue_max_size; //used for statistics
+ unsigned m_iterations; //used for statistics
+
+ SortedSources m_sources;
+};
+
+inline void GeodesicAlgorithmExact::best_point_on_the_edge_set(SurfacePoint& point,
+ std::vector<edge_pointer> const& storage,
+ interval_pointer& best_interval,
+ double& best_total_distance,
+ double& best_interval_position)
+{
+ best_total_distance = 1e100;
+ for(unsigned i=0; i<storage.size(); ++i)
+ {
+ edge_pointer e = storage[i];
+ list_pointer list = interval_list(e);
+
+ double offset;
+ double distance;
+ interval_pointer interval;
+
+ list->find_closest_point(&point,
+ offset,
+ distance,
+ interval);
+
+ if(distance < best_total_distance)
+ {
+ best_interval = interval;
+ best_total_distance = distance;
+ best_interval_position = offset;
+ }
+ }
+}
+
+inline void GeodesicAlgorithmExact::possible_traceback_edges(SurfacePoint& point,
+ std::vector<edge_pointer>& storage)
+{
+ storage.clear();
+
+ if(point.type() == VERTEX)
+ {
+ vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
+ for(unsigned i=0; i<v->adjacent_faces().size(); ++i)
+ {
+ face_pointer f = v->adjacent_faces()[i];
+ storage.push_back(f->opposite_edge(v));
+ }
+ }
+ else if(point.type() == EDGE)
+ {
+ edge_pointer e = static_cast<edge_pointer>(point.base_element());
+ for(unsigned i=0; i<e->adjacent_faces().size(); ++i)
+ {
+ face_pointer f = e->adjacent_faces()[i];
+
+ storage.push_back(f->next_edge(e,e->v0()));
+ storage.push_back(f->next_edge(e,e->v1()));
+ }
+ }
+ else
+ {
+ face_pointer f = static_cast<face_pointer>(point.base_element());
+ storage.push_back(f->adjacent_edges()[0]);
+ storage.push_back(f->adjacent_edges()[1]);
+ storage.push_back(f->adjacent_edges()[2]);
+ }
+}
+
+
+inline long GeodesicAlgorithmExact::visible_from_source(SurfacePoint& point) //negative if not visible
+{
+ assert(point.type() != UNDEFINED_POINT);
+
+ if(point.type() == EDGE)
+ {
+ edge_pointer e = static_cast<edge_pointer>(point.base_element());
+ list_pointer list = interval_list(e);
+ double position = std::min(point.distance(e->v0()), e->length());
+ interval_pointer interval = list->covering_interval(position);
+ //assert(interval);
+ if(interval && interval->visible_from_source())
+ {
+ return (long)interval->source_index();
+ }
+ else
+ {
+ return -1;
+ }
+ }
+ else if(point.type() == FACE)
+ {
+ return -1;
+ }
+ else if(point.type() == VERTEX)
+ {
+ vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
+ for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
+ {
+ edge_pointer e = v->adjacent_edges()[i];
+ list_pointer list = interval_list(e);
+
+ double position = e->v0()->id() == v->id() ? 0.0 : e->length();
+ interval_pointer interval = list->covering_interval(position);
+ if(interval && interval->visible_from_source())
+ {
+ return (long)interval->source_index();
+ }
+ }
+
+ return -1;
+ }
+
+ assert(0);
+ return 0;
+}
+
+inline double GeodesicAlgorithmExact::compute_positive_intersection(double start,
+ double pseudo_x,
+ double pseudo_y,
+ double sin_alpha,
+ double cos_alpha)
+{
+ assert(pseudo_y < 0);
+
+ double denominator = sin_alpha*(pseudo_x - start) - cos_alpha*pseudo_y;
+ if(denominator<0.0)
+ {
+ return -1.0;
+ }
+
+ double numerator = -pseudo_y*start;
+
+ if(numerator < 1e-30)
+ {
+ return 0.0;
+ }
+
+ if(denominator < 1e-30)
+ {
+ return -1.0;
+ }
+
+ return numerator/denominator;
+}
+
+inline void GeodesicAlgorithmExact::list_edges_visible_from_source(MeshElementBase* p,
+ std::vector<edge_pointer>& storage)
+{
+ assert(p->type() != UNDEFINED_POINT);
+
+ if(p->type() == FACE)
+ {
+ face_pointer f = static_cast<face_pointer>(p);
+ for(unsigned i=0; i<3; ++i)
+ {
+ storage.push_back(f->adjacent_edges()[i]);
+ }
+ }
+ else if(p->type() == EDGE)
+ {
+ edge_pointer e = static_cast<edge_pointer>(p);
+ storage.push_back(e);
+ }
+ else //VERTEX
+ {
+ vertex_pointer v = static_cast<vertex_pointer>(p);
+ for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
+ {
+ storage.push_back(v->adjacent_edges()[i]);
+ }
+
+ }
+}
+
+inline bool GeodesicAlgorithmExact::erase_from_queue(interval_pointer p)
+{
+ if(p->min() < GEODESIC_INF/10.0)// && p->min >= queue->begin()->first)
+ {
+ assert(m_queue.count(p)<=1); //the set is unique
+
+ IntervalQueue::iterator it = m_queue.find(p);
+
+ if(it != m_queue.end())
+ {
+ m_queue.erase(it);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+inline unsigned GeodesicAlgorithmExact::intersect_intervals(interval_pointer zero,
+ IntervalWithStop* one) //intersecting two intervals with up to three intervals in the end
+{
+ assert(zero->edge()->id() == one->edge()->id());
+ assert(zero->stop() > one->start() && zero->start() < one->stop());
+ assert(one->min() < GEODESIC_INF/10.0);
+
+ double const local_epsilon = SMALLEST_INTERVAL_RATIO*one->edge()->length();
+
+ unsigned N=0;
+ if(zero->min() > GEODESIC_INF/10.0)
+ {
+ start[0] = zero->start();
+ if(zero->start() < one->start() - local_epsilon)
+ {
+ map[0] = OLD;
+ start[1] = one->start();
+ map[1] = NEW;
+ N = 2;
+ }
+ else
+ {
+ map[0] = NEW;
+ N = 1;
+ }
+
+ if(zero->stop() > one->stop() + local_epsilon)
+ {
+ map[N] = OLD; //"zero" interval
+ start[N++] = one->stop();
+ }
+
+ start[N+1] = zero->stop();
+ return N;
+ }
+
+ double const local_small_epsilon = 1e-8*one->edge()->length();
+
+ double D = zero->d() - one->d();
+ double x0 = zero->pseudo_x();
+ double x1 = one->pseudo_x();
+ double R0 = x0*x0 + zero->pseudo_y()*zero->pseudo_y();
+ double R1 = x1*x1 + one->pseudo_y()*one->pseudo_y();
+
+ double inter[2]; //points of intersection
+ char Ninter=0; //number of the points of the intersection
+
+ if(std::abs(D)<local_epsilon) //if d1 == d0, equation is linear
+ {
+ double denom = x1 - x0;
+ if(std::abs(denom)>local_small_epsilon)
+ {
+ inter[0] = (R1 - R0)/(2.*denom); //one solution
+ Ninter = 1;
+ }
+ }
+ else
+ {
+ double D2 = D*D;
+ double Q = 0.5*(R1-R0-D2);
+ double X = x0 - x1;
+
+ double A = X*X - D2;
+ double B = Q*X + D2*x0;
+ double C = Q*Q - D2*R0;
+
+ if (std::abs(A)<local_small_epsilon) //if A == 0, linear equation
+ {
+ if(std::abs(B)>local_small_epsilon)
+ {
+ inter[0] = -C/B; //one solution
+ Ninter = 1;
+ }
+ }
+ else
+ {
+ double det = B*B-A*C;
+ if(det>local_small_epsilon*local_small_epsilon) //two roots
+ {
+ det = sqrt(det);
+ if(A>0.0) //make sure that the roots are ordered
+ {
+ inter[0] = (-B - det)/A;
+ inter[1] = (-B + det)/A;
+ }
+ else
+ {
+ inter[0] = (-B + det)/A;
+ inter[1] = (-B - det)/A;
+ }
+
+ if(inter[1] - inter[0] > local_small_epsilon)
+ {
+ Ninter = 2;
+ }
+ else
+ {
+ Ninter = 1;
+ }
+ }
+ else if(det>=0.0) //single root
+ {
+ inter[0] = -B/A;
+ Ninter = 1;
+ }
+ }
+ }
+ //---------------------------find possible intervals---------------------------------------
+ double left = std::max(zero->start(), one->start()); //define left and right boundaries of the intersection of the intervals
+ double right = std::min(zero->stop(), one->stop());
+
+ double good_start[4]; //points of intersection within the (left, right) limits +"left" + "right"
+ good_start[0] = left;
+ char Ngood_start=1; //number of the points of the intersection
+
+ for(char i=0; i<Ninter; ++i) //for all points of intersection
+ {
+ double x = inter[i];
+ if(x > left + local_epsilon && x < right - local_epsilon)
+ {
+ good_start[Ngood_start++] = x;
+ }
+ }
+ good_start[Ngood_start++] = right;
+
+ MapType mid_map[3];
+ for(char i=0; i<Ngood_start-1; ++i)
+ {
+ double mid = (good_start[i] + good_start[i+1])*0.5;
+ mid_map[i] = zero->signal(mid) <= one->signal(mid) ? OLD : NEW;
+ }
+
+ //-----------------------------------output----------------------------------
+ N = 0;
+ if(zero->start() < left - local_epsilon) //additional "zero" interval
+ {
+ if(mid_map[0] == OLD) //first interval in the map is already the old one
+ {
+ good_start[0] = zero->start();
+ }
+ else
+ {
+ map[N] = OLD; //"zero" interval
+ start[N++] = zero->start();
+ }
+ }
+
+ for(long i=0;i<Ngood_start-1;++i) //for all intervals
+ {
+ MapType current_map = mid_map[i];
+ if(N==0 || map[N-1] != current_map)
+ {
+ map[N] = current_map;
+ start[N++] = good_start[i];
+ }
+ }
+
+ if(zero->stop() > one->stop() + local_epsilon)
+ {
+ if(N==0 || map[N-1] == NEW)
+ {
+ map[N] = OLD; //"zero" interval
+ start[N++] = one->stop();
+ }
+ }
+
+ start[0] = zero->start(); // just to make sure that epsilons do not damage anything
+ //start[N] = zero->stop();
+
+ return N;
+}
+
+inline void GeodesicAlgorithmExact::initialize_propagation_data()
+{
+ clear();
+
+ IntervalWithStop candidate;
+ std::vector<edge_pointer> edges_visible_from_source;
+ for(unsigned i=0; i<m_sources.size(); ++i) //for all edges adjacent to the starting vertex
+ {
+ SurfacePoint* source = &m_sources[i];
+
+ edges_visible_from_source.clear();
+ list_edges_visible_from_source(source->base_element(),
+ edges_visible_from_source);
+
+ for(unsigned j=0; j<edges_visible_from_source.size(); ++j)
+ {
+ edge_pointer e = edges_visible_from_source[j];
+ candidate.initialize(e, source, i);
+ candidate.stop() = e->length();
+ candidate.compute_min_distance(candidate.stop());
+ candidate.direction() = Interval::FROM_SOURCE;
+
+ update_list_and_queue(interval_list(e), &candidate, 1);
+ }
+ }
+}
+
+inline void GeodesicAlgorithmExact::propagate(std::vector<SurfacePoint>& sources,
+ double max_propagation_distance, //propagation algorithm stops after reaching the certain distance from the source
+ std::vector<SurfacePoint>* stop_points)
+{
+ set_stop_conditions(stop_points, max_propagation_distance);
+ set_sources(sources);
+ initialize_propagation_data();
+
+ clock_t start = clock();
+
+ unsigned satisfied_index = 0;
+
+ m_iterations = 0; //for statistics
+ m_queue_max_size = 0;
+
+ IntervalWithStop candidates[2];
+
+ while(!m_queue.empty())
+ {
+ m_queue_max_size = std::max(static_cast<unsigned int>(m_queue.size()), m_queue_max_size);
+
+ unsigned const check_period = 10;
+ if(++m_iterations % check_period == 0) //check if we covered all required vertices
+ {
+ if (check_stop_conditions(satisfied_index))
+ {
+ break;
+ }
+ }
+
+ interval_pointer min_interval = *m_queue.begin();
+ m_queue.erase(m_queue.begin());
+ edge_pointer edge = min_interval->edge();
+ list_pointer list = interval_list(edge);
+
+ assert(min_interval->d() < GEODESIC_INF);
+
+ bool const first_interval = min_interval->start() == 0.0;
+ //bool const last_interval = min_interval->stop() == edge->length();
+ bool const last_interval = min_interval->next() == NULL;
+
+ bool const turn_left = edge->v0()->saddle_or_boundary();
+ bool const turn_right = edge->v1()->saddle_or_boundary();
+
+ for(unsigned i=0; i<edge->adjacent_faces().size(); ++i) //two possible faces to propagate
+ {
+ if(!edge->is_boundary()) //just in case, always propagate boundary edges
+ {
+ if((i == 0 && min_interval->direction() == Interval::FROM_FACE_0) ||
+ (i == 1 && min_interval->direction() == Interval::FROM_FACE_1))
+ {
+ continue;
+ }
+ }
+
+ face_pointer face = edge->adjacent_faces()[i]; //if we come from 1, go to 2
+ edge_pointer next_edge = face->next_edge(edge,edge->v0());
+
+ unsigned num_propagated = compute_propagated_parameters(min_interval->pseudo_x(),
+ min_interval->pseudo_y(),
+ min_interval->d(), //parameters of the interval
+ min_interval->start(),
+ min_interval->stop(), //start/end of the interval
+ face->vertex_angle(edge->v0()), //corner angle
+ next_edge->length(), //length of the new edge
+ first_interval, //if it is the first interval on the edge
+ last_interval,
+ turn_left,
+ turn_right,
+ candidates); //if it is the last interval on the edge
+ bool propagate_to_right = true;
+
+ if(num_propagated)
+ {
+ if(candidates[num_propagated-1].stop() != next_edge->length())
+ {
+ propagate_to_right = false;
+ }
+
+ bool const invert = next_edge->v0()->id() != edge->v0()->id(); //if the origins coinside, do not invert intervals
+
+ construct_propagated_intervals(invert, //do not inverse
+ next_edge,
+ face,
+ candidates,
+ num_propagated,
+ min_interval);
+
+ update_list_and_queue(interval_list(next_edge),
+ candidates,
+ num_propagated);
+ }
+
+ if(propagate_to_right)
+ {
+ //propogation to the right edge
+ double length = edge->length();
+ next_edge = face->next_edge(edge,edge->v1());
+
+ num_propagated = compute_propagated_parameters(length - min_interval->pseudo_x(),
+ min_interval->pseudo_y(),
+ min_interval->d(), //parameters of the interval
+ length - min_interval->stop(),
+ length - min_interval->start(), //start/end of the interval
+ face->vertex_angle(edge->v1()), //corner angle
+ next_edge->length(), //length of the new edge
+ last_interval, //if it is the first interval on the edge
+ first_interval,
+ turn_right,
+ turn_left,
+ candidates); //if it is the last interval on the edge
+
+ if(num_propagated)
+ {
+ bool const invert = next_edge->v0()->id() != edge->v1()->id(); //if the origins coinside, do not invert intervals
+
+ construct_propagated_intervals(invert, //do not inverse
+ next_edge,
+ face,
+ candidates,
+ num_propagated,
+ min_interval);
+
+ update_list_and_queue(interval_list(next_edge),
+ candidates,
+ num_propagated);
+ }
+ }
+ }
+ }
+
+ m_propagation_distance_stopped = m_queue.empty() ? GEODESIC_INF : (*m_queue.begin())->min();
+ clock_t stop = clock();
+ m_time_consumed = (static_cast<double>(stop)-static_cast<double>(start))/CLOCKS_PER_SEC;
+
+/* for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
+ {
+ list_pointer list = &m_edge_interval_lists[i];
+ interval_pointer p = list->first();
+ assert(p->start() == 0.0);
+ while(p->next())
+ {
+ assert(p->stop() == p->next()->start());
+ assert(p->d() < GEODESIC_INF);
+ p = p->next();
+ }
+ }*/
+}
+
+
+inline bool GeodesicAlgorithmExact::check_stop_conditions(unsigned& index)
+{
+ double queue_distance = (*m_queue.begin())->min();
+ if(queue_distance < stop_distance())
+ {
+ return false;
+ }
+
+ while(index < m_stop_vertices.size())
+ {
+ vertex_pointer v = m_stop_vertices[index].first;
+ edge_pointer edge = v->adjacent_edges()[0]; //take any edge
+
+ double distance = edge->v0()->id() == v->id() ?
+ interval_list(edge)->signal(0.0) :
+ interval_list(edge)->signal(edge->length());
+
+ if(queue_distance < distance + m_stop_vertices[index].second)
+ {
+ return false;
+ }
+
+ ++index;
+ }
+ return true;
+}
+
+
+inline void GeodesicAlgorithmExact::update_list_and_queue(list_pointer list,
+ IntervalWithStop* candidates, //up to two candidates
+ unsigned num_candidates)
+{
+ assert(num_candidates <= 2);
+ //assert(list->first() != NULL);
+ edge_pointer edge = list->edge();
+ double const local_epsilon = SMALLEST_INTERVAL_RATIO * edge->length();
+
+ if(list->first() == NULL)
+ {
+ interval_pointer* p = &list->first();
+ IntervalWithStop* first;
+ IntervalWithStop* second;
+
+ if(num_candidates == 1)
+ {
+ first = candidates;
+ second = candidates;
+ first->compute_min_distance(first->stop());
+ }
+ else
+ {
+ if(candidates->start() <= (candidates+1)->start())
+ {
+ first = candidates;
+ second = candidates+1;
+ }
+ else
+ {
+ first = candidates+1;
+ second = candidates;
+ }
+ assert(first->stop() == second->start());
+
+ first->compute_min_distance(first->stop());
+ second->compute_min_distance(second->stop());
+ }
+
+ if(first->start() > 0.0)
+ {
+ *p = m_memory_allocator.allocate();
+ (*p)->initialize(edge);
+ p = &(*p)->next();
+ }
+
+ *p = m_memory_allocator.allocate();
+ memcpy(*p,first,sizeof(Interval));
+ m_queue.insert(*p);
+
+ if(num_candidates == 2)
+ {
+ p = &(*p)->next();
+ *p = m_memory_allocator.allocate();
+ memcpy(*p,second,sizeof(Interval));
+ m_queue.insert(*p);
+ }
+
+ if(second->stop() < edge->length())
+ {
+ p = &(*p)->next();
+ *p = m_memory_allocator.allocate();
+ (*p)->initialize(edge);
+ (*p)->start() = second->stop();
+ }
+ else
+ {
+ (*p)->next() = NULL;
+ }
+ return;
+ }
+
+ bool propagate_flag;
+
+ for(unsigned i=0; i<num_candidates; ++i) //for all new intervals
+ {
+ IntervalWithStop* q = &candidates[i];
+
+ interval_pointer previous = NULL;
+
+ interval_pointer p = list->first();
+ assert(p->start() == 0.0);
+
+ while(p != NULL && p->stop() - local_epsilon < q->start())
+ {
+ p = p->next();
+ }
+
+ while(p != NULL && p->start() < q->stop() - local_epsilon) //go through all old intervals
+ {
+ unsigned const N = intersect_intervals(p, q); //interset two intervals
+
+ if(N == 1)
+ {
+ if(map[0]==OLD) //if "p" is always better, we do not need to update anything)
+ {
+ if(previous) //close previous interval and put in into the queue
+ {
+ previous->next() = p;
+ previous->compute_min_distance(p->start());
+ m_queue.insert(previous);
+ previous = NULL;
+ }
+
+ p = p->next();
+
+ }
+ else if(previous) //extend previous interval to cover everything; remove p
+ {
+ previous->next() = p->next();
+ erase_from_queue(p);
+ m_memory_allocator.deallocate(p);
+
+ p = previous->next();
+ }
+ else //p becomes "previous"
+ {
+ previous = p;
+ interval_pointer next = p->next();
+ erase_from_queue(p);
+
+ memcpy(previous,q,sizeof(Interval));
+
+ previous->start() = start[0];
+ previous->next() = next;
+
+ p = next;
+ }
+ continue;
+ }
+
+ //update_flag = true;
+
+ Interval swap(*p); //used for swapping information
+ propagate_flag = erase_from_queue(p);
+
+ for(unsigned j=1; j<N; ++j) //no memory is needed for the first one
+ {
+ i_new[j] = m_memory_allocator.allocate(); //create new intervals
+ }
+
+ if(map[0]==OLD) //finish previous, if any
+ {
+ if(previous)
+ {
+ previous->next() = p;
+ previous->compute_min_distance(previous->stop());
+ m_queue.insert(previous);
+ previous = NULL;
+ }
+ i_new[0] = p;
+ p->next() = i_new[1];
+ p->start() = start[0];
+ }
+ else if(previous) //extend previous interval to cover everything; remove p
+ {
+ i_new[0] = previous;
+ previous->next() = i_new[1];
+ m_memory_allocator.deallocate(p);
+ previous = NULL;
+ }
+ else //p becomes "previous"
+ {
+ i_new[0] = p;
+ memcpy(p,q,sizeof(Interval));
+
+ p->next() = i_new[1];
+ p->start() = start[0];
+ }
+
+ assert(!previous);
+
+ for(unsigned j=1; j<N; ++j)
+ {
+ interval_pointer current_interval = i_new[j];
+
+ if(map[j] == OLD)
+ {
+ memcpy(current_interval,&swap,sizeof(Interval));
+ }
+ else
+ {
+ memcpy(current_interval,q,sizeof(Interval));
+ }
+
+ if(j == N-1)
+ {
+ current_interval->next() = swap.next();
+ }
+ else
+ {
+ current_interval->next() = i_new[j+1];
+ }
+
+ current_interval->start() = start[j];
+ }
+
+ for(unsigned j=0; j<N; ++j) //find "min" and add the intervals to the queue
+ {
+ if(j==N-1 && map[j]==NEW)
+ {
+ previous = i_new[j];
+ }
+ else
+ {
+ interval_pointer current_interval = i_new[j];
+
+ current_interval->compute_min_distance(current_interval->stop()); //compute minimal distance
+
+ if(map[j]==NEW || (map[j]==OLD && propagate_flag))
+ {
+ m_queue.insert(current_interval);
+ }
+ }
+ }
+
+ p = swap.next();
+ }
+
+ if(previous) //close previous interval and put in into the queue
+ {
+ previous->compute_min_distance(previous->stop());
+ m_queue.insert(previous);
+ previous = NULL;
+ }
+ }
+}
+
+inline unsigned GeodesicAlgorithmExact::compute_propagated_parameters(double pseudo_x,
+ double pseudo_y,
+ double d, //parameters of the interval
+ double begin,
+ double end, //start/end of the interval
+ double alpha, //corner angle
+ double L, //length of the new edge
+ bool first_interval, //if it is the first interval on the edge
+ bool last_interval,
+ bool turn_left,
+ bool turn_right,
+ IntervalWithStop* candidates) //if it is the last interval on the edge
+{
+ assert(pseudo_y<=0.0);
+ assert(d<GEODESIC_INF/10.0);
+ assert(begin<=end);
+ assert(first_interval ? (begin == 0.0) : true);
+
+ IntervalWithStop* p = candidates;
+
+ if(std::abs(pseudo_y) <= 1e-30) //pseudo-source is on the edge
+ {
+ if(first_interval && pseudo_x <= 0.0)
+ {
+ p->start() = 0.0;
+ p->stop() = L;
+ p->d() = d - pseudo_x;
+ p->pseudo_x() = 0.0;
+ p->pseudo_y() = 0.0;
+ return 1;
+ }
+ else if(last_interval && pseudo_x >= end)
+ {
+ p->start() = 0.0;
+ p->stop() = L;
+ p->d() = d + pseudo_x-end;
+ p->pseudo_x() = end*cos(alpha);
+ p->pseudo_y() = -end*sin(alpha);
+ return 1;
+ }
+ else if(pseudo_x >= begin && pseudo_x <= end)
+ {
+ p->start() = 0.0;
+ p->stop() = L;
+ p->d() = d;
+ p->pseudo_x() = pseudo_x*cos(alpha);
+ p->pseudo_y() = -pseudo_x*sin(alpha);
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ double sin_alpha = sin(alpha);
+ double cos_alpha = cos(alpha);
+
+ //important: for the first_interval, this function returns zero only if the new edge is "visible" from the source
+ //if the new edge can be covered only after turn_over, the value is negative (-1.0)
+ double L1 = compute_positive_intersection(begin,
+ pseudo_x,
+ pseudo_y,
+ sin_alpha,
+ cos_alpha);
+
+ if(L1 < 0 || L1 >= L)
+ {
+ if(first_interval && turn_left)
+ {
+ p->start() = 0.0;
+ p->stop() = L;
+ p->d() = d + sqrt(pseudo_x*pseudo_x + pseudo_y*pseudo_y);
+ p->pseudo_y() = 0.0;
+ p->pseudo_x() = 0.0;
+ return 1;
+ }
+ else
+ {
+ return 0;
+ }
+ }
+
+ double L2 = compute_positive_intersection(end,
+ pseudo_x,
+ pseudo_y,
+ sin_alpha,
+ cos_alpha);
+
+ if(L2 < 0 || L2 >= L)
+ {
+ p->start() = L1;
+ p->stop() = L;
+ p->d() = d;
+ p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
+ p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
+
+ return 1;
+ }
+
+ p->start() = L1;
+ p->stop() = L2;
+ p->d() = d;
+ p->pseudo_x() = cos_alpha*pseudo_x + sin_alpha*pseudo_y;
+ p->pseudo_y() = -sin_alpha*pseudo_x + cos_alpha*pseudo_y;
+ assert(p->pseudo_y() <= 0.0);
+
+ if(!(last_interval && turn_right))
+ {
+ return 1;
+ }
+ else
+ {
+ p = candidates + 1;
+
+ p->start() = L2;
+ p->stop() = L;
+ double dx = pseudo_x - end;
+ p->d() = d + sqrt(dx*dx + pseudo_y*pseudo_y);
+ p->pseudo_x() = end*cos_alpha;
+ p->pseudo_y() = -end*sin_alpha;
+
+ return 2;
+ }
+}
+
+inline void GeodesicAlgorithmExact::construct_propagated_intervals(bool invert,
+ edge_pointer edge,
+ face_pointer face, //constructs iNew from the rest of the data
+ IntervalWithStop* candidates,
+ unsigned& num_candidates,
+ interval_pointer source_interval) //up to two candidates
+{
+ double edge_length = edge->length();
+ double local_epsilon = SMALLEST_INTERVAL_RATIO * edge_length;
+
+ //kill very small intervals in order to avoid precision problems
+ if(num_candidates == 2)
+ {
+ double start = std::min(candidates->start(), (candidates+1)->start());
+ double stop = std::max(candidates->stop(), (candidates+1)->stop());
+ if(candidates->stop()-candidates->start() < local_epsilon) // kill interval 0
+ {
+ *candidates = *(candidates+1);
+ num_candidates = 1;
+ candidates->start() = start;
+ candidates->stop() = stop;
+ }
+ else if ((candidates+1)->stop() - (candidates+1)->start() < local_epsilon)
+ {
+ num_candidates = 1;
+ candidates->start() = start;
+ candidates->stop() = stop;
+ }
+ }
+
+ IntervalWithStop* first;
+ IntervalWithStop* second;
+ if(num_candidates == 1)
+ {
+ first = candidates;
+ second = candidates;
+ }
+ else
+ {
+ if(candidates->start() <= (candidates+1)->start())
+ {
+ first = candidates;
+ second = candidates+1;
+ }
+ else
+ {
+ first = candidates+1;
+ second = candidates;
+ }
+ assert(first->stop() == second->start());
+ }
+
+ if(first->start() < local_epsilon)
+ {
+ first->start() = 0.0;
+ }
+ if(edge_length - second->stop() < local_epsilon)
+ {
+ second->stop() = edge_length;
+ }
+
+ //invert intervals if necessary; fill missing data and set pointers correctly
+ Interval::DirectionType direction = edge->adjacent_faces()[0]->id() == face->id() ?
+ Interval::FROM_FACE_0 :
+ Interval::FROM_FACE_1;
+
+ if(!invert) //in this case everything is straighforward, we do not have to invert the intervals
+ {
+ for(unsigned i=0; i<num_candidates; ++i)
+ {
+ IntervalWithStop* p = candidates + i;
+
+ p->next() = (i == num_candidates - 1) ? NULL : candidates + i + 1;
+ p->edge() = edge;
+ p->direction() = direction;
+ p->source_index() = source_interval->source_index();
+
+ p->min() = 0.0; //it will be changed later on
+
+ assert(p->start() < p->stop());
+ }
+ }
+ else //now we have to invert the intervals
+ {
+ for(unsigned i=0; i<num_candidates; ++i)
+ {
+ IntervalWithStop* p = candidates + i;
+
+ p->next() = (i == 0) ? NULL : candidates + i - 1;
+ p->edge() = edge;
+ p->direction() = direction;
+ p->source_index() = source_interval->source_index();
+
+ double length = edge_length;
+ p->pseudo_x() = length - p->pseudo_x();
+
+ double start = length - p->stop();
+ p->stop() = length - p->start();
+ p->start() = start;
+
+ p->min() = 0;
+
+ assert(p->start() < p->stop());
+ assert(p->start() >= 0.0);
+ assert(p->stop() <= edge->length());
+ }
+ }
+}
+
+
+inline unsigned GeodesicAlgorithmExact::best_source(SurfacePoint& point, //quickly find what source this point belongs to and what is the distance to this source
+ double& best_source_distance)
+{
+ double best_interval_position;
+ unsigned best_source_index;
+
+ best_first_interval(point,
+ best_source_distance,
+ best_interval_position,
+ best_source_index);
+
+ return best_source_index;
+}
+
+inline interval_pointer GeodesicAlgorithmExact::best_first_interval(SurfacePoint& point,
+ double& best_total_distance,
+ double& best_interval_position,
+ unsigned& best_source_index)
+{
+ assert(point.type() != UNDEFINED_POINT);
+
+ interval_pointer best_interval = NULL;
+ best_total_distance = GEODESIC_INF;
+
+ if(point.type() == EDGE)
+ {
+ edge_pointer e = static_cast<edge_pointer>(point.base_element());
+ list_pointer list = interval_list(e);
+
+ best_interval_position = point.distance(e->v0());
+ best_interval = list->covering_interval(best_interval_position);
+ if(best_interval)
+ {
+ //assert(best_interval && best_interval->d() < GEODESIC_INF);
+ best_total_distance = best_interval->signal(best_interval_position);
+ best_source_index = best_interval->source_index();
+ }
+ }
+ else if(point.type() == FACE)
+ {
+ face_pointer f = static_cast<face_pointer>(point.base_element());
+ for(unsigned i=0; i<3; ++i)
+ {
+ edge_pointer e = f->adjacent_edges()[i];
+ list_pointer list = interval_list(e);
+
+ double offset;
+ double distance;
+ interval_pointer interval;
+
+ list->find_closest_point(&point,
+ offset,
+ distance,
+ interval);
+
+ if(interval && distance < best_total_distance)
+ {
+ best_interval = interval;
+ best_total_distance = distance;
+ best_interval_position = offset;
+ best_source_index = interval->source_index();
+ }
+ }
+
+ //check for all sources that might be located inside this face
+ SortedSources::sorted_iterator_pair local_sources = m_sources.sources(f);
+ for(SortedSources::sorted_iterator it=local_sources.first; it != local_sources.second; ++it)
+ {
+ SurfacePointWithIndex* source = *it;
+ double distance = point.distance(source);
+ if(distance < best_total_distance)
+ {
+ best_interval = NULL;
+ best_total_distance = distance;
+ best_interval_position = 0.0;
+ best_source_index = source->index();
+ }
+ }
+ }
+ else if(point.type() == VERTEX)
+ {
+ vertex_pointer v = static_cast<vertex_pointer>(point.base_element());
+ for(unsigned i=0; i<v->adjacent_edges().size(); ++i)
+ {
+ edge_pointer e = v->adjacent_edges()[i];
+ list_pointer list = interval_list(e);
+
+ double position = e->v0()->id() == v->id() ? 0.0 : e->length();
+ interval_pointer interval = list->covering_interval(position);
+ if(interval)
+ {
+ double distance = interval->signal(position);
+
+ if(distance < best_total_distance)
+ {
+ best_interval = interval;
+ best_total_distance = distance;
+ best_interval_position = position;
+ best_source_index = interval->source_index();
+ }
+ }
+ }
+ }
+
+ if(best_total_distance > m_propagation_distance_stopped) //result is unreliable
+ {
+ best_total_distance = GEODESIC_INF;
+ return NULL;
+ }
+ else
+ {
+ return best_interval;
+ }
+}
+
+inline void GeodesicAlgorithmExact::trace_back(SurfacePoint& destination, //trace back piecewise-linear path
+ std::vector<SurfacePoint>& path)
+{
+ path.clear();
+ double best_total_distance;
+ double best_interval_position;
+ unsigned source_index = std::numeric_limits<unsigned>::max();
+ interval_pointer best_interval = best_first_interval(destination,
+ best_total_distance,
+ best_interval_position,
+ source_index);
+
+ if(best_total_distance >= GEODESIC_INF/2.0) //unable to find the right path
+ {
+ return;
+ }
+
+ path.push_back(destination);
+
+ if(best_interval) //if we did not hit the face source immediately
+ {
+ std::vector<edge_pointer> possible_edges;
+ possible_edges.reserve(10);
+
+ while(visible_from_source(path.back()) < 0) //while this point is not in the direct visibility of some source (if we are inside the FACE, we obviously hit the source)
+ {
+ SurfacePoint& q = path.back();
+
+ possible_traceback_edges(q, possible_edges);
+
+ interval_pointer interval;
+ double total_distance;
+ double position;
+
+ best_point_on_the_edge_set(q,
+ possible_edges,
+ interval,
+ total_distance,
+ position);
+
+ //std::cout << total_distance + length(path) << std::endl;
+ assert(total_distance<GEODESIC_INF);
+ source_index = interval->source_index();
+
+ edge_pointer e = interval->edge();
+ double local_epsilon = SMALLEST_INTERVAL_RATIO*e->length();
+ if(position < local_epsilon)
+ {
+ path.push_back(SurfacePoint(e->v0()));
+ }
+ else if(position > e->length()-local_epsilon)
+ {
+ path.push_back(SurfacePoint(e->v1()));
+ }
+ else
+ {
+ double normalized_position = position/e->length();
+ path.push_back(SurfacePoint(e, normalized_position));
+ }
+ }
+ }
+
+ SurfacePoint& source = static_cast<SurfacePoint&>(m_sources[source_index]);
+ if(path.back().distance(&source) > 0)
+ {
+ path.push_back(source);
+ }
+}
+
+inline void GeodesicAlgorithmExact::print_statistics()
+{
+ GeodesicAlgorithmBase::print_statistics();
+
+ unsigned interval_counter = 0;
+ for(unsigned i=0; i<m_edge_interval_lists.size(); ++i)
+ {
+ interval_counter += m_edge_interval_lists[i].number_of_intervals();
+ }
+ double intervals_per_edge = (double)interval_counter/(double)m_edge_interval_lists.size();
+
+ double memory = m_edge_interval_lists.size()*sizeof(IntervalList) +
+ interval_counter*sizeof(Interval);
+
+ std::cout << "uses about " << memory/1e6 << "Mb of memory" <<std::endl;
+ std::cout << interval_counter << " total intervals, or "
+ << intervals_per_edge << " intervals per edge"
+ << std::endl;
+ std::cout << "maximum interval queue size is " << m_queue_max_size << std::endl;
+ std::cout << "number of interval propagations is " << m_iterations << std::endl;
+}
+
+} //geodesic
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVS,
+ typename DerivedFS,
+ typename DerivedVT,
+ typename DerivedFT,
+ typename DerivedD>
+IGL_INLINE void igl::exact_geodesic(
+ const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ const Eigen::MatrixBase<DerivedVS> &VS,
+ const Eigen::MatrixBase<DerivedFS> &FS,
+ const Eigen::MatrixBase<DerivedVT> &VT,
+ const Eigen::MatrixBase<DerivedFT> &FT,
+ Eigen::PlainObjectBase<DerivedD> &D)
+{
+ assert(V.cols() == 3 && F.cols() == 3 && "Only support 3D triangle mesh");
+ assert(VS.cols() ==1 && FS.cols() == 1 && VT.cols() == 1 && FT.cols() ==1 && "Only support one dimensional inputs");
+ std::vector<typename DerivedV::Scalar> points(V.rows() * V.cols());
+ std::vector<typename DerivedF::Scalar> faces(F.rows() * F.cols());
+ for (int i = 0; i < points.size(); i++)
+ {
+ points[i] = V(i / 3, i % 3);
+ }
+ for (int i = 0; i < faces.size(); i++)
+ {
+ faces[i] = F(i / 3, i % 3);
+ }
+
+ igl::geodesic::Mesh mesh;
+ mesh.initialize_mesh_data(points, faces);
+ igl::geodesic::GeodesicAlgorithmExact exact_algorithm(&mesh);
+
+ std::vector<igl::geodesic::SurfacePoint> source(VS.rows() + FS.rows());
+ std::vector<igl::geodesic::SurfacePoint> target(VT.rows() + FT.rows());
+ for (int i = 0; i < VS.rows(); i++)
+ {
+ source[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VS(i)]));
+ }
+ for (int i = 0; i < FS.rows(); i++)
+ {
+ source[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FS(i)]));
+ }
+
+ for (int i = 0; i < VT.rows(); i++)
+ {
+ target[i] = (igl::geodesic::SurfacePoint(&mesh.vertices()[VT(i)]));
+ }
+ for (int i = 0; i < FT.rows(); i++)
+ {
+ target[i] = (igl::geodesic::SurfacePoint(&mesh.faces()[FT(i)]));
+ }
+
+ exact_algorithm.propagate(source);
+ std::vector<igl::geodesic::SurfacePoint> path;
+ D.resize(target.size(), 1);
+ for (int i = 0; i < target.size(); i++)
+ {
+ exact_algorithm.trace_back(target[i], path);
+ D(i) = igl::geodesic::length(path);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::exact_geodesic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1>> &);
+template void igl::exact_geodesic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/exact_geodesic.h b/xs/src/igl/exact_geodesic.h
new file mode 100644
index 000000000..cec59de69
--- /dev/null
+++ b/xs/src/igl/exact_geodesic.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Zhongshi Jiang <jiangzs@nyu.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_EXACT_GEODESIC_H
+#define IGL_EXACT_GEODESIC_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Exact geodesic algorithm for triangular mesh with the implementation from https://code.google.com/archive/p/geodesic/,
+ // and the algorithm first described by Mitchell, Mount and Papadimitriou in 1987
+ //
+ // Inputs:
+ // V #V by 3 list of 3D vertex positions
+ // F #F by 3 list of mesh faces
+ // VS #VS by 1 vector specifying indices of source vertices
+ // FS #FS by 1 vector specifying indices of source faces
+ // VT #VT by 1 vector specifying indices of target vertices
+ // FT #FT by 1 vector specifying indices of target faces
+ // Output:
+ // D #VT+#FT by 1 vector of geodesic distances of each target w.r.t. the nearest one in the source set
+ //
+ // Note:
+ // Specifying a face as target/source means its center.
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVS,
+ typename DerivedFS,
+ typename DerivedVT,
+ typename DerivedFT,
+ typename DerivedD>
+ IGL_INLINE void exact_geodesic(
+ const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ const Eigen::MatrixBase<DerivedVS> &VS,
+ const Eigen::MatrixBase<DerivedFS> &FS,
+ const Eigen::MatrixBase<DerivedVT> &VT,
+ const Eigen::MatrixBase<DerivedFT> &FT,
+ Eigen::PlainObjectBase<DerivedD> &D);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "exact_geodesic.cpp"
+#endif
+
+#endif \ No newline at end of file
diff --git a/xs/src/igl/example_fun.cpp b/xs/src/igl/example_fun.cpp
new file mode 100644
index 000000000..9796c68e3
--- /dev/null
+++ b/xs/src/igl/example_fun.cpp
@@ -0,0 +1,23 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "example_fun.h"
+#include <iostream>
+
+template <typename Printable>
+IGL_INLINE bool igl::example_fun(const Printable & input)
+{
+ using namespace std;
+ cout<<"example_fun: "<<input<<endl;
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::example_fun<double>(const double& input);
+template bool igl::example_fun<int>(const int& input);
+#endif
diff --git a/xs/src/igl/example_fun.h b/xs/src/igl/example_fun.h
new file mode 100644
index 000000000..16c9ec645
--- /dev/null
+++ b/xs/src/igl/example_fun.h
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EXAMPLE_FUN_H
+#define IGL_EXAMPLE_FUN_H
+
+#include "igl_inline.h"
+
+namespace igl
+{
+ // This is an example of a function, it takes a templated parameter and
+ // shovels it into cout
+ //
+ // Templates:
+ // T type that supports
+ // Input:
+ // input some input of a Printable type
+ // Returns true for the sake of returning something
+ template <typename Printable>
+ IGL_INLINE bool example_fun(const Printable & input);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "example_fun.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/exterior_edges.cpp b/xs/src/igl/exterior_edges.cpp
new file mode 100644
index 000000000..04c1e9b8a
--- /dev/null
+++ b/xs/src/igl/exterior_edges.cpp
@@ -0,0 +1,106 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "exterior_edges.h"
+#include "oriented_facets.h"
+#include "sort.h"
+#include "unique_rows.h"
+
+#include <cassert>
+#include <unordered_map>
+#include <utility>
+#include <iostream>
+
+//template <typename T> inline int sgn(T val) {
+// return (T(0) < val) - (val < T(0));
+//}
+
+//static void mod2(std::pair<const std::pair<const int, const int>, int>& p)
+//{
+// using namespace std;
+// // Be sure that sign of mod matches sign of argument
+// p.second = p.second%2 ? sgn(p.second) : 0;
+//}
+
+//// http://stackoverflow.com/a/5517869/148668
+//struct Compare
+//{
+// int i;
+// Compare(const int& i) : i(i) {}
+//};
+//bool operator==(const std::pair<std::pair<const int, const int>,int>&p, const Compare& c)
+//{
+// return c.i == p.second;
+//}
+//bool operator==(const Compare& c, const std::pair<std::pair<const int, const int>, int> &p)
+//{
+// return c.i == p.second;
+//}
+
+IGL_INLINE void igl::exterior_edges(
+ const Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(F.cols() == 3);
+ const size_t m = F.rows();
+ MatrixXi all_E,sall_E,sort_order;
+ // Sort each edge by index
+ oriented_facets(F,all_E);
+ sort(all_E,2,true,sall_E,sort_order);
+ // Find unique edges
+ MatrixXi uE;
+ VectorXi IA,EMAP;
+ unique_rows(sall_E,uE,IA,EMAP);
+ VectorXi counts = VectorXi::Zero(uE.rows());
+ for(size_t a = 0;a<3*m;a++)
+ {
+ counts(EMAP(a)) += (sort_order(a)==0?1:-1);
+ }
+
+ E.resize(all_E.rows(),2);
+ {
+ int e = 0;
+ const size_t nue = uE.rows();
+ // Append each unique edge with a non-zero amount of signed occurrences
+ for(size_t ue = 0; ue<nue; ue++)
+ {
+ const int count = counts(ue);
+ size_t i,j;
+ if(count == 0)
+ {
+ continue;
+ }else if(count < 0)
+ {
+ i = uE(ue,1);
+ j = uE(ue,0);
+ }else if(count > 0)
+ {
+ i = uE(ue,0);
+ j = uE(ue,1);
+ }
+ // Append edge for every repeated entry
+ const int abs_count = abs(count);
+ for(int k = 0;k<abs_count;k++)
+ {
+ E(e,0) = i;
+ E(e,1) = j;
+ e++;
+ }
+ }
+ E.conservativeResize(e,2);
+ }
+}
+
+IGL_INLINE Eigen::MatrixXi igl::exterior_edges( const Eigen::MatrixXi & F)
+{
+ using namespace Eigen;
+ MatrixXi E;
+ exterior_edges(F,E);
+ return E;
+}
diff --git a/xs/src/igl/exterior_edges.h b/xs/src/igl/exterior_edges.h
new file mode 100644
index 000000000..8ce80e67b
--- /dev/null
+++ b/xs/src/igl/exterior_edges.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EXTERIOR_EDGES_H
+#define IGL_EXTERIOR_EDGES_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // EXTERIOR_EDGES Determines boundary "edges" and also edges with an
+ // odd number of occurrences where seeing edge (i,j) counts as +1 and seeing
+ // the opposite edge (j,i) counts as -1
+ //
+ // Inputs:
+ // F #F by simplex_size list of "faces"
+ // Outputs:
+ // E #E by simplex_size-1 list of exterior edges
+ //
+ IGL_INLINE void exterior_edges(
+ const Eigen::MatrixXi & F,
+ Eigen::MatrixXi & E);
+ // Inline version
+ IGL_INLINE Eigen::MatrixXi exterior_edges( const Eigen::MatrixXi & F);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "exterior_edges.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/extract_manifold_patches.cpp b/xs/src/igl/extract_manifold_patches.cpp
new file mode 100644
index 000000000..92269e2c8
--- /dev/null
+++ b/xs/src/igl/extract_manifold_patches.cpp
@@ -0,0 +1,103 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "extract_manifold_patches.h"
+#include "unique_edge_map.h"
+#include <cassert>
+#include <limits>
+#include <queue>
+
+template<
+ typename DerivedF,
+ typename DerivedEMAP,
+ typename uE2EType,
+ typename DerivedP>
+IGL_INLINE size_t igl::extract_manifold_patches(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ Eigen::PlainObjectBase<DerivedP>& P)
+{
+ assert(F.cols() == 3);
+ const size_t num_faces = F.rows();
+
+ auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
+ auto face_and_corner_index_to_edge_index = [&](size_t fi, size_t ci) {
+ return ci*num_faces + fi;
+ };
+ auto is_manifold_edge = [&](size_t fi, size_t ci) -> bool {
+ const size_t ei = face_and_corner_index_to_edge_index(fi, ci);
+ return uE2E[EMAP(ei, 0)].size() == 2;
+ };
+ auto get_adj_face_index = [&](size_t fi, size_t ci) -> size_t {
+ const size_t ei = face_and_corner_index_to_edge_index(fi, ci);
+ const auto& adj_faces = uE2E[EMAP(ei, 0)];
+ assert(adj_faces.size() == 2);
+ if (adj_faces[0] == ei) {
+ return edge_index_to_face_index(adj_faces[1]);
+ } else {
+ assert(adj_faces[1] == ei);
+ return edge_index_to_face_index(adj_faces[0]);
+ }
+ };
+
+ typedef typename DerivedP::Scalar Scalar;
+ const Scalar INVALID = std::numeric_limits<Scalar>::max();
+ P.resize(num_faces,1);
+ P.setConstant(INVALID);
+ size_t num_patches = 0;
+ for (size_t i=0; i<num_faces; i++) {
+ if (P(i,0) != INVALID) continue;
+
+ std::queue<size_t> Q;
+ Q.push(i);
+ P(i,0) = num_patches;
+ while (!Q.empty()) {
+ const size_t fid = Q.front();
+ Q.pop();
+ for (size_t j=0; j<3; j++) {
+ if (is_manifold_edge(fid, j)) {
+ const size_t adj_fid = get_adj_face_index(fid, j);
+ if (P(adj_fid,0) == INVALID) {
+ Q.push(adj_fid);
+ P(adj_fid,0) = num_patches;
+ }
+ }
+ }
+ }
+ num_patches++;
+ }
+ assert((P.array() != INVALID).all());
+
+ return num_patches;
+}
+
+template<
+ typename DerivedF,
+ typename DerivedP>
+IGL_INLINE size_t igl::extract_manifold_patches(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedP>& P)
+{
+ Eigen::MatrixXi E, uE;
+ Eigen::VectorXi EMAP;
+ std::vector<std::vector<size_t> > uE2E;
+ igl::unique_edge_map(F, E, uE, EMAP, uE2E);
+ return igl::extract_manifold_patches(F, EMAP, uE2E, P);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template unsigned long igl::extract_manifold_patches<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template size_t igl::extract_manifold_patches<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template unsigned long igl::extract_manifold_patches<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template unsigned __int64 igl::extract_manifold_patches<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+template unsigned __int64 igl::extract_manifold_patches<class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64, class Eigen::Matrix<int, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/extract_manifold_patches.h b/xs/src/igl/extract_manifold_patches.h
new file mode 100644
index 000000000..6bc25d537
--- /dev/null
+++ b/xs/src/igl/extract_manifold_patches.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_EXTRACT_MANIFOLD_PATCHES
+#define IGL_EXTRACT_MANIFOLD_PATCHES
+
+#include "igl_inline.h"
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl {
+ // Extract a set of maximal patches from a given mesh.
+ // A maximal patch is a subset of the input faces that are connected via
+ // manifold edges; a patch is as large as possible.
+ //
+ // Inputs:
+ // F #F by 3 list representing triangles.
+ // EMAP #F*3 list of indices of unique undirected edges.
+ // uE2E #uE list of lists of indices into E of coexisting edges.
+ //
+ // Output:
+ // P #F list of patch incides.
+ //
+ // Returns:
+ // number of manifold patches.
+ template <
+ typename DerivedF,
+ typename DerivedEMAP,
+ typename uE2EType,
+ typename DerivedP>
+ IGL_INLINE size_t extract_manifold_patches(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ Eigen::PlainObjectBase<DerivedP>& P);
+ template <
+ typename DerivedF,
+ typename DerivedP>
+ IGL_INLINE size_t extract_manifold_patches(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedP>& P);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "extract_manifold_patches.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/extract_non_manifold_edge_curves.cpp b/xs/src/igl/extract_non_manifold_edge_curves.cpp
new file mode 100644
index 000000000..c4a5274a6
--- /dev/null
+++ b/xs/src/igl/extract_non_manifold_edge_curves.cpp
@@ -0,0 +1,123 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "extract_non_manifold_edge_curves.h"
+#include <algorithm>
+#include <cassert>
+#include <list>
+#include <vector>
+#include <unordered_map>
+
+template<
+typename DerivedF,
+typename DerivedEMAP,
+typename uE2EType >
+IGL_INLINE void igl::extract_non_manifold_edge_curves(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedEMAP>& /*EMAP*/,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<size_t> >& curves) {
+ const size_t num_faces = F.rows();
+ assert(F.cols() == 3);
+ //typedef std::pair<size_t, size_t> Edge;
+ auto edge_index_to_face_index = [&](size_t ei) { return ei % num_faces; };
+ auto edge_index_to_corner_index = [&](size_t ei) { return ei / num_faces; };
+ auto get_edge_end_points = [&](size_t ei, size_t& s, size_t& d) {
+ const size_t fi = edge_index_to_face_index(ei);
+ const size_t ci = edge_index_to_corner_index(ei);
+ s = F(fi, (ci+1)%3);
+ d = F(fi, (ci+2)%3);
+ };
+
+ curves.clear();
+ const size_t num_unique_edges = uE2E.size();
+ std::unordered_multimap<size_t, size_t> vertex_edge_adjacency;
+ std::vector<size_t> non_manifold_edges;
+ for (size_t i=0; i<num_unique_edges; i++) {
+ const auto& adj_edges = uE2E[i];
+ if (adj_edges.size() == 2) continue;
+
+ const size_t ei = adj_edges[0];
+ size_t s,d;
+ get_edge_end_points(ei, s, d);
+ vertex_edge_adjacency.insert({{s, i}, {d, i}});
+ non_manifold_edges.push_back(i);
+ assert(vertex_edge_adjacency.count(s) > 0);
+ assert(vertex_edge_adjacency.count(d) > 0);
+ }
+
+ auto expand_forward = [&](std::list<size_t>& edge_curve,
+ size_t& front_vertex, size_t& end_vertex) {
+ while(vertex_edge_adjacency.count(front_vertex) == 2 &&
+ front_vertex != end_vertex) {
+ auto adj_edges = vertex_edge_adjacency.equal_range(front_vertex);
+ for (auto itr = adj_edges.first; itr!=adj_edges.second; itr++) {
+ const size_t uei = itr->second;
+ assert(uE2E.at(uei).size() != 2);
+ const size_t ei = uE2E[uei][0];
+ if (uei == edge_curve.back()) continue;
+ size_t s,d;
+ get_edge_end_points(ei, s, d);
+ edge_curve.push_back(uei);
+ if (s == front_vertex) {
+ front_vertex = d;
+ } else if (d == front_vertex) {
+ front_vertex = s;
+ } else {
+ throw "Invalid vertex/edge adjacency!";
+ }
+ break;
+ }
+ }
+ };
+
+ auto expand_backward = [&](std::list<size_t>& edge_curve,
+ size_t& front_vertex, size_t& end_vertex) {
+ while(vertex_edge_adjacency.count(front_vertex) == 2 &&
+ front_vertex != end_vertex) {
+ auto adj_edges = vertex_edge_adjacency.equal_range(front_vertex);
+ for (auto itr = adj_edges.first; itr!=adj_edges.second; itr++) {
+ const size_t uei = itr->second;
+ assert(uE2E.at(uei).size() != 2);
+ const size_t ei = uE2E[uei][0];
+ if (uei == edge_curve.front()) continue;
+ size_t s,d;
+ get_edge_end_points(ei, s, d);
+ edge_curve.push_front(uei);
+ if (s == front_vertex) {
+ front_vertex = d;
+ } else if (d == front_vertex) {
+ front_vertex = s;
+ } else {
+ throw "Invalid vertex/edge adjcency!";
+ }
+ break;
+ }
+ }
+ };
+
+ std::vector<bool> visited(num_unique_edges, false);
+ for (const size_t i : non_manifold_edges) {
+ if (visited[i]) continue;
+ std::list<size_t> edge_curve;
+ edge_curve.push_back(i);
+
+ const auto& adj_edges = uE2E[i];
+ assert(adj_edges.size() != 2);
+ const size_t ei = adj_edges[0];
+ size_t s,d;
+ get_edge_end_points(ei, s, d);
+
+ expand_forward(edge_curve, d, s);
+ expand_backward(edge_curve, s, d);
+ curves.emplace_back(edge_curve.begin(), edge_curve.end());
+ for (auto itr = edge_curve.begin(); itr!=edge_curve.end(); itr++) {
+ visited[*itr] = true;
+ }
+ }
+
+}
diff --git a/xs/src/igl/extract_non_manifold_edge_curves.h b/xs/src/igl/extract_non_manifold_edge_curves.h
new file mode 100644
index 000000000..173e0c5a2
--- /dev/null
+++ b/xs/src/igl/extract_non_manifold_edge_curves.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NON_MANIFOLD_EDGE_CURVES
+#define IGL_NON_MANIFOLD_EDGE_CURVES
+
+#include "igl_inline.h"
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl {
+ // Extract non-manifold curves from a given mesh.
+ // A non-manifold curves are a set of connected non-manifold edges that
+ // does not touch other non-manifold edges except at the end points.
+ // They are also maximal in the sense that they cannot be expanded by
+ // including more edges.
+ //
+ // Assumes the input mesh have all self-intersection resolved. See
+ // ``igl::cgal::remesh_self_intersection`` for more details.
+ //
+ // Inputs:
+ // F #F by 3 list representing triangles.
+ // EMAP #F*3 list of indices of unique undirected edges.
+ // uE2E #uE list of lists of indices into E of coexisting edges.
+ //
+ // Output:
+ // curves An array of arries of unique edge indices.
+ template<
+ typename DerivedF,
+ typename DerivedEMAP,
+ typename uE2EType>
+ IGL_INLINE void extract_non_manifold_edge_curves(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ const std::vector<std::vector<uE2EType> >& uE2E,
+ std::vector<std::vector<size_t> >& curves);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "extract_non_manifold_edge_curves.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/face_areas.cpp b/xs/src/igl/face_areas.cpp
new file mode 100644
index 000000000..74bf7fce0
--- /dev/null
+++ b/xs/src/igl/face_areas.cpp
@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "face_areas.h"
+#include "edge_lengths.h"
+#include "doublearea.h"
+
+template <typename DerivedV, typename DerivedT, typename DerivedA>
+IGL_INLINE void igl::face_areas(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedA>& A)
+{
+ assert(T.cols() == 4);
+ DerivedA L;
+ edge_lengths(V,T,L);
+ return face_areas(L,A);
+}
+
+template <typename DerivedL, typename DerivedA>
+IGL_INLINE void igl::face_areas(
+ const Eigen::MatrixBase<DerivedL>& L,
+ Eigen::PlainObjectBase<DerivedA>& A)
+{
+ return face_areas(
+ L,std::numeric_limits<typename DerivedL::Scalar>::quiet_NaN(),A);
+}
+
+template <typename DerivedL, typename DerivedA>
+IGL_INLINE void igl::face_areas(
+ const Eigen::MatrixBase<DerivedL>& L,
+ const typename DerivedL::Scalar doublearea_nan_replacement,
+ Eigen::PlainObjectBase<DerivedA>& A)
+{
+ using namespace Eigen;
+ assert(L.cols() == 6);
+ const int m = L.rows();
+ // (unsigned) face Areas (opposite vertices: 1 2 3 4)
+ Matrix<typename DerivedA::Scalar,Dynamic,1>
+ A0(m,1), A1(m,1), A2(m,1), A3(m,1);
+ Matrix<typename DerivedA::Scalar,Dynamic,3>
+ L0(m,3), L1(m,3), L2(m,3), L3(m,3);
+ L0<<L.col(1),L.col(2),L.col(3);
+ L1<<L.col(0),L.col(2),L.col(4);
+ L2<<L.col(0),L.col(1),L.col(5);
+ L3<<L.col(3),L.col(4),L.col(5);
+ doublearea(L0,doublearea_nan_replacement,A0);
+ doublearea(L1,doublearea_nan_replacement,A1);
+ doublearea(L2,doublearea_nan_replacement,A2);
+ doublearea(L3,doublearea_nan_replacement,A3);
+ A.resize(m,4);
+ A.col(0) = 0.5*A0;
+ A.col(1) = 0.5*A1;
+ A.col(2) = 0.5*A2;
+ A.col(3) = 0.5*A3;
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::face_areas<Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&);
+#endif
diff --git a/xs/src/igl/face_areas.h b/xs/src/igl/face_areas.h
new file mode 100644
index 000000000..9676deadc
--- /dev/null
+++ b/xs/src/igl/face_areas.h
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FACE_AREAS_H
+#define IGL_FACE_AREAS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Constructs a list of face areas of faces opposite each index in a tet list
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // T #T by 3 list of tet mesh indices into V
+ // Outputs:
+ // A #T by 4 list of face areas corresponding to faces opposite vertices
+ // 0,1,2,3
+ //
+ template <typename DerivedV, typename DerivedT, typename DerivedA>
+ IGL_INLINE void face_areas(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedA>& A);
+ // Compute tet-mesh face areas from edge lengths.
+ //
+ // Inputs:
+ // L #T by 6 list of tet-mesh edge lengths corresponding to edges
+ // [3 0],[3 1],[3 2],[1 2],[2 0],[0 1]
+ // Outputs:
+ // A #T by 4 list of face areas corresponding to faces opposite vertices
+ // 0,1,2,3: i.e. made of edges [123],[024],[015],[345]
+ //
+ //
+ template <typename DerivedL, typename DerivedA>
+ IGL_INLINE void face_areas(
+ const Eigen::MatrixBase<DerivedL>& L,
+ Eigen::PlainObjectBase<DerivedA>& A);
+ // doublearea_nan_replacement See doublearea.h
+ template <typename DerivedL, typename DerivedA>
+ IGL_INLINE void face_areas(
+ const Eigen::MatrixBase<DerivedL>& L,
+ const typename DerivedL::Scalar doublearea_nan_replacement,
+ Eigen::PlainObjectBase<DerivedA>& A);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "face_areas.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/face_occurrences.cpp b/xs/src/igl/face_occurrences.cpp
new file mode 100644
index 000000000..4ef43f822
--- /dev/null
+++ b/xs/src/igl/face_occurrences.cpp
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "face_occurrences.h"
+
+#include <map>
+#include "sort.h"
+#include <cassert>
+
+template <typename IntegerF, typename IntegerC>
+IGL_INLINE void igl::face_occurrences(
+ const std::vector<std::vector<IntegerF> > & F,
+ std::vector<IntegerC> & C)
+{
+ using namespace std;
+
+ // Get a list of sorted faces
+ vector<vector<IntegerF> > sortedF = F;
+ for(int i = 0; i < (int)F.size();i++)
+ {
+ sort(sortedF[i].begin(),sortedF[i].end());
+ }
+ // Count how many times each sorted face occurs
+ map<vector<IntegerF>,int> counts;
+ for(int i = 0; i < (int)sortedF.size();i++)
+ {
+ if(counts.find(sortedF[i]) == counts.end())
+ {
+ // initialize to count of 1
+ counts[sortedF[i]] = 1;
+ }else
+ {
+ // increment count
+ counts[sortedF[i]]++;
+ assert(counts[sortedF[i]] == 2 && "Input should be manifold");
+ }
+ }
+
+ // Resize output to fit number of ones
+ C.resize(F.size());
+ for(int i = 0;i< (int)F.size();i++)
+ {
+ // sorted face should definitely be in counts map
+ assert(counts.find(sortedF[i]) != counts.end());
+ C[i] = counts[sortedF[i]];
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::face_occurrences<unsigned int, int>(std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > > const&, std::vector<int, std::allocator<int> >&);
+template void igl::face_occurrences<int, int>(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<int, std::allocator<int> >&);
+#endif
diff --git a/xs/src/igl/face_occurrences.h b/xs/src/igl/face_occurrences.h
new file mode 100644
index 000000000..de47b504c
--- /dev/null
+++ b/xs/src/igl/face_occurrences.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FACE_OCCURRENCES
+#define IGL_FACE_OCCURRENCES
+#include "igl_inline.h"
+
+#include <vector>
+namespace igl
+{
+ // Count the occruances of each face (row) in a list of face indices
+ // (irrespecitive of order)
+ // Inputs:
+ // F #F by simplex-size
+ // Outputs
+ // C #F list of counts
+ // Known bug: triangles/tets only (where ignoring order still gives simplex)
+ template <typename IntegerF, typename IntegerC>
+ IGL_INLINE void face_occurrences(
+ const std::vector<std::vector<IntegerF> > & F,
+ std::vector<IntegerC> & C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "face_occurrences.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/faces_first.cpp b/xs/src/igl/faces_first.cpp
new file mode 100644
index 000000000..9c0fa0d0b
--- /dev/null
+++ b/xs/src/igl/faces_first.cpp
@@ -0,0 +1,103 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "faces_first.h"
+
+#include <vector>
+#include <Eigen/Dense>
+
+template <typename MatV, typename MatF, typename VecI>
+IGL_INLINE void igl::faces_first(
+ const MatV & V,
+ const MatF & F,
+ MatV & RV,
+ MatF & RF,
+ VecI & IM)
+{
+ assert(&V != &RV);
+ assert(&F != &RF);
+ using namespace std;
+ using namespace Eigen;
+ vector<bool> in_face(V.rows());
+ for(int i = 0; i<F.rows(); i++)
+ {
+ for(int j = 0; j<F.cols(); j++)
+ {
+ in_face[F(i,j)] = true;
+ }
+ }
+ // count number of vertices not in faces
+ int num_in_F = 0;
+ for(int i = 0;i<V.rows();i++)
+ {
+ num_in_F += (in_face[i]?1:0);
+ }
+ // list of unique vertices that occur in F
+ VectorXi U(num_in_F);
+ // list of unique vertices that do not occur in F
+ VectorXi NU(V.rows()-num_in_F);
+ int Ui = 0;
+ int NUi = 0;
+ // loop over vertices
+ for(int i = 0;i<V.rows();i++)
+ {
+ if(in_face[i])
+ {
+ U(Ui) = i;
+ Ui++;
+ }else
+ {
+ NU(NUi) = i;
+ NUi++;
+ }
+ }
+ IM.resize(V.rows());
+ // reindex vertices that occur in faces to be first
+ for(int i = 0;i<U.size();i++)
+ {
+ IM(U(i)) = i;
+ }
+ // reindex vertices that do not occur in faces to come after those that do
+ for(int i = 0;i<NU.size();i++)
+ {
+ IM(NU(i)) = i+U.size();
+ }
+ RF.resizeLike(F);
+ // Reindex faces
+ for(int i = 0; i<F.rows(); i++)
+ {
+ for(int j = 0; j<F.cols(); j++)
+ {
+ RF(i,j) = IM(F(i,j));
+ }
+ }
+ RV.resizeLike(V);
+ // Reorder vertices
+ for(int i = 0;i<V.rows();i++)
+ {
+ RV.row(IM(i)) = V.row(i);
+ }
+}
+
+template <typename MatV, typename MatF, typename VecI>
+IGL_INLINE void igl::faces_first(
+ MatV & V,
+ MatF & F,
+ VecI & IM)
+{
+ MatV RV;
+ // Copying F may not be needed, seems RF = F is safe (whereas RV = V is not)
+ MatF RF;
+ igl::faces_first(V,F,RV,RF,IM);
+ V = RV;
+ F = RF;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::faces_first<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+#endif
diff --git a/xs/src/igl/faces_first.h b/xs/src/igl/faces_first.h
new file mode 100644
index 000000000..92d1d5565
--- /dev/null
+++ b/xs/src/igl/faces_first.h
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FACES_FIRST_H
+#define IGL_FACES_FIRST_H
+#include "igl_inline.h"
+namespace igl
+{
+ // FACES_FIRST Reorder vertices so that vertices in face list come before
+ // vertices that don't appear in the face list. This is especially useful if
+ // the face list contains only surface faces and you want surface vertices
+ // listed before internal vertices
+ //
+ // [RV,RT,RF,IM] = faces_first(V,T,F);
+ //
+ // Templates:
+ // MatV matrix for vertex positions, e.g. MatrixXd
+ // MatF matrix for face indices, e.g. MatrixXi
+ // VecI vector for index map, e.g. VectorXi
+ // Input:
+ // V # vertices by 3 vertex positions
+ // F # faces by 3 list of face indices
+ // Output:
+ // RV # vertices by 3 vertex positions, order such that if the jth vertex is
+ // some face in F, and the kth vertex is not then j comes before k
+ // RF # faces by 3 list of face indices, reindexed to use RV
+ // IM #V by 1 list of indices such that: RF = IM(F) and RT = IM(T)
+ // and RV(IM,:) = V
+ //
+ //
+ // Example:
+ // // Tet mesh in (V,T,F)
+ // faces_first(V,F,IM);
+ // T = T.unaryExpr(bind1st(mem_fun( static_cast<VectorXi::Scalar&
+ // (VectorXi::*)(VectorXi::Index)>(&VectorXi::operator())),
+ // &IM)).eval();
+ template <typename MatV, typename MatF, typename VecI>
+ IGL_INLINE void faces_first(
+ const MatV & V,
+ const MatF & F,
+ MatV & RV,
+ MatF & RF,
+ VecI & IM);
+ // Virtual "in place" wrapper
+ template <typename MatV, typename MatF, typename VecI>
+ IGL_INLINE void faces_first(
+ MatV & V,
+ MatF & F,
+ VecI & IM);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "faces_first.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/facet_components.cpp b/xs/src/igl/facet_components.cpp
new file mode 100644
index 000000000..9df7583e3
--- /dev/null
+++ b/xs/src/igl/facet_components.cpp
@@ -0,0 +1,92 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "facet_components.h"
+#include <igl/triangle_triangle_adjacency.h>
+#include <vector>
+#include <queue>
+template <typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::facet_components(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ using namespace std;
+ typedef typename DerivedF::Index Index;
+ vector<vector<vector<Index > > > TT;
+ vector<vector<vector<Index > > > TTi;
+ triangle_triangle_adjacency(F,TT,TTi);
+ Eigen::VectorXi counts;
+ return facet_components(TT,C,counts);
+}
+
+template <
+ typename TTIndex,
+ typename DerivedC,
+ typename Derivedcounts>
+IGL_INLINE void igl::facet_components(
+ const std::vector<std::vector<std::vector<TTIndex > > > & TT,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<Derivedcounts> & counts)
+{
+ using namespace std;
+ typedef TTIndex Index;
+ const Index m = TT.size();
+ C.resize(m,1);
+ vector<bool> seen(m,false);
+ Index id = 0;
+ vector<Index> vcounts;
+ for(Index g = 0;g<m;g++)
+ {
+ if(seen[g])
+ {
+ continue;
+ }
+ vcounts.push_back(0);
+ queue<Index> Q;
+ Q.push(g);
+ while(!Q.empty())
+ {
+ const Index f = Q.front();
+ Q.pop();
+ if(seen[f])
+ {
+ continue;
+ }
+ seen[f] = true;
+ vcounts[id]++;
+ C(f,0) = id;
+ // Face f's neighbor lists opposite opposite each corner
+ for(const auto & c : TT[f])
+ {
+ // Each neighbor
+ for(const auto & n : c)
+ {
+ if(!seen[n])
+ {
+ Q.push(n);
+ }
+ }
+ }
+ }
+ id++;
+ }
+ assert((size_t) id == vcounts.size());
+ const size_t ncc = vcounts.size();
+ assert((size_t)C.maxCoeff()+1 == ncc);
+ counts.resize(ncc,1);
+ for(size_t i = 0;i<ncc;i++)
+ {
+ counts(i) = vcounts[i];
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::facet_components<long, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::facet_components<int, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::facet_components<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/facet_components.h b/xs/src/igl/facet_components.h
new file mode 100644
index 000000000..8fe28583c
--- /dev/null
+++ b/xs/src/igl/facet_components.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef FACET_COMPONENTS_H
+#define FACET_COMPONENTS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ // Compute connected components of facets based on edge-edge adjacency.
+ //
+ // Inputs:
+ // F #F by 3 list of triangle indices
+ // Outputs:
+ // C #F list of connected component ids
+ template <typename DerivedF, typename DerivedC>
+ IGL_INLINE void facet_components(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ // Inputs:
+ // TT #TT by 3 list of list of adjacency triangles (see
+ // triangle_triangle_adjacency.h)
+ // Outputs:
+ // C #F list of connected component ids
+ // counts #C list of number of facets in each components
+ template <
+ typename TTIndex,
+ typename DerivedC,
+ typename Derivedcounts>
+ IGL_INLINE void facet_components(
+ const std::vector<std::vector<std::vector<TTIndex > > > & TT,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<Derivedcounts> & counts);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "facet_components.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/false_barycentric_subdivision.cpp b/xs/src/igl/false_barycentric_subdivision.cpp
new file mode 100644
index 000000000..8ea807a50
--- /dev/null
+++ b/xs/src/igl/false_barycentric_subdivision.cpp
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "false_barycentric_subdivision.h"
+
+#include "verbose.h"
+#include <algorithm>
+#include <igl/barycenter.h>
+
+template <typename Scalar, typename Index>
+IGL_INLINE void igl::false_barycentric_subdivision(
+ const Eigen::PlainObjectBase<Scalar> & V,
+ const Eigen::PlainObjectBase<Index> & F,
+ Eigen::PlainObjectBase<Scalar> & VD,
+ Eigen::PlainObjectBase<Index> & FD)
+{
+ using namespace Eigen;
+ // Compute face barycenter
+ Eigen::MatrixXd BC;
+ igl::barycenter(V,F,BC);
+
+ // Add the barycenters to the vertices
+ VD.resize(V.rows()+F.rows(),3);
+ VD.block(0,0,V.rows(),3) = V;
+ VD.block(V.rows(),0,F.rows(),3) = BC;
+
+ // Each face is split four ways
+ FD.resize(F.rows()*3,3);
+
+ for (unsigned i=0; i<F.rows(); ++i)
+ {
+ int i0 = F(i,0);
+ int i1 = F(i,1);
+ int i2 = F(i,2);
+ int i3 = V.rows() + i;
+
+ Vector3i F0,F1,F2;
+ F0 << i0,i1,i3;
+ F1 << i1,i2,i3;
+ F2 << i2,i0,i3;
+
+ FD.row(i*3 + 0) = F0;
+ FD.row(i*3 + 1) = F1;
+ FD.row(i*3 + 2) = F2;
+ }
+
+
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::false_barycentric_subdivision<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::false_barycentric_subdivision<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/false_barycentric_subdivision.h b/xs/src/igl/false_barycentric_subdivision.h
new file mode 100644
index 000000000..98426b572
--- /dev/null
+++ b/xs/src/igl/false_barycentric_subdivision.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ADD_BARYCENTER_H
+#define IGL_ADD_BARYCENTER_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Refine the mesh by adding the barycenter of each face
+ // Inputs:
+ // V #V by 3 coordinates of the vertices
+ // F #F by 3 list of mesh faces (must be triangles)
+ // Outputs:
+ // VD #V + #F by 3 coordinate of the vertices of the dual mesh
+ // The added vertices are added at the end of VD (should not be
+ // same references as (V,F)
+ // FD #F*3 by 3 faces of the dual mesh
+ //
+ template <typename Scalar, typename Index>
+ IGL_INLINE void false_barycentric_subdivision(
+ const Eigen::PlainObjectBase<Scalar> & V,
+ const Eigen::PlainObjectBase<Index> & F,
+ Eigen::PlainObjectBase<Scalar> & VD,
+ Eigen::PlainObjectBase<Index> & FD);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "false_barycentric_subdivision.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/fast_winding_number.cpp b/xs/src/igl/fast_winding_number.cpp
new file mode 100644
index 000000000..a69785feb
--- /dev/null
+++ b/xs/src/igl/fast_winding_number.cpp
@@ -0,0 +1,324 @@
+#include "fast_winding_number.h"
+#include "octree.h"
+#include "knn.h"
+#include "parallel_for.h"
+#include "PI.h"
+#include <vector>
+
+namespace igl {
+ template <typename DerivedP, typename DerivedA, typename DerivedN,
+ typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+ typename DerivedEC>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedA>& A,
+ const std::vector<std::vector<Index> > & point_indices,
+ const Eigen::MatrixBase<DerivedCH>& CH,
+ const int expansion_order,
+ Eigen::PlainObjectBase<DerivedCM>& CM,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedEC>& EC)
+ {
+ typedef typename DerivedP::Scalar real_p;
+ typedef typename DerivedN::Scalar real_n;
+ typedef typename DerivedA::Scalar real_a;
+ typedef typename DerivedCM::Scalar real_cm;
+ typedef typename DerivedR::Scalar real_r;
+ typedef typename DerivedEC::Scalar real_ec;
+
+ typedef Eigen::Matrix<real_p,1,3> RowVec3p;
+
+ int m = CH.size();
+ int num_terms;
+
+ assert(expansion_order < 3 && expansion_order >= 0 && "m must be less than n");
+ if(expansion_order == 0){
+ num_terms = 3;
+ } else if(expansion_order ==1){
+ num_terms = 3 + 9;
+ } else if(expansion_order == 2){
+ num_terms = 3 + 9 + 27;
+ }
+
+ R.resize(m);
+ CM.resize(m,3);
+ EC.resize(m,num_terms);
+ EC.setZero(m,num_terms);
+ std::function< void(const int) > helper;
+ helper = [&helper,
+ &P,&N,&A,&expansion_order,&point_indices,&CH,&EC,&R,&CM]
+ (const int index)-> void
+ {
+ Eigen::Matrix<real_cm,1,3> masscenter;
+ masscenter << 0,0,0;
+ Eigen::Matrix<real_ec,1,3> zeroth_expansion;
+ zeroth_expansion << 0,0,0;
+ real_p areatotal = 0.0;
+ for(int j = 0; j < point_indices.at(index).size(); j++){
+ int curr_point_index = point_indices.at(index).at(j);
+
+ areatotal += A(curr_point_index);
+ masscenter += A(curr_point_index)*P.row(curr_point_index);
+ zeroth_expansion += A(curr_point_index)*N.row(curr_point_index);
+ }
+
+ masscenter = masscenter/areatotal;
+ CM.row(index) = masscenter;
+ EC.block(index,0,1,3) = zeroth_expansion;
+
+ real_r max_norm = 0;
+ real_r curr_norm;
+
+ for(int i = 0; i < point_indices.at(index).size(); i++){
+ //Get max distance from center of mass:
+ int curr_point_index = point_indices.at(index).at(i);
+ Eigen::Matrix<real_r,1,3> point =
+ P.row(curr_point_index)-masscenter;
+ curr_norm = point.norm();
+ if(curr_norm > max_norm){
+ max_norm = curr_norm;
+ }
+
+ //Calculate higher order terms if necessary
+ Eigen::Matrix<real_ec,3,3> TempCoeffs;
+ if(EC.cols() >= (3+9)){
+ TempCoeffs = A(curr_point_index)*point.transpose()*
+ N.row(curr_point_index);
+ EC.block(index,3,1,9) +=
+ Eigen::Map<Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
+ TempCoeffs.size());
+ }
+
+ if(EC.cols() == (3+9+27)){
+ for(int k = 0; k < 3; k++){
+ TempCoeffs = 0.5 * point(k) * (A(curr_point_index)*
+ point.transpose()*N.row(curr_point_index));
+ EC.block(index,12+9*k,1,9) += Eigen::Map<
+ Eigen::Matrix<real_ec,1,9> >(TempCoeffs.data(),
+ TempCoeffs.size());
+ }
+ }
+ }
+
+ R(index) = max_norm;
+ if(CH(index,0) != -1)
+ {
+ for(int i = 0; i < 8; i++){
+ int child = CH(index,i);
+ helper(child);
+ }
+ }
+ };
+ helper(0);
+ }
+
+ template <typename DerivedP, typename DerivedA, typename DerivedN,
+ typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+ typename DerivedEC, typename DerivedQ, typename BetaType,
+ typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedA>& A,
+ const std::vector<std::vector<Index> > & point_indices,
+ const Eigen::MatrixBase<DerivedCH>& CH,
+ const Eigen::MatrixBase<DerivedCM>& CM,
+ const Eigen::MatrixBase<DerivedR>& R,
+ const Eigen::MatrixBase<DerivedEC>& EC,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ const BetaType beta,
+ Eigen::PlainObjectBase<DerivedWN>& WN){
+
+ typedef typename DerivedP::Scalar real_p;
+ typedef typename DerivedN::Scalar real_n;
+ typedef typename DerivedA::Scalar real_a;
+ typedef typename DerivedCM::Scalar real_cm;
+ typedef typename DerivedR::Scalar real_r;
+ typedef typename DerivedEC::Scalar real_ec;
+ typedef typename DerivedQ::Scalar real_q;
+ typedef typename DerivedWN::Scalar real_wn;
+
+ typedef Eigen::Matrix<real_q,1,3> RowVec;
+ typedef Eigen::Matrix<real_ec,3,3> EC_3by3;
+
+ auto direct_eval = [](const RowVec & loc,
+ const Eigen::Matrix<real_ec,1,3> & anorm){
+ real_wn wn = (loc(0)*anorm(0)+loc(1)*anorm(1)+loc(2)*anorm(2))
+ /(4.0*igl::PI*std::pow(loc.norm(),3));
+ if(std::isnan(wn)){
+ return 0.5;
+ }else{
+ return wn;
+ }
+ };
+
+ auto expansion_eval = [&direct_eval](const RowVec & loc,
+ const Eigen::RowVectorXd & EC){
+ real_wn wn = direct_eval(loc,EC.head<3>());
+ double r = loc.norm();
+ if(EC.size()>3){
+ Eigen::Matrix<real_ec,3,3> SecondDerivative =
+ Eigen::Matrix<real_ec,3,3>::Identity()/(4.0*igl::PI*std::pow(r,3));
+ SecondDerivative += -3.0*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,5));
+ Eigen::Matrix<real_ec,1,9> derivative_vector =
+ Eigen::Map<Eigen::Matrix<real_ec,1,9> >(SecondDerivative.data(),
+ SecondDerivative.size());
+ wn += derivative_vector.cwiseProduct(EC.segment<9>(3)).sum();
+ }
+ if(EC.size()>3+9){
+ Eigen::Matrix<real_ec,3,3> ThirdDerivative;
+ for(int i = 0; i < 3; i++){
+ ThirdDerivative =
+ 15.0*loc(i)*loc.transpose()*loc/(4.0*igl::PI*std::pow(r,7));
+ Eigen::Matrix<real_ec,3,3> Diagonal;
+ Diagonal << loc(i), 0, 0,
+ 0, loc(i), 0,
+ 0, 0, loc(i);
+ Eigen::Matrix<real_ec,3,3> RowCol;
+ RowCol.setZero(3,3);
+ RowCol.row(i) = loc;
+ Eigen::Matrix<real_ec,3,3> RowColT = RowCol.transpose();
+ RowCol = RowCol + RowColT;
+ ThirdDerivative +=
+ -3.0/(4.0*igl::PI*std::pow(r,5))*(RowCol+Diagonal);
+ Eigen::Matrix<real_ec,1,9> derivative_vector =
+ Eigen::Map<Eigen::Matrix<real_ec,1,9> >(ThirdDerivative.data(),
+ ThirdDerivative.size());
+ wn += derivative_vector.cwiseProduct(
+ EC.segment<9>(12 + i*9)).sum();
+ }
+ }
+ return wn;
+ };
+
+ int m = Q.rows();
+ WN.resize(m,1);
+
+ std::function< real_wn(const RowVec, const std::vector<int>) > helper;
+ helper = [&helper,
+ &P,&N,&A,
+ &point_indices,&CH,
+ &CM,&R,&EC,&beta,
+ &direct_eval,&expansion_eval]
+ (const RowVec query, const std::vector<int> near_indices)-> real_wn
+ {
+ std::vector<int> new_near_indices;
+ real_wn wn = 0;
+ for(int i = 0; i < near_indices.size(); i++){
+ int index = near_indices.at(i);
+ //Leaf Case, Brute force
+ if(CH(index,0) == -1){
+ for(int j = 0; j < point_indices.at(index).size(); j++){
+ int curr_row = point_indices.at(index).at(j);
+ wn += direct_eval(P.row(curr_row)-query,
+ N.row(curr_row)*A(curr_row));
+ }
+ }
+ //Non-Leaf Case
+ else {
+ for(int child = 0; child < 8; child++){
+ int child_index = CH(index,child);
+ if(point_indices.at(child_index).size() > 0){
+ if((CM.row(child_index)-query).norm() > beta*R(child_index)){
+ if(CH(child_index,0) == -1){
+ for(int j=0;j<point_indices.at(child_index).size();j++){
+ int curr_row = point_indices.at(child_index).at(j);
+ wn += direct_eval(P.row(curr_row)-query,
+ N.row(curr_row)*A(curr_row));
+ }
+ }else{
+ wn += expansion_eval(CM.row(child_index)-query,
+ EC.row(child_index));
+ }
+ }else {
+ new_near_indices.emplace_back(child_index);
+ }
+ }
+ }
+ }
+ }
+ if(new_near_indices.size() > 0){
+ wn += helper(query,new_near_indices);
+ }
+ return wn;
+ };
+
+
+ if(beta > 0){
+ std::vector<int> near_indices_start = {0};
+ igl::parallel_for(m,[&](int iter){
+ WN(iter) = helper(Q.row(iter),near_indices_start);
+ },1000);
+ } else {
+ igl::parallel_for(m,[&](int iter){
+ double wn = 0;
+ for(int j = 0; j <P.rows(); j++){
+ wn += direct_eval(P.row(j)-Q.row(iter),N.row(j)*A(j));
+ }
+ WN(iter) = wn;
+ },1000);
+ }
+ }
+
+ template <typename DerivedP, typename DerivedA, typename DerivedN,
+ typename DerivedQ, typename BetaType, typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedA>& A,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ const int expansion_order,
+ const BetaType beta,
+ Eigen::PlainObjectBase<DerivedWN>& WN
+ ){
+ typedef typename DerivedWN::Scalar real;
+
+ std::vector<std::vector<int> > point_indices;
+ Eigen::Matrix<int,Eigen::Dynamic,8> CH;
+ Eigen::Matrix<real,Eigen::Dynamic,3> CN;
+ Eigen::Matrix<real,Eigen::Dynamic,1> W;
+
+ octree(P,point_indices,CH,CN,W);
+
+ Eigen::Matrix<real,Eigen::Dynamic,Eigen::Dynamic> EC;
+ Eigen::Matrix<real,Eigen::Dynamic,3> CM;
+ Eigen::Matrix<real,Eigen::Dynamic,1> R;
+
+ fast_winding_number(P,N,A,point_indices,CH,expansion_order,CM,R,EC);
+ fast_winding_number(P,N,A,point_indices,CH,CM,R,EC,Q,beta,WN);
+ }
+
+ template <typename DerivedP, typename DerivedA, typename DerivedN,
+ typename DerivedQ, typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedA>& A,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ Eigen::PlainObjectBase<DerivedWN>& WN
+ ){
+ fast_winding_number(P,N,A,Q,2,2.0,WN);
+ }
+}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/xs/src/igl/fast_winding_number.h b/xs/src/igl/fast_winding_number.h
new file mode 100644
index 000000000..6d4bc1ed7
--- /dev/null
+++ b/xs/src/igl/fast_winding_number.h
@@ -0,0 +1,122 @@
+#ifndef IGL_FAST_WINDING_NUMBER
+#define IGL_FAST_WINDING_NUMBER
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ // Generate the precomputation for the fast winding number for point data
+ // [Barill et. al 2018].
+ //
+ // Given a set of 3D points P, with normals N, areas A, along with octree
+ // data, and an expansion order, we define a taylor series expansion at each
+ // octree cell.
+ //
+ // The octree data is designed to come from igl::octree, and the areas
+ // (if not obtained at scan time), may be calculated using
+ // igl::copyleft::cgal::point_areas.
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ // N #P by 3 list of point normals
+ // A #P by 1 list of point areas
+ // point_indices a vector of vectors, where the ith entry is a vector of
+ // the indices into P that are the ith octree cell's points
+ // CH #OctreeCells by 8, where the ith row is the indices of
+ // the ith octree cell's children
+ // expansion_order the order of the taylor expansion. We support 0,1,2.
+ // Outputs:
+ // CM #OctreeCells by 3 list of each cell's center of mass
+ // R #OctreeCells by 1 list of each cell's maximum distance of any point
+ // to the center of mass
+ // EC #OctreeCells by #TaylorCoefficients list of expansion coefficients.
+ // (Note that #TaylorCoefficients = ∑_{i=1}^{expansion_order} 3^i)
+ //
+ template <typename DerivedP, typename DerivedA, typename DerivedN,
+ typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+ typename DerivedEC>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedA>& A,
+ const std::vector<std::vector<Index> > & point_indices,
+ const Eigen::MatrixBase<DerivedCH>& CH,
+ const int exansion_order,
+ Eigen::PlainObjectBase<DerivedCM>& CM,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedEC>& EC);
+
+ // Evaluate the fast winding number for point data, having already done the
+ // the precomputation
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ // N #P by 3 list of point normals
+ // A #P by 1 list of point areas
+ // point_indices a vector of vectors, where the ith entry is a vector of
+ // the indices into P that are the ith octree cell's points
+ // CH #OctreeCells by 8, where the ith row is the indices of
+ // the ith octree cell's children
+ // CM #OctreeCells by 3 list of each cell's center of mass
+ // R #OctreeCells by 1 list of each cell's maximum distance of any point
+ // to the center of mass
+ // EC #OctreeCells by #TaylorCoefficients list of expansion coefficients.
+ // (Note that #TaylorCoefficients = ∑_{i=1}^{expansion_order} 3^i)
+ // Q #Q by 3 list of query points for the winding number
+ // beta This is a Barnes-Hut style accuracy term that separates near feild
+ // from far field. The higher the beta, the more accurate and slower
+ // the evaluation. We reccommend using a beta value of 2. Note that
+ // for a beta value ≤ 0, we use the direct evaluation, rather than
+ // the fast approximation
+ // Outputs:
+ // WN #Q by 1 list of windinng number values at each query point
+ //
+ template <typename DerivedP, typename DerivedA, typename DerivedN,
+ typename Index, typename DerivedCH, typename DerivedCM, typename DerivedR,
+ typename DerivedEC, typename DerivedQ, typename BetaType,
+ typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedA>& A,
+ const std::vector<std::vector<Index> > & point_indices,
+ const Eigen::MatrixBase<DerivedCH>& CH,
+ const Eigen::MatrixBase<DerivedCM>& CM,
+ const Eigen::MatrixBase<DerivedR>& R,
+ const Eigen::MatrixBase<DerivedEC>& EC,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ const BetaType beta,
+ Eigen::PlainObjectBase<DerivedWN>& WN);
+
+ // Evaluate the fast winding number for point data, with default expansion
+ // order and beta (both are set to 2).
+ //
+ // This function performes the precomputation and evaluation all in one.
+ // If you need to acess the precomuptation for repeated evaluations, use the
+ // two functions designed for exposed precomputation (described above).
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ // N #P by 3 list of point normals
+ // A #P by 1 list of point areas
+ // Q #Q by 3 list of query points for the winding number
+ // beta This is a Barnes-Hut style accuracy term that separates near feild
+ // from far field. The higher the beta, the more accurate and slower
+ // the evaluation. We reccommend using a beta value of 2.
+ // expansion_order the order of the taylor expansion. We support 0,1,2.
+ // Outputs:
+ // WN #Q by 1 list of windinng number values at each query point
+ //
+ template <typename DerivedP, typename DerivedA, typename DerivedN,
+ typename DerivedQ, typename DerivedWN>
+ IGL_INLINE void fast_winding_number(const Eigen::MatrixBase<DerivedP>& P,
+ const Eigen::MatrixBase<DerivedN>& N,
+ const Eigen::MatrixBase<DerivedA>& A,
+ const Eigen::MatrixBase<DerivedQ>& Q,
+ Eigen::PlainObjectBase<DerivedWN>& WN
+ );
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "fast_winding_number.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/file_contents_as_string.cpp b/xs/src/igl/file_contents_as_string.cpp
new file mode 100644
index 000000000..fd945dff2
--- /dev/null
+++ b/xs/src/igl/file_contents_as_string.cpp
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "file_contents_as_string.h"
+
+#include <fstream>
+#include <cstdio>
+#include <cassert>
+
+IGL_INLINE bool igl::file_contents_as_string(
+ const std::string file_name,
+ std::string & content)
+{
+ std::ifstream ifs(file_name.c_str());
+ // Check that opening the stream worked successfully
+ if(!ifs.good())
+ {
+ fprintf(
+ stderr,
+ "IOError: file_contents_as_string() cannot open %s\n",
+ file_name.c_str());
+ return false;
+ }
+ // Stream file contents into string
+ content = std::string(
+ (std::istreambuf_iterator<char>(ifs)),
+ (std::istreambuf_iterator<char>()));
+ return true;
+}
+
+IGL_INLINE std::string igl::file_contents_as_string(
+ const std::string file_name)
+{
+ std::string content;
+#ifndef NDEBUG
+ bool ret =
+#endif
+ file_contents_as_string(file_name,content);
+ assert(ret && "file_contents_as_string failed to read string from file");
+ return content;
+}
diff --git a/xs/src/igl/file_contents_as_string.h b/xs/src/igl/file_contents_as_string.h
new file mode 100644
index 000000000..22ce1fc53
--- /dev/null
+++ b/xs/src/igl/file_contents_as_string.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FILE_CONTENTS_AS_STRING_H
+#define IGL_FILE_CONTENTS_AS_STRING_H
+#include "igl_inline.h"
+
+#include <string>
+namespace igl
+{
+ // Read a files contents as plain text into a given string
+ // Inputs:
+ // file_name path to file to be read
+ // Outputs:
+ // content output string containing contents of the given file
+ // Returns true on succes, false on error
+ IGL_INLINE bool file_contents_as_string(
+ const std::string file_name,
+ std::string & content);
+ IGL_INLINE std::string file_contents_as_string(
+ const std::string file_name);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "file_contents_as_string.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/file_dialog_open.cpp b/xs/src/igl/file_dialog_open.cpp
new file mode 100644
index 000000000..66c2aca0e
--- /dev/null
+++ b/xs/src/igl/file_dialog_open.cpp
@@ -0,0 +1,87 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "file_dialog_open.h"
+#include <cstdio>
+#include <cstring>
+
+#ifdef _WIN32
+ #include <windows.h>
+ #undef max
+ #undef min
+
+ #include <Commdlg.h>
+#endif
+
+IGL_INLINE std::string igl::file_dialog_open()
+{
+ const int FILE_DIALOG_MAX_BUFFER = 1024;
+ char buffer[FILE_DIALOG_MAX_BUFFER];
+
+#ifdef __APPLE__
+ // For apple use applescript hack
+ FILE * output = popen(
+ "osascript -e \""
+ " tell application \\\"System Events\\\"\n"
+ " activate\n"
+ " set existing_file to choose file\n"
+ " end tell\n"
+ " set existing_file_path to (POSIX path of (existing_file))\n"
+ "\" 2>/dev/null | tr -d '\n' ","r");
+ while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+ {
+ }
+#elif defined _WIN32
+
+ // Use native windows file dialog box
+ // (code contributed by Tino Weinkauf)
+
+ OPENFILENAME ofn; // common dialog box structure
+ char szFile[260]; // buffer for file name
+
+ // Initialize OPENFILENAME
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = NULL;
+ ofn.lpstrFile = new char[100];
+ // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
+ // use the contents of szFile to initialize itself.
+ ofn.lpstrFile[0] = '\0';
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFilter = "*.*\0";//off\0*.off\0obj\0*.obj\0mp\0*.mp\0";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+
+ // Display the Open dialog box.
+ int pos = 0;
+ if (GetOpenFileName(&ofn)==TRUE)
+ {
+ while(ofn.lpstrFile[pos] != '\0')
+ {
+ buffer[pos] = (char)ofn.lpstrFile[pos];
+ pos++;
+ }
+ }
+ buffer[pos] = 0;
+#else
+
+ // For linux use zenity
+ FILE * output = popen("/usr/bin/zenity --file-selection","r");
+ while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+ {
+ }
+
+ if (strlen(buffer) > 0)
+ {
+ buffer[strlen(buffer)-1] = 0;
+ }
+#endif
+ return std::string(buffer);
+}
diff --git a/xs/src/igl/file_dialog_open.h b/xs/src/igl/file_dialog_open.h
new file mode 100644
index 000000000..1b17ea4c6
--- /dev/null
+++ b/xs/src/igl/file_dialog_open.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FILE_DIALOG_OPEN_H
+#define IGL_FILE_DIALOG_OPEN_H
+#include "igl_inline.h"
+
+#include <string>
+
+namespace igl
+{
+ // Returns a string with a path to an existing file
+ // The string is returned empty if no file is selected
+ // (on Linux machines, it assumes that Zenity is installed)
+ //
+ // Usage:
+ // std::string str = get_open_file_path();
+ IGL_INLINE std::string file_dialog_open();
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "file_dialog_open.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/file_dialog_save.cpp b/xs/src/igl/file_dialog_save.cpp
new file mode 100644
index 000000000..90687fa5c
--- /dev/null
+++ b/xs/src/igl/file_dialog_save.cpp
@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "file_dialog_save.h"
+#include <cstdio>
+#include <cstring>
+
+#ifdef _WIN32
+ #include <windows.h>
+ #include <Commdlg.h>
+#endif
+
+IGL_INLINE std::string igl::file_dialog_save()
+{
+ const int FILE_DIALOG_MAX_BUFFER = 1024;
+ char buffer[FILE_DIALOG_MAX_BUFFER];
+#ifdef __APPLE__
+ // For apple use applescript hack
+ // There is currently a bug in Applescript that strips extensions off
+ // of chosen existing files in the "choose file name" dialog
+ // I'm assuming that will be fixed soon
+ FILE * output = popen(
+ "osascript -e \""
+ " tell application \\\"System Events\\\"\n"
+ " activate\n"
+ " set existing_file to choose file name\n"
+ " end tell\n"
+ " set existing_file_path to (POSIX path of (existing_file))\n"
+ "\" 2>/dev/null | tr -d '\n' ","r");
+ while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+ {
+ }
+#elif defined _WIN32
+
+ // Use native windows file dialog box
+ // (code contributed by Tino Weinkauf)
+
+ OPENFILENAME ofn; // common dialog box structure
+ char szFile[260]; // buffer for file name
+
+ // Initialize OPENFILENAME
+ ZeroMemory(&ofn, sizeof(ofn));
+ ofn.lStructSize = sizeof(ofn);
+ ofn.hwndOwner = NULL;//hwnd;
+ ofn.lpstrFile = new char[100];
+ // Set lpstrFile[0] to '\0' so that GetOpenFileName does not
+ // use the contents of szFile to initialize itself.
+ ofn.lpstrFile[0] = '\0';
+ ofn.nMaxFile = sizeof(szFile);
+ ofn.lpstrFilter = "";
+ ofn.nFilterIndex = 1;
+ ofn.lpstrFileTitle = NULL;
+ ofn.nMaxFileTitle = 0;
+ ofn.lpstrInitialDir = NULL;
+ ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;
+
+ // Display the Open dialog box.
+ int pos = 0;
+ if (GetSaveFileName(&ofn)==TRUE)
+ {
+ while(ofn.lpstrFile[pos] != '\0')
+ {
+ buffer[pos] = (char)ofn.lpstrFile[pos];
+ pos++;
+ }
+ buffer[pos] = 0;
+ }
+
+#else
+ // For every other machine type use zenity
+ FILE * output = popen("/usr/bin/zenity --file-selection --save","r");
+ while ( fgets(buffer, FILE_DIALOG_MAX_BUFFER, output) != NULL )
+ {
+ }
+
+ if (strlen(buffer) > 0)
+ {
+ buffer[strlen(buffer)-1] = 0;
+ }
+#endif
+ return std::string(buffer);
+}
diff --git a/xs/src/igl/file_dialog_save.h b/xs/src/igl/file_dialog_save.h
new file mode 100644
index 000000000..f04075758
--- /dev/null
+++ b/xs/src/igl/file_dialog_save.h
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FILE_DIALOG_SAVE_H
+#define IGL_FILE_DIALOG_SAVE_H
+#include "igl_inline.h"
+
+#include <string>
+
+namespace igl
+{
+ // Returns a string with a path to a new/existing file
+ // The string is returned empty if no file is selected
+ // (on Linux machines, it assumes that Zenity is installed)
+ //
+ // Usage:
+ // char buffer[FILE_DIALOG_MAX_BUFFER];
+ // get_save_file_path(buffer);
+ IGL_INLINE std::string file_dialog_save();
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "file_dialog_save.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/file_exists.cpp b/xs/src/igl/file_exists.cpp
new file mode 100644
index 000000000..f1a30630b
--- /dev/null
+++ b/xs/src/igl/file_exists.cpp
@@ -0,0 +1,16 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "file_exists.h"
+
+#include <sys/stat.h>
+
+IGL_INLINE bool igl::file_exists(const std::string filename)
+{
+ struct stat status;
+ return (stat(filename.c_str(),&status)==0);
+}
diff --git a/xs/src/igl/file_exists.h b/xs/src/igl/file_exists.h
new file mode 100644
index 000000000..e011d977e
--- /dev/null
+++ b/xs/src/igl/file_exists.h
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FILE_EXISTS_H
+#define IGL_FILE_EXISTS_H
+#include "igl_inline.h"
+#include <string>
+namespace igl
+{
+ // Check if a file or directory exists like PHP's file_exists function:
+ // http://php.net/manual/en/function.file-exists.php
+ // Input:
+ // filename path to file
+ // Returns true if file exists and is readable and false if file doesn't
+ // exist or *is not readable*
+ IGL_INLINE bool file_exists(const std::string filename);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "file_exists.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/find.cpp b/xs/src/igl/find.cpp
new file mode 100644
index 000000000..65e7580ca
--- /dev/null
+++ b/xs/src/igl/find.cpp
@@ -0,0 +1,138 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "find.h"
+
+#include "verbose.h"
+#include <iostream>
+
+template <
+ typename T,
+ typename DerivedI,
+ typename DerivedJ,
+ typename DerivedV>
+IGL_INLINE void igl::find(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::DenseBase<DerivedI> & I,
+ Eigen::DenseBase<DerivedJ> & J,
+ Eigen::DenseBase<DerivedV> & V)
+{
+ // Resize outputs to fit nonzeros
+ I.derived().resize(X.nonZeros(),1);
+ J.derived().resize(X.nonZeros(),1);
+ V.derived().resize(X.nonZeros(),1);
+
+ int i = 0;
+ // Iterate over outside
+ for(int k=0; k<X.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<T>::InnerIterator it (X,k); it; ++it)
+ {
+ V(i) = it.value();
+ I(i) = it.row();
+ J(i) = it.col();
+ i++;
+ }
+ }
+}
+
+template <
+ typename DerivedX,
+ typename DerivedI,
+ typename DerivedJ,
+ typename DerivedV>
+IGL_INLINE void igl::find(
+ const Eigen::DenseBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedV> & V)
+{
+ const int nnz = X.count();
+ I.resize(nnz,1);
+ J.resize(nnz,1);
+ V.resize(nnz,1);
+ {
+ int k = 0;
+ for(int j = 0;j<X.cols();j++)
+ {
+ for(int i = 0;i<X.rows();i++)
+ {
+ if(X(i,j))
+ {
+ I(k) = i;
+ J(k) = j;
+ V(k) = X(i,j);
+ k++;
+ }
+ }
+ }
+ }
+}
+
+template <
+ typename DerivedX,
+ typename DerivedI>
+IGL_INLINE void igl::find(
+ const Eigen::DenseBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ const int nnz = X.count();
+ I.resize(nnz,1);
+ {
+ int k = 0;
+ for(int j = 0;j<X.cols();j++)
+ {
+ for(int i = 0;i<X.rows();i++)
+ {
+ if(X(i,j))
+ {
+ I(k) = i+X.rows()*j;
+ k++;
+ }
+ }
+ }
+ }
+}
+
+template <typename T>
+IGL_INLINE void igl::find(
+ const Eigen::SparseVector<T>& X,
+ Eigen::Matrix<int,Eigen::Dynamic,1> & I,
+ Eigen::Matrix<T,Eigen::Dynamic,1> & V)
+{
+ // Resize outputs to fit nonzeros
+ I.resize(X.nonZeros());
+ V.resize(X.nonZeros());
+
+ int i = 0;
+ // loop over non-zeros
+ for(typename Eigen::SparseVector<T>::InnerIterator it(X); it; ++it)
+ {
+ I(i) = it.index();
+ V(i) = it.value();
+ i++;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+
+template void igl::find<bool, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
+template void igl::find<Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Array<bool, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find<double, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::find<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::find<double, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::find<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find<double, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+#else
+template void igl::find<Eigen::CwiseBinaryOp<Eigen::internal::scalar_cmp_op<long, (Eigen::internal::ComparisonName)0>, Eigen::PartialReduxExpr<Eigen::Array<bool, -1, 3, 0, -1, 3>, Eigen::internal::member_count<long>, 1> const, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<long>, Eigen::Array<long, -1, 1, 0, -1, 1> > const>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::CwiseBinaryOp<Eigen::internal::scalar_cmp_op<long, (Eigen::internal::ComparisonName)0>, Eigen::PartialReduxExpr<Eigen::Array<bool, -1, 3, 0, -1, 3>, Eigen::internal::member_count<long>, 1> const, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<long>, Eigen::Array<long, -1, 1, 0, -1, 1> > const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find<Eigen::CwiseBinaryOp<Eigen::internal::scalar_cmp_op<int, (Eigen::internal::ComparisonName)0>, Eigen::Array<int, -1, 1, 0, -1, 1> const, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<int>, Eigen::Array<int, -1, 1, 0, -1, 1> > const>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::CwiseBinaryOp<Eigen::internal::scalar_cmp_op<int, (Eigen::internal::ComparisonName)0>, Eigen::Array<int, -1, 1, 0, -1, 1> const, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<int>, Eigen::Array<int, -1, 1, 0, -1, 1> > const> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
+
+#endif
diff --git a/xs/src/igl/find.h b/xs/src/igl/find.h
new file mode 100644
index 000000000..85eb65770
--- /dev/null
+++ b/xs/src/igl/find.h
@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FIND_H
+#define IGL_FIND_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Find the non-zero entries and there respective indices in a sparse matrix.
+ // Like matlab's [I,J,V] = find(X)
+ //
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Input:
+ // X m by n matrix whose entries are to be found
+ // Outputs:
+ // I nnz vector of row indices of non zeros entries in X
+ // J nnz vector of column indices of non zeros entries in X
+ // V nnz vector of type T non-zeros entries in X
+ //
+ template <
+ typename T,
+ typename DerivedI,
+ typename DerivedJ,
+ typename DerivedV>
+ IGL_INLINE void find(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::DenseBase<DerivedI> & I,
+ Eigen::DenseBase<DerivedJ> & J,
+ Eigen::DenseBase<DerivedV> & V);
+ template <
+ typename DerivedX,
+ typename DerivedI,
+ typename DerivedJ,
+ typename DerivedV>
+ IGL_INLINE void find(
+ const Eigen::DenseBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedV> & V);
+ template <
+ typename DerivedX,
+ typename DerivedI>
+ IGL_INLINE void find(
+ const Eigen::DenseBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedI> & I);
+ // Find the non-zero entries and there respective indices in a sparse vector.
+ // Similar to matlab's [I,J,V] = find(X), but instead of [I,J] being
+ // subscripts into X, since X is a vector we just return I, a list of indices
+ // into X
+ //
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Input:
+ // X vector whose entries are to be found
+ // Outputs:
+ // I nnz vector of indices of non zeros entries in X
+ // V nnz vector of type T non-zeros entries in X
+ template <typename T>
+ IGL_INLINE void find(
+ const Eigen::SparseVector<T>& X,
+ Eigen::Matrix<int,Eigen::Dynamic,1> & I,
+ Eigen::Matrix<T,Eigen::Dynamic,1> & V);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "find.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/find_cross_field_singularities.cpp b/xs/src/igl/find_cross_field_singularities.cpp
new file mode 100644
index 000000000..31a5bb714
--- /dev/null
+++ b/xs/src/igl/find_cross_field_singularities.cpp
@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "find_cross_field_singularities.h"
+
+#include <vector>
+#include <igl/cross_field_missmatch.h>
+#include <igl/is_border_vertex.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/is_border_vertex.h>
+#include <igl/cross_field_missmatch.h>
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedO>
+IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch,
+ Eigen::PlainObjectBase<DerivedO> &isSingularity,
+ Eigen::PlainObjectBase<DerivedO> &singularityIndex)
+{
+ std::vector<bool> V_border = igl::is_border_vertex(V,F);
+
+ std::vector<std::vector<int> > VF;
+ std::vector<std::vector<int> > VFi;
+ igl::vertex_triangle_adjacency(V,F,VF,VFi);
+
+
+ isSingularity.setZero(V.rows(),1);
+ singularityIndex.setZero(V.rows(),1);
+ for (unsigned int vid=0;vid<V.rows();vid++)
+ {
+ ///check that is on border..
+ if (V_border[vid])
+ continue;
+
+ int missmatch=0;
+ for (unsigned int i=0;i<VF[vid].size();i++)
+ {
+ // look for the vertex
+ int j=-1;
+ for (unsigned z=0; z<3; ++z)
+ if (F(VF[vid][i],z) == vid)
+ j=z;
+ assert(j!=-1);
+
+ missmatch+=Handle_MMatch(VF[vid][i],j);
+ }
+ missmatch=missmatch%4;
+
+ isSingularity(vid)=(missmatch!=0);
+ singularityIndex(vid)=missmatch;
+ }
+
+
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedO>
+IGL_INLINE void igl::find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const Eigen::PlainObjectBase<DerivedV> &PD2,
+ Eigen::PlainObjectBase<DerivedO> &isSingularity,
+ Eigen::PlainObjectBase<DerivedO> &singularityIndex,
+ bool isCombed)
+{
+ Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 3> Handle_MMatch;
+
+ igl::cross_field_missmatch(V, F, PD1, PD2, isCombed, Handle_MMatch);
+ igl::find_cross_field_singularities(V, F, Handle_MMatch, isSingularity, singularityIndex);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&,
+Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, bool);
+template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, bool);
+template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::find_cross_field_singularities<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/find_cross_field_singularities.h b/xs/src/igl/find_cross_field_singularities.h
new file mode 100644
index 000000000..caded2019
--- /dev/null
+++ b/xs/src/igl/find_cross_field_singularities.h
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_FIND_CROSS_FIELD_SINGULARITIES_H
+#define IGL_FIND_CROSS_FIELD_SINGULARITIES_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Computes singularities of a cross field, assumed combed
+
+
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigen Matrix of face (quad) indices
+ // Handle_MMatch #F by 3 eigen Matrix containing the integer missmatch of the cross field
+ // across all face edges
+ // Output:
+ // isSingularity #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex
+ // singularityIndex #V by 1 integer eigen Vector containing the singularity indices
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedM, typename DerivedO>
+ IGL_INLINE void find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedM> &Handle_MMatch,
+ Eigen::PlainObjectBase<DerivedO> &isSingularity,
+ Eigen::PlainObjectBase<DerivedO> &singularityIndex);
+
+ // Wrapper that calculates the missmatch if it is not provided.
+ // Note that the field in PD1 and PD2 MUST BE combed (see igl::comb_cross_field).
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 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
+ // Output:
+ // isSingularity #V by 1 boolean eigen Vector indicating the presence of a singularity on a vertex
+ // singularityIndex #V by 1 integer eigen Vector containing the singularity indices
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedO>
+ IGL_INLINE void find_cross_field_singularities(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const Eigen::PlainObjectBase<DerivedV> &PD2,
+ Eigen::PlainObjectBase<DerivedO> &isSingularity,
+ Eigen::PlainObjectBase<DerivedO> &singularityIndex,
+ bool isCombed = false);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "find_cross_field_singularities.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/find_zero.cpp b/xs/src/igl/find_zero.cpp
new file mode 100644
index 000000000..d0a7b35e6
--- /dev/null
+++ b/xs/src/igl/find_zero.cpp
@@ -0,0 +1,48 @@
+#include "find_zero.h"
+#include "for_each.h"
+#include "any.h"
+
+template <typename AType, typename DerivedI>
+IGL_INLINE void igl::find_zero(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ assert((dim == 1 || dim == 2) && "dim must be 2 or 1");
+ // Get size of input
+ int m = A.rows();
+ int n = A.cols();
+ // I starts by containing guess where 0 might be
+ I = DerivedI::Zero(dim==1?n:m);
+ Eigen::Array<bool,Eigen::Dynamic,1> found =
+ Eigen::Array<bool,Eigen::Dynamic,1>::Zero(dim==1?n:m);
+ const auto func = [&I,&found,&dim](int i, int j, const int v)
+ {
+ if(dim == 2)
+ {
+ std::swap(i,j);
+ }
+ // Coded as if dim == 1, assuming swap for dim == 2
+ // Have we already found a zero?
+ if(!found(j))
+ {
+ if(I(j) != i || v == 0)
+ {
+ // either there was an implicit zero between the last element and this
+ // one, or this one is zero
+ found(j) = true;
+ }else
+ {
+ // If not found, then guess that next element will be zero
+ I(j) = I(j)+1;
+ }
+ }
+ };
+ for_each(A,func);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::find_zero<bool, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/find_zero.h b/xs/src/igl/find_zero.h
new file mode 100644
index 000000000..0739be1cf
--- /dev/null
+++ b/xs/src/igl/find_zero.h
@@ -0,0 +1,28 @@
+#ifndef IGL_FIND_ZERO_H
+#define IGL_FIND_ZERO_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Find the first zero (whether implicit or explicitly stored) in the
+ // rows/columns of a matrix.
+ // Inputs:
+ // A m by n sparse matrix
+ // dim dimension along which to check for any (1 or 2)
+ // Output:
+ // I n-long vector (if dim == 1) {m means no zeros found}
+ // or
+ // I m-long vector (if dim == 2) {n means no zeros found}
+ //
+ template <typename AType, typename DerivedI>
+ IGL_INLINE void find_zero(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedI> & I);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "find_zero.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/fit_plane.cpp b/xs/src/igl/fit_plane.cpp
new file mode 100644
index 000000000..83f11738f
--- /dev/null
+++ b/xs/src/igl/fit_plane.cpp
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "fit_plane.h"
+#include <iostream>
+
+IGL_INLINE void igl::fit_plane(
+ const Eigen::MatrixXd & V,
+ Eigen::RowVector3d & N,
+ Eigen::RowVector3d & C)
+{
+ assert(V.rows()>0);
+
+ Eigen::Vector3d sum = V.colwise().sum();
+
+ Eigen::Vector3d center = sum.array()/(double(V.rows()));
+
+ C = center;
+
+ double sumXX=0.0f,sumXY=0.0f,sumXZ=0.0f;
+ double sumYY=0.0f,sumYZ=0.0f;
+ double sumZZ=0.0f;
+
+ for(int i=0;i<V.rows();i++)
+ {
+ double diffX=V(i,0)-center(0);
+ double diffY=V(i,1)-center(1);
+ double diffZ=V(i,2)-center(2);
+ sumXX+=diffX*diffX;
+ sumXY+=diffX*diffY;
+ sumXZ+=diffX*diffZ;
+ sumYY+=diffY*diffY;
+ sumYZ+=diffY*diffZ;
+ sumZZ+=diffZ*diffZ;
+ }
+
+ Eigen::MatrixXd m(3,3);
+ m << sumXX,sumXY,sumXZ,
+ sumXY,sumYY,sumYZ,
+ sumXZ,sumYZ,sumZZ;
+
+ Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> es(m);
+
+ N = es.eigenvectors().col(0);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+#endif
+
+
+
diff --git a/xs/src/igl/fit_plane.h b/xs/src/igl/fit_plane.h
new file mode 100644
index 000000000..f69ce811b
--- /dev/null
+++ b/xs/src/igl/fit_plane.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FIT_PLANE_H
+#define IGL_FIT_PLANE_H
+
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // This function fits a plane to a point cloud.
+ //
+ // Input:
+ // V #Vx3 matrix. The 3D point cloud, one row for each vertex.
+ // Output:
+ // N 1x3 Vector. The normal of the fitted plane.
+ // C 1x3 Vector. A point that lies in the fitted plane.
+ // From http://missingbytes.blogspot.com/2012/06/fitting-plane-to-point-cloud.html
+
+ IGL_INLINE void fit_plane(
+ const Eigen::MatrixXd & V,
+ Eigen::RowVector3d & N,
+ Eigen::RowVector3d & C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "fit_plane.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/fit_rotations.cpp b/xs/src/igl/fit_rotations.cpp
new file mode 100644
index 000000000..927e8992e
--- /dev/null
+++ b/xs/src/igl/fit_rotations.cpp
@@ -0,0 +1,225 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "fit_rotations.h"
+#include "polar_svd3x3.h"
+#include "repmat.h"
+#include "verbose.h"
+#include "polar_dec.h"
+#include "polar_svd.h"
+#include "C_STR.h"
+#include <iostream>
+
+template <typename DerivedS, typename DerivedD>
+IGL_INLINE void igl::fit_rotations(
+ const Eigen::PlainObjectBase<DerivedS> & S,
+ const bool single_precision,
+ Eigen::PlainObjectBase<DerivedD> & R)
+{
+ using namespace std;
+ const int dim = S.cols();
+ const int nr = S.rows()/dim;
+ assert(nr * dim == S.rows());
+ assert(dim == 3);
+
+ // resize output
+ R.resize(dim,dim*nr); // hopefully no op (should be already allocated)
+
+ //std::cout<<"S=["<<std::endl<<S<<std::endl<<"];"<<std::endl;
+ //MatrixXd si(dim,dim);
+ Eigen::Matrix<typename DerivedS::Scalar,3,3> si;// = Eigen::Matrix3d::Identity();
+ // loop over number of rotations we're computing
+ for(int r = 0;r<nr;r++)
+ {
+ // build this covariance matrix
+ for(int i = 0;i<dim;i++)
+ {
+ for(int j = 0;j<dim;j++)
+ {
+ si(i,j) = S(i*nr+r,j);
+ }
+ }
+ typedef Eigen::Matrix<typename DerivedD::Scalar,3,3> Mat3;
+ typedef Eigen::Matrix<typename DerivedD::Scalar,3,1> Vec3;
+ Mat3 ri;
+ if(single_precision)
+ {
+ polar_svd3x3(si, ri);
+ }else
+ {
+ Mat3 ti,ui,vi;
+ Vec3 _;
+ igl::polar_svd(si,ri,ti,ui,_,vi);
+ }
+ assert(ri.determinant() >= 0);
+ R.block(0,r*dim,dim,dim) = ri.block(0,0,dim,dim).transpose();
+ //cout<<matlab_format(si,C_STR("si_"<<r))<<endl;
+ //cout<<matlab_format(ri.transpose().eval(),C_STR("ri_"<<r))<<endl;
+ }
+}
+
+template <typename DerivedS, typename DerivedD>
+IGL_INLINE void igl::fit_rotations_planar(
+ const Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedD> & R)
+{
+ using namespace std;
+ const int dim = S.cols();
+ const int nr = S.rows()/dim;
+ //assert(dim == 2 && "_planar input should be 2D");
+ assert(nr * dim == S.rows());
+
+ // resize output
+ R.resize(dim,dim*nr); // hopefully no op (should be already allocated)
+
+ Eigen::Matrix<typename DerivedS::Scalar,2,2> si;
+ // loop over number of rotations we're computing
+ for(int r = 0;r<nr;r++)
+ {
+ // build this covariance matrix
+ for(int i = 0;i<2;i++)
+ {
+ for(int j = 0;j<2;j++)
+ {
+ si(i,j) = S(i*nr+r,j);
+ }
+ }
+ typedef Eigen::Matrix<typename DerivedD::Scalar,2,2> Mat2;
+ typedef Eigen::Matrix<typename DerivedD::Scalar,2,1> Vec2;
+ Mat2 ri,ti,ui,vi;
+ Vec2 _;
+ igl::polar_svd(si,ri,ti,ui,_,vi);
+#ifndef FIT_ROTATIONS_ALLOW_FLIPS
+ // Check for reflection
+ if(ri.determinant() < 0)
+ {
+ vi.col(1) *= -1.;
+ ri = ui * vi.transpose();
+ }
+ assert(ri.determinant() >= 0);
+#endif
+
+ // Not sure why polar_dec computes transpose...
+ R.block(0,r*dim,dim,dim).setIdentity();
+ R.block(0,r*dim,2,2) = ri.transpose();
+ }
+}
+
+
+#ifdef __SSE__
+IGL_INLINE void igl::fit_rotations_SSE(
+ const Eigen::MatrixXf & S,
+ Eigen::MatrixXf & R)
+{
+ const int cStep = 4;
+
+ assert(S.cols() == 3);
+ const int dim = 3; //S.cols();
+ const int nr = S.rows()/dim;
+ assert(nr * dim == S.rows());
+
+ // resize output
+ R.resize(dim,dim*nr); // hopefully no op (should be already allocated)
+
+ Eigen::Matrix<float, 3*cStep, 3> siBig;
+ // using SSE decompose cStep matrices at a time:
+ int r = 0;
+ for( ; r<nr; r+=cStep)
+ {
+ int numMats = cStep;
+ if (r + cStep >= nr) numMats = nr - r;
+ // build siBig:
+ for (int k=0; k<numMats; k++)
+ {
+ for(int i = 0;i<dim;i++)
+ {
+ for(int j = 0;j<dim;j++)
+ {
+ siBig(i + 3*k, j) = S(i*nr + r + k, j);
+ }
+ }
+ }
+ Eigen::Matrix<float, 3*cStep, 3> ri;
+ polar_svd3x3_sse(siBig, ri);
+
+ for (int k=0; k<cStep; k++)
+ assert(ri.block(3*k, 0, 3, 3).determinant() >= 0);
+
+ // Not sure why polar_dec computes transpose...
+ for (int k=0; k<numMats; k++)
+ {
+ R.block(0, (r + k)*dim, dim, dim) = ri.block(3*k, 0, dim, dim).transpose();
+ }
+ }
+}
+
+IGL_INLINE void igl::fit_rotations_SSE(
+ const Eigen::MatrixXd & S,
+ Eigen::MatrixXd & R)
+{
+ const Eigen::MatrixXf Sf = S.cast<float>();
+ Eigen::MatrixXf Rf;
+ fit_rotations_SSE(Sf,Rf);
+ R = Rf.cast<double>();
+}
+#endif
+
+#ifdef __AVX__
+IGL_INLINE void igl::fit_rotations_AVX(
+ const Eigen::MatrixXf & S,
+ Eigen::MatrixXf & R)
+{
+ const int cStep = 8;
+
+ assert(S.cols() == 3);
+ const int dim = 3; //S.cols();
+ const int nr = S.rows()/dim;
+ assert(nr * dim == S.rows());
+
+ // resize output
+ R.resize(dim,dim*nr); // hopefully no op (should be already allocated)
+
+ Eigen::Matrix<float, 3*cStep, 3> siBig;
+ // using SSE decompose cStep matrices at a time:
+ int r = 0;
+ for( ; r<nr; r+=cStep)
+ {
+ int numMats = cStep;
+ if (r + cStep >= nr) numMats = nr - r;
+ // build siBig:
+ for (int k=0; k<numMats; k++)
+ {
+ for(int i = 0;i<dim;i++)
+ {
+ for(int j = 0;j<dim;j++)
+ {
+ siBig(i + 3*k, j) = S(i*nr + r + k, j);
+ }
+ }
+ }
+ Eigen::Matrix<float, 3*cStep, 3> ri;
+ polar_svd3x3_avx(siBig, ri);
+
+ for (int k=0; k<cStep; k++)
+ assert(ri.block(3*k, 0, 3, 3).determinant() >= 0);
+
+ // Not sure why polar_dec computes transpose...
+ for (int k=0; k<numMats; k++)
+ {
+ R.block(0, (r + k)*dim, dim, dim) = ri.block(3*k, 0, dim, dim).transpose();
+ }
+ }
+}
+#endif
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::fit_rotations<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::fit_rotations_planar<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::fit_rotations_planar<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+template void igl::fit_rotations<Eigen::Matrix<float,-1,-1,0,-1,-1>,Eigen::Matrix<float,-1,-1,0,-1,-1> >(Eigen::PlainObjectBase<Eigen::Matrix<float,-1,-1,0,-1,-1> > const &,bool,Eigen::PlainObjectBase<Eigen::Matrix<float,-1,-1,0,-1,-1> > &);
+#endif
diff --git a/xs/src/igl/fit_rotations.h b/xs/src/igl/fit_rotations.h
new file mode 100644
index 000000000..1a18fd322
--- /dev/null
+++ b/xs/src/igl/fit_rotations.h
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FIT_ROTATIONS_H
+#define IGL_FIT_ROTATIONS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Known issues: This seems to be implemented in Eigen/Geometry:
+ // Eigen::umeyama
+ //
+ // FIT_ROTATIONS Given an input mesh and new positions find rotations for
+ // every covariance matrix in a stack of covariance matrices
+ //
+ // Inputs:
+ // S nr*dim by dim stack of covariance matrices
+ // single_precision whether to use single precision (faster)
+ // Outputs:
+ // R dim by dim * nr list of rotations
+ //
+ template <typename DerivedS, typename DerivedD>
+ IGL_INLINE void fit_rotations(
+ const Eigen::PlainObjectBase<DerivedS> & S,
+ const bool single_precision,
+ Eigen::PlainObjectBase<DerivedD> & R);
+
+ // FIT_ROTATIONS Given an input mesh and new positions find 2D rotations for
+ // every vertex that best maps its one ring to the new one ring
+ //
+ // Inputs:
+ // S nr*dim by dim stack of covariance matrices, third column and every
+ // third row will be ignored
+ // Outputs:
+ // R dim by dim * nr list of rotations, third row and third column of each
+ // rotation will just be identity
+ //
+ template <typename DerivedS, typename DerivedD>
+ IGL_INLINE void fit_rotations_planar(
+ const Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedD> & R);
+#ifdef __SSE__
+ IGL_INLINE void fit_rotations_SSE( const Eigen::MatrixXf & S, Eigen::MatrixXf & R);
+ IGL_INLINE void fit_rotations_SSE( const Eigen::MatrixXd & S, Eigen::MatrixXd & R);
+#endif
+#ifdef __AVX__
+ IGL_INLINE void fit_rotations_AVX( const Eigen::MatrixXf & S, Eigen::MatrixXf & R);
+#endif
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "fit_rotations.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/flip_avoiding_line_search.cpp b/xs/src/igl/flip_avoiding_line_search.cpp
new file mode 100644
index 000000000..8554303c2
--- /dev/null
+++ b/xs/src/igl/flip_avoiding_line_search.cpp
@@ -0,0 +1,320 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "flip_avoiding_line_search.h"
+#include "line_search.h"
+#include "PI.h"
+
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl
+{
+ namespace flip_avoiding
+ {
+ //---------------------------------------------------------------------------
+ // x - array of size 3
+ // In case 3 real roots: => x[0], x[1], x[2], return 3
+ // 2 real roots: x[0], x[1], return 2
+ // 1 real root : x[0], x[1] ± i*x[2], return 1
+ // http://math.ivanovo.ac.ru/dalgebra/Khashin/poly/index.html
+ IGL_INLINE int SolveP3(std::vector<double>& x,double a,double b,double c)
+ { // solve cubic equation x^3 + a*x^2 + b*x + c
+ using namespace std;
+ double a2 = a*a;
+ double q = (a2 - 3*b)/9;
+ double r = (a*(2*a2-9*b) + 27*c)/54;
+ double r2 = r*r;
+ double q3 = q*q*q;
+ double A,B;
+ if(r2<q3)
+ {
+ double t=r/sqrt(q3);
+ if( t<-1) t=-1;
+ if( t> 1) t= 1;
+ t=acos(t);
+ a/=3; q=-2*sqrt(q);
+ x[0]=q*cos(t/3)-a;
+ x[1]=q*cos((t+(2*igl::PI))/3)-a;
+ x[2]=q*cos((t-(2*igl::PI))/3)-a;
+ return(3);
+ }
+ else
+ {
+ A =-pow(fabs(r)+sqrt(r2-q3),1./3);
+ if( r<0 ) A=-A;
+ B = A==0? 0 : B=q/A;
+
+ a/=3;
+ x[0] =(A+B)-a;
+ x[1] =-0.5*(A+B)-a;
+ x[2] = 0.5*sqrt(3.)*(A-B);
+ if(fabs(x[2])<1e-14)
+ {
+ x[2]=x[1]; return(2);
+ }
+ return(1);
+ }
+ }
+
+ IGL_INLINE double get_smallest_pos_quad_zero(double a,double b, double c)
+ {
+ using namespace std;
+ double t1, t2;
+ if(std::abs(a) > 1.0e-10)
+ {
+ double delta_in = pow(b, 2) - 4 * a * c;
+ if(delta_in <= 0)
+ {
+ return INFINITY;
+ }
+
+ double delta = sqrt(delta_in); // delta >= 0
+ if(b >= 0) // avoid subtracting two similar numbers
+ {
+ double bd = - b - delta;
+ t1 = 2 * c / bd;
+ t2 = bd / (2 * a);
+ }
+ else
+ {
+ double bd = - b + delta;
+ t1 = bd / (2 * a);
+ t2 = (2 * c) / bd;
+ }
+
+ assert (std::isfinite(t1));
+ assert (std::isfinite(t2));
+
+ if(a < 0) std::swap(t1, t2); // make t1 > t2
+ // return the smaller positive root if it exists, otherwise return infinity
+ if(t1 > 0)
+ {
+ return t2 > 0 ? t2 : t1;
+ }
+ else
+ {
+ return INFINITY;
+ }
+ }
+ else
+ {
+ if(b == 0) return INFINITY; // just to avoid divide-by-zero
+ t1 = -c / b;
+ return t1 > 0 ? t1 : INFINITY;
+ }
+ }
+
+ IGL_INLINE double get_min_pos_root_2D(const Eigen::MatrixXd& uv,
+ const Eigen::MatrixXi& F,
+ Eigen::MatrixXd& d,
+ int f)
+ {
+ using namespace std;
+ /*
+ Finding the smallest timestep t s.t a triangle get degenerated (<=> det = 0)
+ The following code can be derived by a symbolic expression in matlab:
+
+ Symbolic matlab:
+ U11 = sym('U11');
+ U12 = sym('U12');
+ U21 = sym('U21');
+ U22 = sym('U22');
+ U31 = sym('U31');
+ U32 = sym('U32');
+
+ V11 = sym('V11');
+ V12 = sym('V12');
+ V21 = sym('V21');
+ V22 = sym('V22');
+ V31 = sym('V31');
+ V32 = sym('V32');
+
+ t = sym('t');
+
+ U1 = [U11,U12];
+ U2 = [U21,U22];
+ U3 = [U31,U32];
+
+ V1 = [V11,V12];
+ V2 = [V21,V22];
+ V3 = [V31,V32];
+
+ A = [(U2+V2*t) - (U1+ V1*t)];
+ B = [(U3+V3*t) - (U1+ V1*t)];
+ C = [A;B];
+
+ solve(det(C), t);
+ cf = coeffs(det(C),t); % Now cf(1),cf(2),cf(3) holds the coefficients for the polynom. at order c,b,a
+ */
+
+ int v1 = F(f,0); int v2 = F(f,1); int v3 = F(f,2);
+ // get quadratic coefficients (ax^2 + b^x + c)
+ const double& U11 = uv(v1,0);
+ const double& U12 = uv(v1,1);
+ const double& U21 = uv(v2,0);
+ const double& U22 = uv(v2,1);
+ const double& U31 = uv(v3,0);
+ const double& U32 = uv(v3,1);
+
+ const double& V11 = d(v1,0);
+ const double& V12 = d(v1,1);
+ const double& V21 = d(v2,0);
+ const double& V22 = d(v2,1);
+ const double& V31 = d(v3,0);
+ const double& V32 = d(v3,1);
+
+ double a = V11*V22 - V12*V21 - V11*V32 + V12*V31 + V21*V32 - V22*V31;
+ double b = U11*V22 - U12*V21 - U21*V12 + U22*V11 - U11*V32 + U12*V31 + U31*V12 - U32*V11 + U21*V32 - U22*V31 - U31*V22 + U32*V21;
+ double c = U11*U22 - U12*U21 - U11*U32 + U12*U31 + U21*U32 - U22*U31;
+
+ return get_smallest_pos_quad_zero(a,b,c);
+ }
+
+ IGL_INLINE double get_min_pos_root_3D(const Eigen::MatrixXd& uv,
+ const Eigen::MatrixXi& F,
+ Eigen::MatrixXd& direc,
+ int f)
+ {
+ using namespace std;
+ /*
+ Searching for the roots of:
+ +-1/6 * |ax ay az 1|
+ |bx by bz 1|
+ |cx cy cz 1|
+ |dx dy dz 1|
+ Every point ax,ay,az has a search direction a_dx,a_dy,a_dz, and so we add those to the matrix, and solve the cubic to find the step size t for a 0 volume
+ Symbolic matlab:
+ syms a_x a_y a_z a_dx a_dy a_dz % tetrahedera point and search direction
+ syms b_x b_y b_z b_dx b_dy b_dz
+ syms c_x c_y c_z c_dx c_dy c_dz
+ syms d_x d_y d_z d_dx d_dy d_dz
+ syms t % Timestep var, this is what we're looking for
+
+
+ a_plus_t = [a_x,a_y,a_z] + t*[a_dx,a_dy,a_dz];
+ b_plus_t = [b_x,b_y,b_z] + t*[b_dx,b_dy,b_dz];
+ c_plus_t = [c_x,c_y,c_z] + t*[c_dx,c_dy,c_dz];
+ d_plus_t = [d_x,d_y,d_z] + t*[d_dx,d_dy,d_dz];
+
+ vol_mat = [a_plus_t,1;b_plus_t,1;c_plus_t,1;d_plus_t,1]
+ //cf = coeffs(det(vol_det),t); % Now cf(1),cf(2),cf(3),cf(4) holds the coefficients for the polynom
+ [coefficients,terms] = coeffs(det(vol_det),t); % terms = [ t^3, t^2, t, 1], Coefficients hold the coeff we seek
+ */
+ int v1 = F(f,0); int v2 = F(f,1); int v3 = F(f,2); int v4 = F(f,3);
+ const double& a_x = uv(v1,0);
+ const double& a_y = uv(v1,1);
+ const double& a_z = uv(v1,2);
+ const double& b_x = uv(v2,0);
+ const double& b_y = uv(v2,1);
+ const double& b_z = uv(v2,2);
+ const double& c_x = uv(v3,0);
+ const double& c_y = uv(v3,1);
+ const double& c_z = uv(v3,2);
+ const double& d_x = uv(v4,0);
+ const double& d_y = uv(v4,1);
+ const double& d_z = uv(v4,2);
+
+ const double& a_dx = direc(v1,0);
+ const double& a_dy = direc(v1,1);
+ const double& a_dz = direc(v1,2);
+ const double& b_dx = direc(v2,0);
+ const double& b_dy = direc(v2,1);
+ const double& b_dz = direc(v2,2);
+ const double& c_dx = direc(v3,0);
+ const double& c_dy = direc(v3,1);
+ const double& c_dz = direc(v3,2);
+ const double& d_dx = direc(v4,0);
+ const double& d_dy = direc(v4,1);
+ const double& d_dz = direc(v4,2);
+
+ // Find solution for: a*t^3 + b*t^2 + c*d +d = 0
+ double a = a_dx*b_dy*c_dz - a_dx*b_dz*c_dy - a_dy*b_dx*c_dz + a_dy*b_dz*c_dx + a_dz*b_dx*c_dy - a_dz*b_dy*c_dx - a_dx*b_dy*d_dz + a_dx*b_dz*d_dy + a_dy*b_dx*d_dz - a_dy*b_dz*d_dx - a_dz*b_dx*d_dy + a_dz*b_dy*d_dx + a_dx*c_dy*d_dz - a_dx*c_dz*d_dy - a_dy*c_dx*d_dz + a_dy*c_dz*d_dx + a_dz*c_dx*d_dy - a_dz*c_dy*d_dx - b_dx*c_dy*d_dz + b_dx*c_dz*d_dy + b_dy*c_dx*d_dz - b_dy*c_dz*d_dx - b_dz*c_dx*d_dy + b_dz*c_dy*d_dx;
+
+ double b = a_dy*b_dz*c_x - a_dy*b_x*c_dz - a_dz*b_dy*c_x + a_dz*b_x*c_dy + a_x*b_dy*c_dz - a_x*b_dz*c_dy - a_dx*b_dz*c_y + a_dx*b_y*c_dz + a_dz*b_dx*c_y - a_dz*b_y*c_dx - a_y*b_dx*c_dz + a_y*b_dz*c_dx + a_dx*b_dy*c_z - a_dx*b_z*c_dy - a_dy*b_dx*c_z + a_dy*b_z*c_dx + a_z*b_dx*c_dy - a_z*b_dy*c_dx - a_dy*b_dz*d_x + a_dy*b_x*d_dz + a_dz*b_dy*d_x - a_dz*b_x*d_dy - a_x*b_dy*d_dz + a_x*b_dz*d_dy + a_dx*b_dz*d_y - a_dx*b_y*d_dz - a_dz*b_dx*d_y + a_dz*b_y*d_dx + a_y*b_dx*d_dz - a_y*b_dz*d_dx - a_dx*b_dy*d_z + a_dx*b_z*d_dy + a_dy*b_dx*d_z - a_dy*b_z*d_dx - a_z*b_dx*d_dy + a_z*b_dy*d_dx + a_dy*c_dz*d_x - a_dy*c_x*d_dz - a_dz*c_dy*d_x + a_dz*c_x*d_dy + a_x*c_dy*d_dz - a_x*c_dz*d_dy - a_dx*c_dz*d_y + a_dx*c_y*d_dz + a_dz*c_dx*d_y - a_dz*c_y*d_dx - a_y*c_dx*d_dz + a_y*c_dz*d_dx + a_dx*c_dy*d_z - a_dx*c_z*d_dy - a_dy*c_dx*d_z + a_dy*c_z*d_dx + a_z*c_dx*d_dy - a_z*c_dy*d_dx - b_dy*c_dz*d_x + b_dy*c_x*d_dz + b_dz*c_dy*d_x - b_dz*c_x*d_dy - b_x*c_dy*d_dz + b_x*c_dz*d_dy + b_dx*c_dz*d_y - b_dx*c_y*d_dz - b_dz*c_dx*d_y + b_dz*c_y*d_dx + b_y*c_dx*d_dz - b_y*c_dz*d_dx - b_dx*c_dy*d_z + b_dx*c_z*d_dy + b_dy*c_dx*d_z - b_dy*c_z*d_dx - b_z*c_dx*d_dy + b_z*c_dy*d_dx;
+
+ double c = a_dz*b_x*c_y - a_dz*b_y*c_x - a_x*b_dz*c_y + a_x*b_y*c_dz + a_y*b_dz*c_x - a_y*b_x*c_dz - a_dy*b_x*c_z + a_dy*b_z*c_x + a_x*b_dy*c_z - a_x*b_z*c_dy - a_z*b_dy*c_x + a_z*b_x*c_dy + a_dx*b_y*c_z - a_dx*b_z*c_y - a_y*b_dx*c_z + a_y*b_z*c_dx + a_z*b_dx*c_y - a_z*b_y*c_dx - a_dz*b_x*d_y + a_dz*b_y*d_x + a_x*b_dz*d_y - a_x*b_y*d_dz - a_y*b_dz*d_x + a_y*b_x*d_dz + a_dy*b_x*d_z - a_dy*b_z*d_x - a_x*b_dy*d_z + a_x*b_z*d_dy + a_z*b_dy*d_x - a_z*b_x*d_dy - a_dx*b_y*d_z + a_dx*b_z*d_y + a_y*b_dx*d_z - a_y*b_z*d_dx - a_z*b_dx*d_y + a_z*b_y*d_dx + a_dz*c_x*d_y - a_dz*c_y*d_x - a_x*c_dz*d_y + a_x*c_y*d_dz + a_y*c_dz*d_x - a_y*c_x*d_dz - a_dy*c_x*d_z + a_dy*c_z*d_x + a_x*c_dy*d_z - a_x*c_z*d_dy - a_z*c_dy*d_x + a_z*c_x*d_dy + a_dx*c_y*d_z - a_dx*c_z*d_y - a_y*c_dx*d_z + a_y*c_z*d_dx + a_z*c_dx*d_y - a_z*c_y*d_dx - b_dz*c_x*d_y + b_dz*c_y*d_x + b_x*c_dz*d_y - b_x*c_y*d_dz - b_y*c_dz*d_x + b_y*c_x*d_dz + b_dy*c_x*d_z - b_dy*c_z*d_x - b_x*c_dy*d_z + b_x*c_z*d_dy + b_z*c_dy*d_x - b_z*c_x*d_dy - b_dx*c_y*d_z + b_dx*c_z*d_y + b_y*c_dx*d_z - b_y*c_z*d_dx - b_z*c_dx*d_y + b_z*c_y*d_dx;
+
+ double d = a_x*b_y*c_z - a_x*b_z*c_y - a_y*b_x*c_z + a_y*b_z*c_x + a_z*b_x*c_y - a_z*b_y*c_x - a_x*b_y*d_z + a_x*b_z*d_y + a_y*b_x*d_z - a_y*b_z*d_x - a_z*b_x*d_y + a_z*b_y*d_x + a_x*c_y*d_z - a_x*c_z*d_y - a_y*c_x*d_z + a_y*c_z*d_x + a_z*c_x*d_y - a_z*c_y*d_x - b_x*c_y*d_z + b_x*c_z*d_y + b_y*c_x*d_z - b_y*c_z*d_x - b_z*c_x*d_y + b_z*c_y*d_x;
+
+ if (std::abs(a)<=1.e-10)
+ {
+ return get_smallest_pos_quad_zero(b,c,d);
+ }
+ b/=a; c/=a; d/=a; // normalize it all
+ std::vector<double> res(3);
+ int real_roots_num = SolveP3(res,b,c,d);
+ switch (real_roots_num)
+ {
+ case 1:
+ return (res[0] >= 0) ? res[0]:INFINITY;
+ case 2:
+ {
+ double max_root = std::max(res[0],res[1]); double min_root = std::min(res[0],res[1]);
+ if (min_root > 0) return min_root;
+ if (max_root > 0) return max_root;
+ return INFINITY;
+ }
+ case 3:
+ default:
+ {
+ std::sort(res.begin(),res.end());
+ if (res[0] > 0) return res[0];
+ if (res[1] > 0) return res[1];
+ if (res[2] > 0) return res[2];
+ return INFINITY;
+ }
+ }
+ }
+
+ IGL_INLINE double compute_max_step_from_singularities(const Eigen::MatrixXd& uv,
+ const Eigen::MatrixXi& F,
+ Eigen::MatrixXd& d)
+ {
+ using namespace std;
+ double max_step = INFINITY;
+
+ // The if statement is outside the for loops to avoid branching/ease parallelizing
+ if (uv.cols() == 2)
+ {
+ for (int f = 0; f < F.rows(); f++)
+ {
+ double min_positive_root = get_min_pos_root_2D(uv,F,d,f);
+ max_step = std::min(max_step, min_positive_root);
+ }
+ }
+ else
+ { // volumetric deformation
+ for (int f = 0; f < F.rows(); f++)
+ {
+ double min_positive_root = get_min_pos_root_3D(uv,F,d,f);
+ max_step = std::min(max_step, min_positive_root);
+ }
+ }
+ return max_step;
+ }
+ }
+}
+
+IGL_INLINE double igl::flip_avoiding_line_search(
+ const Eigen::MatrixXi F,
+ Eigen::MatrixXd& cur_v,
+ Eigen::MatrixXd& dst_v,
+ std::function<double(Eigen::MatrixXd&)> energy,
+ double cur_energy)
+{
+ using namespace std;
+ Eigen::MatrixXd d = dst_v - cur_v;
+
+ double min_step_to_singularity = igl::flip_avoiding::compute_max_step_from_singularities(cur_v,F,d);
+ double max_step_size = std::min(1., min_step_to_singularity*0.8);
+
+ return igl::line_search(cur_v,d,max_step_size, energy, cur_energy);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+#endif
diff --git a/xs/src/igl/flip_avoiding_line_search.h b/xs/src/igl/flip_avoiding_line_search.h
new file mode 100644
index 000000000..29eb9dee0
--- /dev/null
+++ b/xs/src/igl/flip_avoiding_line_search.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FLIP_AVOIDING_LINE_SEARCH_H
+#define IGL_FLIP_AVOIDING_LINE_SEARCH_H
+#include "igl_inline.h"
+#include "PI.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // A bisection line search for a mesh based energy that avoids triangle flips as suggested in
+ // "Bijective Parameterization with Free Boundaries" (Smith J. and Schaefer S., 2015).
+ //
+ // The user specifies an initial vertices position (that has no flips) and target one (that my have flipped triangles).
+ // This method first computes the largest step in direction of the destination vertices that does not incur flips,
+ // and then minimizes a given energy using this maximal step and a bisection linesearch (see igl::line_search).
+ //
+ // Supports both triangle and tet meshes.
+ //
+ // Inputs:
+ // F #F by 3/4 list of mesh faces or tets
+ // cur_v #V by dim list of variables
+ // dst_v #V by dim list of target vertices. This mesh may have flipped triangles
+ // energy A function to compute the mesh-based energy (return an energy that is bigger than 0)
+ // cur_energy(OPTIONAL) The energy at the given point. Helps save redundant computations.
+ // This is optional. If not specified, the function will compute it.
+ // Outputs:
+ // cur_v #V by dim list of variables at the new location
+ // Returns the energy at the new point
+ IGL_INLINE double flip_avoiding_line_search(
+ const Eigen::MatrixXi F,
+ Eigen::MatrixXd& cur_v,
+ Eigen::MatrixXd& dst_v,
+ std::function<double(Eigen::MatrixXd&)> energy,
+ double cur_energy = -1);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "flip_avoiding_line_search.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/flip_edge.cpp b/xs/src/igl/flip_edge.cpp
new file mode 100644
index 000000000..b34581449
--- /dev/null
+++ b/xs/src/igl/flip_edge.cpp
@@ -0,0 +1,153 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "flip_edge.h"
+
+template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DeriveduE,
+ typename DerivedEMAP,
+ typename uE2EType>
+IGL_INLINE void igl::flip_edge(
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DeriveduE> & uE,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
+ std::vector<std::vector<uE2EType> > & uE2E,
+ const size_t uei)
+{
+ typedef typename DerivedF::Scalar Index;
+ const size_t num_faces = F.rows();
+ assert(F.cols() == 3);
+ // v1 v1
+ // /|\ / \
+ // / | \ /f1 \
+ // v3 /f2|f1\ v4 => v3 /_____\ v4
+ // \ | / \ f2 /
+ // \ | / \ /
+ // \|/ \ /
+ // v2 v2
+ auto& half_edges = uE2E[uei];
+ if (half_edges.size() != 2) {
+ throw "Cannot flip non-manifold or boundary edge";
+ }
+
+ const size_t f1 = half_edges[0] % num_faces;
+ const size_t f2 = half_edges[1] % num_faces;
+ const size_t c1 = half_edges[0] / num_faces;
+ const size_t c2 = half_edges[1] / num_faces;
+ assert(c1 < 3);
+ assert(c2 < 3);
+
+ assert(f1 != f2);
+ const size_t v1 = F(f1, (c1+1)%3);
+ const size_t v2 = F(f1, (c1+2)%3);
+ const size_t v4 = F(f1, c1);
+ const size_t v3 = F(f2, c2);
+ assert(F(f2, (c2+2)%3) == v1);
+ assert(F(f2, (c2+1)%3) == v2);
+
+ const size_t e_12 = half_edges[0];
+ const size_t e_24 = f1 + ((c1 + 1) % 3) * num_faces;
+ const size_t e_41 = f1 + ((c1 + 2) % 3) * num_faces;
+ const size_t e_21 = half_edges[1];
+ const size_t e_13 = f2 + ((c2 + 1) % 3) * num_faces;
+ const size_t e_32 = f2 + ((c2 + 2) % 3) * num_faces;
+ assert(E(e_12, 0) == v1);
+ assert(E(e_12, 1) == v2);
+ assert(E(e_24, 0) == v2);
+ assert(E(e_24, 1) == v4);
+ assert(E(e_41, 0) == v4);
+ assert(E(e_41, 1) == v1);
+ assert(E(e_21, 0) == v2);
+ assert(E(e_21, 1) == v1);
+ assert(E(e_13, 0) == v1);
+ assert(E(e_13, 1) == v3);
+ assert(E(e_32, 0) == v3);
+ assert(E(e_32, 1) == v2);
+
+ const size_t ue_24 = EMAP(e_24);
+ const size_t ue_41 = EMAP(e_41);
+ const size_t ue_13 = EMAP(e_13);
+ const size_t ue_32 = EMAP(e_32);
+
+ F(f1, 0) = v1;
+ F(f1, 1) = v3;
+ F(f1, 2) = v4;
+ F(f2, 0) = v2;
+ F(f2, 1) = v4;
+ F(f2, 2) = v3;
+
+ uE(uei, 0) = v3;
+ uE(uei, 1) = v4;
+
+ const size_t new_e_34 = f1;
+ const size_t new_e_41 = f1 + num_faces;
+ const size_t new_e_13 = f1 + num_faces*2;
+ const size_t new_e_43 = f2;
+ const size_t new_e_32 = f2 + num_faces;
+ const size_t new_e_24 = f2 + num_faces*2;
+
+ E(new_e_34, 0) = v3;
+ E(new_e_34, 1) = v4;
+ E(new_e_41, 0) = v4;
+ E(new_e_41, 1) = v1;
+ E(new_e_13, 0) = v1;
+ E(new_e_13, 1) = v3;
+ E(new_e_43, 0) = v4;
+ E(new_e_43, 1) = v3;
+ E(new_e_32, 0) = v3;
+ E(new_e_32, 1) = v2;
+ E(new_e_24, 0) = v2;
+ E(new_e_24, 1) = v4;
+
+ EMAP(new_e_34) = uei;
+ EMAP(new_e_43) = uei;
+ EMAP(new_e_41) = ue_41;
+ EMAP(new_e_13) = ue_13;
+ EMAP(new_e_32) = ue_32;
+ EMAP(new_e_24) = ue_24;
+
+ auto replace = [](std::vector<Index>& array, Index old_v, Index new_v) {
+ std::replace(array.begin(), array.end(), old_v, new_v);
+ };
+ replace(uE2E[uei], e_12, new_e_34);
+ replace(uE2E[uei], e_21, new_e_43);
+ replace(uE2E[ue_13], e_13, new_e_13);
+ replace(uE2E[ue_32], e_32, new_e_32);
+ replace(uE2E[ue_24], e_24, new_e_24);
+ replace(uE2E[ue_41], e_41, new_e_41);
+
+#ifndef NDEBUG
+ auto sanity_check = [&](size_t ue) {
+ const auto& adj_faces = uE2E[ue];
+ if (adj_faces.size() == 2) {
+ const size_t first_f = adj_faces[0] % num_faces;
+ const size_t first_c = adj_faces[0] / num_faces;
+ const size_t second_f = adj_faces[1] % num_faces;
+ const size_t second_c = adj_faces[1] / num_faces;
+ const size_t vertex_0 = F(first_f, (first_c+1) % 3);
+ const size_t vertex_1 = F(first_f, (first_c+2) % 3);
+ assert(vertex_0 == F(second_f, (second_c+2) % 3));
+ assert(vertex_1 == F(second_f, (second_c+1) % 3));
+ }
+ };
+
+ sanity_check(uei);
+ sanity_check(ue_13);
+ sanity_check(ue_32);
+ sanity_check(ue_24);
+ sanity_check(ue_41);
+#endif
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::flip_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, unsigned long);
+#endif \ No newline at end of file
diff --git a/xs/src/igl/flip_edge.h b/xs/src/igl/flip_edge.h
new file mode 100644
index 000000000..3c43198a6
--- /dev/null
+++ b/xs/src/igl/flip_edge.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_FLIP_EDGE_H
+#define IGL_FLIP_EDGE_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Flip an edge in a triangle mesh. The edge specified by uei must have
+ // exactly **two** adjacent faces. Violation will result in exception.
+ // Another warning: edge flipping could convert manifold mesh into
+ // non-manifold.
+ //
+ // Inputs:
+ // F #F by 3 list of triangles.
+ // E #F*3 by 2 list of all of directed edges
+ // uE #uE by 2 list of unique undirected edges
+ // EMAP #F*3 list of indices into uE, mapping each directed edge to unique
+ // undirected edge
+ // uE2E #uE list of lists of indices into E of coexisting edges
+ // ue index into uE the edge to be flipped.
+ //
+ // Output:
+ // Updated F, E, uE, EMAP and uE2E.
+ template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DeriveduE,
+ typename DerivedEMAP,
+ typename uE2EType>
+ IGL_INLINE void flip_edge(
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DeriveduE> & uE,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
+ std::vector<std::vector<uE2EType> > & uE2E,
+ const size_t uei);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "flip_edge.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/flipped_triangles.cpp b/xs/src/igl/flipped_triangles.cpp
new file mode 100644
index 000000000..ea76e5c84
--- /dev/null
+++ b/xs/src/igl/flipped_triangles.cpp
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich <michaelrabinovich27@gmail.com@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "flipped_triangles.h"
+
+#include "list_to_matrix.h"
+#include <vector>
+template <typename DerivedV, typename DerivedF, typename DerivedX>
+IGL_INLINE void igl::flipped_triangles(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedX> & X)
+{
+ assert(V.cols() == 2 && "V should contain 2D positions");
+ std::vector<typename DerivedX::Scalar> flip_idx;
+ for (int i = 0; i < F.rows(); i++)
+ {
+ // https://www.cs.cmu.edu/~quake/robust.html
+ typedef Eigen::Matrix<typename DerivedV::Scalar,1,2> RowVector2S;
+ RowVector2S v1_n = V.row(F(i,0));
+ RowVector2S v2_n = V.row(F(i,1));
+ RowVector2S v3_n = V.row(F(i,2));
+ Eigen::Matrix<typename DerivedV::Scalar,3,3> T2_Homo;
+ T2_Homo.col(0) << v1_n(0),v1_n(1),1.;
+ T2_Homo.col(1) << v2_n(0),v2_n(1),1.;
+ T2_Homo.col(2) << v3_n(0),v3_n(1),1.;
+ double det = T2_Homo.determinant();
+ assert(det == det && "det should not be NaN");
+ if (det < 0)
+ {
+ flip_idx.push_back(i);
+ }
+ }
+ igl::list_to_matrix(flip_idx,X);
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE Eigen::VectorXi igl::flipped_triangles(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F)
+{
+ Eigen::VectorXi X;
+ flipped_triangles(V,F,X);
+ return X;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::flipped_triangles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::flipped_triangles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/flipped_triangles.h b/xs/src/igl/flipped_triangles.h
new file mode 100644
index 000000000..b06d9329b
--- /dev/null
+++ b/xs/src/igl/flipped_triangles.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich <michaelrabinovich27@gmail.com@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FLIPPED_TRIANGLES_H
+#define IGL_FLIPPED_TRIANGLES_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+namespace igl
+{
+ // Finds the ids of the flipped triangles of the mesh V,F in the UV mapping uv
+ //
+ // Inputs:
+ // V #V by 2 list of mesh vertex positions
+ // F #F by 3 list of mesh faces (must be triangles)
+ // Outputs:
+ // X #flipped list of containing the indices into F of the flipped triangles
+ // Wrapper with return type
+ template <typename DerivedV, typename DerivedF, typename DerivedX>
+ IGL_INLINE void flipped_triangles(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedX> & X);
+ template <typename Scalar, typename Index>
+ IGL_INLINE Eigen::VectorXi flipped_triangles(
+ const Eigen::PlainObjectBase<Scalar> & V,
+ const Eigen::PlainObjectBase<Index> & F);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "flipped_triangles.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/flood_fill.cpp b/xs/src/igl/flood_fill.cpp
new file mode 100644
index 000000000..a6c91361d
--- /dev/null
+++ b/xs/src/igl/flood_fill.cpp
@@ -0,0 +1,103 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "flood_fill.h"
+#include <limits>
+
+template <typename Derivedres, typename DerivedS>
+IGL_INLINE void igl::flood_fill(
+ const Eigen::MatrixBase<Derivedres>& res,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef typename DerivedS::Scalar Scalar;
+ const auto flood = [&res,&S] (
+ const int xi,
+ const int yi,
+ const int zi,
+ const int signed_xi,
+ const int signed_yi,
+ const int signed_zi,
+ const Scalar s)
+ {
+ // flood fill this value back on this row
+ for(int bxi = xi;signed_xi<--bxi;)
+ {
+ S(bxi+res(0)*(yi + res(1)*zi)) = s;
+ }
+ // flood fill this value back on any previous rows
+ for(int byi = yi;signed_yi<--byi;)
+ {
+ for(int xi = 0;xi<res(0);xi++)
+ {
+ S(xi+res(0)*(byi + res(1)*zi)) = s;
+ }
+ }
+ // flood fill this value back on any previous "sheets"
+ for(int bzi = zi;signed_zi<--bzi;)
+ {
+ for(int yi = 0;yi<res(1);yi++)
+ {
+ for(int xi = 0;xi<res(0);xi++)
+ {
+ S(xi+res(0)*(yi + res(1)*bzi)) = s;
+ }
+ }
+ }
+ };
+ int signed_zi = -1;
+ Scalar s = numeric_limits<Scalar>::quiet_NaN();
+ for(int zi = 0;zi<res(2);zi++)
+ {
+ int signed_yi = -1;
+ if(zi != 0)
+ {
+ s = S(0+res(0)*(0 + res(1)*(zi-1)));
+ }
+ for(int yi = 0;yi<res(1);yi++)
+ {
+ // index of last signed item on this row
+ int signed_xi = -1;
+ if(yi != 0)
+ {
+ s = S(0+res(0)*(yi-1 + res(1)*zi));
+ }
+ for(int xi = 0;xi<res(0);xi++)
+ {
+ int i = xi+res(0)*(yi + res(1)*zi);
+ if(S(i)!=S(i))
+ {
+ if(s == s)
+ {
+ S(i) = s;
+ }
+ continue;
+ }
+ s = S(i);
+ flood(xi,yi,zi,signed_xi,signed_yi,signed_zi,s);
+ // remember this position
+ signed_xi = xi;
+ signed_yi = yi;
+ signed_zi = zi;
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::flood_fill<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::flood_fill<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::flood_fill<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::flood_fill<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::flood_fill<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/flood_fill.h b/xs/src/igl/flood_fill.h
new file mode 100644
index 000000000..7eef01b3c
--- /dev/null
+++ b/xs/src/igl/flood_fill.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FLOOD_FILL_H
+#define IGL_FLOOD_FILL_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Given a 3D array with sparse non-nan (number?) data fill in the NaNs via
+ // flood fill. This should ensure that, e.g., if data near 0 always has a band
+ // (surface) of numbered and signed data, then components of nans will be
+ // correctly signed.
+ //
+ // Inputs:
+ // res 3-long list of dimensions of grid
+ // S res(0)*res(1)*res(2) list of scalar values (with (many) nans), see
+ // output
+ // Outputs:
+ // S flood fill data in place
+ template <typename Derivedres, typename DerivedS>
+ IGL_INLINE void flood_fill(
+ const Eigen::MatrixBase<Derivedres>& res,
+ Eigen::PlainObjectBase<DerivedS> & S);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "flood_fill.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/floor.cpp b/xs/src/igl/floor.cpp
new file mode 100644
index 000000000..7538b7e01
--- /dev/null
+++ b/xs/src/igl/floor.cpp
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "floor.h"
+#include <cmath>
+#include <iostream>
+
+template < typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::floor(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedY>& Y)
+{
+ using namespace std;
+ //Y = DerivedY::Zero(m,n);
+//#pragma omp parallel for
+ //for(int i = 0;i<m;i++)
+ //{
+ // for(int j = 0;j<n;j++)
+ // {
+ // Y(i,j) = std::floor(X(i,j));
+ // }
+ //}
+ typedef typename DerivedX::Scalar Scalar;
+ Y = X.unaryExpr([](const Scalar &x)->Scalar{return std::floor(x);}).template cast<typename DerivedY::Scalar >();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::floor<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::floor<Eigen::Array<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Array<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::floor<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/floor.h b/xs/src/igl/floor.h
new file mode 100644
index 000000000..a84d52068
--- /dev/null
+++ b/xs/src/igl/floor.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FLOOR_H
+#define IGL_FLOOR_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Floor a given matrix to nearest integers
+ //
+ // Inputs:
+ // X m by n matrix of scalars
+ // Outputs:
+ // Y m by n matrix of floored integers
+ template < typename DerivedX, typename DerivedY>
+ IGL_INLINE void floor(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedY>& Y);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "floor.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/for_each.h b/xs/src/igl/for_each.h
new file mode 100644
index 000000000..6ba03ba1c
--- /dev/null
+++ b/xs/src/igl/for_each.h
@@ -0,0 +1,78 @@
+#ifndef IGL_FOR_EACH_H
+#define IGL_FOR_EACH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // FOR_EACH Call a given function for each non-zero (i.e., explicit value
+ // might actually be ==0) in a Sparse Matrix A _in order (of storage)_. This is
+ // useless unless func has _side-effects_.
+ //
+ // Inputs:
+ // A m by n SparseMatrix
+ // func function handle with prototype "compatible with" `void (Index i,
+ // Index j, Scalar & v)`. Return values will be ignored.
+ //
+ // See also: std::for_each
+ template <typename AType, typename Func>
+ inline void for_each(
+ const Eigen::SparseMatrix<AType> & A,
+ const Func & func);
+ template <typename DerivedA, typename Func>
+ inline void for_each(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Func & func);
+}
+
+// Implementation
+
+template <typename AType, typename Func>
+inline void igl::for_each(
+ const Eigen::SparseMatrix<AType> & A,
+ const Func & func)
+{
+ // Can **not** use parallel for because this must be _in order_
+ // Iterate over outside
+ for(int k=0; k<A.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<AType>::InnerIterator it (A,k); it; ++it)
+ {
+ func(it.row(),it.col(),it.value());
+ }
+ }
+}
+
+template <typename DerivedA, typename Func>
+inline void igl::for_each(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Func & func)
+{
+ // Can **not** use parallel for because this must be _in order_
+ if(A.IsRowMajor)
+ {
+ for(typename DerivedA::Index i = 0;i<A.rows();i++)
+ {
+ for(typename DerivedA::Index j = 0;j<A.cols();j++)
+ {
+ func(i,j,A(i,j));
+ }
+ }
+ }else
+ {
+ for(typename DerivedA::Index j = 0;j<A.cols();j++)
+ {
+ for(typename DerivedA::Index i = 0;i<A.rows();i++)
+ {
+ func(i,j,A(i,j));
+ }
+ }
+ }
+
+}
+
+//#ifndef IGL_STATIC_LIBRARY
+//# include "for_each.cpp"
+//#endif
+#endif
diff --git a/xs/src/igl/forward_kinematics.cpp b/xs/src/igl/forward_kinematics.cpp
new file mode 100644
index 000000000..c473453c9
--- /dev/null
+++ b/xs/src/igl/forward_kinematics.cpp
@@ -0,0 +1,115 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "forward_kinematics.h"
+#include <functional>
+#include <iostream>
+
+IGL_INLINE void igl::forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ const std::vector<Eigen::Vector3d> & dT,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ,
+ std::vector<Eigen::Vector3d> & vT)
+{
+ using namespace std;
+ using namespace Eigen;
+ const int m = BE.rows();
+ assert(m == P.rows());
+ assert(m == (int)dQ.size());
+ assert(m == (int)dT.size());
+ vector<bool> computed(m,false);
+ vQ.resize(m);
+ vT.resize(m);
+ // Dynamic programming
+ function<void (int) > fk_helper = [&] (int b)
+ {
+ if(!computed[b])
+ {
+ if(P(b) < 0)
+ {
+ // base case for roots
+ vQ[b] = dQ[b];
+ const Vector3d r = C.row(BE(b,0)).transpose();
+ vT[b] = r-dQ[b]*r + dT[b];
+ }else
+ {
+ // Otherwise first compute parent's
+ const int p = P(b);
+ fk_helper(p);
+ vQ[b] = vQ[p] * dQ[b];
+ const Vector3d r = C.row(BE(b,0)).transpose();
+ vT[b] = vT[p] - vQ[b]*r + vQ[p]*(r + dT[b]);
+ }
+ computed[b] = true;
+ }
+ };
+ for(int b = 0;b<m;b++)
+ {
+ fk_helper(b);
+ }
+}
+
+IGL_INLINE void igl::forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ,
+ std::vector<Eigen::Vector3d> & vT)
+{
+ std::vector<Eigen::Vector3d> dT(BE.rows(),Eigen::Vector3d(0,0,0));
+ return forward_kinematics(C,BE,P,dQ,dT,vQ,vT);
+}
+
+IGL_INLINE void igl::forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ const std::vector<Eigen::Vector3d> & dT,
+ Eigen::MatrixXd & T)
+{
+ using namespace Eigen;
+ using namespace std;
+ vector< Quaterniond,aligned_allocator<Quaterniond> > vQ;
+ vector< Vector3d> vT;
+ forward_kinematics(C,BE,P,dQ,dT,vQ,vT);
+ const int dim = C.cols();
+ T.resize(BE.rows()*(dim+1),dim);
+ for(int e = 0;e<BE.rows();e++)
+ {
+ Affine3d a = Affine3d::Identity();
+ a.translate(vT[e]);
+ a.rotate(vQ[e]);
+ T.block(e*(dim+1),0,dim+1,dim) =
+ a.matrix().transpose().block(0,0,dim+1,dim);
+ }
+}
+
+IGL_INLINE void igl::forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ Eigen::MatrixXd & T)
+{
+ std::vector<Eigen::Vector3d> dT(BE.rows(),Eigen::Vector3d(0,0,0));
+ return forward_kinematics(C,BE,P,dQ,dT,T);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/forward_kinematics.h b/xs/src/igl/forward_kinematics.h
new file mode 100644
index 000000000..2b3d2db6d
--- /dev/null
+++ b/xs/src/igl/forward_kinematics.h
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FORWARD_KINEMATICS_H
+#define IGL_FORWARD_KINEMATICS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#include <vector>
+
+namespace igl
+{
+ // Given a skeleton and a set of relative bone rotations compute absolute
+ // rigid transformations for each bone.
+ //
+ // Inputs:
+ // C #C by dim list of joint positions
+ // BE #BE by 2 list of bone edge indices
+ // P #BE list of parent indices into BE
+ // dQ #BE list of relative rotations
+ // dT #BE list of relative translations
+ // Outputs:
+ // vQ #BE list of absolute rotations
+ // vT #BE list of absolute translations
+ IGL_INLINE void forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ const std::vector<Eigen::Vector3d> & dT,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ,
+ std::vector<Eigen::Vector3d> & vT);
+ // Wrapper assuming each dT[i] == {0,0,0}
+ IGL_INLINE void forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & vQ,
+ std::vector<Eigen::Vector3d> & vT);
+
+ // Outputs:
+ // T #BE*(dim+1) by dim stack of transposed transformation matrices
+ IGL_INLINE void forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ const std::vector<Eigen::Vector3d> & dT,
+ Eigen::MatrixXd & T);
+ IGL_INLINE void forward_kinematics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > & dQ,
+ Eigen::MatrixXd & T);
+
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "forward_kinematics.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/frame_field_deformer.cpp b/xs/src/igl/frame_field_deformer.cpp
new file mode 100644
index 000000000..c22200f1b
--- /dev/null
+++ b/xs/src/igl/frame_field_deformer.cpp
@@ -0,0 +1,411 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "frame_field_deformer.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+#include <vector>
+
+#include <igl/cotmatrix_entries.h>
+#include <igl/cotmatrix.h>
+#include <igl/vertex_triangle_adjacency.h>
+
+namespace igl
+{
+
+class Frame_field_deformer
+{
+public:
+
+ IGL_INLINE Frame_field_deformer();
+ IGL_INLINE ~Frame_field_deformer();
+
+ // Initialize the optimizer
+ IGL_INLINE void init(const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F, const Eigen::MatrixXd& _D1, const Eigen::MatrixXd& _D2, double _Lambda, double _perturb_rotations, int _fixed = 1);
+
+ // Run N optimization steps
+ IGL_INLINE void optimize(int N, bool reset = false);
+
+ // Reset optimization
+ IGL_INLINE void reset_opt();
+
+ // Precomputation of all components
+ IGL_INLINE void precompute_opt();
+
+ // Precomputation for deformation energy
+ IGL_INLINE void precompute_ARAP(Eigen::SparseMatrix<double> & Lff, Eigen::MatrixXd & LfcVc);
+
+ // Precomputation for regularization
+ IGL_INLINE void precompute_SMOOTH(Eigen::SparseMatrix<double> & MS, Eigen::MatrixXd & bS);
+
+ // extracts a r x c block from sparse matrix mat into sparse matrix m1
+ // (r0,c0) is upper left entry of block
+ IGL_INLINE void extractBlock(Eigen::SparseMatrix<double> & mat, int r0, int c0, int r, int c, Eigen::SparseMatrix<double> & m1);
+
+ // computes optimal rotations for faces of m wrt current coords in mw.V
+ // returns a 3x3 matrix
+ IGL_INLINE void compute_optimal_rotations();
+
+ // global optimization step - linear system
+ IGL_INLINE void compute_optimal_positions();
+
+ // compute the output XField from deformation gradient
+ IGL_INLINE void computeXField(std::vector< Eigen::Matrix<double,3,2> > & XF);
+
+ // computes in WW the ideal warp at each tri to make the frame field a cross
+ IGL_INLINE void compute_idealWarp(std::vector< Eigen::Matrix<double,3,3> > & WW);
+
+ // -------------------------------- Variables ----------------------------------------------------
+
+ // Mesh I/O:
+
+ Eigen::MatrixXd V; // Original mesh - vertices
+ Eigen::MatrixXi F; // Original mesh - faces
+
+ std::vector<std::vector<int> > VT; // Vertex to triangle topology
+ std::vector<std::vector<int> > VTi; // Vertex to triangle topology
+
+ Eigen::MatrixXd V_w; // Warped mesh - vertices
+
+ std::vector< Eigen::Matrix<double,3,2> > FF; // frame field FF in 3D (parallel to m.F)
+ std::vector< Eigen::Matrix<double,3,3> > WW; // warping matrices to make a cross field (parallel to m.F)
+ std::vector< Eigen::Matrix<double,3,2> > XF; // pseudo-cross field from solution (parallel to m.F)
+
+ int fixed;
+
+ double perturb_rotations; // perturbation to rotation matrices
+
+ // Numerics
+ int nfree,nconst; // number of free/constrained vertices in the mesh - default all-but-1/1
+ Eigen::MatrixXd C; // cotangent matrix of m
+ Eigen::SparseMatrix<double> L; // Laplacian matrix of m
+
+ Eigen::SparseMatrix<double> M; // matrix for global optimization - pre-conditioned
+ Eigen::MatrixXd RHS; // pre-computed part of known term in global optimization
+ std::vector< Eigen::Matrix<double,3,3> > RW; // optimal rotation-warping matrices (parallel to m.F) -- INCORPORATES WW
+ Eigen::SimplicialCholesky<Eigen::SparseMatrix<double> > solver; // solver for linear system in global opt.
+
+ // Parameters
+private:
+ double Lambda = 0.1; // weight of energy regularization
+
+};
+
+ IGL_INLINE Frame_field_deformer::Frame_field_deformer() {}
+
+ IGL_INLINE Frame_field_deformer::~Frame_field_deformer() {}
+
+ IGL_INLINE void Frame_field_deformer::init(const Eigen::MatrixXd& _V,
+ const Eigen::MatrixXi& _F,
+ const Eigen::MatrixXd& _D1,
+ const Eigen::MatrixXd& _D2,
+ double _Lambda,
+ double _perturb_rotations,
+ int _fixed)
+{
+ V = _V;
+ F = _F;
+
+ assert(_D1.rows() == _D2.rows());
+
+ FF.clear();
+ for (unsigned i=0; i < _D1.rows(); ++i)
+ {
+ Eigen::Matrix<double,3,2> ff;
+ ff.col(0) = _D1.row(i);
+ ff.col(1) = _D2.row(i);
+ FF.push_back(ff);
+ }
+
+ fixed = _fixed;
+ Lambda = _Lambda;
+ perturb_rotations = _perturb_rotations;
+
+ reset_opt();
+ precompute_opt();
+}
+
+
+IGL_INLINE void Frame_field_deformer::optimize(int N, bool reset)
+{
+ //Reset optimization
+ if (reset)
+ reset_opt();
+
+ // Iterative Local/Global optimization
+ for (int i=0; i<N;i++)
+ {
+ compute_optimal_rotations();
+ compute_optimal_positions();
+ computeXField(XF);
+ }
+}
+
+IGL_INLINE void Frame_field_deformer::reset_opt()
+{
+ V_w = V;
+
+ for (unsigned i=0; i<V_w.rows(); ++i)
+ for (unsigned j=0; j<V_w.cols(); ++j)
+ V_w(i,j) += (double(rand())/double(RAND_MAX))*10e-4*perturb_rotations;
+
+}
+
+// precomputation of all components
+IGL_INLINE void Frame_field_deformer::precompute_opt()
+{
+ using namespace Eigen;
+ nfree = V.rows() - fixed; // free vertices (at the beginning ov m.V) - global
+ nconst = V.rows()-nfree; // #constrained vertices
+ igl::vertex_triangle_adjacency(V,F,VT,VTi); // compute vertex to face relationship
+
+ igl::cotmatrix_entries(V,F,C); // cotangent matrix for opt. rotations - global
+
+ igl::cotmatrix(V,F,L);
+
+ SparseMatrix<double> MA; // internal matrix for ARAP-warping energy
+ MatrixXd LfcVc; // RHS (partial) for ARAP-warping energy
+ SparseMatrix<double> MS; // internal matrix for smoothing energy
+ MatrixXd bS; // RHS (full) for smoothing energy
+
+ precompute_ARAP(MA,LfcVc); // precompute terms for the ARAP-warp part
+ precompute_SMOOTH(MS,bS); // precompute terms for the smoothing part
+ compute_idealWarp(WW); // computes the ideal warps
+ RW.resize(F.rows()); // init rotation matrices - global
+
+ M = (1-Lambda)*MA + Lambda*MS; // matrix for linear system - global
+
+ RHS = (1-Lambda)*LfcVc + Lambda*bS; // RHS (partial) for linear system - global
+ solver.compute(M); // system pre-conditioning
+ if (solver.info()!=Eigen::Success) {fprintf(stderr,"Decomposition failed in pre-conditioning!\n"); exit(-1);}
+
+ fprintf(stdout,"Preconditioning done.\n");
+
+}
+
+IGL_INLINE void Frame_field_deformer::precompute_ARAP(Eigen::SparseMatrix<double> & Lff, Eigen::MatrixXd & LfcVc)
+{
+ using namespace Eigen;
+ fprintf(stdout,"Precomputing ARAP terms\n");
+ SparseMatrix<double> LL = -4*L;
+ Lff = SparseMatrix<double>(nfree,nfree);
+ extractBlock(LL,0,0,nfree,nfree,Lff);
+ SparseMatrix<double> Lfc = SparseMatrix<double>(nfree,nconst);
+ extractBlock(LL,0,nfree,nfree,nconst,Lfc);
+ LfcVc = - Lfc * V_w.block(nfree,0,nconst,3);
+}
+
+IGL_INLINE void Frame_field_deformer::precompute_SMOOTH(Eigen::SparseMatrix<double> & MS, Eigen::MatrixXd & bS)
+{
+ using namespace Eigen;
+ fprintf(stdout,"Precomputing SMOOTH terms\n");
+
+ SparseMatrix<double> LL = 4*L*L;
+
+ // top-left
+ MS = SparseMatrix<double>(nfree,nfree);
+ extractBlock(LL,0,0,nfree,nfree,MS);
+
+ // top-right
+ SparseMatrix<double> Mfc = SparseMatrix<double>(nfree,nconst);
+ extractBlock(LL,0,nfree,nfree,nconst,Mfc);
+
+ MatrixXd MfcVc = Mfc * V_w.block(nfree,0,nconst,3);
+ bS = (LL*V).block(0,0,nfree,3)-MfcVc;
+
+}
+
+ IGL_INLINE void Frame_field_deformer::extractBlock(Eigen::SparseMatrix<double> & mat, int r0, int c0, int r, int c, Eigen::SparseMatrix<double> & m1)
+{
+ std::vector<Eigen::Triplet<double> > tripletList;
+ for (int k=c0; k<c0+c; ++k)
+ for (Eigen::SparseMatrix<double>::InnerIterator it(mat,k); it; ++it)
+ {
+ if (it.row()>=r0 && it.row()<r0+r)
+ tripletList.push_back(Eigen::Triplet<double>(it.row()-r0,it.col()-c0,it.value()));
+ }
+ m1.setFromTriplets(tripletList.begin(), tripletList.end());
+}
+
+IGL_INLINE void Frame_field_deformer::compute_optimal_rotations()
+{
+ using namespace Eigen;
+ Matrix<double,3,3> r,S,P,PP,D;
+
+ for (int i=0;i<F.rows();i++)
+ {
+ // input tri --- could be done once and saved in a matrix
+ P.col(0) = (V.row(F(i,1))-V.row(F(i,0))).transpose();
+ P.col(1) = (V.row(F(i,2))-V.row(F(i,1))).transpose();
+ P.col(2) = (V.row(F(i,0))-V.row(F(i,2))).transpose();
+
+ P = WW[i] * P; // apply ideal warp
+
+ // current tri
+ PP.col(0) = (V_w.row(F(i,1))-V_w.row(F(i,0))).transpose();
+ PP.col(1) = (V_w.row(F(i,2))-V_w.row(F(i,1))).transpose();
+ PP.col(2) = (V_w.row(F(i,0))-V_w.row(F(i,2))).transpose();
+
+ // cotangents
+ D << C(i,2), 0, 0,
+ 0, C(i,0), 0,
+ 0, 0, C(i,1);
+
+ S = PP*D*P.transpose();
+ Eigen::JacobiSVD<Matrix<double,3,3> > svd(S, Eigen::ComputeFullU | Eigen::ComputeFullV );
+ Matrix<double,3,3> su = svd.matrixU();
+ Matrix<double,3,3> sv = svd.matrixV();
+ r = su*sv.transpose();
+
+ if (r.determinant()<0) // correct reflections
+ {
+ su(0,2)=-su(0,2); su(1,2)=-su(1,2); su(2,2)=-su(2,2);
+ r = su*sv.transpose();
+ }
+ RW[i] = r*WW[i]; // RW INCORPORATES IDEAL WARP WW!!!
+ }
+}
+
+IGL_INLINE void Frame_field_deformer::compute_optimal_positions()
+{
+ using namespace Eigen;
+ // compute variable RHS of ARAP-warp part of the system
+ MatrixXd b(nfree,3); // fx3 known term of the system
+ MatrixXd X; // result
+ int t; // triangles incident to edge (i,j)
+ int vi,i1,i2; // index of vertex i wrt tri t0
+
+ for (int i=0;i<nfree;i++)
+ {
+ b.row(i) << 0.0, 0.0, 0.0;
+ for (int k=0;k<(int)VT[i].size();k++) // for all incident triangles
+ {
+ t = VT[i][k]; // incident tri
+ vi = (i==F(t,0))?0:(i==F(t,1))?1:(i==F(t,2))?2:3; // index of i in t
+ assert(vi!=3);
+ i1 = F(t,(vi+1)%3);
+ i2 = F(t,(vi+2)%3);
+ b.row(i)+=(C(t,(vi+2)%3)*RW[t]*(V.row(i1)-V.row(i)).transpose()).transpose();
+ b.row(i)+=(C(t,(vi+1)%3)*RW[t]*(V.row(i2)-V.row(i)).transpose()).transpose();
+ }
+ }
+ b/=2.0;
+ b=-4*b;
+
+ b*=(1-Lambda); // blend
+
+ b+=RHS; // complete known term
+
+ X = solver.solve(b);
+ if (solver.info()!=Eigen::Success) {printf("Solving linear system failed!\n"); return;}
+
+ // copy result to mw.V
+ for (int i=0;i<nfree;i++)
+ V_w.row(i)=X.row(i);
+
+}
+
+ IGL_INLINE void Frame_field_deformer::computeXField(std::vector< Eigen::Matrix<double,3,2> > & XF)
+{
+ using namespace Eigen;
+ Matrix<double,3,3> P,PP,DG;
+ XF.resize(F.rows());
+
+ for (int i=0;i<F.rows();i++)
+ {
+ int i0,i1,i2;
+ // indexes of vertices of face i
+ i0 = F(i,0); i1 = F(i,1); i2 = F(i,2);
+
+ // input frame
+ P.col(0) = (V.row(i1)-V.row(i0)).transpose();
+ P.col(1) = (V.row(i2)-V.row(i0)).transpose();
+ P.col(2) = P.col(0).cross(P.col(1));
+
+ // output triangle brought to origin
+ PP.col(0) = (V_w.row(i1)-V_w.row(i0)).transpose();
+ PP.col(1) = (V_w.row(i2)-V_w.row(i0)).transpose();
+ PP.col(2) = PP.col(0).cross(PP.col(1));
+
+ // deformation gradient
+ DG = PP * P.inverse();
+ XF[i] = DG * FF[i];
+ }
+}
+
+// computes in WW the ideal warp at each tri to make the frame field a cross
+ IGL_INLINE void Frame_field_deformer::compute_idealWarp(std::vector< Eigen::Matrix<double,3,3> > & WW)
+{
+ using namespace Eigen;
+
+ WW.resize(F.rows());
+ for (int i=0;i<(int)FF.size();i++)
+ {
+ Vector3d v0,v1,v2;
+ v0 = FF[i].col(0);
+ v1 = FF[i].col(1);
+ v2=v0.cross(v1); v2.normalize(); // normal
+
+ Matrix3d A,AI; // compute affine map A that brings:
+ A << v0[0], v1[0], v2[0], // first vector of FF to x unary vector
+ v0[1], v1[1], v2[1], // second vector of FF to xy plane
+ v0[2], v1[2], v2[2]; // triangle normal to z unary vector
+ AI = A.inverse();
+
+ // polar decomposition to discard rotational component (unnecessary but makes it easier)
+ Eigen::JacobiSVD<Matrix<double,3,3> > svd(AI, Eigen::ComputeFullU | Eigen::ComputeFullV );
+ //Matrix<double,3,3> au = svd.matrixU();
+ Matrix<double,3,3> av = svd.matrixV();
+ DiagonalMatrix<double,3> as(svd.singularValues());
+ WW[i] = av*as*av.transpose();
+ }
+}
+
+}
+
+
+IGL_INLINE void igl::frame_field_deformer(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::MatrixXd& FF1,
+ const Eigen::MatrixXd& FF2,
+ Eigen::MatrixXd& V_d,
+ Eigen::MatrixXd& FF1_d,
+ Eigen::MatrixXd& FF2_d,
+ const int iterations,
+ const double lambda,
+ const bool perturb_initial_guess)
+{
+ using namespace Eigen;
+ // Solvers
+ Frame_field_deformer deformer;
+
+ // Init optimizer
+ deformer.init(V, F, FF1, FF2, lambda, perturb_initial_guess ? 0.1 : 0);
+
+ // Optimize
+ deformer.optimize(iterations,true);
+
+ // Copy positions
+ V_d = deformer.V_w;
+
+ // Allocate
+ FF1_d.resize(F.rows(),3);
+ FF2_d.resize(F.rows(),3);
+
+ // Copy frame field
+ for(unsigned i=0; i<deformer.XF.size(); ++i)
+ {
+ FF1_d.row(i) = deformer.XF[i].col(0);
+ FF2_d.row(i) = deformer.XF[i].col(1);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/frame_field_deformer.h b/xs/src/igl/frame_field_deformer.h
new file mode 100644
index 000000000..02a5b9ea2
--- /dev/null
+++ b/xs/src/igl/frame_field_deformer.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FRAME_FIELD_DEFORMER_H
+#define IGL_FRAME_FIELD_DEFORMER_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Deform a mesh to transform the given per-face frame field to be as close
+ // as possible to a cross field, in the least square sense.
+ //
+ // Inputs:
+ // V #V by 3 coordinates of the vertices
+ // F #F by 3 list of mesh faces (must be triangles)
+ // FF1 #F by 3 first representative vector of the frame field
+ // FF2 #F by 3 second representative vector of the frame field
+ // lambda laplacian regularization parameter 0=no regularization 1=full regularization
+ //
+ // Outputs:
+ // V_d #F by 3 deformed, first representative vector
+ // V_d #F by 3 deformed, first representative vector
+ // V_d #F by 3 deformed, first representative vector
+ //
+ IGL_INLINE void frame_field_deformer(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::MatrixXd& FF1,
+ const Eigen::MatrixXd& FF2,
+ Eigen::MatrixXd& V_d,
+ Eigen::MatrixXd& FF1_d,
+ Eigen::MatrixXd& FF2_d,
+ const int iterations = 50,
+ const double lambda = 0.1,
+ const bool perturb_initial_guess = true);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "frame_field_deformer.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/frame_to_cross_field.cpp b/xs/src/igl/frame_to_cross_field.cpp
new file mode 100644
index 000000000..e4d6bc713
--- /dev/null
+++ b/xs/src/igl/frame_to_cross_field.cpp
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "frame_to_cross_field.h"
+#include <igl/local_basis.h>
+#include <igl/dot_row.h>
+
+IGL_INLINE void igl::frame_to_cross_field(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::MatrixXd& FF1,
+ const Eigen::MatrixXd& FF2,
+ Eigen::MatrixXd& X)
+{
+ using namespace Eigen;
+
+ // Generate local basis
+ MatrixXd B1, B2, B3;
+
+ igl::local_basis(V,F,B1,B2,B3);
+
+ // Project the frame fields in the local basis
+ MatrixXd d1, d2;
+ d1.resize(F.rows(),2);
+ d2.resize(F.rows(),2);
+
+ d1 << igl::dot_row(B1,FF1), igl::dot_row(B2,FF1);
+ d2 << igl::dot_row(B1,FF2), igl::dot_row(B2,FF2);
+
+ X.resize(F.rows(), 3);
+
+ for (int i=0;i<F.rows();i++)
+ {
+ Vector2d v1 = d1.row(i);
+ Vector2d v2 = d2.row(i);
+
+ // define inverse map that maps the canonical axis to the given frame directions
+ Matrix2d A;
+ A << v1[0], v2[0],
+ v1[1], v2[1];
+
+ // find the closest rotation
+ Eigen::JacobiSVD<Matrix<double,2,2> > svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV );
+ Matrix2d C = svd.matrixU() * svd.matrixV().transpose();
+
+ Vector2d v = C.col(0);
+ X.row(i) = v(0) * B1.row(i) + v(1) * B2.row(i);
+ }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/frame_to_cross_field.h b/xs/src/igl/frame_to_cross_field.h
new file mode 100644
index 000000000..f9bdd3d5f
--- /dev/null
+++ b/xs/src/igl/frame_to_cross_field.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FRAME_TO_CROSS_FIELD_H
+#define IGL_FRAME_TO_CROSS_FIELD_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Convert a frame field into its closest cross field
+ // Inputs:
+ // V #V by 3 coordinates of the vertices
+ // F #F by 3 list of mesh faces (must be triangles)
+ // FF1 #F by 3 the first representative vector of the frame field (up to permutation and sign)
+ // FF2 #F by 3 the second representative vector of the frame field (up to permutation and sign)
+ //
+ // Outputs:
+ // X #F by 3 representative vector of the closest cross field
+ //
+ IGL_INLINE void frame_to_cross_field(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::MatrixXd& FF1,
+ const Eigen::MatrixXd& FF2,
+ Eigen::MatrixXd& X);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "frame_to_cross_field.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/frustum.cpp b/xs/src/igl/frustum.cpp
new file mode 100644
index 000000000..2926106e6
--- /dev/null
+++ b/xs/src/igl/frustum.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "frustum.h"
+template < typename DerivedP>
+IGL_INLINE void igl::frustum(
+ const typename DerivedP::Scalar left,
+ const typename DerivedP::Scalar right,
+ const typename DerivedP::Scalar bottom,
+ const typename DerivedP::Scalar top,
+ const typename DerivedP::Scalar nearVal,
+ const typename DerivedP::Scalar farVal,
+ Eigen::PlainObjectBase<DerivedP> & P)
+{
+ P.setConstant(4,4,0.);
+ P(0,0) = (2.0 * nearVal) / (right - left);
+ P(1,1) = (2.0 * nearVal) / (top - bottom);
+ P(0,2) = (right + left) / (right - left);
+ P(1,2) = (top + bottom) / (top - bottom);
+ P(2,2) = -(farVal + nearVal) / (farVal - nearVal);
+ P(3,2) = -1.0;
+ P(2,3) = -(2.0 * farVal * nearVal) / (farVal - nearVal);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::frustum<Eigen::Matrix<float, 4, 4, 0, 4, 4> >(Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> >&);
+#endif
diff --git a/xs/src/igl/frustum.h b/xs/src/igl/frustum.h
new file mode 100644
index 000000000..4a92e1a81
--- /dev/null
+++ b/xs/src/igl/frustum.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_FRUSTUM_H
+#define IGL_FRUSTUM_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Implementation of the deprecated glFrustum function.
+ //
+ // Inputs:
+ // left coordinate of left vertical clipping plane
+ // right coordinate of right vertical clipping plane
+ // bottom coordinate of bottom vertical clipping plane
+ // top coordinate of top vertical clipping plane
+ // nearVal distance to near plane
+ // farVal distance to far plane
+ // Outputs:
+ // P 4x4 perspective matrix
+ template < typename DerivedP>
+ IGL_INLINE void frustum(
+ const typename DerivedP::Scalar left,
+ const typename DerivedP::Scalar right,
+ const typename DerivedP::Scalar bottom,
+ const typename DerivedP::Scalar top,
+ const typename DerivedP::Scalar nearVal,
+ const typename DerivedP::Scalar farVal,
+ Eigen::PlainObjectBase<DerivedP> & P);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "frustum.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/gaussian_curvature.cpp b/xs/src/igl/gaussian_curvature.cpp
new file mode 100644
index 000000000..ca05129df
--- /dev/null
+++ b/xs/src/igl/gaussian_curvature.cpp
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "gaussian_curvature.h"
+#include "internal_angles.h"
+#include "PI.h"
+#include <iostream>
+template <typename DerivedV, typename DerivedF, typename DerivedK>
+IGL_INLINE void igl::gaussian_curvature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedK> & K)
+{
+ using namespace Eigen;
+ using namespace std;
+ // internal corner angles
+ Matrix<
+ typename DerivedV::Scalar,
+ DerivedF::RowsAtCompileTime,
+ DerivedF::ColsAtCompileTime> A;
+ internal_angles(V,F,A);
+ K.resize(V.rows(),1);
+ K.setConstant(V.rows(),1,2.*PI);
+ assert(A.rows() == F.rows());
+ assert(A.cols() == F.cols());
+ assert(K.rows() == V.rows());
+ assert(F.maxCoeff() < V.rows());
+ assert(K.cols() == 1);
+ const int Frows = F.rows();
+ //K_G(x_i) = (2π - ∑θj)
+//#ifndef IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE
+//# define IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE 1000
+//#endif
+//#pragma omp parallel for if (Frows>IGL_GAUSSIAN_CURVATURE_OMP_MIN_VALUE)
+ for(int f = 0;f<Frows;f++)
+ {
+ // throw normal at each corner
+ for(int j = 0; j < 3;j++)
+ {
+ // Q: Does this need to be critical?
+ // H: I think so, sadly. Maybe there's a way to use reduction
+//#pragma omp critical
+ K(F(f,j),0) -= A(f,j);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::gaussian_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::gaussian_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/gaussian_curvature.h b/xs/src/igl/gaussian_curvature.h
new file mode 100644
index 000000000..d8ddbc8ad
--- /dev/null
+++ b/xs/src/igl/gaussian_curvature.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_GAUSSIAN_CURVATURE_H
+#define IGL_GAUSSIAN_CURVATURE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute discrete local integral gaussian curvature (angle deficit, without
+ // averaging by local area).
+ //
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigen Matrix of face (triangle) indices
+ // Output:
+ // K #V by 1 eigen Matrix of discrete gaussian curvature values
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedK>
+ IGL_INLINE void gaussian_curvature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedK> & K);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "gaussian_curvature.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/get_seconds.cpp b/xs/src/igl/get_seconds.cpp
new file mode 100644
index 000000000..fac4a3a69
--- /dev/null
+++ b/xs/src/igl/get_seconds.cpp
@@ -0,0 +1,15 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "get_seconds.h"
+#include <chrono>
+IGL_INLINE double igl::get_seconds()
+{
+ return
+ std::chrono::duration<double>(
+ std::chrono::system_clock::now().time_since_epoch()).count();
+}
diff --git a/xs/src/igl/get_seconds.h b/xs/src/igl/get_seconds.h
new file mode 100644
index 000000000..411d6e41d
--- /dev/null
+++ b/xs/src/igl/get_seconds.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_GET_SECONDS_H
+#define IGL_GET_SECONDS_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Return the current time in seconds since program start
+ //
+ // Example:
+ // const auto & tictoc = []()
+ // {
+ // static double t_start = igl::get_seconds();
+ // double diff = igl::get_seconds()-t_start;
+ // t_start += diff;
+ // return diff;
+ // };
+ // tictoc();
+ // ... // part 1
+ // cout<<"part 1: "<<tictoc()<<endl;
+ // ... // part 2
+ // cout<<"part 2: "<<tictoc()<<endl;
+ // ... // etc
+ IGL_INLINE double get_seconds();
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "get_seconds.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/get_seconds_hires.cpp b/xs/src/igl/get_seconds_hires.cpp
new file mode 100644
index 000000000..15f26dc9e
--- /dev/null
+++ b/xs/src/igl/get_seconds_hires.cpp
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "get_seconds_hires.h"
+
+#if _WIN32
+# include <windows.h>
+# include <cassert>
+IGL_INLINE double igl::get_seconds_hires()
+{
+ LARGE_INTEGER li_freq, li_current;
+ const bool ret = QueryPerformanceFrequency(&li_freq);
+ const bool ret2 = QueryPerformanceCounter(&li_current);
+ assert(ret && ret2);
+ assert(li_freq.QuadPart > 0);
+ return double(li_current.QuadPart) / double(li_freq.QuadPart);
+}
+#else
+# include "get_seconds.h"
+IGL_INLINE double igl::get_seconds_hires()
+{
+ // Sorry I've no idea how performance counters work on Mac...
+ return igl::get_seconds();
+}
+#endif
diff --git a/xs/src/igl/get_seconds_hires.h b/xs/src/igl/get_seconds_hires.h
new file mode 100644
index 000000000..abe8956b5
--- /dev/null
+++ b/xs/src/igl/get_seconds_hires.h
@@ -0,0 +1,22 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_GET_SECONDS_HIRES_H
+#define IGL_GET_SECONDS_HIRES_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Return the current time in seconds using performance counters
+ IGL_INLINE double get_seconds_hires();
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "get_seconds_hires.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/grad.cpp b/xs/src/igl/grad.cpp
new file mode 100644
index 000000000..cc86e9e81
--- /dev/null
+++ b/xs/src/igl/grad.cpp
@@ -0,0 +1,243 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "grad.h"
+#include <Eigen/Geometry>
+#include <vector>
+
+#include "PI.h"
+#include "per_face_normals.h"
+#include "volume.h"
+#include "doublearea.h"
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void grad_tet(const Eigen::PlainObjectBase<DerivedV>&V,
+ const Eigen::PlainObjectBase<DerivedF>&T,
+ Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+ bool uniform) {
+ using namespace Eigen;
+ assert(T.cols() == 4);
+ const int n = V.rows(); int m = T.rows();
+
+ /*
+ F = [ ...
+ T(:,1) T(:,2) T(:,3); ...
+ T(:,1) T(:,3) T(:,4); ...
+ T(:,1) T(:,4) T(:,2); ...
+ T(:,2) T(:,4) T(:,3)]; */
+ MatrixXi F(4*m,3);
+ for (int i = 0; i < m; i++) {
+ F.row(0*m + i) << T(i,0), T(i,1), T(i,2);
+ F.row(1*m + i) << T(i,0), T(i,2), T(i,3);
+ F.row(2*m + i) << T(i,0), T(i,3), T(i,1);
+ F.row(3*m + i) << T(i,1), T(i,3), T(i,2);
+ }
+ // compute volume of each tet
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> vol;
+ igl::volume(V,T,vol);
+
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> A(F.rows());
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> N(F.rows(),3);
+ if (!uniform) {
+ // compute tetrahedron face normals
+ igl::per_face_normals(V,F,N); int norm_rows = N.rows();
+ for (int i = 0; i < norm_rows; i++)
+ N.row(i) /= N.row(i).norm();
+ igl::doublearea(V,F,A); A/=2.;
+ } else {
+ // Use a uniform tetrahedra as a reference, with the same volume as the original one:
+ //
+ // Use normals of the uniform tet (V = h*[0,0,0;1,0,0;0.5,sqrt(3)/2.,0;0.5,sqrt(3)/6.,sqrt(2)/sqrt(3)])
+ // 0 0 1.0000
+ // 0.8165 -0.4714 -0.3333
+ // 0 0.9428 -0.3333
+ // -0.8165 -0.4714 -0.3333
+ for (int i = 0; i < m; i++) {
+ N.row(0*m+i) << 0,0,1;
+ double a = sqrt(2)*std::cbrt(3*vol(i)); // area of a face in a uniform tet with volume = vol(i)
+ A(0*m+i) = (pow(a,2)*sqrt(3))/4.;
+ }
+ for (int i = 0; i < m; i++) {
+ N.row(1*m+i) << 0.8165,-0.4714,-0.3333;
+ double a = sqrt(2)*std::cbrt(3*vol(i));
+ A(1*m+i) = (pow(a,2)*sqrt(3))/4.;
+ }
+ for (int i = 0; i < m; i++) {
+ N.row(2*m+i) << 0,0.9428,-0.3333;
+ double a = sqrt(2)*std::cbrt(3*vol(i));
+ A(2*m+i) = (pow(a,2)*sqrt(3))/4.;
+ }
+ for (int i = 0; i < m; i++) {
+ N.row(3*m+i) << -0.8165,-0.4714,-0.3333;
+ double a = sqrt(2)*std::cbrt(3*vol(i));
+ A(3*m+i) = (pow(a,2)*sqrt(3))/4.;
+ }
+
+ }
+
+ /* G = sparse( ...
+ [0*m + repmat(1:m,1,4) ...
+ 1*m + repmat(1:m,1,4) ...
+ 2*m + repmat(1:m,1,4)], ...
+ repmat([T(:,4);T(:,2);T(:,3);T(:,1)],3,1), ...
+ repmat(A./(3*repmat(vol,4,1)),3,1).*N(:), ...
+ 3*m,n);*/
+ std::vector<Triplet<double> > G_t;
+ for (int i = 0; i < 4*m; i++) {
+ int T_j; // j indexes : repmat([T(:,4);T(:,2);T(:,3);T(:,1)],3,1)
+ switch (i/m) {
+ case 0:
+ T_j = 3;
+ break;
+ case 1:
+ T_j = 1;
+ break;
+ case 2:
+ T_j = 2;
+ break;
+ case 3:
+ T_j = 0;
+ break;
+ }
+ int i_idx = i%m;
+ int j_idx = T(i_idx,T_j);
+
+ double val_before_n = A(i)/(3*vol(i_idx));
+ G_t.push_back(Triplet<double>(0*m+i_idx, j_idx, val_before_n * N(i,0)));
+ G_t.push_back(Triplet<double>(1*m+i_idx, j_idx, val_before_n * N(i,1)));
+ G_t.push_back(Triplet<double>(2*m+i_idx, j_idx, val_before_n * N(i,2)));
+ }
+ G.resize(3*m,n);
+ G.setFromTriplets(G_t.begin(), G_t.end());
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void grad_tri(const Eigen::PlainObjectBase<DerivedV>&V,
+ const Eigen::PlainObjectBase<DerivedF>&F,
+ Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+ bool uniform)
+{
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3>
+ eperp21(F.rows(),3), eperp13(F.rows(),3);
+
+ for (int i=0;i<F.rows();++i)
+ {
+ // renaming indices of vertices of triangles for convenience
+ int i1 = F(i,0);
+ int i2 = F(i,1);
+ int i3 = F(i,2);
+
+ // #F x 3 matrices of triangle edge vectors, named after opposite vertices
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v32 = V.row(i3) - V.row(i2);
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v13 = V.row(i1) - V.row(i3);
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v21 = V.row(i2) - V.row(i1);
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> n = v32.cross(v13);
+ // area of parallelogram is twice area of triangle
+ // area of parallelogram is || v1 x v2 ||
+ // This does correct l2 norm of rows, so that it contains #F list of twice
+ // triangle areas
+ double dblA = std::sqrt(n.dot(n));
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> u(0,0,1);
+ if (!uniform) {
+ // now normalize normals to get unit normals
+ u = n / dblA;
+ } else {
+ // Abstract equilateral triangle v1=(0,0), v2=(h,0), v3=(h/2, (sqrt(3)/2)*h)
+
+ // get h (by the area of the triangle)
+ double h = sqrt( (dblA)/sin(igl::PI / 3.0)); // (h^2*sin(60))/2. = Area => h = sqrt(2*Area/sin_60)
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> v1,v2,v3;
+ v1 << 0,0,0;
+ v2 << h,0,0;
+ v3 << h/2.,(sqrt(3)/2.)*h,0;
+
+ // now fix v32,v13,v21 and the normal
+ v32 = v3-v2;
+ v13 = v1-v3;
+ v21 = v2-v1;
+ n = v32.cross(v13);
+ }
+
+ // rotate each vector 90 degrees around normal
+ double norm21 = std::sqrt(v21.dot(v21));
+ double norm13 = std::sqrt(v13.dot(v13));
+ eperp21.row(i) = u.cross(v21);
+ eperp21.row(i) = eperp21.row(i) / std::sqrt(eperp21.row(i).dot(eperp21.row(i)));
+ eperp21.row(i) *= norm21 / dblA;
+ eperp13.row(i) = u.cross(v13);
+ eperp13.row(i) = eperp13.row(i) / std::sqrt(eperp13.row(i).dot(eperp13.row(i)));
+ eperp13.row(i) *= norm13 / dblA;
+ }
+
+ std::vector<int> rs;
+ rs.reserve(F.rows()*4*3);
+ std::vector<int> cs;
+ cs.reserve(F.rows()*4*3);
+ std::vector<double> vs;
+ vs.reserve(F.rows()*4*3);
+
+ // row indices
+ for(int r=0;r<3;r++)
+ {
+ for(int j=0;j<4;j++)
+ {
+ for(int i=r*F.rows();i<(r+1)*F.rows();i++) rs.push_back(i);
+ }
+ }
+
+ // column indices
+ for(int r=0;r<3;r++)
+ {
+ for(int i=0;i<F.rows();i++) cs.push_back(F(i,1));
+ for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
+ for(int i=0;i<F.rows();i++) cs.push_back(F(i,2));
+ for(int i=0;i<F.rows();i++) cs.push_back(F(i,0));
+ }
+
+ // values
+ for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,0));
+ for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,0));
+ for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,0));
+ for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,0));
+ for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,1));
+ for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,1));
+ for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,1));
+ for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,1));
+ for(int i=0;i<F.rows();i++) vs.push_back(eperp13(i,2));
+ for(int i=0;i<F.rows();i++) vs.push_back(-eperp13(i,2));
+ for(int i=0;i<F.rows();i++) vs.push_back(eperp21(i,2));
+ for(int i=0;i<F.rows();i++) vs.push_back(-eperp21(i,2));
+
+ // create sparse gradient operator matrix
+ G.resize(3*F.rows(),V.rows());
+ std::vector<Eigen::Triplet<typename DerivedV::Scalar> > triplets;
+ for (int i=0;i<(int)vs.size();++i)
+ {
+ triplets.push_back(Eigen::Triplet<typename DerivedV::Scalar>(rs[i],cs[i],vs[i]));
+ }
+ G.setFromTriplets(triplets.begin(), triplets.end());
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::grad(const Eigen::PlainObjectBase<DerivedV>&V,
+ const Eigen::PlainObjectBase<DerivedF>&F,
+ Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+ bool uniform)
+{
+ assert(F.cols() == 3 || F.cols() == 4);
+ if (F.cols() == 3)
+ return grad_tri(V,F,G,uniform);
+ if (F.cols() == 4)
+ return grad_tet(V,F,G,uniform);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::grad<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, 0, int>&, bool);
+template void igl::grad<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::SparseMatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>::Scalar, 0, int>&, bool);
+#endif
diff --git a/xs/src/igl/grad.h b/xs/src/igl/grad.h
new file mode 100644
index 000000000..df375ba61
--- /dev/null
+++ b/xs/src/igl/grad.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_GRAD_MAT_H
+#define IGL_GRAD_MAT_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl {
+ // GRAD
+ // G = grad(V,F)
+ //
+ // Compute the numerical gradient operator
+ //
+ // Inputs:
+ // V #vertices by 3 list of mesh vertex positions
+ // F #faces by 3 list of mesh face indices [or a #faces by 4 list of tetrahedral indices]
+ // uniform boolean (default false) - Use a uniform mesh instead of the vertices V
+ // Outputs:
+ // G #faces*dim by #V Gradient operator
+ //
+
+ // Gradient of a scalar function defined on piecewise linear elements (mesh)
+ // is constant on each triangle [tetrahedron] i,j,k:
+ // grad(Xijk) = (Xj-Xi) * (Vi - Vk)^R90 / 2A + (Xk-Xi) * (Vj - Vi)^R90 / 2A
+ // where Xi is the scalar value at vertex i, Vi is the 3D position of vertex
+ // i, and A is the area of triangle (i,j,k). ^R90 represent a rotation of
+ // 90 degrees
+ //
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void grad(const Eigen::PlainObjectBase<DerivedV>&V,
+ const Eigen::PlainObjectBase<DerivedF>&F,
+ Eigen::SparseMatrix<typename DerivedV::Scalar> &G,
+ bool uniform = false);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "grad.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/grid.cpp b/xs/src/igl/grid.cpp
new file mode 100644
index 000000000..f572a0571
--- /dev/null
+++ b/xs/src/igl/grid.cpp
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "grid.h"
+
+template <
+ typename Derivedres,
+ typename DerivedGV>
+IGL_INLINE void igl::grid(
+ const Eigen::MatrixBase<Derivedres> & res,
+ Eigen::PlainObjectBase<DerivedGV> & GV)
+{
+ using namespace Eigen;
+ typedef typename DerivedGV::Scalar Scalar;
+ GV.resize(res(0)*res(1)*res(2),3);
+ for(int zi = 0;zi<res(2);zi++)
+ {
+ const auto lerp =
+ [&](const Scalar di, const int d)->Scalar{return di/(Scalar)(res(d)-1);};
+ const Scalar z = lerp(zi,2);
+ for(int yi = 0;yi<res(1);yi++)
+ {
+ const Scalar y = lerp(yi,1);
+ for(int xi = 0;xi<res(0);xi++)
+ {
+ const Scalar x = lerp(xi,0);
+ const int gi = xi+res(0)*(yi + res(1)*zi);
+ GV.row(gi) =
+ Eigen::Matrix<Scalar,1,3>(x,y,z);
+ }
+ }
+ }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::grid<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::grid<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::grid<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::grid<Eigen::Matrix<int, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::grid<Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/grid.h b/xs/src/igl/grid.h
new file mode 100644
index 000000000..27894f628
--- /dev/null
+++ b/xs/src/igl/grid.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_GRID_H
+#define IGL_GRID_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Construct vertices of a regular grid, suitable for input to
+ // `igl::marching_cubes`
+ //
+ // Inputs:
+ // res 3-long list of number of vertices along the x y and z dimensions
+ // Outputs:
+ // GV res(0)*res(1)*res(2) by 3 list of mesh vertex positions.
+ //
+ template <
+ typename Derivedres,
+ typename DerivedGV>
+ IGL_INLINE void grid(
+ const Eigen::MatrixBase<Derivedres> & res,
+ Eigen::PlainObjectBase<DerivedGV> & GV);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "grid.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/grid_search.cpp b/xs/src/igl/grid_search.cpp
new file mode 100644
index 000000000..93cbc0dde
--- /dev/null
+++ b/xs/src/igl/grid_search.cpp
@@ -0,0 +1,64 @@
+#include "grid_search.h"
+#include <iostream>
+#include <cassert>
+
+template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB,
+ typename DerivedI>
+IGL_INLINE Scalar igl::grid_search(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const Eigen::MatrixBase<DerivedI> & I,
+ DerivedX & X)
+{
+ Scalar fval = std::numeric_limits<Scalar>::max();
+ const int dim = LB.size();
+ assert(UB.size() == dim && "UB should match LB size");
+ assert(I.size() == dim && "I should match LB size");
+ X.resize(dim);
+
+ // Working X value
+ DerivedX Xrun(dim);
+ std::function<void(const int, DerivedX &)> looper;
+ int calls = 0;
+ looper = [&](
+ const int d,
+ DerivedX & Xrun)
+ {
+ assert(d < dim);
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1> vals =
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1>::LinSpaced(I(d),LB(d),UB(d));
+ for(int c = 0;c<I(d);c++)
+ {
+ Xrun(d) = vals(c);
+ if(d+1 < dim)
+ {
+ looper(d+1,Xrun);
+ }else
+ {
+ //std::cout<<"call: "<<calls<<std::endl;
+ // Base case
+ const Scalar val = f(Xrun);
+ calls++;
+ if(val < fval)
+ {
+ fval = val;
+ X = Xrun;
+ std::cout<<calls<<": "<<fval<<" | "<<X<<std::endl;
+ }
+ }
+ }
+ };
+ looper(0,Xrun);
+
+ return fval;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template double igl::grid_search<double, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<int, 1, 3, 1, 1, 3> >(std::function<double (Eigen::Matrix<double, 1, 3, 1, 1, 3>&)>, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, Eigen::Matrix<double, 1, 3, 1, 1, 3>&);
+template float igl::grid_search<float, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<int, 1, -1, 1, 1, -1> >(std::function<float (Eigen::Matrix<float, 1, -1, 1, 1, -1>&)>, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 1, -1, 1, 1, -1> > const&, Eigen::Matrix<float, 1, -1, 1, 1, -1>&);
+#endif
diff --git a/xs/src/igl/grid_search.h b/xs/src/igl/grid_search.h
new file mode 100644
index 000000000..83a86663e
--- /dev/null
+++ b/xs/src/igl/grid_search.h
@@ -0,0 +1,42 @@
+#ifndef IGL_GRID_SEARCH_H
+#define IGL_GRID_SEARCH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <functional>
+namespace igl
+{
+ // Solve the problem:
+ //
+ // minimize f(x)
+ // subject to lb ≤ x ≤ ub
+ //
+ // by exhaustive grid search.
+ //
+ // Inputs:
+ // f function to minimize
+ // LB #X vector of finite lower bounds
+ // UB #X vector of finite upper bounds
+ // I #X vector of number of steps for each variable
+ // Outputs:
+ // X #X optimal parameter vector
+ // Returns f(X)
+ //
+ template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB,
+ typename DerivedI>
+ IGL_INLINE Scalar grid_search(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const Eigen::MatrixBase<DerivedI> & I,
+ DerivedX & X);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "grid_search.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/group_sum_matrix.cpp b/xs/src/igl/group_sum_matrix.cpp
new file mode 100644
index 000000000..d3cf0bff2
--- /dev/null
+++ b/xs/src/igl/group_sum_matrix.cpp
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "group_sum_matrix.h"
+
+template <typename T>
+IGL_INLINE void igl::group_sum_matrix(
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
+ const int k,
+ Eigen::SparseMatrix<T>& A)
+{
+ // number of vertices
+ int n = G.rows();
+ assert(k > G.maxCoeff());
+
+ A.resize(k,n);
+
+ // builds A such that A(i,j) = 1 where i corresponds to group i and j
+ // corresponds to vertex j
+
+ // Loop over vertices
+ for(int j = 0;j<n;j++)
+ {
+ A.insert(G(j),j) = 1;
+ }
+
+ A.makeCompressed();
+}
+
+template <typename T>
+IGL_INLINE void igl::group_sum_matrix(
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
+ Eigen::SparseMatrix<T>& A)
+{
+ return group_sum_matrix(G,G.maxCoeff()+1,A);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::group_sum_matrix<double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::group_sum_matrix<double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/group_sum_matrix.h b/xs/src/igl/group_sum_matrix.h
new file mode 100644
index 000000000..805544b0b
--- /dev/null
+++ b/xs/src/igl/group_sum_matrix.h
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_GROUP_SUM_MATRIX_H
+#define IGL_GROUP_SUM_MATRIX_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // GROUP_SUM_MATRIX Builds a matrix A such that A*V computes the sum of
+ // vertices in each group specified by G
+ //
+ // group_sum_matrix(G,k,A);
+ //
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // G #V list of group indices (0 to k-1) for each vertex, such that vertex i
+ // is assigned to group G(i)
+ // k #groups, good choice is max(G)+1
+ // Outputs:
+ // A #groups by #V sparse matrix such that A*V = group_sums
+ //
+ template <typename T>
+ IGL_INLINE void group_sum_matrix(
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
+ const int k,
+ Eigen::SparseMatrix<T>& A);
+ // Wrapper with k = max(G)+1
+ template <typename T>
+ IGL_INLINE void group_sum_matrix(
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & G,
+ Eigen::SparseMatrix<T>& A);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "group_sum_matrix.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/guess_extension.cpp b/xs/src/igl/guess_extension.cpp
new file mode 100644
index 000000000..8e8e449a1
--- /dev/null
+++ b/xs/src/igl/guess_extension.cpp
@@ -0,0 +1,106 @@
+#include "guess_extension.h"
+
+#include <string.h>
+
+#include "is_stl.h"
+#include "ply.h"
+
+IGL_INLINE void igl::guess_extension(FILE * fp, std::string & guess)
+{
+ const auto is_off = [](FILE * fp)-> bool
+ {
+ char header[1000];
+ const std::string OFF("OFF");
+ const std::string NOFF("NOFF");
+ const std::string COFF("COFF");
+ bool f = (fscanf(fp,"%s\n",header)==1 && (
+ std::string(header).compare(0, OFF.length(), OFF)==0 ||
+ std::string(header).compare(0, COFF.length(), COFF)==0 ||
+ std::string(header).compare(0,NOFF.length(),NOFF)==0));
+ rewind(fp);
+ return f;
+ };
+ const auto is_ply = [](FILE * ply_file) -> bool
+ {
+ int nelems;
+ char ** elem_names;
+ igl::ply::PlyFile * in_ply = igl::ply::ply_read(ply_file,&nelems,&elem_names);
+ if(in_ply==NULL)
+ {
+ return false;
+ }
+ free(in_ply);
+ rewind(ply_file);
+ return true;
+ };
+ const auto is_wrl = [](FILE * wrl_file)->bool
+ {
+ bool still_comments = true;
+ char line[1000];
+ std::string needle("point [");
+ std::string haystack;
+ while(still_comments)
+ {
+ if(fgets(line,1000,wrl_file) == NULL)
+ {
+ rewind(wrl_file);
+ return false;
+ }
+ haystack = std::string(line);
+ still_comments = std::string::npos == haystack.find(needle);
+ }
+ rewind(wrl_file);
+ return true;
+ };
+ const auto is_mesh = [](FILE * mesh_file )->bool
+ {
+ char line[2048];
+ // eat comments at beginning of file
+ bool still_comments= true;
+ while(still_comments)
+ {
+ if(fgets(line,2048,mesh_file) == NULL)
+ {
+ rewind(mesh_file);
+ return false;
+ }
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+ char str[2048];
+ sscanf(line," %s",str);
+ // check that first word is MeshVersionFormatted
+ if(0!=strcmp(str,"MeshVersionFormatted"))
+ {
+ rewind(mesh_file);
+ return false;
+ }
+ rewind(mesh_file);
+ return true;
+ };
+ guess = "obj";
+ if(is_mesh(fp))
+ {
+ guess = "mesh";
+ }else if(is_off(fp))
+ {
+ guess = "off";
+ }else if(is_ply(fp))
+ {
+ guess = "ply";
+ }else if(igl::is_stl(fp))
+ {
+ guess = "stl";
+ }else if(is_wrl(fp))
+ {
+ guess = "wrl";
+ }
+ // else obj
+ rewind(fp);
+}
+
+IGL_INLINE std::string igl::guess_extension(FILE * fp)
+{
+ std::string guess;
+ guess_extension(fp,guess);
+ return guess;
+}
diff --git a/xs/src/igl/guess_extension.h b/xs/src/igl/guess_extension.h
new file mode 100644
index 000000000..77df6f523
--- /dev/null
+++ b/xs/src/igl/guess_extension.h
@@ -0,0 +1,25 @@
+#ifndef IGL_GUESS_EXTENSION_H
+#define IGL_GUESS_EXTENSION_H
+#include "igl_inline.h"
+#include <string>
+#include <cstdio>
+namespace igl
+{
+ // Given a file pointer at the beginning of a "mesh" file, try to guess the
+ // extension of the file format it comes from. The file pointer is rewound on
+ // return.
+ //
+ // Inputs:
+ // fp file pointer (see output)
+ // Outputs:
+ // fp file pointer rewound
+ // guess extension as string. One of "mesh",{"obj"},"off","ply","stl", or
+ // "wrl"
+ //
+ IGL_INLINE void guess_extension(FILE * fp, std::string & guess);
+ IGL_INLINE std::string guess_extension(FILE * fp);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "guess_extension.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/harmonic.cpp b/xs/src/igl/harmonic.cpp
new file mode 100644
index 000000000..aa07245a1
--- /dev/null
+++ b/xs/src/igl/harmonic.cpp
@@ -0,0 +1,175 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "harmonic.h"
+#include "adjacency_matrix.h"
+#include "cotmatrix.h"
+#include "diag.h"
+#include "invert_diag.h"
+#include "isdiag.h"
+#include "massmatrix.h"
+#include "min_quad_with_fixed.h"
+#include "speye.h"
+#include "sum.h"
+#include <Eigen/Sparse>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+IGL_INLINE bool igl::harmonic(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W)
+{
+ using namespace Eigen;
+ typedef typename DerivedV::Scalar Scalar;
+ SparseMatrix<Scalar> L,M;
+ cotmatrix(V,F,L);
+ if(k>1)
+ {
+ massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
+ }
+ return harmonic(L,M,b,bc,k,W);
+}
+
+template <
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+IGL_INLINE bool igl::harmonic(
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W)
+{
+ using namespace Eigen;
+ typedef typename Derivedbc::Scalar Scalar;
+ SparseMatrix<Scalar> A;
+ adjacency_matrix(F,A);
+ // sum each row
+ SparseVector<Scalar> Asum;
+ sum(A,1,Asum);
+ // Convert row sums into diagonal of sparse matrix
+ SparseMatrix<Scalar> Adiag;
+ diag(Asum,Adiag);
+ SparseMatrix<Scalar> L = A-Adiag;
+ SparseMatrix<Scalar> M;
+ speye(L.rows(),M);
+ return harmonic(L,M,b,bc,k,W);
+}
+
+template <
+ typename DerivedL,
+ typename DerivedM,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+IGL_INLINE bool igl::harmonic(
+ const Eigen::SparseMatrix<DerivedL> & L,
+ const Eigen::SparseMatrix<DerivedM> & M,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W)
+{
+ const int n = L.rows();
+ assert(n == L.cols() && "L must be square");
+ assert((k==1 || n == M.cols() ) && "M must be same size as L");
+ assert((k==1 || n == M.rows() ) && "M must be square");
+ assert((k==1 || igl::isdiag(M)) && "Mass matrix should be diagonal");
+
+ Eigen::SparseMatrix<DerivedL> Q;
+ igl::harmonic(L,M,k,Q);
+
+ typedef DerivedL Scalar;
+ min_quad_with_fixed_data<Scalar> data;
+ min_quad_with_fixed_precompute(Q,b,Eigen::SparseMatrix<Scalar>(),true,data);
+ W.resize(n,bc.cols());
+ typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
+ const VectorXS B = VectorXS::Zero(n,1);
+ for(int w = 0;w<bc.cols();w++)
+ {
+ const VectorXS bcw = bc.col(w);
+ VectorXS Ww;
+ if(!min_quad_with_fixed_solve(data,B,bcw,VectorXS(),Ww))
+ {
+ return false;
+ }
+ W.col(w) = Ww;
+ }
+ return true;
+}
+
+template <
+ typename DerivedL,
+ typename DerivedM,
+ typename DerivedQ>
+IGL_INLINE void igl::harmonic(
+ const Eigen::SparseMatrix<DerivedL> & L,
+ const Eigen::SparseMatrix<DerivedM> & M,
+ const int k,
+ Eigen::SparseMatrix<DerivedQ> & Q)
+{
+ assert(L.rows() == L.cols()&&"L should be square");
+ Q = -L;
+ if(k == 1) return;
+ assert(L.rows() == M.rows()&&"L should match M's dimensions");
+ assert(M.rows() == M.cols()&&"M should be square");
+ Eigen::SparseMatrix<DerivedM> Mi;
+ invert_diag(M,Mi);
+ // This is **not** robust for k>2. See KKT system in [Jacobson et al. 2010]
+ // of the kharmonic function in gptoolbox
+ for(int p = 1;p<k;p++)
+ {
+ Q = (Q*Mi*-L).eval();
+ }
+}
+
+#include "find.h"
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedQ>
+IGL_INLINE void igl::harmonic(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const int k,
+ Eigen::SparseMatrix<DerivedQ> & Q)
+{
+ Eigen::SparseMatrix<DerivedQ> L,M;
+ cotmatrix(V,F,L);
+ if(k>1)
+ {
+ massmatrix(V,F,MASSMATRIX_TYPE_DEFAULT,M);
+ }
+ return harmonic(L,M,k,Q);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::harmonic<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::SparseMatrix<double, 0, int>&);
+// generated by autoexplicit.sh
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::harmonic<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/harmonic.h b/xs/src/igl/harmonic.h
new file mode 100644
index 000000000..1a48ecfb5
--- /dev/null
+++ b/xs/src/igl/harmonic.h
@@ -0,0 +1,122 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HARMONIC_H
+#define IGL_HARMONIC_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Compute k-harmonic weight functions "coordinates".
+ //
+ //
+ // Inputs:
+ // V #V by dim vertex positions
+ // F #F by simplex-size list of element indices
+ // b #b boundary indices into V
+ // bc #b by #W list of boundary values
+ // k power of harmonic operation (1: harmonic, 2: biharmonic, etc)
+ // Outputs:
+ // W #V by #W list of weights
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+ IGL_INLINE bool harmonic(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W);
+ // Compute harmonic map using uniform laplacian operator
+ //
+ // Inputs:
+ // F #F by simplex-size list of element indices
+ // b #b boundary indices into V
+ // bc #b by #W list of boundary values
+ // k power of harmonic operation (1: harmonic, 2: biharmonic, etc)
+ // Outputs:
+ // W #V by #W list of weights
+ //
+ template <
+ typename DerivedF,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+ IGL_INLINE bool harmonic(
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W);
+ // Compute a harmonic map using a given Laplacian and mass matrix
+ //
+ // Inputs:
+ // L #V by #V discrete (integrated) Laplacian
+ // M #V by #V mass matrix
+ // b #b boundary indices into V
+ // bc #b by #W list of boundary values
+ // k power of harmonic operation (1: harmonic, 2: biharmonic, etc)
+ // Outputs:
+ // W #V by #V list of weights
+ template <
+ typename DerivedL,
+ typename DerivedM,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+ IGL_INLINE bool harmonic(
+ const Eigen::SparseMatrix<DerivedL> & L,
+ const Eigen::SparseMatrix<DerivedM> & M,
+ const Eigen::MatrixBase<Derivedb> & b,
+ const Eigen::MatrixBase<Derivedbc> & bc,
+ const int k,
+ Eigen::PlainObjectBase<DerivedW> & W);
+ // Build the discrete k-harmonic operator (computing integrated quantities).
+ // That is, if the k-harmonic PDE is Q x = 0, then this minimizes x' Q x
+ //
+ // Inputs:
+ // L #V by #V discrete (integrated) Laplacian
+ // M #V by #V mass matrix
+ // k power of harmonic operation (1: harmonic, 2: biharmonic, etc)
+ // Outputs:
+ // Q #V by #V discrete (integrated) k-Laplacian
+ template <
+ typename DerivedL,
+ typename DerivedM,
+ typename DerivedQ>
+ IGL_INLINE void harmonic(
+ const Eigen::SparseMatrix<DerivedL> & L,
+ const Eigen::SparseMatrix<DerivedM> & M,
+ const int k,
+ Eigen::SparseMatrix<DerivedQ> & Q);
+ // Inputs:
+ // V #V by dim vertex positions
+ // F #F by simplex-size list of element indices
+ // k power of harmonic operation (1: harmonic, 2: biharmonic, etc)
+ // Outputs:
+ // Q #V by #V discrete (integrated) k-Laplacian
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedQ>
+ IGL_INLINE void harmonic(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const int k,
+ Eigen::SparseMatrix<DerivedQ> & Q);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+#include "harmonic.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/harwell_boeing.cpp b/xs/src/igl/harwell_boeing.cpp
new file mode 100644
index 000000000..895416510
--- /dev/null
+++ b/xs/src/igl/harwell_boeing.cpp
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "harwell_boeing.h"
+
+template <typename Scalar, typename Index>
+IGL_INLINE void igl::harwell_boeing(
+ const Eigen::SparseMatrix<Scalar> & A,
+ int & num_rows,
+ std::vector<Scalar> & V,
+ std::vector<Index> & R,
+ std::vector<Index> & C)
+{
+ num_rows = A.rows();
+ int num_cols = A.cols();
+ int nnz = A.nonZeros();
+ V.resize(nnz);
+ R.resize(nnz);
+ C.resize(num_cols+1);
+
+ // Assumes outersize is columns
+ assert(A.cols() == A.outerSize());
+ int column_pointer = 0;
+ int i = 0;
+ int k = 0;
+ // Iterate over outside
+ for(; k<A.outerSize(); ++k)
+ {
+ C[k] = column_pointer;
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ V[i] = it.value();
+ R[i] = it.row();
+ i++;
+ // Also increment column pointer
+ column_pointer++;
+ }
+ }
+ // by convention C[num_cols] = nnz
+ C[k] = column_pointer;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::harwell_boeing<double, int>(Eigen::SparseMatrix<double, 0, int> const&, int&, std::vector<double, std::allocator<double> >&, std::vector<int, std::allocator<int> >&, std::vector<int, std::allocator<int> >&);
+#endif
diff --git a/xs/src/igl/harwell_boeing.h b/xs/src/igl/harwell_boeing.h
new file mode 100644
index 000000000..df166ab82
--- /dev/null
+++ b/xs/src/igl/harwell_boeing.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HARWELL_BOEING_H
+#define IGL_HARWELL_BOEING_H
+#include "igl_inline.h"
+
+#include <Eigen/Sparse>
+#include <vector>
+
+
+namespace igl
+{
+ // Convert the matrix to Compressed sparse column (CSC or CCS) format,
+ // also known as Harwell Boeing format. As described:
+ // http://netlib.org/linalg/html_templates/node92.html
+ // or
+ // http://en.wikipedia.org/wiki/Sparse_matrix
+ // #Compressed_sparse_column_.28CSC_or_CCS.29
+ // Templates:
+ // Scalar type of sparse matrix like double
+ // Inputs:
+ // A sparse m by n matrix
+ // Outputs:
+ // num_rows number of rows
+ // V non-zero values, row indices running fastest, size(V) = nnz
+ // R row indices corresponding to vals, size(R) = nnz
+ // C index in vals of first entry in each column, size(C) = num_cols+1
+ //
+ // All indices and pointers are 0-based
+ template <typename Scalar, typename Index>
+ IGL_INLINE void harwell_boeing(
+ const Eigen::SparseMatrix<Scalar> & A,
+ int & num_rows,
+ std::vector<Scalar> & V,
+ std::vector<Index> & R,
+ std::vector<Index> & C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "harwell_boeing.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/hausdorff.cpp b/xs/src/igl/hausdorff.cpp
new file mode 100644
index 000000000..9b1ad4743
--- /dev/null
+++ b/xs/src/igl/hausdorff.cpp
@@ -0,0 +1,89 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "hausdorff.h"
+#include "point_mesh_squared_distance.h"
+
+template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename Scalar>
+IGL_INLINE void igl::hausdorff(
+ const Eigen::PlainObjectBase<DerivedVA> & VA,
+ const Eigen::PlainObjectBase<DerivedFA> & FA,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ Scalar & d)
+{
+ using namespace Eigen;
+ assert(VA.cols() == 3 && "VA should contain 3d points");
+ assert(FA.cols() == 3 && "FA should contain triangles");
+ assert(VB.cols() == 3 && "VB should contain 3d points");
+ assert(FB.cols() == 3 && "FB should contain triangles");
+ Matrix<Scalar,Dynamic,1> sqr_DBA,sqr_DAB;
+ Matrix<typename DerivedVA::Index,Dynamic,1> I;
+ Matrix<typename DerivedVA::Scalar,Dynamic,3> C;
+ point_mesh_squared_distance(VB,VA,FA,sqr_DBA,I,C);
+ point_mesh_squared_distance(VA,VB,FB,sqr_DAB,I,C);
+ const Scalar dba = sqr_DBA.maxCoeff();
+ const Scalar dab = sqr_DAB.maxCoeff();
+ d = sqrt(std::max(dba,dab));
+}
+
+template <
+ typename DerivedV,
+ typename Scalar>
+IGL_INLINE void igl::hausdorff(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const std::function<Scalar(const Scalar &,const Scalar &, const Scalar &)> & dist_to_B,
+ Scalar & l,
+ Scalar & u)
+{
+ // e 3-long vector of opposite edge lengths
+ Eigen::Matrix<typename DerivedV::Scalar,1,3> e;
+ // Maximum edge length
+ Scalar e_max = 0;
+ for(int i=0;i<3;i++)
+ {
+ e(i) = (V.row((i+1)%3)-V.row((i+2)%3)).norm();
+ e_max = std::max(e_max,e(i));
+ }
+ // Semiperimeter
+ const Scalar s = (e(0)+e(1)+e(2))*0.5;
+ // Area
+ const Scalar A = sqrt(s*(s-e(0))*(s-e(1))*(s-e(2)));
+ // Circumradius
+ const Scalar R = e(0)*e(1)*e(2)/(4.*A);
+ // inradius
+ const Scalar r = A/s;
+ // Initialize lower bound to ∞
+ l = std::numeric_limits<Scalar>::infinity();
+ // d 3-long vector of distance from each corner to B
+ Eigen::Matrix<typename DerivedV::Scalar,1,3> d;
+ Scalar u1 = std::numeric_limits<Scalar>::infinity();
+ Scalar u2 = 0;
+ for(int i=0;i<3;i++)
+ {
+ d(i) = dist_to_B(V(i,0),V(i,1),V(i,2));
+ // Lower bound is simply the max over vertex distances
+ l = std::max(d(i),l);
+ // u1 is the minimum of corner distances + maximum adjacent edge
+ u1 = std::min(u1,d(i) + std::max(e((i+1)%3),e((i+2)%3)));
+ // u2 first takes the maximum over corner distances
+ u2 = std::max(u2,d(i));
+ }
+ // u2 is the distance from the circumcenter/midpoint of obtuse edge plus the
+ // largest corner distance
+ u2 += (s-r>2.*R ? R : 0.5*e_max);
+ u = std::min(u1,u2);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::hausdorff<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double&);
+#endif
diff --git a/xs/src/igl/hausdorff.h b/xs/src/igl/hausdorff.h
new file mode 100644
index 000000000..92e22b333
--- /dev/null
+++ b/xs/src/igl/hausdorff.h
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HAUSDORFF_H
+#define IGL_HAUSDORFF_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <functional>
+
+namespace igl
+{
+ // HAUSDORFF compute the Hausdorff distance between mesh (VA,FA) and mesh
+ // (VB,FB). This is the
+ //
+ // d(A,B) = max ( max min d(a,b) , max min d(b,a) )
+ // a∈A b∈B b∈B a∈A
+ //
+ // Known issue: This is only computing max(min(va,B),min(vb,A)). This is
+ // better than max(min(va,Vb),min(vb,Va)). This (at least) is missing
+ // "edge-edge" cases like the distance between the two different
+ // triangulations of a non-planar quad in 3D. Even simpler, consider the
+ // Hausdorff distance between the non-convex, block letter V polygon (with 7
+ // vertices) in 2D and its convex hull. The Hausdorff distance is defined by
+ // the midpoint in the middle of the segment across the concavity and some
+ // non-vertex point _on the edge_ of the V.
+ //
+ // Inputs:
+ // VA #VA by 3 list of vertex positions
+ // FA #FA by 3 list of face indices into VA
+ // VB #VB by 3 list of vertex positions
+ // FB #FB by 3 list of face indices into VB
+ // Outputs:
+ // d hausdorff distance
+ // //pair 2 by 3 list of "determiner points" so that pair(1,:) is from A
+ // // and pair(2,:) is from B
+ //
+ template <
+ typename DerivedVA,
+ typename DerivedFA,
+ typename DerivedVB,
+ typename DerivedFB,
+ typename Scalar>
+ IGL_INLINE void hausdorff(
+ const Eigen::PlainObjectBase<DerivedVA> & VA,
+ const Eigen::PlainObjectBase<DerivedFA> & FA,
+ const Eigen::PlainObjectBase<DerivedVB> & VB,
+ const Eigen::PlainObjectBase<DerivedFB> & FB,
+ Scalar & d);
+ // Compute lower and upper bounds (l,u) on the Hausdorff distance between a triangle
+ // (V) and a pointset (e.g., mesh, triangle soup) given by a distance function
+ // handle (dist_to_B).
+ //
+ // Inputs:
+ // V 3 by 3 list of corner positions so that V.row(i) is the position of the
+ // ith corner
+ // dist_to_B function taking the x,y,z coordinate of a query position and
+ // outputting the closest-point distance to some point-set B
+ // Outputs:
+ // l lower bound on Hausdorff distance
+ // u upper bound on Hausdorff distance
+ //
+ template <
+ typename DerivedV,
+ typename Scalar>
+ IGL_INLINE void hausdorff(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const std::function<
+ Scalar(const Scalar &,const Scalar &, const Scalar &)> & dist_to_B,
+ Scalar & l,
+ Scalar & u);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "hausdorff.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/hessian.cpp b/xs/src/igl/hessian.cpp
new file mode 100644
index 000000000..ebf81cd7d
--- /dev/null
+++ b/xs/src/igl/hessian.cpp
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+// and Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "hessian.h"
+#include <vector>
+
+#include "grad.h"
+#include "igl/doublearea.h"
+#include "igl/repdiag.h"
+
+
+
+template <typename DerivedV, typename DerivedF, typename Scalar>
+IGL_INLINE void igl::hessian(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& H)
+{
+ typedef typename DerivedV::Scalar denseScalar;
+ typedef typename Eigen::Matrix<denseScalar, Eigen::Dynamic, 1> VecXd;
+ typedef typename Eigen::SparseMatrix<Scalar> SparseMat;
+ typedef typename Eigen::DiagonalMatrix
+ <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
+
+ int dim = V.cols();
+ assert((dim==2 || dim==3) &&
+ "The dimension of the vertices should be 2 or 3");
+
+ //Construct the combined gradient matric
+ SparseMat G;
+ igl::grad(DerivedV(V),
+ DerivedF(F),
+ G, false);
+ SparseMat GG(F.rows(), dim*V.rows());
+ GG.reserve(G.nonZeros());
+ for(int i=0; i<dim; ++i)
+ GG.middleCols(i*G.cols(),G.cols()) = G.middleRows(i*F.rows(),F.rows());
+ SparseMat D;
+ igl::repdiag(GG,dim,D);
+
+ //Compute area matrix
+ VecXd areas;
+ igl::doublearea(V, F, areas);
+ DiagMat A = (0.5*areas).replicate(dim,1).asDiagonal();
+
+ //Compute FEM Hessian
+ H = D.transpose()*A*G;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::hessian<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/hessian.h b/xs/src/igl/hessian.h
new file mode 100644
index 000000000..360750d2c
--- /dev/null
+++ b/xs/src/igl/hessian.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+// and Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_FEM_HESSIAN_H
+#define IGL_FEM_HESSIAN_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+
+namespace igl
+{
+ // Constructs the finite element Hessian matrix
+ // as described in https://arxiv.org/abs/1707.04348,
+ // Natural Boundary Conditions for Smoothing in Geometry Processing
+ // (Oded Stein, Eitan Grinspun, Max Wardetzky, Alec Jacobson)
+ // The interior vertices are NOT set to zero yet.
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by 3 list of mesh faces (must be triangles)
+ // Outputs:
+ // H #V by #V Hessian energy matrix, each column i
+ // corresponding to V(i,:)
+ //
+ //
+ //
+ template <typename DerivedV, typename DerivedF, typename Scalar>
+ IGL_INLINE void hessian(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& H);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "hessian.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/hessian_energy.cpp b/xs/src/igl/hessian_energy.cpp
new file mode 100644
index 000000000..fa0b10a7d
--- /dev/null
+++ b/xs/src/igl/hessian_energy.cpp
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+// and Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "hessian_energy.h"
+#include <vector>
+
+#include "hessian.h"
+#include "massmatrix.h"
+#include "boundary_loop.h"
+
+
+template <typename DerivedV, typename DerivedF, typename Scalar>
+IGL_INLINE void igl::hessian_energy(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& Q)
+{
+ typedef typename DerivedV::Scalar denseScalar;
+ typedef typename Eigen::Matrix<denseScalar, Eigen::Dynamic, 1> VecXd;
+ typedef typename Eigen::SparseMatrix<Scalar> SparseMat;
+ typedef typename Eigen::DiagonalMatrix
+ <Scalar, Eigen::Dynamic, Eigen::Dynamic> DiagMat;
+
+ int dim = V.cols();
+ assert((dim==2 || dim==3) &&
+ "The dimension of the vertices should be 2 or 3");
+
+ SparseMat M;
+ igl::massmatrix(V,F,igl::MASSMATRIX_TYPE_VORONOI,M);
+
+ //Kill non-interior DOFs
+ VecXd Mint = M.diagonal();
+ std::vector<std::vector<int> > bdryLoop;
+ igl::boundary_loop(DerivedF(F),bdryLoop);
+ for(const std::vector<int>& loop : bdryLoop)
+ for(const int& bdryVert : loop)
+ Mint(bdryVert) = 0.;
+
+ //Invert Mint
+ for(int i=0; i<Mint.rows(); ++i)
+ if(Mint(i) > 0)
+ Mint(i) = 1./Mint(i);
+
+ //Repeat Mint to form diaginal matrix
+ DiagMat stackedMinv = Mint.replicate(dim*dim,1).asDiagonal();
+
+ //Compute squared Hessian
+ SparseMat H;
+ igl::hessian(V,F,H);
+ Q = H.transpose()*stackedMinv*H;
+
+}
+
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::hessian_energy<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/hessian_energy.h b/xs/src/igl/hessian_energy.h
new file mode 100644
index 000000000..e53373580
--- /dev/null
+++ b/xs/src/igl/hessian_energy.h
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+// and Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HESSIAN_ENERGY_H
+#define IGL_HESSIAN_ENERGY_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+
+namespace igl
+{
+ // Constructs the Hessian energy matrix using mixed FEM
+ // as described in https://arxiv.org/abs/1707.04348
+ // Natural Boundary Conditions for Smoothing in Geometry Processing
+ // (Oded Stein, Eitan Grinspun, Max Wardetzky, Alec Jacobson)
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by 3 list of mesh faces (must be triangles)
+ // Outputs:
+ // Q #V by #V Hessian energy matrix, each row/column i
+ // corresponding to V(i,:)
+ //
+ //
+ //
+ template <typename DerivedV, typename DerivedF, typename Scalar>
+ IGL_INLINE void hessian_energy(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& Q);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "hessian_energy.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/histc.cpp b/xs/src/igl/histc.cpp
new file mode 100644
index 000000000..3f967b3be
--- /dev/null
+++ b/xs/src/igl/histc.cpp
@@ -0,0 +1,113 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "histc.h"
+#include <cassert>
+#include <iostream>
+
+template <typename DerivedX, typename DerivedE, typename DerivedN, typename DerivedB>
+IGL_INLINE void igl::histc(
+ const Eigen::MatrixBase<DerivedX > & X,
+ const Eigen::MatrixBase<DerivedE > & E,
+ Eigen::PlainObjectBase<DerivedN > & N,
+ Eigen::PlainObjectBase<DerivedB > & B)
+{
+ histc(X,E,B);
+ const int n = E.size();
+ const int m = X.size();
+ assert(m == B.size());
+ N.resize(n,1);
+ N.setConstant(0);
+#pragma omp parallel for
+ for(int j = 0;j<m;j++)
+ {
+ if(B(j) >= 0)
+ {
+#pragma omp atomic
+ N(B(j))++;
+ }
+ }
+}
+
+template <typename DerivedX, typename DerivedE, typename DerivedB>
+IGL_INLINE void igl::histc(
+ const Eigen::MatrixBase<DerivedX > & X,
+ const Eigen::MatrixBase<DerivedE > & E,
+ Eigen::PlainObjectBase<DerivedB > & B)
+{
+ const int m = X.size();
+ using namespace std;
+ assert(
+ (E.bottomRightCorner(E.size()-1,1) -
+ E.topLeftCorner(E.size()-1,1)).maxCoeff() >= 0 &&
+ "E should be monotonically increasing");
+ B.resize(m,1);
+#pragma omp parallel for
+ for(int j = 0;j<m;j++)
+ {
+ const double x = X(j);
+ // Boring one-offs
+ if(x < E(0) || x > E(E.size()-1))
+ {
+ B(j) = -1;
+ continue;
+ }
+ // Find x in E
+ int l = 0;
+ int h = E.size()-1;
+ int k = l;
+ while((h-l)>1)
+ {
+ assert(x >= E(l));
+ assert(x <= E(h));
+ k = (h+l)/2;
+ if(x < E(k))
+ {
+ h = k;
+ }else
+ {
+ l = k;
+ }
+ }
+ if(x == E(h))
+ {
+ k = h;
+ }else
+ {
+ k = l;
+ }
+ B(j) = k;
+ }
+}
+
+template <typename DerivedE>
+IGL_INLINE void igl::histc(
+ const typename DerivedE::Scalar & x,
+ const Eigen::MatrixBase<DerivedE > & E,
+ typename DerivedE::Index & b)
+{
+ Eigen::Matrix<typename DerivedE::Scalar,1,1> X;
+ X(0) = x;
+ Eigen::Matrix<typename DerivedE::Index,1,1> B;
+ hist(X,E,B);
+ b = B(0);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::histc<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::histc<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::histc<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::histc<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::histc<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+#else
+template void igl::histc<Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<int, true>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<int, true>, Eigen::Matrix<int, -1, 1, 0, -1, 1> > > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
+
+#endif
diff --git a/xs/src/igl/histc.h b/xs/src/igl/histc.h
new file mode 100644
index 000000000..2f0ed9135
--- /dev/null
+++ b/xs/src/igl/histc.h
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HISTC_H
+#define IGL_HISTC_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Like matlab's histc. Count occurrences of values in X between consecutive
+ // entries in E
+ //
+ // Inputs:
+ // X m-long Vector of values
+ // E n-long Monotonically increasing vector of edges
+ // Outputs:
+ // N n-long vector where N(k) reveals how many values in X fall between
+ // E(k) <= X < E(k+1)
+ // B m-long vector of bin ids so that B(j) = k if E(k) <= X(j) < E(k+1).
+ // B(j) = -1 if X(j) is outside of E.
+ //
+ // O(n+m*log(n))
+ template <typename DerivedX, typename DerivedE, typename DerivedN, typename DerivedB>
+ IGL_INLINE void histc(
+ const Eigen::MatrixBase<DerivedX > & X,
+ const Eigen::MatrixBase<DerivedE > & E,
+ Eigen::PlainObjectBase<DerivedN > & N,
+ Eigen::PlainObjectBase<DerivedB > & B);
+ // Truly O(m*log(n))
+ template <typename DerivedX, typename DerivedE, typename DerivedB>
+ IGL_INLINE void histc(
+ const Eigen::MatrixBase<DerivedX > & X,
+ const Eigen::MatrixBase<DerivedE > & E,
+ Eigen::PlainObjectBase<DerivedB > & B);
+ // Scalar search wrapper
+ template <typename DerivedE>
+ IGL_INLINE void histc(
+ const typename DerivedE::Scalar & x,
+ const Eigen::MatrixBase<DerivedE > & E,
+ typename DerivedE::Index & b);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "histc.cpp"
+#endif
+
+#endif
+
+
+
diff --git a/xs/src/igl/hsv_to_rgb.cpp b/xs/src/igl/hsv_to_rgb.cpp
new file mode 100644
index 000000000..a1727ff50
--- /dev/null
+++ b/xs/src/igl/hsv_to_rgb.cpp
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "hsv_to_rgb.h"
+#include <cmath>
+
+
+template <typename T>
+IGL_INLINE void igl::hsv_to_rgb(const T * hsv, T * rgb)
+{
+ igl::hsv_to_rgb(
+ hsv[0],hsv[1],hsv[2],
+ rgb[0],rgb[1],rgb[2]);
+}
+
+template <typename T>
+IGL_INLINE void igl::hsv_to_rgb(
+ const T & h, const T & s, const T & v,
+ T & r, T & g, T & b)
+{
+ // From medit
+ double f,p,q,t,hh;
+ int i;
+ hh = ((int)h % 360) / 60.;
+ i = (int)std::floor(hh); /* largest int <= h */
+ f = hh - i; /* fractional part of h */
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ switch(i) {
+ case 0: r = v; g = t; b = p; break;
+ case 1: r = q; g = v; b = p; break;
+ case 2: r = p; g = v; b = t; break;
+ case 3: r = p; g = q; b = v; break;
+ case 4: r = t; g = p; b = v; break;
+ case 5: r = v; g = p; b = q; break;
+ }
+}
+
+template <typename DerivedH, typename DerivedR>
+void igl::hsv_to_rgb(
+ const Eigen::PlainObjectBase<DerivedH> & H,
+ Eigen::PlainObjectBase<DerivedR> & R)
+{
+ assert(H.cols() == 3);
+ R.resizeLike(H);
+ for(typename DerivedH::Index r = 0;r<H.rows();r++)
+ {
+ typename DerivedH::Scalar hsv[3];
+ hsv[0] = H(r,0);
+ hsv[1] = H(r,1);
+ hsv[2] = H(r,2);
+ typename DerivedR::Scalar rgb[] = {0,0,0};
+ hsv_to_rgb(hsv,rgb);
+ R(r,0) = rgb[0];
+ R(r,1) = rgb[1];
+ R(r,2) = rgb[2];
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::hsv_to_rgb<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::hsv_to_rgb<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+template void igl::hsv_to_rgb<Eigen::Matrix<unsigned char, 64, 3, 1, 64, 3>, Eigen::Matrix<unsigned char, 64, 3, 1, 64, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<unsigned char, 64, 3, 1, 64, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned char, 64, 3, 1, 64, 3> >&);
+template void igl::hsv_to_rgb<Eigen::Matrix<float, 64, 3, 1, 64, 3>, Eigen::Matrix<float, 64, 3, 1, 64, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 64, 3, 1, 64, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 64, 3, 1, 64, 3> >&);
+template void igl::hsv_to_rgb<double>(double const*, double*);
+#endif
diff --git a/xs/src/igl/hsv_to_rgb.h b/xs/src/igl/hsv_to_rgb.h
new file mode 100644
index 000000000..aeb64d9d3
--- /dev/null
+++ b/xs/src/igl/hsv_to_rgb.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_HSV_TO_RGB_H
+#define IGL_HSV_TO_RGB_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Convert RGB to HSV
+ //
+ // Inputs:
+ // h hue value (degrees: [0,360])
+ // s saturation value ([0,1])
+ // v value value ([0,1])
+ // Outputs:
+ // r red value ([0,1])
+ // g green value ([0,1])
+ // b blue value ([0,1])
+ template <typename T>
+ IGL_INLINE void hsv_to_rgb(const T * hsv, T * rgb);
+ template <typename T>
+ IGL_INLINE void hsv_to_rgb(
+ const T & h, const T & s, const T & v,
+ T & r, T & g, T & b);
+ template <typename DerivedH, typename DerivedR>
+ void hsv_to_rgb(
+ const Eigen::PlainObjectBase<DerivedH> & H,
+ Eigen::PlainObjectBase<DerivedR> & R);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "hsv_to_rgb.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/igl_inline.h b/xs/src/igl/igl_inline.h
new file mode 100644
index 000000000..20c9630e4
--- /dev/null
+++ b/xs/src/igl/igl_inline.h
@@ -0,0 +1,18 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+// This should *NOT* be contained in a IGL_*_H ifdef, since it may be defined
+// differently based on when it is included
+#ifdef IGL_INLINE
+#undef IGL_INLINE
+#endif
+
+#ifndef IGL_STATIC_LIBRARY
+# define IGL_INLINE inline
+#else
+# define IGL_INLINE
+#endif
diff --git a/xs/src/igl/in_element.cpp b/xs/src/igl/in_element.cpp
new file mode 100644
index 000000000..dcdfd8a89
--- /dev/null
+++ b/xs/src/igl/in_element.cpp
@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "in_element.h"
+
+template <typename DerivedV, typename DerivedQ, int DIM>
+IGL_INLINE void igl::in_element(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::MatrixXi & Ele,
+ const Eigen::PlainObjectBase<DerivedQ> & Q,
+ const AABB<DerivedV,DIM> & aabb,
+ Eigen::VectorXi & I)
+{
+ using namespace std;
+ using namespace Eigen;
+ const int Qr = Q.rows();
+ I.setConstant(Qr,1,-1);
+#pragma omp parallel for if (Qr>10000)
+ for(int e = 0;e<Qr;e++)
+ {
+ // find all
+ const auto R = aabb.find(V,Ele,Q.row(e).eval(),true);
+ if(!R.empty())
+ {
+ I(e) = R[0];
+ }
+ }
+}
+
+template <typename DerivedV, typename DerivedQ, int DIM, typename Scalar>
+IGL_INLINE void igl::in_element(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::MatrixXi & Ele,
+ const Eigen::PlainObjectBase<DerivedQ> & Q,
+ const AABB<DerivedV,DIM> & aabb,
+ Eigen::SparseMatrix<Scalar> & I)
+{
+ using namespace std;
+ using namespace Eigen;
+ const int Qr = Q.rows();
+ std::vector<Triplet<Scalar> > IJV;
+ IJV.reserve(Qr);
+#pragma omp parallel for if (Qr>10000)
+ for(int e = 0;e<Qr;e++)
+ {
+ // find all
+ const auto R = aabb.find(V,Ele,Q.row(e).eval(),false);
+ for(const auto r : R)
+ {
+#pragma omp critical
+ IJV.push_back(Triplet<Scalar>(e,r,1));
+ }
+ }
+ I.resize(Qr,Ele.rows());
+ I.setFromTriplets(IJV.begin(),IJV.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::in_element<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 2> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+template void igl::in_element<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+#endif
diff --git a/xs/src/igl/in_element.h b/xs/src/igl/in_element.h
new file mode 100644
index 000000000..dcbc03aa6
--- /dev/null
+++ b/xs/src/igl/in_element.h
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IN_ELEMENT_H
+#define IGL_IN_ELEMENT_H
+
+#include "igl_inline.h"
+#include "AABB.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Determine whether each point in a list of points is in the elements of a
+ // mesh.
+ //
+ // templates:
+ // DIM dimension of vertices in V (# of columns)
+ // Inputs:
+ // V #V by dim list of mesh vertex positions.
+ // Ele #Ele by dim+1 list of mesh indices into #V.
+ // Q #Q by dim list of query point positions
+ // aabb axis-aligned bounding box tree object (see AABB.h)
+ // Outputs:
+ // I #Q list of indices into Ele of first containing element (-1 means no
+ // containing element)
+ template <typename DerivedV, typename DerivedQ, int DIM>
+ IGL_INLINE void in_element(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::MatrixXi & Ele,
+ const Eigen::PlainObjectBase<DerivedQ> & Q,
+ const AABB<DerivedV,DIM> & aabb,
+ Eigen::VectorXi & I);
+ // Outputs:
+ // I #Q by #Ele sparse matrix revealing whether each element contains each
+ // point: I(q,e) means point q is in element e
+ template <typename DerivedV, typename DerivedQ, int DIM, typename Scalar>
+ IGL_INLINE void in_element(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::MatrixXi & Ele,
+ const Eigen::PlainObjectBase<DerivedQ> & Q,
+ const AABB<DerivedV,DIM> & aabb,
+ Eigen::SparseMatrix<Scalar> & I);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+#include "in_element.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/infinite_cost_stopping_condition.cpp b/xs/src/igl/infinite_cost_stopping_condition.cpp
new file mode 100644
index 000000000..033f2b678
--- /dev/null
+++ b/xs/src/igl/infinite_cost_stopping_condition.cpp
@@ -0,0 +1,108 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "infinite_cost_stopping_condition.h"
+
+IGL_INLINE void igl::infinite_cost_stopping_condition(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> & stopping_condition)
+{
+ stopping_condition =
+ [&cost_and_placement]
+ (
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ const std::set<std::pair<double,int> > & Q,
+ const std::vector<std::set<std::pair<double,int> >::iterator > & Qit,
+ const Eigen::MatrixXd & C,
+ const int e,
+ const int /*e1*/,
+ const int /*e2*/,
+ const int /*f1*/,
+ const int /*f2*/)->bool
+ {
+ Eigen::RowVectorXd p;
+ double cost;
+ cost_and_placement(e,V,F,E,EMAP,EF,EI,cost,p);
+ return std::isinf(cost);
+ };
+}
+
+IGL_INLINE
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)>
+ igl::infinite_cost_stopping_condition(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement)
+{
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> stopping_condition;
+ infinite_cost_stopping_condition(cost_and_placement,stopping_condition);
+ return stopping_condition;
+}
+
diff --git a/xs/src/igl/infinite_cost_stopping_condition.h b/xs/src/igl/infinite_cost_stopping_condition.h
new file mode 100644
index 000000000..d37e98025
--- /dev/null
+++ b/xs/src/igl/infinite_cost_stopping_condition.h
@@ -0,0 +1,85 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_INFINITE_COST_STOPPING_CONDITION_H
+#define IGL_INFINITE_COST_STOPPING_CONDITION_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include <set>
+#include <functional>
+namespace igl
+{
+ // Stopping condition function compatible with igl::decimate. The output
+ // function handle will return true if cost of next edge is infinite.
+ //
+ // Inputs:
+ // cost_and_placement handle being used by igl::collapse_edge
+ // Outputs:
+ // stopping_condition
+ //
+ IGL_INLINE void infinite_cost_stopping_condition(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> & stopping_condition);
+ IGL_INLINE
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)>
+ infinite_cost_stopping_condition(
+ const std::function<void(
+ const int,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "infinite_cost_stopping_condition.cpp"
+#endif
+#endif
+
+
diff --git a/xs/src/igl/inradius.cpp b/xs/src/igl/inradius.cpp
new file mode 100644
index 000000000..d5a06ab50
--- /dev/null
+++ b/xs/src/igl/inradius.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "inradius.h"
+#include "edge_lengths.h"
+#include "doublearea.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedR>
+IGL_INLINE void igl::inradius(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedR> & r)
+{
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> l;
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,1> R;
+ igl::edge_lengths(V,F,l);
+ // If R is the circumradius,
+ // R*r = (abc)/(2*(a+b+c))
+ // R = abc/(4*area)
+ // r(abc/(4*area)) = (abc)/(2*(a+b+c))
+ // r/(4*area) = 1/(2*(a+b+c))
+ // r = (2*area)/(a+b+c)
+ DerivedR A;
+ igl::doublearea(l,0.,A);
+ r = A.array() /l.array().rowwise().sum();
+}
diff --git a/xs/src/igl/inradius.h b/xs/src/igl/inradius.h
new file mode 100644
index 000000000..07166b4b9
--- /dev/null
+++ b/xs/src/igl/inradius.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_INRADIUS_H
+#define IGL_INRADIUS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute the inradius 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 inradii
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedR>
+ IGL_INLINE void inradius(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedR> & R);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "inradius.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/internal_angles.cpp b/xs/src/igl/internal_angles.cpp
new file mode 100644
index 000000000..5c6e8dfbe
--- /dev/null
+++ b/xs/src/igl/internal_angles.cpp
@@ -0,0 +1,130 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+// Copyright (C) 2015 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "internal_angles.h"
+#include "squared_edge_lengths.h"
+#include "parallel_for.h"
+#include "get_seconds.h"
+
+template <typename DerivedV, typename DerivedF, typename DerivedK>
+IGL_INLINE void igl::internal_angles(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedK> & K)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef typename DerivedV::Scalar Scalar;
+ if(F.cols() == 3)
+ {
+ // Edge lengths
+ Matrix<
+ Scalar,
+ DerivedF::RowsAtCompileTime,
+ DerivedF::ColsAtCompileTime> L_sq;
+ igl::squared_edge_lengths(V,F,L_sq);
+
+ assert(F.cols() == 3 && "F should contain triangles");
+ igl::internal_angles_using_squared_edge_lengths(L_sq,K);
+ }else
+ {
+ assert(V.cols() == 3 && "If F contains non-triangle facets, V must be 3D");
+ K.resizeLike(F);
+ auto corner = [](
+ const typename DerivedV::ConstRowXpr & x,
+ const typename DerivedV::ConstRowXpr & y,
+ const typename DerivedV::ConstRowXpr & z)
+ {
+ typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
+ RowVector3S v1 = (x-y).normalized();
+ RowVector3S v2 = (z-y).normalized();
+ // http://stackoverflow.com/questions/10133957/signed-angle-between-two-vectors-without-a-reference-plane
+ Scalar s = v1.cross(v2).norm();
+ Scalar c = v1.dot(v2);
+ return atan2(s, c);
+ };
+ for(unsigned i=0; i<F.rows(); ++i)
+ {
+ for(unsigned j=0; j<F.cols(); ++j)
+ {
+ K(i,j) = corner(
+ V.row(F(i,int(j-1+F.cols())%F.cols())),
+ V.row(F(i,j)),
+ V.row(F(i,(j+1+F.cols())%F.cols()))
+ );
+ }
+ }
+ }
+}
+
+template <typename DerivedL, typename DerivedK>
+IGL_INLINE void igl::internal_angles_using_squared_edge_lengths(
+ const Eigen::MatrixBase<DerivedL>& L_sq,
+ Eigen::PlainObjectBase<DerivedK> & K)
+{
+ typedef typename DerivedL::Index Index;
+ assert(L_sq.cols() == 3 && "Edge-lengths should come from triangles");
+ const Index m = L_sq.rows();
+ K.resize(m,3);
+ parallel_for(
+ m,
+ [&L_sq,&K](const Index f)
+ {
+ for(size_t d = 0;d<3;d++)
+ {
+ const auto & s1 = L_sq(f,d);
+ const auto & s2 = L_sq(f,(d+1)%3);
+ const auto & s3 = L_sq(f,(d+2)%3);
+ K(f,d) = acos((s3 + s2 - s1)/(2.*sqrt(s3*s2)));
+ }
+ },
+ 1000l);
+}
+
+template <typename DerivedL, typename DerivedK>
+IGL_INLINE void igl::internal_angles_using_edge_lengths(
+ const Eigen::MatrixBase<DerivedL>& L,
+ Eigen::PlainObjectBase<DerivedK> & K)
+{
+ // Note:
+ // Usage of internal_angles_using_squared_edge_lengths() is preferred to internal_angles_using_squared_edge_lengths()
+ // This function is deprecated and probably will be removed in future versions
+ typedef typename DerivedL::Index Index;
+ assert(L.cols() == 3 && "Edge-lengths should come from triangles");
+ const Index m = L.rows();
+ K.resize(m,3);
+ parallel_for(
+ m,
+ [&L,&K](const Index f)
+ {
+ for(size_t d = 0;d<3;d++)
+ {
+ const auto & s1 = L(f,d);
+ const auto & s2 = L(f,(d+1)%3);
+ const auto & s3 = L(f,(d+2)%3);
+ K(f,d) = acos((s3*s3 + s2*s2 - s1*s1)/(2.*s3*s2));
+ }
+ },
+ 1000l);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::internal_angles<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::internal_angles<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::internal_angles<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::internal_angles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::internal_angles<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::internal_angles<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::internal_angles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::internal_angles<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::internal_angles<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/internal_angles.h b/xs/src/igl/internal_angles.h
new file mode 100644
index 000000000..1dd990ed4
--- /dev/null
+++ b/xs/src/igl/internal_angles.h
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_INTERNAL_ANGLES_H
+#define IGL_INTERNAL_ANGLES_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute internal angles for a triangle mesh
+ //
+ // Inputs:
+ // V #V by dim eigen Matrix of mesh vertex nD positions
+ // F #F by poly-size eigen Matrix of face (triangle) indices
+ // Output:
+ // K #F by poly-size eigen Matrix of internal angles
+ // for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+ //
+ // Known Issues:
+ // if poly-size ≠ 3 then dim must equal 3.
+ template <typename DerivedV, typename DerivedF, typename DerivedK>
+ IGL_INLINE void internal_angles(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedK> & K);
+ // Inputs:
+ // L_sq #F by 3 list of squared edge lengths
+ // Output:
+ // K #F by poly-size eigen Matrix of internal angles
+ // for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+ //
+ // Note:
+ // Usage of internal_angles_using_squared_edge_lengths is preferred to internal_angles_using_squared_edge_lengths
+ template <typename DerivedL, typename DerivedK>
+ IGL_INLINE void internal_angles_using_squared_edge_lengths(
+ const Eigen::MatrixBase<DerivedL>& L_sq,
+ Eigen::PlainObjectBase<DerivedK> & K);
+ // Inputs:
+ // L #F by 3 list of edge lengths
+ // Output:
+ // K #F by poly-size eigen Matrix of internal angles
+ // for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+ //
+ // Note:
+ // Usage of internal_angles_using_squared_edge_lengths is preferred to internal_angles_using_squared_edge_lengths
+ // This function is deprecated and probably will be removed in future versions
+ template <typename DerivedL, typename DerivedK>
+ IGL_INLINE void internal_angles_using_edge_lengths(
+ const Eigen::MatrixBase<DerivedL>& L,
+ Eigen::PlainObjectBase<DerivedK> & K);}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "internal_angles.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/intersect.cpp b/xs/src/igl/intersect.cpp
new file mode 100644
index 000000000..f930fc0be
--- /dev/null
+++ b/xs/src/igl/intersect.cpp
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "intersect.h"
+template <class M>
+IGL_INLINE void igl::intersect(const M & A, const M & B, M & C)
+{
+ // Stupid O(size(A) * size(B)) to do it
+ // Alec: This should be implemented by using unique and sort like `setdiff`
+ M dyn_C(A.size() > B.size() ? A.size() : B.size(),1);
+ // count of intersects
+ int c = 0;
+ // Loop over A
+ for(int i = 0;i<A.size();i++)
+ {
+ // Loop over B
+ for(int j = 0;j<B.size();j++)
+ {
+ if(A(i) == B(j))
+ {
+ dyn_C(c) = A(i);
+ c++;
+ }
+ }
+ }
+
+ // resize output
+ C.resize(c,1);
+ // Loop over intersects
+ for(int i = 0;i<c;i++)
+ {
+ C(i) = dyn_C(i);
+ }
+}
+
+template <class M>
+IGL_INLINE M igl::intersect(const M & A, const M & B)
+{
+ M C;
+ intersect(A,B,C);
+ return C;
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::intersect<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+#endif
diff --git a/xs/src/igl/intersect.h b/xs/src/igl/intersect.h
new file mode 100644
index 000000000..be4da91e5
--- /dev/null
+++ b/xs/src/igl/intersect.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_INTERSECT_H
+#define IGL_INTERSECT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Determine the intersect between two sets of coefficients using ==
+ // Templates:
+ // M matrix type that implements indexing by global index M(i)
+ // Inputs:
+ // A matrix of coefficients
+ // B matrix of coefficients
+ // Output:
+ // C matrix of elements appearing in both A and B, C is always resized to
+ // have a single column
+ template <class M>
+ IGL_INLINE void intersect(const M & A, const M & B, M & C);
+ // Last argument as return
+ template <class M>
+ IGL_INLINE M intersect(const M & A, const M & B);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "intersect.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/invert_diag.cpp b/xs/src/igl/invert_diag.cpp
new file mode 100644
index 000000000..b87a8d5b4
--- /dev/null
+++ b/xs/src/igl/invert_diag.cpp
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "invert_diag.h"
+
+template <typename T>
+IGL_INLINE void igl::invert_diag(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::SparseMatrix<T>& Y)
+{
+#ifndef NDEBUG
+ typename Eigen::SparseVector<T> dX = X.diagonal().sparseView();
+ // Check that there are no zeros along the diagonal
+ assert(dX.nonZeros() == dX.size());
+#endif
+ // http://www.alecjacobson.com/weblog/?p=2552
+ if(&Y != &X)
+ {
+ Y = X;
+ }
+ // Iterate over outside
+ for(int k=0; k<Y.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<T>::InnerIterator it (Y,k); it; ++it)
+ {
+ if(it.col() == it.row())
+ {
+ T v = it.value();
+ assert(v != 0);
+ v = ((T)1.0)/v;
+ Y.coeffRef(it.row(),it.col()) = v;
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::invert_diag<double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::invert_diag<float>(Eigen::SparseMatrix<float, 0, int> const&, Eigen::SparseMatrix<float, 0, int>&);
+#endif
diff --git a/xs/src/igl/invert_diag.h b/xs/src/igl/invert_diag.h
new file mode 100644
index 000000000..2194b3f14
--- /dev/null
+++ b/xs/src/igl/invert_diag.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_INVERT_DIAG_H
+#define IGL_INVERT_DIAG_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Invert the diagonal entries of a matrix (if the matrix is a diagonal
+ // matrix then this amounts to inverting the matrix)
+
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // X an m by n sparse matrix
+ // Outputs:
+ // Y an m by n sparse matrix
+ template <typename T>
+ IGL_INLINE void invert_diag(
+ const Eigen::SparseMatrix<T>& X,
+ Eigen::SparseMatrix<T>& Y);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "invert_diag.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/is_border_vertex.cpp b/xs/src/igl/is_border_vertex.cpp
new file mode 100644
index 000000000..a337609ae
--- /dev/null
+++ b/xs/src/igl/is_border_vertex.cpp
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_border_vertex.h"
+#include <vector>
+
+#include "triangle_triangle_adjacency.h"
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE std::vector<bool> igl::is_border_vertex(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F)
+{
+ DerivedF FF;
+ igl::triangle_triangle_adjacency(F,FF);
+ std::vector<bool> ret(V.rows());
+ for(unsigned i=0; i<ret.size();++i)
+ ret[i] = false;
+
+ for(unsigned i=0; i<F.rows();++i)
+ for(unsigned j=0;j<F.cols();++j)
+ if(FF(i,j) == -1)
+ {
+ ret[F(i,j)] = true;
+ ret[F(i,(j+1)%F.cols())] = true;
+ }
+ return ret;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template std::vector<bool, std::allocator<bool> > igl::is_border_vertex<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+template std::vector<bool, std::allocator<bool> > igl::is_border_vertex<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template std::vector<bool, std::allocator<bool> > igl::is_border_vertex<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/is_border_vertex.h b/xs/src/igl/is_border_vertex.h
new file mode 100644
index 000000000..2e611ac11
--- /dev/null
+++ b/xs/src/igl/is_border_vertex.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_BORDER_VERTEX_H
+#define IGL_IS_BORDER_VERTEX_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Determine vertices on open boundary of a (manifold) mesh with triangle
+ // faces F
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // F #F by 3 list of triangle indices
+ // Returns #V vector of bools revealing whether vertices are on boundary
+ //
+ // Known Bugs: - does not depend on V
+ // - assumes mesh is edge manifold
+ //
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE std::vector<bool> is_border_vertex(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_border_vertex.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_boundary_edge.cpp b/xs/src/igl/is_boundary_edge.cpp
new file mode 100644
index 000000000..679214bbc
--- /dev/null
+++ b/xs/src/igl/is_boundary_edge.cpp
@@ -0,0 +1,122 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_boundary_edge.h"
+#include "unique_rows.h"
+#include "sort.h"
+
+template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DerivedB>
+void igl::is_boundary_edge(
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedB> & B)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Should be triangles
+ assert(F.cols() == 3);
+ // Should be edges
+ assert(E.cols() == 2);
+ // number of faces
+ const int m = F.rows();
+ // Collect all directed edges after E
+ MatrixXi EallE(E.rows()+3*m,2);
+ EallE.block(0,0,E.rows(),E.cols()) = E;
+ for(int e = 0;e<3;e++)
+ {
+ for(int f = 0;f<m;f++)
+ {
+ for(int c = 0;c<2;c++)
+ {
+ // 12 20 01
+ EallE(E.rows()+m*e+f,c) = F(f,(c+1+e)%3);
+ }
+ }
+ }
+ // sort directed edges into undirected edges
+ MatrixXi sorted_EallE,_;
+ sort(EallE,2,true,sorted_EallE,_);
+ // Determine unique undirected edges E and map to directed edges EMAP
+ MatrixXi uE;
+ VectorXi EMAP;
+ unique_rows(sorted_EallE,uE,_,EMAP);
+ // Counts of occurrences
+ VectorXi N = VectorXi::Zero(uE.rows());
+ for(int e = 0;e<EMAP.rows();e++)
+ {
+ N(EMAP(e))++;
+ }
+ B.resize(E.rows());
+ // Look of occurrences of 2: one for original and another for boundary
+ for(int e = 0;e<E.rows();e++)
+ {
+ B(e) = (N(EMAP(e)) == 2);
+ }
+}
+
+
+template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DerivedB,
+ typename DerivedEMAP>
+void igl::is_boundary_edge(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Should be triangles
+ assert(F.cols() == 3);
+ // number of faces
+ const int m = F.rows();
+ // Collect all directed edges after E
+ MatrixXi allE(3*m,2);
+ for(int e = 0;e<3;e++)
+ {
+ for(int f = 0;f<m;f++)
+ {
+ for(int c = 0;c<2;c++)
+ {
+ // 12 20 01
+ allE(m*e+f,c) = F(f,(c+1+e)%3);
+ }
+ }
+ }
+ // sort directed edges into undirected edges
+ MatrixXi sorted_allE,_;
+ sort(allE,2,true,sorted_allE,_);
+ // Determine unique undirected edges E and map to directed edges EMAP
+ unique_rows(sorted_allE,E,_,EMAP);
+ // Counts of occurrences
+ VectorXi N = VectorXi::Zero(E.rows());
+ for(int e = 0;e<EMAP.rows();e++)
+ {
+ N(EMAP(e))++;
+ }
+ B.resize(E.rows());
+ // Look of occurrences of 1
+ for(int e = 0;e<E.rows();e++)
+ {
+ B(e) = N(e) == 1;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation:
+template void igl::is_boundary_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::is_boundary_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
+template void igl::is_boundary_edge<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&);
+template void igl::is_boundary_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::is_boundary_edge<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::is_boundary_edge<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/is_boundary_edge.h b/xs/src/igl/is_boundary_edge.h
new file mode 100644
index 000000000..f68ebb7e4
--- /dev/null
+++ b/xs/src/igl/is_boundary_edge.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IS_BOUNDARY_EDGE_H
+#define IS_BOUNDARY_EDGE_H
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // IS_BOUNDARY_EDGE Determine for each edge E if it is a "boundary edge" in F.
+ // Boundary edges are undirected edges which occur only once.
+ //
+ // Inputs:
+ // E #E by 2 list of edges
+ // F #F by 3 list of triangles
+ // Outputs:
+ // B #E list bools. true iff unoriented edge occurs exactly once in F
+ // (non-manifold and non-existant edges will be false)
+ //
+ template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DerivedB>
+ void is_boundary_edge(
+ const Eigen::PlainObjectBase<DerivedE> & E,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedB> & B);
+ // Wrapper where Edges should also be computed from F
+ // E #E by 2 list of edges
+ // EMAP #F*3 list of indices mapping allE to E
+ template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DerivedB,
+ typename DerivedEMAP>
+ void is_boundary_edge(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_boundary_edge.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_dir.cpp b/xs/src/igl/is_dir.cpp
new file mode 100644
index 000000000..e7346c1dd
--- /dev/null
+++ b/xs/src/igl/is_dir.cpp
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_dir.h"
+
+#include <sys/stat.h>
+
+#ifndef S_ISDIR
+#define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR)
+#endif
+
+#ifndef S_ISREG
+#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+#endif
+
+IGL_INLINE bool igl::is_dir(const char * filename)
+{
+ struct stat status;
+ if(stat(filename,&status)!=0)
+ {
+ // path does not exist
+ return false;
+ }
+ // Tests whether existing path is a directory
+ return S_ISDIR(status.st_mode);
+}
diff --git a/xs/src/igl/is_dir.h b/xs/src/igl/is_dir.h
new file mode 100644
index 000000000..68e30a564
--- /dev/null
+++ b/xs/src/igl/is_dir.h
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_DIR_H
+#define IGL_IS_DIR_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Act like php's is_dir function
+ // http://php.net/manual/en/function.is-dir.php
+ // Tells whether the given filename is a directory.
+ // Input:
+ // filename Path to the file. If filename is a relative filename, it will
+ // be checked relative to the current working directory.
+ // Returns TRUE if the filename exists and is a directory, FALSE
+ // otherwise.
+ IGL_INLINE bool is_dir(const char * filename);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_dir.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_edge_manifold.cpp b/xs/src/igl/is_edge_manifold.cpp
new file mode 100644
index 000000000..1b106056e
--- /dev/null
+++ b/xs/src/igl/is_edge_manifold.cpp
@@ -0,0 +1,104 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_edge_manifold.h"
+#include "oriented_facets.h"
+#include "unique_simplices.h"
+
+#include <algorithm>
+#include <vector>
+
+template <
+ typename DerivedF,
+ typename DerivedBF,
+ typename DerivedE,
+ typename DerivedEMAP,
+ typename DerivedBE>
+IGL_INLINE bool igl::is_edge_manifold(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedBF>& BF,
+ Eigen::PlainObjectBase<DerivedE>& E,
+ Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedBE>& BE)
+{
+ using namespace Eigen;
+ typedef typename DerivedF::Index Index;
+ typedef Matrix<typename DerivedF::Scalar,Dynamic,1> VectorXF;
+ typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixXF2;
+ MatrixXF2 allE;
+ oriented_facets(F,allE);
+ // Find unique undirected edges and mapping
+ VectorXF _;
+ unique_simplices(allE,E,_,EMAP);
+ std::vector<typename DerivedF::Index> count(E.rows(),0);
+ for(Index e = 0;e<EMAP.rows();e++)
+ {
+ count[EMAP[e]]++;
+ }
+ const Index m = F.rows();
+ BF.resize(m,3);
+ BE.resize(E.rows(),1);
+ bool all = true;
+ for(Index e = 0;e<EMAP.rows();e++)
+ {
+ const bool manifold = count[EMAP[e]] <= 2;
+ all &= BF(e%m,e/m) = manifold;
+ BE(EMAP[e]) = manifold;
+ }
+ return all;
+}
+
+template <typename DerivedF>
+IGL_INLINE bool igl::is_edge_manifold(
+ const Eigen::MatrixBase<DerivedF>& F)
+{
+ // TODO: It's bothersome that this is not calling/reusing the code from the
+ // overload above. This could result in disagreement.
+
+ // List of edges (i,j,f,c) where edge i<j is associated with corner i of face
+ // f
+ std::vector<std::vector<int> > TTT;
+ for(int f=0;f<F.rows();++f)
+ for (int i=0;i<3;++i)
+ {
+ // v1 v2 f ei
+ int v1 = F(f,i);
+ int v2 = F(f,(i+1)%3);
+ if (v1 > v2) std::swap(v1,v2);
+ std::vector<int> r(4);
+ r[0] = v1; r[1] = v2;
+ r[2] = f; r[3] = i;
+ TTT.push_back(r);
+ }
+ // Sort lexicographically
+ std::sort(TTT.begin(),TTT.end());
+
+ for(int i=2;i<(int)TTT.size();++i)
+ {
+ // Check any edges occur 3 times
+ std::vector<int>& r1 = TTT[i-2];
+ std::vector<int>& r2 = TTT[i-1];
+ std::vector<int>& r3 = TTT[i];
+ if ( (r1[0] == r2[0] && r2[0] == r3[0])
+ &&
+ (r1[1] == r2[1] && r2[1] == r3[1]) )
+ {
+ return false;
+ }
+ }
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::is_edge_manifold<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&);
+// generated by autoexplicit.sh
+//template bool igl::is_edge_manifold<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&);
+template bool igl::is_edge_manifold<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::is_edge_manifold<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+#endif
diff --git a/xs/src/igl/is_edge_manifold.h b/xs/src/igl/is_edge_manifold.h
new file mode 100644
index 000000000..5832806ac
--- /dev/null
+++ b/xs/src/igl/is_edge_manifold.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_EDGE_MANIFOLD_H
+#define IGL_IS_EDGE_MANIFOLD_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl
+{
+ // check if the mesh is edge-manifold
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions **unneeded**
+ // F #F by 3 list of triangle indices
+ // Returns whether mesh is edge manifold.
+ //
+ // Known Bugs:
+ // Does not check for non-manifold vertices
+ //
+ // See also: is_vertex_manifold
+ template <
+ typename DerivedF,
+ typename DerivedBF,
+ typename DerivedE,
+ typename DerivedEMAP,
+ typename DerivedBE>
+ IGL_INLINE bool is_edge_manifold(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedBF>& BF,
+ Eigen::PlainObjectBase<DerivedE>& E,
+ Eigen::PlainObjectBase<DerivedEMAP>& EMAP,
+ Eigen::PlainObjectBase<DerivedBE>& BE);
+ template <typename DerivedF>
+ IGL_INLINE bool is_edge_manifold(
+ const Eigen::MatrixBase<DerivedF>& F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_edge_manifold.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_file.cpp b/xs/src/igl/is_file.cpp
new file mode 100644
index 000000000..6c040b86c
--- /dev/null
+++ b/xs/src/igl/is_file.cpp
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_file.h"
+
+#include <sys/stat.h>
+#ifdef _WIN32
+# ifndef S_ISREG
+# define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
+# endif
+#endif
+IGL_INLINE bool igl::is_file(const char * filename)
+{
+ struct stat status;
+ if(stat(filename,&status)!=0)
+ {
+ // path does not exist
+ return false;
+ }
+ // Tests whether existing path is a regular file
+ return S_ISREG(status.st_mode);
+}
diff --git a/xs/src/igl/is_file.h b/xs/src/igl/is_file.h
new file mode 100644
index 000000000..5610c7ff3
--- /dev/null
+++ b/xs/src/igl/is_file.h
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_FILE_H
+#define IGL_IS_FILE_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Act like php's is_file function
+ // http://php.net/manual/en/function.is-file.php
+ // Tells whether the given filename is a regular file.
+ // Input:
+ // filename Path to the file. If filename is a relative filename, it will
+ // be checked relative to the current working directory.
+ // Returns TRUE if the filename exists and is a regular file, FALSE
+ // otherwise.
+ IGL_INLINE bool is_file(const char * filename);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_file.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_irregular_vertex.cpp b/xs/src/igl/is_irregular_vertex.cpp
new file mode 100644
index 000000000..34665d66f
--- /dev/null
+++ b/xs/src/igl/is_irregular_vertex.cpp
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_irregular_vertex.h"
+#include <vector>
+
+#include "is_border_vertex.h"
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE std::vector<bool> igl::is_irregular_vertex(const Eigen::PlainObjectBase<DerivedV> &V, const Eigen::PlainObjectBase<DerivedF> &F)
+{
+ Eigen::VectorXi count = Eigen::VectorXi::Zero(F.maxCoeff());
+
+ for(unsigned i=0; i<F.rows();++i)
+ {
+ for(unsigned j=0; j<F.cols();++j)
+ {
+ if (F(i,j) < F(i,(j+1)%F.cols())) // avoid duplicate edges
+ {
+ count(F(i,j )) += 1;
+ count(F(i,(j+1)%F.cols())) += 1;
+ }
+ }
+ }
+
+ std::vector<bool> border = is_border_vertex(V,F);
+
+ std::vector<bool> res(count.size());
+
+ for (unsigned i=0; i<res.size(); ++i)
+ res[i] = !border[i] && count[i] != (F.cols() == 3 ? 6 : 4 );
+
+ return res;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template std::vector<bool, std::allocator<bool> > igl::is_irregular_vertex<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+template std::vector<bool, std::allocator<bool> > igl::is_irregular_vertex<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/is_irregular_vertex.h b/xs/src/igl/is_irregular_vertex.h
new file mode 100644
index 000000000..e07e5ab70
--- /dev/null
+++ b/xs/src/igl/is_irregular_vertex.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_IRREGULAR_VERTEX_H
+#define IGL_IS_IRREGULAR_VERTEX_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Determine if a vertex is irregular, i.e. it has more than 6 (triangles)
+ // or 4 (quads) incident edges. Vertices on the boundary are ignored.
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // F #F by 3[4] list of triangle[quads] indices
+ // Returns #V vector of bools revealing whether vertices are singular
+ //
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE std::vector<bool> is_irregular_vertex(const Eigen::PlainObjectBase<DerivedV> &V, const Eigen::PlainObjectBase<DerivedF> &F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_irregular_vertex.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_planar.cpp b/xs/src/igl/is_planar.cpp
new file mode 100644
index 000000000..6058a03d4
--- /dev/null
+++ b/xs/src/igl/is_planar.cpp
@@ -0,0 +1,18 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_planar.h"
+IGL_INLINE bool igl::is_planar(const Eigen::MatrixXd & V)
+{
+ if(V.size() == 0) return false;
+ if(V.cols() == 2) return true;
+ for(int i = 0;i<V.rows();i++)
+ {
+ if(V(i,2) != 0) return false;
+ }
+ return true;
+}
diff --git a/xs/src/igl/is_planar.h b/xs/src/igl/is_planar.h
new file mode 100644
index 000000000..645403da5
--- /dev/null
+++ b/xs/src/igl/is_planar.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_PLANAR_H
+#define IGL_IS_PLANAR_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Determine if a set of points lies on the XY plane
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // Return true if a mesh has constant value of 0 in z coordinate
+ //
+ // Known bugs: Doesn't determine if vertex is flat if it doesn't lie on the
+ // XY plane.
+ IGL_INLINE bool is_planar(const Eigen::MatrixXd & V);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_planar.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/is_readable.cpp b/xs/src/igl/is_readable.cpp
new file mode 100644
index 000000000..eb5e95347
--- /dev/null
+++ b/xs/src/igl/is_readable.cpp
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_readable.h"
+
+#ifdef _WIN32
+# include <cstdio>
+IGL_INLINE bool igl::is_readable(const char* filename)
+{
+ FILE * f = fopen(filename,"r");
+ if(f == NULL)
+ {
+ return false;
+ }
+ fclose(f);
+ return true;
+}
+#else
+# include <sys/stat.h>
+# include <unistd.h>
+# include <iostream>
+IGL_INLINE bool igl::is_readable(const char* filename)
+{
+ // Check if file already exists
+ struct stat status;
+ if(stat(filename,&status)!=0)
+ {
+ return false;
+ }
+
+ // Get current users uid and gid
+ uid_t this_uid = getuid();
+ gid_t this_gid = getgid();
+
+ // Dealing with owner
+ if( this_uid == status.st_uid )
+ {
+ return S_IRUSR & status.st_mode;
+ }
+
+ // Dealing with group member
+ if( this_gid == status.st_gid )
+ {
+ return S_IRGRP & status.st_mode;
+ }
+
+ // Dealing with other
+ return S_IROTH & status.st_mode;
+
+}
+#endif
diff --git a/xs/src/igl/is_readable.h b/xs/src/igl/is_readable.h
new file mode 100644
index 000000000..689701285
--- /dev/null
+++ b/xs/src/igl/is_readable.h
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_READABLE_H
+#define IGL_IS_READABLE_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Check if a file is reabable like PHP's is_readable function:
+ // http://www.php.net/manual/en/function.is-readable.php
+ // Input:
+ // filename path to file
+ // Returns true if file exists and is readable and false if file doesn't
+ // exist or *is not readable*
+ //
+ // Note: Windows version will not check user or group ids
+ IGL_INLINE bool is_readable(const char * filename);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_readable.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_sparse.cpp b/xs/src/igl/is_sparse.cpp
new file mode 100644
index 000000000..507393d85
--- /dev/null
+++ b/xs/src/igl/is_sparse.cpp
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_sparse.h"
+template <typename T>
+IGL_INLINE bool igl::is_sparse(
+ const Eigen::SparseMatrix<T> & A)
+{
+ return true;
+}
+template <typename DerivedA>
+IGL_INLINE bool igl::is_sparse(
+ const Eigen::PlainObjectBase<DerivedA>& A)
+{
+ return false;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::is_sparse<double>(Eigen::SparseMatrix<double, 0, int> const&);
+// generated by autoexplicit.sh
+template bool igl::is_sparse<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/is_sparse.h b/xs/src/igl/is_sparse.h
new file mode 100644
index 000000000..9547bb8e8
--- /dev/null
+++ b/xs/src/igl/is_sparse.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_SPARSE_H
+#define IGL_IS_SPARSE_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Determine if a matrix A is sparse
+ //
+ // Template:
+ // T,DerivedA defines scalar type
+ // Inputs:
+ // A matrix in question
+ // Returns true if A is represented with a sparse matrix
+ template <typename T>
+ IGL_INLINE bool is_sparse(
+ const Eigen::SparseMatrix<T> & A);
+ template <typename DerivedA>
+ IGL_INLINE bool is_sparse(
+ const Eigen::PlainObjectBase<DerivedA>& A);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_sparse.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/is_stl.cpp b/xs/src/igl/is_stl.cpp
new file mode 100644
index 000000000..240703616
--- /dev/null
+++ b/xs/src/igl/is_stl.cpp
@@ -0,0 +1,64 @@
+#include "is_stl.h"
+#include <string>
+IGL_INLINE bool igl::is_stl(FILE * stl_file, bool & is_ascii)
+{
+
+ // solid?
+ // YES NO
+ // / if .stl, definitely binary
+ // /
+ // perfect size?
+ // YES NO
+ //
+ const auto perfect_size = [](FILE * stl_file)->bool
+ {
+ //stl_file = freopen(NULL,"rb",stl_file);
+ // Read 80 header
+ char header[80];
+ if(fread(header,sizeof(char),80,stl_file)!=80)
+ {
+ return false;
+ }
+ // Read number of triangles
+ unsigned int num_tri;
+ if(fread(&num_tri,sizeof(unsigned int),1,stl_file)!=1)
+ {
+ return false;
+ }
+ fseek(stl_file,0,SEEK_END);
+ int file_size = ftell(stl_file);
+ fseek(stl_file,0,SEEK_SET);
+ //stl_file = freopen(NULL,"r",stl_file);
+ return (file_size == 80 + 4 + (4*12 + 2) * num_tri);
+ };
+ // Specifically 80 character header
+ char header[80];
+ char solid[80];
+ is_ascii = true;
+ bool f = true;
+ if(fread(header,1,80,stl_file) != 80)
+ {
+ f = false;
+ goto finish;
+ }
+
+ sscanf(header,"%s",solid);
+ if(std::string("solid") == solid)
+ {
+ f = true;
+ is_ascii = !perfect_size(stl_file);
+ }else
+ {
+ is_ascii = false;
+ f = perfect_size(stl_file);
+ }
+finish:
+ rewind(stl_file);
+ return f;
+}
+
+IGL_INLINE bool igl::is_stl(FILE * stl_file)
+{
+ bool is_ascii;
+ return is_stl(stl_file,is_ascii);
+}
diff --git a/xs/src/igl/is_stl.h b/xs/src/igl/is_stl.h
new file mode 100644
index 000000000..e8f78df1a
--- /dev/null
+++ b/xs/src/igl/is_stl.h
@@ -0,0 +1,21 @@
+#ifndef IGL_IS_STL_H
+#define IGL_IS_STL_H
+#include "igl_inline.h"
+#include <cstdio>
+namespace igl
+{
+ // Given a file pointer, determine if it contains an .stl file and then
+ // rewind it.
+ //
+ // Inputs:
+ // stl_file pointer to file
+ // Outputs:
+ // is_ascii flag whether stl is ascii
+ // Returns whether stl_file is an .stl file
+ IGL_INLINE bool is_stl(FILE * stl_file, bool & is_ascii);
+ IGL_INLINE bool is_stl(FILE * stl_file);
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "is_stl.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/is_symmetric.cpp b/xs/src/igl/is_symmetric.cpp
new file mode 100644
index 000000000..f40473b66
--- /dev/null
+++ b/xs/src/igl/is_symmetric.cpp
@@ -0,0 +1,73 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_symmetric.h"
+#include "find.h"
+
+template <typename T>
+IGL_INLINE bool igl::is_symmetric(const Eigen::SparseMatrix<T>& A)
+{
+ if(A.rows() != A.cols())
+ {
+ return false;
+ }
+ assert(A.size() != 0);
+ Eigen::SparseMatrix<T> AT = A.transpose();
+ Eigen::SparseMatrix<T> AmAT = A-AT;
+ //// Eigen screws up something with LLT if you try to do
+ //SparseMatrix<T> AmAT = A-A.transpose();
+ //// Eigen crashes at runtime if you try to do
+ // return (A-A.transpose()).nonZeros() == 0;
+ return AmAT.nonZeros() == 0;
+}
+
+template <typename DerivedA>
+IGL_INLINE bool igl::is_symmetric(
+ const Eigen::PlainObjectBase<DerivedA>& A)
+{
+ if(A.rows() != A.cols())
+ {
+ return false;
+ }
+ assert(A.size() != 0);
+ return (A-A.transpose()).eval().nonZeros() == 0;
+}
+
+template <typename AType, typename epsilonT>
+IGL_INLINE bool igl::is_symmetric(
+ const Eigen::SparseMatrix<AType>& A,
+ const epsilonT epsilon)
+{
+ using namespace Eigen;
+ using namespace std;
+ if(A.rows() != A.cols())
+ {
+ return false;
+ }
+ assert(A.size() != 0);
+ SparseMatrix<AType> AT = A.transpose();
+ SparseMatrix<AType> AmAT = A-AT;
+ VectorXi AmATI,AmATJ;
+ Matrix<AType,Dynamic,1> AmATV;
+ find(AmAT,AmATI,AmATJ,AmATV);
+ if(AmATI.size() == 0)
+ {
+ return true;
+ }
+
+ return AmATV.maxCoeff() < epsilon && AmATV.minCoeff() > -epsilon;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::is_symmetric<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+// generated by autoexplicit.sh
+template bool igl::is_symmetric<double>(Eigen::SparseMatrix<double, 0, int> const&);
+template bool igl::is_symmetric<double, double>(Eigen::SparseMatrix<double, 0, int> const&, double);
+template bool igl::is_symmetric<double, int>(Eigen::SparseMatrix<double, 0, int> const&, int);
+#endif
diff --git a/xs/src/igl/is_symmetric.h b/xs/src/igl/is_symmetric.h
new file mode 100644
index 000000000..31725298e
--- /dev/null
+++ b/xs/src/igl/is_symmetric.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_SYMMETRIC_H
+#define IGL_IS_SYMMETRIC_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Returns true if the given matrix is symmetric
+ // Inputs:
+ // A m by m matrix
+ // Returns true if the matrix is square and symmetric
+ template <typename AT>
+ IGL_INLINE bool is_symmetric(const Eigen::SparseMatrix<AT>& A);
+ // Inputs:
+ // epsilon threshold on L1 difference between A and A'
+ template <typename AT, typename epsilonT>
+ IGL_INLINE bool is_symmetric(const Eigen::SparseMatrix<AT>& A, const epsilonT epsilon);
+ template <typename DerivedA>
+ IGL_INLINE bool is_symmetric(
+ const Eigen::PlainObjectBase<DerivedA>& A);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_symmetric.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_vertex_manifold.cpp b/xs/src/igl/is_vertex_manifold.cpp
new file mode 100644
index 000000000..d266ebab7
--- /dev/null
+++ b/xs/src/igl/is_vertex_manifold.cpp
@@ -0,0 +1,101 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_vertex_manifold.h"
+#include "triangle_triangle_adjacency.h"
+#include "vertex_triangle_adjacency.h"
+#include "unique.h"
+#include <vector>
+#include <cassert>
+#include <map>
+#include <queue>
+#include <iostream>
+
+template <typename DerivedF,typename DerivedB>
+IGL_INLINE bool igl::is_vertex_manifold(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedB>& B)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(F.cols() == 3 && "F must contain triangles");
+ typedef typename DerivedF::Scalar Index;
+ typedef typename DerivedF::Index FIndex;
+ const FIndex m = F.rows();
+ const Index n = F.maxCoeff()+1;
+ vector<vector<vector<FIndex > > > TT;
+ vector<vector<vector<FIndex > > > TTi;
+ triangle_triangle_adjacency(F,TT,TTi);
+
+ vector<vector<FIndex > > V2F,_1;
+ vertex_triangle_adjacency(n,F,V2F,_1);
+
+ const auto & check_vertex = [&](const Index v)->bool
+ {
+ vector<FIndex> uV2Fv;
+ {
+ vector<size_t> _1,_2;
+ unique(V2F[v],uV2Fv,_1,_2);
+ }
+ const FIndex one_ring_size = uV2Fv.size();
+ if(one_ring_size == 0)
+ {
+ return false;
+ }
+ const FIndex g = uV2Fv[0];
+ queue<Index> Q;
+ Q.push(g);
+ map<FIndex,bool> seen;
+ while(!Q.empty())
+ {
+ const FIndex f = Q.front();
+ Q.pop();
+ if(seen.count(f)==1)
+ {
+ continue;
+ }
+ seen[f] = true;
+ // Face f's neighbor lists opposite opposite each corner
+ for(const auto & c : TT[f])
+ {
+ // Each neighbor
+ for(const auto & n : c)
+ {
+ bool contains_v = false;
+ for(Index nc = 0;nc<F.cols();nc++)
+ {
+ if(F(n,nc) == v)
+ {
+ contains_v = true;
+ break;
+ }
+ }
+ if(seen.count(n)==0 && contains_v)
+ {
+ Q.push(n);
+ }
+ }
+ }
+ }
+ return one_ring_size == (FIndex) seen.size();
+ };
+
+ // Unreferenced vertices are considered non-manifold
+ B.setConstant(n,1,false);
+ // Loop over all vertices touched by F
+ bool all = true;
+ for(Index v = 0;v<n;v++)
+ {
+ all &= B(v) = check_vertex(v);
+ }
+ return all;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::is_vertex_manifold<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::is_vertex_manifold<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/is_vertex_manifold.h b/xs/src/igl/is_vertex_manifold.h
new file mode 100644
index 000000000..bf9caded6
--- /dev/null
+++ b/xs/src/igl/is_vertex_manifold.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_VERTEX_MANIFOLD_H
+#define IGL_IS_VERTEX_MANIFOLD_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Check if a mesh is vertex-manifold. This only checks whether the faces
+ // incident on each vertex form exactly one connected component. Vertices
+ // incident on non-manifold edges are not consider non-manifold by this
+ // function (see is_edge_manifold.h). Unreferenced verties are considered
+ // non-manifold (zero components).
+ //
+ // Inputs:
+ // F #F by 3 list of triangle indices
+ // Outputs:
+ // B #V list indicate whether each vertex is locally manifold.
+ // Returns whether mesh is vertex manifold.
+ //
+ // See also: is_edge_manifold
+ template <typename DerivedF,typename DerivedB>
+ IGL_INLINE bool is_vertex_manifold(
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedB>& B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_vertex_manifold.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/is_writable.cpp b/xs/src/igl/is_writable.cpp
new file mode 100644
index 000000000..f266b0078
--- /dev/null
+++ b/xs/src/igl/is_writable.cpp
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "is_writable.h"
+
+#ifdef _WIN32
+#include <sys/stat.h>
+#ifndef S_IWUSR
+# define S_IWUSR S_IWRITE
+#endif
+IGL_INLINE bool is_writable(const char* filename)
+{
+ // Check if file already exists
+ struct stat status;
+ if(stat(filename,&status)!=0)
+ {
+ return false;
+ }
+
+ return S_IWUSR & status.st_mode;
+}
+#else
+#include <sys/stat.h>
+#include <unistd.h>
+
+IGL_INLINE bool igl::is_writable(const char* filename)
+{
+ // Check if file already exists
+ struct stat status;
+ if(stat(filename,&status)!=0)
+ {
+ return false;
+ }
+
+ // Get current users uid and gid
+ uid_t this_uid = getuid();
+ gid_t this_gid = getgid();
+
+ // Dealing with owner
+ if( this_uid == status.st_uid )
+ {
+ return S_IWUSR & status.st_mode;
+ }
+
+ // Dealing with group member
+ if( this_gid == status.st_gid )
+ {
+ return S_IWGRP & status.st_mode;
+ }
+
+ // Dealing with other
+ return S_IWOTH & status.st_mode;
+}
+#endif
diff --git a/xs/src/igl/is_writable.h b/xs/src/igl/is_writable.h
new file mode 100644
index 000000000..8834e8afb
--- /dev/null
+++ b/xs/src/igl/is_writable.h
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_IS_WRITABLE_H
+#define IGL_IS_WRITABLE_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Check if a file exists *and* is writable like PHP's is_writable function:
+ // http://www.php.net/manual/en/function.is-writable.php
+ // Input:
+ // filename path to file
+ // Returns true if file exists and is writable and false if file doesn't
+ // exist or *is not writable*
+ //
+ // Note: Windows version will not test group and user id
+ IGL_INLINE bool is_writable(const char * filename);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "is_writable.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/isdiag.cpp b/xs/src/igl/isdiag.cpp
new file mode 100644
index 000000000..452341bf8
--- /dev/null
+++ b/xs/src/igl/isdiag.cpp
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "isdiag.h"
+
+template <typename Scalar>
+IGL_INLINE bool igl::isdiag(const Eigen::SparseMatrix<Scalar> & A)
+{
+ // Iterate over outside of A
+ for(int k=0; k<A.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<Scalar>::InnerIterator it (A,k); it; ++it)
+ {
+ if(it.row() != it.col() && it.value()!=0)
+ {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::isdiag<double>(class Eigen::SparseMatrix<double,0,int> const &);
+#endif
diff --git a/xs/src/igl/isdiag.h b/xs/src/igl/isdiag.h
new file mode 100644
index 000000000..2bd555fa3
--- /dev/null
+++ b/xs/src/igl/isdiag.h
@@ -0,0 +1,26 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ISDIAG_H
+#define IGL_ISDIAG_H
+#include "igl_inline.h"
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Determine if a given matrix is diagonal: all non-zeros lie on the
+ // main diagonal.
+ //
+ // Inputs:
+ // A m by n sparse matrix
+ // Returns true iff and only if the matrix is diagonal.
+ template <typename Scalar>
+ IGL_INLINE bool isdiag(const Eigen::SparseMatrix<Scalar> & A);
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "isdiag.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/ismember.cpp b/xs/src/igl/ismember.cpp
new file mode 100644
index 000000000..e3c3fd492
--- /dev/null
+++ b/xs/src/igl/ismember.cpp
@@ -0,0 +1,185 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ismember.h"
+#include "colon.h"
+#include "list_to_matrix.h"
+#include "sort.h"
+#include "sortrows.h"
+#include "unique.h"
+#include "unique_rows.h"
+#include <iostream>
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedIA,
+ typename DerivedLOCB>
+IGL_INLINE void igl::ismember(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedLOCB> & LOCB)
+{
+ using namespace Eigen;
+ using namespace std;
+ IA.resizeLike(A);
+ IA.setConstant(false);
+ LOCB.resizeLike(A);
+ LOCB.setConstant(-1);
+ // boring base cases
+ if(A.size() == 0)
+ {
+ return;
+ }
+ if(B.size() == 0)
+ {
+ return;
+ }
+
+ // Get rid of any duplicates
+ typedef Matrix<typename DerivedA::Scalar,Dynamic,1> VectorA;
+ typedef Matrix<typename DerivedB::Scalar,Dynamic,1> VectorB;
+ const VectorA vA(Eigen::Map<const VectorA>(DerivedA(A).data(), A.cols()*A.rows(),1));
+ const VectorB vB(Eigen::Map<const VectorB>(DerivedB(B).data(), B.cols()*B.rows(),1));
+ VectorA uA;
+ VectorB uB;
+ Eigen::Matrix<typename DerivedA::Index,Dynamic,1> uIA,uIuA,uIB,uIuB;
+ unique(vA,uA,uIA,uIuA);
+ unique(vB,uB,uIB,uIuB);
+ // Sort both
+ VectorA sA;
+ VectorB sB;
+ Eigen::Matrix<typename DerivedA::Index,Dynamic,1> sIA,sIB;
+ sort(uA,1,true,sA,sIA);
+ sort(uB,1,true,sB,sIB);
+
+ Eigen::Matrix<bool,Eigen::Dynamic,1> uF =
+ Eigen::Matrix<bool,Eigen::Dynamic,1>::Zero(sA.size(),1);
+ Eigen::Matrix<typename DerivedLOCB::Scalar, Eigen::Dynamic,1> uLOCB =
+ Eigen::Matrix<typename DerivedLOCB::Scalar,Eigen::Dynamic,1>::
+ Constant(sA.size(),1,-1);
+ {
+ int bi = 0;
+ // loop over sA
+ bool past = false;
+ for(int a = 0;a<sA.size();a++)
+ {
+ while(!past && sA(a)>sB(bi))
+ {
+ bi++;
+ past = bi>=sB.size();
+ }
+ if(!past && sA(a)==sB(bi))
+ {
+ uF(sIA(a)) = true;
+ uLOCB(sIA(a)) = uIB(sIB(bi));
+ }
+ }
+ }
+
+ Map< Matrix<typename DerivedIA::Scalar,Dynamic,1> >
+ vIA(IA.data(),IA.cols()*IA.rows(),1);
+ Map< Matrix<typename DerivedLOCB::Scalar,Dynamic,1> >
+ vLOCB(LOCB.data(),LOCB.cols()*LOCB.rows(),1);
+ for(int a = 0;a<A.size();a++)
+ {
+ vIA(a) = uF(uIuA(a));
+ vLOCB(a) = uLOCB(uIuA(a));
+ }
+}
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedIA,
+ typename DerivedLOCB>
+IGL_INLINE void igl::ismember_rows(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedLOCB> & LOCB)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(A.cols() == B.cols() && "number of columns must match");
+ IA.resize(A.rows(),1);
+ IA.setConstant(false);
+ LOCB.resize(A.rows(),1);
+ LOCB.setConstant(-1);
+ // boring base cases
+ if(A.size() == 0)
+ {
+ return;
+ }
+ if(B.size() == 0)
+ {
+ return;
+ }
+
+ // Get rid of any duplicates
+ DerivedA uA;
+ DerivedB uB;
+ Eigen::Matrix<typename DerivedA::Index,Dynamic,1> uIA,uIuA,uIB,uIuB;
+ unique_rows(A,uA,uIA,uIuA);
+ unique_rows(B,uB,uIB,uIuB);
+ // Sort both
+ DerivedA sA;
+ DerivedB sB;
+ Eigen::Matrix<typename DerivedA::Index,Dynamic,1> sIA,sIB;
+ sortrows(uA,true,sA,sIA);
+ sortrows(uB,true,sB,sIB);
+
+ Eigen::Matrix<bool,Eigen::Dynamic,1> uF =
+ Eigen::Matrix<bool,Eigen::Dynamic,1>::Zero(sA.size(),1);
+ Eigen::Matrix<typename DerivedLOCB::Scalar, Eigen::Dynamic,1> uLOCB =
+ Eigen::Matrix<typename DerivedLOCB::Scalar,Eigen::Dynamic,1>::
+ Constant(sA.size(),1,-1);
+ const auto & row_greater_than = [&sA,&sB](const int a, const int b)
+ {
+ for(int c = 0;c<sA.cols();c++)
+ {
+ if(sA(a,c) > sB(b,c)) return true;
+ if(sA(a,c) < sB(b,c)) return false;
+ }
+ return false;
+ };
+ {
+ int bi = 0;
+ // loop over sA
+ bool past = false;
+ for(int a = 0;a<sA.rows();a++)
+ {
+ assert(bi < sB.rows());
+ while(!past && row_greater_than(a,bi))
+ {
+ bi++;
+ past = bi>=sB.rows();
+ }
+ if(!past && (sA.row(a).array()==sB.row(bi).array()).all() )
+ {
+ uF(sIA(a)) = true;
+ uLOCB(sIA(a)) = uIB(sIB(bi));
+ }
+ }
+ }
+
+ for(int a = 0;a<A.rows();a++)
+ {
+ IA(a) = uF(uIuA(a));
+ LOCB(a) = uLOCB(uIuA(a));
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::ismember<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::ismember_rows<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::ismember_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::ismember_rows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::ismember_rows<Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/ismember.h b/xs/src/igl/ismember.h
new file mode 100644
index 000000000..72be6006d
--- /dev/null
+++ b/xs/src/igl/ismember.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ISMEMBER_H
+#define IGL_ISMEMBER_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Determine if elements of A exist in elements of B
+ //
+ // Inputs:
+ // A ma by na matrix
+ // B mb by nb matrix
+ // Outputs:
+ // IA ma by na matrix of flags whether corresponding element of A exists in
+ // B
+ // LOCB ma by na matrix of indices in B locating matching element (-1 if
+ // not found), indices assume column major ordering
+ //
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedIA,
+ typename DerivedLOCB>
+ IGL_INLINE void ismember(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedLOCB> & LOCB);
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedIA,
+ typename DerivedLOCB>
+ IGL_INLINE void ismember_rows(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedLOCB> & LOCB);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "ismember.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/isolines.cpp b/xs/src/igl/isolines.cpp
new file mode 100644
index 000000000..6d4f87e32
--- /dev/null
+++ b/xs/src/igl/isolines.cpp
@@ -0,0 +1,116 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+
+#include "isolines.h"
+
+#include <vector>
+#include <array>
+#include <iostream>
+
+#include "remove_duplicate_vertices.h"
+
+
+template <typename DerivedV,
+typename DerivedF,
+typename DerivedZ,
+typename DerivedIsoV,
+typename DerivedIsoE>
+IGL_INLINE void igl::isolines(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedZ>& z,
+ const int n,
+ Eigen::PlainObjectBase<DerivedIsoV>& isoV,
+ Eigen::PlainObjectBase<DerivedIsoE>& isoE)
+{
+ //Constants
+ const int dim = V.cols();
+ assert(dim==2 || dim==3);
+ const int nVerts = V.rows();
+ assert(z.rows() == nVerts &&
+ "There must be as many function entries as vertices");
+ const int nFaces = F.rows();
+ const int np1 = n+1;
+ const double min = z.minCoeff(), max = z.maxCoeff();
+
+
+ //Following http://www.alecjacobson.com/weblog/?p=2529
+ typedef typename DerivedZ::Scalar Scalar;
+ typedef Eigen::Matrix<Scalar, Eigen::Dynamic, 1> Vec;
+ Vec iso(np1);
+ for(int i=0; i<np1; ++i)
+ iso(i) = Scalar(i)/Scalar(n)*(max-min) + min;
+
+ typedef Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic> Matrix;
+ std::array<Matrix,3> t{{Matrix(nFaces, np1),
+ Matrix(nFaces, np1), Matrix(nFaces, np1)}};
+ for(int i=0; i<nFaces; ++i) {
+ for(int k=0; k<3; ++k) {
+ const Scalar z1=z(F(i,k)), z2=z(F(i,(k+1)%3));
+ for(int j=0; j<np1; ++j) {
+ t[k](i,j) = (iso(j)-z1) / (z2-z1);
+ if(t[k](i,j)<0 || t[k](i,j)>1)
+ t[k](i,j) = std::numeric_limits<Scalar>::quiet_NaN();
+ }
+ }
+ }
+
+ std::array<std::vector<int>,3> Fij, Iij;
+ for(int i=0; i<nFaces; ++i) {
+ for(int j=0; j<np1; ++j) {
+ for(int k=0; k<3; ++k) {
+ const int kp1=(k+1)%3, kp2=(k+2)%3;
+ if(std::isfinite(t[kp1](i,j)) && std::isfinite(t[kp2](i,j))) {
+ Fij[k].push_back(i);
+ Iij[k].push_back(j);
+ }
+ }
+ }
+ }
+
+ const int K = Fij[0].size()+Fij[1].size()+Fij[2].size();
+ isoV.resize(2*K, dim);
+ int b = 0;
+ for(int k=0; k<3; ++k) {
+ const int kp1=(k+1)%3, kp2=(k+2)%3;
+ for(int i=0; i<Fij[k].size(); ++i) {
+ isoV.row(b+i) = (1.-t[kp1](Fij[k][i],Iij[k][i]))*
+ V.row(F(Fij[k][i],kp1)) +
+ t[kp1](Fij[k][i],Iij[k][i])*V.row(F(Fij[k][i],kp2));
+ isoV.row(K+b+i) = (1.-t[kp2](Fij[k][i],Iij[k][i]))*
+ V.row(F(Fij[k][i],kp2)) +
+ t[kp2](Fij[k][i],Iij[k][i])*V.row(F(Fij[k][i],k));
+ }
+ b += Fij[k].size();
+ }
+
+ isoE.resize(K,2);
+ for(int i=0; i<K; ++i)
+ isoE.row(i) << i, K+i;
+
+
+ //Remove double entries
+ typedef typename DerivedIsoV::Scalar LScalar;
+ typedef typename DerivedIsoE::Scalar LInt;
+ typedef Eigen::Matrix<LInt, Eigen::Dynamic, 1> LIVec;
+ typedef Eigen::Matrix<LScalar, Eigen::Dynamic, Eigen::Dynamic> LMat;
+ typedef Eigen::Matrix<LInt, Eigen::Dynamic, Eigen::Dynamic> LIMat;
+ LIVec dummy1, dummy2;
+ igl::remove_duplicate_vertices(LMat(isoV), LIMat(isoE),
+ 2.2204e-15, isoV, dummy1, dummy2, isoE);
+
+}
+
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::isolines<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int const, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > &);
+#endif
+
diff --git a/xs/src/igl/isolines.h b/xs/src/igl/isolines.h
new file mode 100644
index 000000000..3b5199b6a
--- /dev/null
+++ b/xs/src/igl/isolines.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+
+#ifndef IGL_ISOLINES_H
+#define IGL_ISOLINES_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+
+namespace igl
+{
+ // Constructs isolines for a function z given on a mesh (V,F)
+ //
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by 3 list of mesh faces (must be triangles)
+ // z #V by 1 list of function values evaluated at vertices
+ // n the number of desired isolines
+ // Outputs:
+ // isoV #isoV by dim list of isoline vertex positions
+ // isoE #isoE by 2 list of isoline edge positions
+ //
+ //
+
+ template <typename DerivedV,
+ typename DerivedF,
+ typename DerivedZ,
+ typename DerivedIsoV,
+ typename DerivedIsoE>
+ IGL_INLINE void isolines(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedZ>& z,
+ const int n,
+ Eigen::PlainObjectBase<DerivedIsoV>& isoV,
+ Eigen::PlainObjectBase<DerivedIsoE>& isoE);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "isolines.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/jet.cpp b/xs/src/igl/jet.cpp
new file mode 100644
index 000000000..373f23bcb
--- /dev/null
+++ b/xs/src/igl/jet.cpp
@@ -0,0 +1,93 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "jet.h"
+#include "colormap.h"
+
+template <typename T>
+IGL_INLINE void igl::jet(const T x, T * rgb)
+{
+ igl::colormap(igl::COLOR_MAP_TYPE_JET, x, rgb);
+}
+
+template <typename T>
+IGL_INLINE void igl::jet(const T x_in, T & r, T & g, T & b)
+{
+ // Only important if the number of colors is small. In which case the rest is
+ // still wrong anyway
+ // x = linspace(0,1,jj)' * (1-1/jj) + 1/jj;
+ //
+ const double rone = 0.8;
+ const double gone = 1.0;
+ const double bone = 1.0;
+ T x = x_in;
+ x = (x_in<0 ? 0 : (x>1 ? 1 : x));
+
+ if (x<1. / 8.)
+ {
+ r = 0;
+ g = 0;
+ b = bone*(0.5 + (x) / (1. / 8.)*0.5);
+ } else if (x<3. / 8.)
+ {
+ r = 0;
+ g = gone*(x - 1. / 8.) / (3. / 8. - 1. / 8.);
+ b = bone;
+ } else if (x<5. / 8.)
+ {
+ r = rone*(x - 3. / 8.) / (5. / 8. - 3. / 8.);
+ g = gone;
+ b = (bone - (x - 3. / 8.) / (5. / 8. - 3. / 8.));
+ } else if (x<7. / 8.)
+ {
+ r = rone;
+ g = (gone - (x - 5. / 8.) / (7. / 8. - 5. / 8.));
+ b = 0;
+ } else
+ {
+ r = (rone - (x - 7. / 8.) / (1. - 7. / 8.)*0.5);
+ g = 0;
+ b = 0;
+ }
+}
+
+template <typename DerivedZ, typename DerivedC>
+IGL_INLINE void igl::jet(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const bool normalize,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ igl::colormap(igl::COLOR_MAP_TYPE_JET,Z, normalize, C);
+}
+
+template <typename DerivedZ, typename DerivedC>
+IGL_INLINE void igl::jet(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const double min_z,
+ const double max_z,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ igl::colormap(igl::COLOR_MAP_TYPE_JET, Z, min_z, max_z, C);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::jet<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::jet<double>(double, double*);
+template void igl::jet<double>(double, double&, double&, double&);
+template void igl::jet<float>(float, float*);
+template void igl::jet<Eigen::Array<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Array<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::jet<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::jet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::jet<float>(float, float&, float&, float&);
+template void igl::jet<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::jet<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::jet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+
+template void igl::jet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/jet.h b/xs/src/igl/jet.h
new file mode 100644
index 000000000..411b53af3
--- /dev/null
+++ b/xs/src/igl/jet.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_JET_H
+#define IGL_JET_H
+#include "igl_inline.h"
+//#ifndef IGL_NO_EIGEN
+# include <Eigen/Dense>
+//#endif
+namespace igl
+{
+ // JET like MATLAB's jet
+ //
+ // Inputs:
+ // m number of colors
+ // Outputs:
+ // J m by list of RGB colors between 0 and 1
+ //
+//#ifndef IGL_NO_EIGEN
+// void jet(const int m, Eigen::MatrixXd & J);
+//#endif
+ // Wrapper for directly computing [r,g,b] values for a given factor f between
+ // 0 and 1
+ //
+ // Inputs:
+ // f factor determining color value as if 0 was min and 1 was max
+ // Outputs:
+ // r red value
+ // g green value
+ // b blue value
+ template <typename T>
+ IGL_INLINE void jet(const T f, T * rgb);
+ template <typename T>
+ IGL_INLINE void jet(const T f, T & r, T & g, T & b);
+ // Inputs:
+ // 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
+ template <typename DerivedZ, typename DerivedC>
+ IGL_INLINE void jet(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const bool normalize,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ // Inputs:
+ // min_z value at blue
+ // max_z value at red
+ template <typename DerivedZ, typename DerivedC>
+ IGL_INLINE void jet(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const double min_Z,
+ const double max_Z,
+ Eigen::PlainObjectBase<DerivedC> & C);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "jet.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/knn.cpp b/xs/src/igl/knn.cpp
new file mode 100644
index 000000000..b2e355df1
--- /dev/null
+++ b/xs/src/igl/knn.cpp
@@ -0,0 +1,105 @@
+#include "knn.h"
+#include "parallel_for.h"
+
+#include <cmath>
+#include <queue>
+
+namespace igl {
+ template <typename DerivedP, typename KType, typename IndexType,
+ typename DerivedCH, typename DerivedCN, typename DerivedW,
+ typename DerivedI>
+ IGL_INLINE void knn(const Eigen::MatrixBase<DerivedP>& P,
+ const KType & k,
+ const std::vector<std::vector<IndexType> > & point_indices,
+ const Eigen::MatrixBase<DerivedCH>& CH,
+ const Eigen::MatrixBase<DerivedCN>& CN,
+ const Eigen::MatrixBase<DerivedW>& W,
+ Eigen::PlainObjectBase<DerivedI> & I)
+ {
+ typedef typename DerivedCN::Scalar CentersType;
+ typedef typename DerivedW::Scalar WidthsType;
+
+ typedef Eigen::Matrix<typename DerivedP::Scalar, 1, 3> RowVector3PType;
+
+ int n = P.rows();
+ const KType real_k = std::min(n,k);
+
+ auto distance_to_width_one_cube = [](RowVector3PType point){
+ return std::sqrt(std::pow(std::max(std::abs(point(0))-1,0.0),2)
+ + std::pow(std::max(std::abs(point(1))-1,0.0),2)
+ + std::pow(std::max(std::abs(point(2))-1,0.0),2));
+ };
+
+ auto distance_to_cube = [&distance_to_width_one_cube]
+ (RowVector3PType point,
+ Eigen::Matrix<CentersType,1,3> cube_center,
+ WidthsType cube_width){
+ RowVector3PType transformed_point = (point-cube_center)/cube_width;
+ return cube_width*distance_to_width_one_cube(transformed_point);
+ };
+
+ I.resize(n,real_k);
+
+ igl::parallel_for(n,[&](int i)
+ {
+ int points_found = 0;
+ RowVector3PType point_of_interest = P.row(i);
+
+ //To make my priority queue take both points and octree cells,
+ //I use the indices 0 to n-1 for the n points,
+ // and the indices n to n+m-1 for the m octree cells
+
+ // Using lambda to compare elements.
+ auto cmp = [&point_of_interest, &P, &CN, &W,
+ &n, &distance_to_cube](int left, int right) {
+ double leftdistance, rightdistance;
+ if(left < n){ //left is a point index
+ leftdistance = (P.row(left) - point_of_interest).norm();
+ } else { //left is an octree cell
+ leftdistance = distance_to_cube(point_of_interest,
+ CN.row(left-n),
+ W(left-n));
+ }
+
+ if(right < n){ //left is a point index
+ rightdistance = (P.row(right) - point_of_interest).norm();
+ } else { //left is an octree cell
+ rightdistance = distance_to_cube(point_of_interest,
+ CN.row(right-n),
+ W(right-n));
+ }
+ return leftdistance >= rightdistance;
+ };
+
+ std::priority_queue<IndexType, std::vector<IndexType>,
+ decltype(cmp)> queue(cmp);
+
+ queue.push(n); //This is the 0th octree cell (ie the root)
+ while(points_found < real_k){
+ IndexType curr_cell_or_point = queue.top();
+ queue.pop();
+ if(curr_cell_or_point < n){ //current index is for is a point
+ I(i,points_found) = curr_cell_or_point;
+ points_found++;
+ } else {
+ IndexType curr_cell = curr_cell_or_point - n;
+ if(CH(curr_cell,0) == -1){ //In the case of a leaf
+ if(point_indices.at(curr_cell).size() > 0){
+ //Assumption: Leaves either have one point, or none
+ queue.push(point_indices.at(curr_cell).at(0));
+ }
+ } else { //Not a leaf
+ for(int j = 0; j < 8; j++){
+ //+n to adjust for the octree cells
+ queue.push(CH(curr_cell,j)+n);
+ }
+ }
+ }
+ }
+ },1000);
+ }
+}
+
+
+
+
diff --git a/xs/src/igl/knn.h b/xs/src/igl/knn.h
new file mode 100644
index 000000000..0411fc3ee
--- /dev/null
+++ b/xs/src/igl/knn.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Gavin Barill <gavinpcb@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/
+
+#ifndef IGL_KNN
+#define IGL_KNN
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Given a 3D set of points P, an whole number k, and an octree
+ // find the indicies of the k nearest neighbors for each point in P.
+ // Note that each point is its own neighbor.
+ //
+ // The octree data structures used in this function are intended to be the
+ // same ones output from igl::octree
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ // k number of neighbors to find
+ // point_indices a vector of vectors, where the ith entry is a vector of
+ // the indices into P that are the ith octree cell's points
+ // CH #OctreeCells by 8, where the ith row is the indices of
+ // the ith octree cell's children
+ // CN #OctreeCells by 3, where the ith row is a 3d row vector
+ // representing the position of the ith cell's center
+ // W #OctreeCells, a vector where the ith entry is the width
+ // of the ith octree cell
+ // Outputs:
+ // I #P by k list of k-nearest-neighbor indices into P
+ template <typename DerivedP, typename KType, typename IndexType,
+ typename DerivedCH, typename DerivedCN, typename DerivedW,
+ typename DerivedI>
+ IGL_INLINE void knn(const Eigen::MatrixBase<DerivedP>& P,
+ const KType & k,
+ const std::vector<std::vector<IndexType> > & point_indices,
+ const Eigen::MatrixBase<DerivedCH>& CH,
+ const Eigen::MatrixBase<DerivedCN>& CN,
+ const Eigen::MatrixBase<DerivedW>& W,
+ Eigen::PlainObjectBase<DerivedI> & I);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "knn.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/launch_medit.cpp b/xs/src/igl/launch_medit.cpp
new file mode 100644
index 000000000..151af8e5b
--- /dev/null
+++ b/xs/src/igl/launch_medit.cpp
@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "launch_medit.h"
+#include "writeMESH.h"
+#include <cstdio>
+#include <iostream>
+#include <string>
+#include <sstream>
+
+#define MEDIT_PATH "/opt/local/bin/medit"
+#define TEMP_MESH_FILE "/var/tmp/temp.mesh"
+#define TEMP_MEDIT_FILE "/var/tmp/temp.medit"
+
+template <typename DerivedV, typename DerivedT, typename DerivedF>
+IGL_INLINE int igl::launch_medit(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const bool wait)
+{
+ using namespace std;
+ // Build medit command, end with & so command returns without waiting
+ stringstream command;
+ command<<MEDIT_PATH<<" "<<TEMP_MESH_FILE<<" "<<TEMP_MEDIT_FILE;
+ if(!wait)
+ {
+ command<<" &";
+ }
+ bool mesh_saved = writeMESH(TEMP_MESH_FILE,V,T,F);
+ if(!mesh_saved)
+ {
+ return -1;
+ }
+ // Write default medit options
+ const string default_medit_file_contents =
+ "BackgroundColor 1 1 1\n"
+ "LineColor 0 0 0\n"
+ "WindowSize 1024 800\n"
+ "RenderMode shading + lines\n";
+ FILE * fp = fopen(TEMP_MEDIT_FILE,"w");
+ if(fp == NULL)
+ {
+ cerr<<"^"<<__FUNCTION__<<": Could not write to "<<TEMP_MEDIT_FILE<<endl;
+ return -1;
+ }
+ fprintf(fp,"%s",default_medit_file_contents.c_str());
+ fclose(fp);
+
+ try
+ {
+ return system(command.str().c_str());
+ }catch(int e)
+ {
+ cerr<<"^"<<__FUNCTION__<<": Calling to medit crashed..."<<endl;
+ return -1;
+ }
+ // Could clean up and delete these files but not really worth it
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template int igl::launch_medit<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool);
+#endif
+
diff --git a/xs/src/igl/launch_medit.h b/xs/src/igl/launch_medit.h
new file mode 100644
index 000000000..8a324bb22
--- /dev/null
+++ b/xs/src/igl/launch_medit.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LAUNCH_MEDIT_H
+#define IGL_LAUNCH_MEDIT_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Writes the tetmesh in (V,T,F) to a temporary file, opens it with medit
+ // (forking with a system call) and returns
+ //
+ //
+ // Templates:
+ // DerivedV real-value: i.e. from MatrixXd
+ // DerivedT integer-value: i.e. from MatrixXi
+ // DerivedF integer-value: i.e. from MatrixXi
+ // Inputs:
+ // V double matrix of vertex positions #V by 3
+ // T #T list of tet indices into vertex positions
+ // F #F list of face indices into vertex positions
+ // wait whether to wait for medit process to finish before returning
+ // Returns returned value of system call (probably not useful if wait=false
+ // because of the fork)
+ template <typename DerivedV, typename DerivedT, typename DerivedF>
+ IGL_INLINE int launch_medit(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const bool wait);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "launch_medit.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/lbs_matrix.cpp b/xs/src/igl/lbs_matrix.cpp
new file mode 100644
index 000000000..a80f74be0
--- /dev/null
+++ b/xs/src/igl/lbs_matrix.cpp
@@ -0,0 +1,184 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "lbs_matrix.h"
+
+IGL_INLINE void igl::lbs_matrix(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ Eigen::MatrixXd & M)
+{
+ using namespace Eigen;
+ // Number of dimensions
+ const int dim = V.cols();
+ // Number of model points
+ const int n = V.rows();
+ // Number of skinning transformations/weights
+ const int m = W.cols();
+
+ // Assumes that first n rows of weights correspond to V
+ assert(W.rows() >= n);
+
+ M.resize(n,(dim+1)*m);
+ for(int j = 0;j<m;j++)
+ {
+ VectorXd Wj = W.block(0,j,V.rows(),1);
+ for(int i = 0;i<(dim+1);i++)
+ {
+ if(i<dim)
+ {
+ M.col(i + j*(dim+1)) =
+ Wj.cwiseProduct(V.col(i));
+ }else
+ {
+ M.col(i + j*(dim+1)).array() = W.block(0,j,V.rows(),1).array();
+ }
+ }
+ }
+}
+
+IGL_INLINE void igl::lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ Eigen::SparseMatrix<double>& M)
+{
+ // number of mesh vertices
+ int n = V.rows();
+ assert(n == W.rows());
+ // dimension of mesh
+ int dim = V.cols();
+ // number of handles
+ int m = W.cols();
+
+ M.resize(n*dim,m*dim*(dim+1));
+
+ // loop over coordinates of mesh vertices
+ for(int x = 0; x < dim; x++)
+ {
+ // loop over mesh vertices
+ for(int j = 0; j < n; j++)
+ {
+ // loop over handles
+ for(int i = 0; i < m; i++)
+ {
+ // loop over cols of affine transformations
+ for(int c = 0; c < (dim+1); c++)
+ {
+ double value = W(j,i);
+ if(c<dim)
+ {
+ value *= V(j,c);
+ }
+ M.insert(x*n + j,x*m + c*m*dim + i) = value;
+ }
+ }
+ }
+ }
+
+ M.makeCompressed();
+}
+
+IGL_INLINE void igl::lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ Eigen::MatrixXd & M)
+{
+ // number of mesh vertices
+ int n = V.rows();
+ assert(n == W.rows());
+ // dimension of mesh
+ int dim = V.cols();
+ // number of handles
+ int m = W.cols();
+ M.resize(n*dim,m*dim*(dim+1));
+
+ // loop over coordinates of mesh vertices
+ for(int x = 0; x < dim; x++)
+ {
+ // loop over mesh vertices
+ for(int j = 0; j < n; j++)
+ {
+ // loop over handles
+ for(int i = 0; i < m; i++)
+ {
+ // loop over cols of affine transformations
+ for(int c = 0; c < (dim+1); c++)
+ {
+ double value = W(j,i);
+ if(c<dim)
+ {
+ value *= V(j,c);
+ }
+ M(x*n + j,x*m + c*m*dim + i) = value;
+ }
+ }
+ }
+ }
+}
+
+IGL_INLINE void igl::lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ const Eigen::MatrixXi & WI,
+ Eigen::SparseMatrix<double>& M)
+{
+ // number of mesh vertices
+ int n = V.rows();
+ assert(n == W.rows());
+ assert(n == WI.rows());
+ // dimension of mesh
+ int dim = V.cols();
+ // number of handles
+ int m = WI.maxCoeff()+1;
+ // max number of influencing handles
+ int k = W.cols();
+ assert(k == WI.cols());
+
+ M.resize(n*dim,m*dim*(dim+1));
+
+ // loop over coordinates of mesh vertices
+ for(int x = 0; x < dim; x++)
+ {
+ // loop over mesh vertices
+ for(int j = 0; j < n; j++)
+ {
+ // loop over handles
+ for(int i = 0; i < k; i++)
+ {
+ // loop over cols of affine transformations
+ for(int c = 0; c < (dim+1); c++)
+ {
+ double value = W(j,i);
+ if(c<dim)
+ {
+ value *= V(j,c);
+ }
+ if(value != 0)
+ {
+ M.insert(x*n + j,x*m + c*m*dim + WI(j,i)) = value;
+ }
+ }
+ }
+ }
+ }
+
+ M.makeCompressed();
+}
+
+
+IGL_INLINE void igl::lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ const Eigen::MatrixXi & WI,
+ Eigen::MatrixXd & M)
+{
+ // Cheapskate wrapper
+ using namespace Eigen;
+ SparseMatrix<double> sM;
+ lbs_matrix_column(V,W,WI,sM);
+ M = MatrixXd(sM);
+}
diff --git a/xs/src/igl/lbs_matrix.h b/xs/src/igl/lbs_matrix.h
new file mode 100644
index 000000000..307273d20
--- /dev/null
+++ b/xs/src/igl/lbs_matrix.h
@@ -0,0 +1,94 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LBS_MATRIX_H
+#define IGL_LBS_MATRIX_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // LBS_MATRIX Linear blend skinning can be expressed by V' = M * T where V' is
+ // a #V by dim matrix of deformed vertex positions (one vertex per row), M is a
+ // #V by (dim+1)*#T (composed of weights and rest positions) and T is a
+ // #T*(dim+1) by dim matrix of #T stacked transposed transformation matrices.
+ // See equations (1) and (2) in "Fast Automatic Skinning Transformations"
+ // [Jacobson et al 2012]
+ //
+ // Inputs:
+ // V #V by dim list of rest positions
+ // W #V+ by #T list of weights
+ // Outputs:
+ // M #V by #T*(dim+1)
+ //
+ // In MATLAB:
+ // kron(ones(1,size(W,2)),[V ones(size(V,1),1)]).*kron(W,ones(1,size(V,2)+1))
+ IGL_INLINE void lbs_matrix(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ Eigen::MatrixXd & M);
+ // LBS_MATRIX construct a matrix that when multiplied against a column of
+ // affine transformation entries computes new coordinates of the vertices
+ //
+ // I'm not sure it makes since that the result is stored as a sparse matrix.
+ // The number of non-zeros per row *is* dependent on the number of mesh
+ // vertices and handles.
+ //
+ // Inputs:
+ // V #V by dim list of vertex rest positions
+ // W #V by #handles list of correspondence weights
+ // Output:
+ // 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
+ IGL_INLINE void lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ Eigen::SparseMatrix<double>& M);
+ IGL_INLINE void lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ Eigen::MatrixXd & M);
+ // Same as LBS_MATRIX above but instead of giving W as a full matrix of weights
+ // (each vertex has #handles weights), a constant number of weights are given
+ // for each vertex.
+ //
+ // Inputs:
+ // V #V by dim list of vertex rest positions
+ // W #V by k list of k correspondence weights per vertex
+ // WI #V by k list of k correspondence weight indices per vertex. Such that
+ // W(j,WI(i)) gives the ith most significant correspondence weight on vertex j
+ // Output:
+ // 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
+ //
+ IGL_INLINE void lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ const Eigen::MatrixXi & WI,
+ Eigen::SparseMatrix<double>& M);
+ IGL_INLINE void lbs_matrix_column(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXd & W,
+ const Eigen::MatrixXi & WI,
+ Eigen::MatrixXd & M);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "lbs_matrix.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/lexicographic_triangulation.cpp b/xs/src/igl/lexicographic_triangulation.cpp
new file mode 100644
index 000000000..ce9e796ae
--- /dev/null
+++ b/xs/src/igl/lexicographic_triangulation.cpp
@@ -0,0 +1,132 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+// Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "lexicographic_triangulation.h"
+#include "sortrows.h"
+
+#include <vector>
+#include <list>
+
+template<
+ typename DerivedP,
+ typename Orient2D,
+ typename DerivedF
+ >
+IGL_INLINE void igl::lexicographic_triangulation(
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Orient2D orient2D,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ typedef typename DerivedP::Scalar Scalar;
+ const size_t num_pts = P.rows();
+ if (num_pts < 3) {
+ throw "At least 3 points are required for triangulation!";
+ }
+
+ // Sort points in lexicographic order.
+ DerivedP ordered_P;
+ Eigen::VectorXi order;
+ igl::sortrows(P, true, ordered_P, order);
+
+ std::vector<Eigen::Vector3i> faces;
+ std::list<int> boundary;
+ const Scalar p0[] = {ordered_P(0, 0), ordered_P(0, 1)};
+ const Scalar p1[] = {ordered_P(1, 0), ordered_P(1, 1)};
+ for (size_t i=2; i<num_pts; i++) {
+ const Scalar curr_p[] = {ordered_P(i, 0), ordered_P(i, 1)};
+ if (faces.size() == 0) {
+ // All points processed so far are collinear.
+ // Check if the current point is collinear with every points before it.
+ auto orientation = orient2D(p0, p1, curr_p);
+ if (orientation != 0) {
+ // Add a fan of triangles eminating from curr_p.
+ if (orientation > 0) {
+ for (size_t j=0; j<=i-2; j++) {
+ faces.push_back({order[j], order[j+1], order[i]});
+ }
+ } else if (orientation < 0) {
+ for (size_t j=0; j<=i-2; j++) {
+ faces.push_back({order[j+1], order[j], order[i]});
+ }
+ }
+ // Initialize current boundary.
+ boundary.insert(boundary.end(), order.data(), order.data()+i+1);
+ if (orientation < 0) {
+ boundary.reverse();
+ }
+ }
+ } else {
+ const size_t bd_size = boundary.size();
+ assert(bd_size >= 3);
+ std::vector<short> orientations;
+ for (auto itr=boundary.begin(); itr!=boundary.end(); itr++) {
+ auto next_itr = std::next(itr, 1);
+ if (next_itr == boundary.end()) {
+ next_itr = boundary.begin();
+ }
+ const Scalar bd_p0[] = {P(*itr, 0), P(*itr, 1)};
+ const Scalar bd_p1[] = {P(*next_itr, 0), P(*next_itr, 1)};
+ auto orientation = orient2D(bd_p0, bd_p1, curr_p);
+ if (orientation < 0) {
+ faces.push_back({*next_itr, *itr, order[i]});
+ }
+ orientations.push_back(orientation);
+ }
+
+ auto left_itr = boundary.begin();
+ auto right_itr = boundary.begin();
+ auto curr_itr = boundary.begin();
+ for (size_t j=0; j<bd_size; j++, curr_itr++) {
+ size_t prev = (j+bd_size-1) % bd_size;
+ if (orientations[j] >= 0 && orientations[prev] < 0) {
+ right_itr = curr_itr;
+ } else if (orientations[j] < 0 && orientations[prev] >= 0) {
+ left_itr = curr_itr;
+ }
+ }
+ assert(left_itr != right_itr);
+
+ for (auto itr=left_itr; itr!=right_itr; itr++) {
+ if (itr == boundary.end()) itr = boundary.begin();
+ if (itr == right_itr) break;
+ if (itr == left_itr || itr == right_itr) continue;
+ itr = boundary.erase(itr);
+ if (itr == boundary.begin()) {
+ itr = boundary.end();
+ } else {
+ itr--;
+ }
+ }
+
+ if (right_itr == boundary.begin()) {
+ assert(std::next(left_itr, 1) == boundary.end());
+ boundary.insert(boundary.end(), order[i]);
+ } else {
+ assert(std::next(left_itr, 1) == right_itr);
+ boundary.insert(right_itr, order[i]);
+ }
+ }
+ }
+
+ const size_t num_faces = faces.size();
+ if (num_faces == 0) {
+ // All input points are collinear.
+ // Do nothing here.
+ } else {
+ F.resize(num_faces, 3);
+ for (size_t i=0; i<num_faces; i++) {
+ F.row(i) = faces[i];
+ }
+ }
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::lexicographic_triangulation<Eigen::Matrix<double, -1, -1, 0, -1, -1>, short (*)(double const*, double const*, double const*), Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, short (*)(double const*, double const*, double const*), Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif \ No newline at end of file
diff --git a/xs/src/igl/lexicographic_triangulation.h b/xs/src/igl/lexicographic_triangulation.h
new file mode 100644
index 000000000..4e0b81eb5
--- /dev/null
+++ b/xs/src/igl/lexicographic_triangulation.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+// Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_LEXICOGRAPHIC_TRIANGULATION_H
+#define IGL_LEXICOGRAPHIC_TRIANGULATION_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Given a set of points in 2D, return a lexicographic triangulation of these
+ // points.
+ //
+ // Inputs:
+ // P #P by 2 list of vertex positions
+ // orient2D A functor such that orient2D(pa, pb, pc) returns
+ // 1 if pa,pb,pc forms a conterclockwise triangle.
+ // -1 if pa,pb,pc forms a clockwise triangle.
+ // 0 if pa,pb,pc are collinear.
+ // where the argument pa,pb,pc are of type Scalar[2].
+ //
+ // Outputs:
+ // F #F by 3 of faces in lexicographic triangulation.
+ template<
+ typename DerivedP,
+ typename Orient2D,
+ typename DerivedF
+ >
+ IGL_INLINE void lexicographic_triangulation(
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Orient2D orient2D,
+ Eigen::PlainObjectBase<DerivedF>& F);
+}
+
+
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "lexicographic_triangulation.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/lim/lim.cpp b/xs/src/igl/lim/lim.cpp
new file mode 100644
index 000000000..1f4659062
--- /dev/null
+++ b/xs/src/igl/lim/lim.cpp
@@ -0,0 +1,137 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "lim.h"
+#include <LIMSolverInterface.h>
+
+
+IGL_INLINE igl::lim::State igl::lim::lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima)
+{
+ return (State)ComputeLIM(
+ vertices,
+ initialVertices,
+ elements,
+ constraintMatrix,
+ constraintTargets,
+ (EnergyType)energyType,
+ tolerance,
+ maxIteration,
+ findLocalMinima
+ );
+}
+
+IGL_INLINE igl::lim::State igl::lim::lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima,
+ bool enableOuput,
+ bool enableBarriers,
+ bool enableAlphaUpdate,
+ double beta,
+ double eps)
+{
+ return (State)ComputeLIM(
+ vertices,
+ initialVertices,
+ elements,
+ constraintMatrix,
+ constraintTargets,
+ (EnergyType)energyType,
+ tolerance,
+ maxIteration,
+ findLocalMinima,
+ enableOuput,
+ enableBarriers,
+ enableAlphaUpdate,
+ beta,
+ eps
+ );
+}
+
+IGL_INLINE igl::lim::State igl::lim::lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const std::vector<int>& borderVertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima)
+{
+ return (State)ComputeLIM(
+ vertices,
+ initialVertices,
+ elements,
+ borderVertices,
+ gradients,
+ constraintMatrix,
+ constraintTargets,
+ (EnergyType)energyType,
+ tolerance,
+ maxIteration,
+ findLocalMinima
+ );
+}
+
+IGL_INLINE igl::lim::State igl::lim::lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const std::vector<int>& borderVertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima,
+ bool enableOuput,
+ bool enableBarriers,
+ bool enableAlphaUpdate,
+ double beta,
+ double eps)
+{
+ return (State)ComputeLIM(
+ vertices,
+ initialVertices,
+ elements,
+ borderVertices,
+ gradients,
+ constraintMatrix,
+ constraintTargets,
+ (EnergyType)energyType,
+ tolerance,
+ maxIteration,
+ findLocalMinima,
+ enableOuput,
+ enableBarriers,
+ enableAlphaUpdate,
+ beta,
+ eps);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/lim/lim.h b/xs/src/igl/lim/lim.h
new file mode 100644
index 000000000..c4d3f4ad4
--- /dev/null
+++ b/xs/src/igl/lim/lim.h
@@ -0,0 +1,133 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LIM_LIM_H
+#define IGL_LIM_LIM_H
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ namespace lim
+ {
+ // Computes a locally injective mapping of a triangle or tet-mesh based on
+ // a deformation energy subject to some provided linear positional
+ // constraints Cv-d.
+ //
+ // Inputs:
+ // vertices vx3 matrix containing vertex position of the mesh
+ // initialVertices vx3 matrix containing vertex position of initial
+ // rest pose mesh
+ // elements exd matrix containing vertex indices of all elements
+ // borderVertices (only needed for 2D LSCM) vector containing indices
+ // of border vertices
+ // gradients (only needed for 2D Poisson) vector containing
+ // partial derivatives of target element gradients
+ // (structure is: [xx_0, xy_0, xx_1, xy_1, ..., xx_v,
+ // xy_v, yx_0, yy_0, yx_1, yy_1, ..., yx_v, yy_v]')
+ // constraintMatrix C: (c)x(v*(d-1)) sparse linear positional constraint
+ // matrix. X an Y-coordinates are alternatingly stacked
+ // per row (structure for triangles: [x_1, y_1, x_2,
+ // y_2, ..., x_v,y_v])
+ // constraintTargets d: c vector target positions
+ // energyType type of used energy:
+ // Dirichlet, Laplacian, Green, ARAP, LSCM, Poisson (only 2D), UniformLaplacian, Identity
+ // tolerance max squared positional constraints error
+ // maxIteration max number of iterations
+ // findLocalMinima iterating until a local minima is found. If not
+ // enabled only tolerance must be fulfilled.
+ // enableOutput (optional) enables the output (#iteration / hessian correction / step size / positional constraints / barrier constraints / deformation energy) (default : true)
+ // enableBarriers (optional) enables the non-flip constraints (default = true)
+ // enableAlphaUpdate (optional) enables dynamic alpha weight adjustment (default = true)
+ // beta (optional) steepness factor of barrier slopes (default: ARAP/LSCM = 0.01, Green = 1)
+ // eps (optional) smallest valid triangle area (default: 1e-5 * smallest triangle)
+ //
+ // where:
+ // v : # vertices
+ // c : # linear constraints
+ // e : # elements of mesh
+ // d : # vertices per element (triangle = 3, tet = 4)
+ //--------------------------------------------------------------------------
+ // Output:
+ // vertices vx3 matrix containing resulting vertex position of the
+ // mesh
+ //--------------------------------------------------------------------------
+ // Return values:
+ // Succeeded : Successful optimization with fulfilled tolerance
+ // LocalMinima : Convergenged to a local minima / tolerance not fulfilled
+ // IterationLimit : Max iteration reached before tolerance was fulfilled
+ // Infeasible : not feasible -> has inverted elements (decrease eps?)
+
+ enum Energy { Dirichlet = 0, Laplacian=1, Green=2, ARAP=3, LSCM=4, Poisson=5, UniformLaplacian=6, Identity=7 };
+ enum State { Uninitialized = -4, Infeasible = -3, IterationLimit = -2, LocalMinima = -1, Running = 0, Succeeded = 1 };
+
+ State lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima);
+
+ State lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima,
+ bool enableOuput,
+ bool enableBarriers,
+ bool enableAlphaUpdate,
+ double beta,
+ double eps);
+
+ State lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const std::vector<int>& borderVertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima);
+
+ State lim(
+ Eigen::Matrix<double,Eigen::Dynamic,3>& vertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,3>& initialVertices,
+ const Eigen::Matrix<int,Eigen::Dynamic,Eigen::Dynamic>& elements,
+ const std::vector<int>& borderVertices,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& gradients,
+ const Eigen::SparseMatrix<double>& constraintMatrix,
+ const Eigen::Matrix<double,Eigen::Dynamic,1>& constraintTargets,
+ Energy energyType,
+ double tolerance,
+ int maxIteration,
+ bool findLocalMinima,
+ bool enableOuput,
+ bool enableBarriers,
+ bool enableAlphaUpdate,
+ double beta,
+ double eps);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "lim.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/limit_faces.cpp b/xs/src/igl/limit_faces.cpp
new file mode 100644
index 000000000..e54c40b45
--- /dev/null
+++ b/xs/src/igl/limit_faces.cpp
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "limit_faces.h"
+
+#include <vector>
+#include <Eigen/Dense>
+
+template <typename MatF, typename VecL>
+IGL_INLINE void igl::limit_faces(
+ const MatF & F,
+ const VecL & L,
+ const bool exclusive,
+ MatF & LF)
+{
+ using namespace std;
+ using namespace Eigen;
+ vector<bool> in(F.rows(),false);
+ int num_in = 0;
+ // loop over faces
+ for(int i = 0;i<F.rows();i++)
+ {
+ bool all = true;
+ bool any = false;
+ for(int j = 0;j<F.cols();j++)
+ {
+ bool found = false;
+ // loop over L
+ for(int l = 0;l<L.size();l++)
+ {
+ if(F(i,j) == L(l))
+ {
+ found = true;
+ break;
+ }
+ }
+ any |= found;
+ all &= found;
+ }
+ in[i] = (exclusive?all:any);
+ num_in += (in[i]?1:0);
+ }
+
+ LF.resize(num_in,F.cols());
+ // loop over faces
+ int lfi = 0;
+ for(int i = 0;i<F.rows();i++)
+ {
+ if(in[i])
+ {
+ LF.row(lfi) = F.row(i);
+ lfi++;
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/limit_faces.h b/xs/src/igl/limit_faces.h
new file mode 100644
index 000000000..635b89170
--- /dev/null
+++ b/xs/src/igl/limit_faces.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LIMIT_FACES_H
+#define IGL_LIMIT_FACES_H
+#include "igl_inline.h"
+namespace igl
+{
+ // LIMIT_FACES limit given faces F to those which contain (only) indices found
+ // in L.
+ //
+ // [LF] = limit_faces(F,L,exclusive);
+ // [LF,in] = limit_faces(F,L,exclusive);
+ //
+ // Templates:
+ // MatF matrix type of faces, matrixXi
+ // VecL matrix type of vertex indices, VectorXi
+ // Inputs:
+ // F #F by 3 list of face indices
+ // L #L by 1 list of allowed indices
+ // exclusive flag specifying whether a face is included only if all its
+ // indices are in L, default is false
+ // Outputs:
+ // LF #LF by 3 list of remaining faces after limiting
+ // in #F list of whether given face was included
+ //
+ template <typename MatF, typename VecL>
+ IGL_INLINE void limit_faces(
+ const MatF & F,
+ const VecL & L,
+ const bool exclusive,
+ MatF & LF);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "limit_faces.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/line_field_missmatch.cpp b/xs/src/igl/line_field_missmatch.cpp
new file mode 100644
index 000000000..21c45b710
--- /dev/null
+++ b/xs/src/igl/line_field_missmatch.cpp
@@ -0,0 +1,144 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Nico Pietroni <nico.pietroni@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "line_field_missmatch.h"
+
+#include <vector>
+#include <deque>
+#include <igl/comb_line_field.h>
+#include <igl/rotate_vectors.h>
+#include <igl/comb_cross_field.h>
+#include <igl/comb_line_field.h>
+#include <igl/per_face_normals.h>
+#include <igl/is_border_vertex.h>
+#include <igl/vertex_triangle_adjacency.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/rotation_matrix_from_directions.h>
+#include <igl/local_basis.h>
+#include <igl/PI.h>
+
+namespace igl {
+template <typename DerivedV, typename DerivedF, typename DerivedO>
+class MissMatchCalculatorLine
+{
+public:
+
+ const Eigen::PlainObjectBase<DerivedV> &V;
+ const Eigen::PlainObjectBase<DerivedF> &F;
+ const Eigen::PlainObjectBase<DerivedV> &PD1;
+ const Eigen::PlainObjectBase<DerivedV> &PD2;
+ DerivedV N;
+
+private:
+ // internal
+ std::vector<bool> V_border; // bool
+ std::vector<std::vector<int> > VF;
+ std::vector<std::vector<int> > VFi;
+ DerivedF TT;
+ DerivedF TTi;
+
+
+private:
+
+ //compute the mismatch between 2 faces
+ inline int MissMatchByLine(const int f0,
+ const int f1)
+ {
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir0 = PD1.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1 = PD1.row(f1);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n0 = N.row(f0);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> n1 = N.row(f1);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> dir1Rot = igl::rotation_matrix_from_directions(n1,n0)*dir1;
+ dir1Rot.normalize();
+
+ // TODO: this should be equivalent to the other code below, to check!
+ // Compute the angle between the two vectors
+ // double a0 = atan2(dir0.dot(B2.row(f0)),dir0.dot(B1.row(f0)));
+ // double a1 = atan2(dir1Rot.dot(B2.row(f0)),dir1Rot.dot(B1.row(f0)));
+ //
+ // double angle_diff = a1-a0; //VectToAngle(f0,dir1Rot);
+
+ double angle_diff = atan2(dir1Rot.dot(PD2.row(f0)),dir1Rot.dot(PD1.row(f0)));
+
+ double step=igl::PI;
+ int i=(int)std::floor((angle_diff/step)+0.5);
+ assert((i>=-2)&&(i<=2));
+ int k=0;
+ if (i>=0)
+ k=i%2;
+ else
+ k=(2+i)%2;
+
+ assert((k==0)||(k==1));
+ return (k*2);
+ }
+
+public:
+
+ inline MissMatchCalculatorLine(const Eigen::PlainObjectBase<DerivedV> &_V,
+ const Eigen::PlainObjectBase<DerivedF> &_F,
+ const Eigen::PlainObjectBase<DerivedV> &_PD1,
+ const Eigen::PlainObjectBase<DerivedV> &_PD2
+ ):
+ V(_V),
+ F(_F),
+ PD1(_PD1),
+ PD2(_PD2)
+ {
+ igl::per_face_normals(V,F,N);
+ V_border = igl::is_border_vertex(V,F);
+ igl::vertex_triangle_adjacency(V,F,VF,VFi);
+ igl::triangle_triangle_adjacency(F,TT,TTi);
+ }
+
+ inline void calculateMissmatchLine(Eigen::PlainObjectBase<DerivedO> &Handle_MMatch)
+ {
+ Handle_MMatch.setConstant(F.rows(),3,-1);
+ for (unsigned int i=0;i<F.rows();i++)
+ {
+ for (int j=0;j<3;j++)
+ {
+ if (i==TT(i,j) || TT(i,j) == -1)
+ Handle_MMatch(i,j)=0;
+ else
+ Handle_MMatch(i,j) = MissMatchByLine(i,TT(i,j));
+ }
+ }
+ }
+
+};
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedO>
+IGL_INLINE void igl::line_field_missmatch(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const bool isCombed,
+ Eigen::PlainObjectBase<DerivedO> &missmatch)
+{
+ DerivedV PD1_combed;
+ DerivedV PD2_combed;
+
+ if (!isCombed)
+ igl::comb_line_field(V,F,PD1,PD1_combed);
+ else
+ {
+ PD1_combed = PD1;
+ }
+ Eigen::MatrixXd B1,B2,B3;
+ igl::local_basis(V,F,B1,B2,B3);
+ PD2_combed = igl::rotate_vectors(PD1_combed, Eigen::VectorXd::Constant(1,igl::PI/2), B1, B2);
+ igl::MissMatchCalculatorLine<DerivedV, DerivedF, DerivedO> sf(V, F, PD1_combed, PD2_combed);
+ sf.calculateMissmatchLine(missmatch);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/line_field_missmatch.h b/xs/src/igl/line_field_missmatch.h
new file mode 100644
index 000000000..a939685cb
--- /dev/null
+++ b/xs/src/igl/line_field_missmatch.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Nico Pietroni <nico.pietroni@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_LINE_FIELD_MISSMATCH_H
+#define IGL_LINE_FIELD_MISSMATCH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Calculates the missmatch (integer), at each face edge, of a cross field defined on the mesh faces.
+ // The integer missmatch is a multiple of pi/2 that transforms the cross on one side of the edge to
+ // the cross on the other side. It represents the deviation from a Lie connection across the edge.
+
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 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
+ // isCombed boolean, specifying whether the field is combed (i.e. matching has been precomputed.
+ // If not, the field is combed first.
+ // Output:
+ // Handle_MMatch #F by 3 eigen Matrix containing the integer missmatch of the cross field
+ // across all face edges
+ //
+
+ template <typename DerivedV, typename DerivedF, typename DerivedO>
+ IGL_INLINE void line_field_missmatch(const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const Eigen::PlainObjectBase<DerivedV> &PD1,
+ const bool isCombed,
+ Eigen::PlainObjectBase<DerivedO> &missmatch);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "line_field_missmatch.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/line_search.cpp b/xs/src/igl/line_search.cpp
new file mode 100644
index 000000000..c94eeaa52
--- /dev/null
+++ b/xs/src/igl/line_search.cpp
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "line_search.h"
+
+IGL_INLINE double igl::line_search(
+ Eigen::MatrixXd& x,
+ const Eigen::MatrixXd& d,
+ double step_size,
+ std::function<double(Eigen::MatrixXd&)> energy,
+ double cur_energy)
+{
+ double old_energy;
+ if (cur_energy > 0)
+ {
+ old_energy = cur_energy;
+ }
+ else
+ {
+ old_energy = energy(x); // no energy was given -> need to compute the current energy
+ }
+ double new_energy = old_energy;
+ int cur_iter = 0; int MAX_STEP_SIZE_ITER = 12;
+
+ while (new_energy >= old_energy && cur_iter < MAX_STEP_SIZE_ITER)
+ {
+ Eigen::MatrixXd new_x = x + step_size * d;
+
+ double cur_e = energy(new_x);
+ if ( cur_e >= old_energy)
+ {
+ step_size /= 2;
+ }
+ else
+ {
+ x = new_x;
+ new_energy = cur_e;
+ }
+ cur_iter++;
+ }
+ return new_energy;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+#endif
diff --git a/xs/src/igl/line_search.h b/xs/src/igl/line_search.h
new file mode 100644
index 000000000..057c6a43f
--- /dev/null
+++ b/xs/src/igl/line_search.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LINE_SEARCH_H
+#define IGL_LINE_SEARCH_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Implement a bisection linesearch to minimize a mesh-based energy on vertices given at 'x' at a search direction 'd',
+ // with initial step size. Stops when a point with lower energy is found, or after maximal iterations have been reached.
+ //
+ // Inputs:
+ // x #X by dim list of variables
+ // d #X by dim list of a given search direction
+ // i_step_size initial step size
+ // energy A function to compute the mesh-based energy (return an energy that is bigger than 0)
+ // cur_energy(OPTIONAL) The energy at the given point. Helps save redundant computations.
+ // This is optional. If not specified, the function will compute it.
+ // Outputs:
+ // x #X by dim list of variables at the new location
+ // Returns the energy at the new point 'x'
+ IGL_INLINE double line_search(
+ Eigen::MatrixXd& x,
+ const Eigen::MatrixXd& d,
+ double i_step_size,
+ std::function<double(Eigen::MatrixXd&)> energy,
+ double cur_energy = -1);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "line_search.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/line_segment_in_rectangle.cpp b/xs/src/igl/line_segment_in_rectangle.cpp
new file mode 100644
index 000000000..6f47c7d4c
--- /dev/null
+++ b/xs/src/igl/line_segment_in_rectangle.cpp
@@ -0,0 +1,103 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "line_segment_in_rectangle.h"
+
+IGL_INLINE bool igl::line_segment_in_rectangle(
+ const Eigen::Vector2d & s,
+ const Eigen::Vector2d & d,
+ const Eigen::Vector2d & A,
+ const Eigen::Vector2d & B)
+{
+ using namespace std;
+ using namespace Eigen;
+ // http://stackoverflow.com/a/100165/148668
+ const auto SegmentIntersectRectangle = [](double a_rectangleMinX,
+ double a_rectangleMinY,
+ double a_rectangleMaxX,
+ double a_rectangleMaxY,
+ double a_p1x,
+ double a_p1y,
+ double a_p2x,
+ double a_p2y)->bool
+ {
+ // Find min and max X for the segment
+
+ double minX = a_p1x;
+ double maxX = a_p2x;
+
+ if(a_p1x > a_p2x)
+ {
+ minX = a_p2x;
+ maxX = a_p1x;
+ }
+
+ // Find the intersection of the segment's and rectangle's x-projections
+
+ if(maxX > a_rectangleMaxX)
+ {
+ maxX = a_rectangleMaxX;
+ }
+
+ if(minX < a_rectangleMinX)
+ {
+ minX = a_rectangleMinX;
+ }
+
+ if(minX > maxX) // If their projections do not intersect return false
+ {
+ return false;
+ }
+
+ // Find corresponding min and max Y for min and max X we found before
+
+ double minY = a_p1y;
+ double maxY = a_p2y;
+
+ double dx = a_p2x - a_p1x;
+
+ if(fabs(dx) > 0.0000001)
+ {
+ double a = (a_p2y - a_p1y) / dx;
+ double b = a_p1y - a * a_p1x;
+ minY = a * minX + b;
+ maxY = a * maxX + b;
+ }
+
+ if(minY > maxY)
+ {
+ double tmp = maxY;
+ maxY = minY;
+ minY = tmp;
+ }
+
+ // Find the intersection of the segment's and rectangle's y-projections
+
+ if(maxY > a_rectangleMaxY)
+ {
+ maxY = a_rectangleMaxY;
+ }
+
+ if(minY < a_rectangleMinY)
+ {
+ minY = a_rectangleMinY;
+ }
+
+ if(minY > maxY) // If Y-projections do not intersect return false
+ {
+ return false;
+ }
+
+ return true;
+ };
+ const double minX = std::min(A(0),B(0));
+ const double minY = std::min(A(1),B(1));
+ const double maxX = std::max(A(0),B(0));
+ const double maxY = std::max(A(1),B(1));
+ bool ret = SegmentIntersectRectangle(minX,minY,maxX,maxY,s(0),s(1),d(0),d(1));
+ return ret;
+}
diff --git a/xs/src/igl/line_segment_in_rectangle.h b/xs/src/igl/line_segment_in_rectangle.h
new file mode 100644
index 000000000..6d7eaf404
--- /dev/null
+++ b/xs/src/igl/line_segment_in_rectangle.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LINE_SEGMENT_IN_RECTANGLE_H
+#define IGL_LINE_SEGMENT_IN_RECTANGLE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Determine whether a line segment overlaps with a rectangle.
+ //
+ // Inputs:
+ // s source point of line segment
+ // d dest point of line segment
+ // A first corner of rectangle
+ // B opposite corner of rectangle
+ // Returns true if line segment is at all inside rectangle
+ IGL_INLINE bool line_segment_in_rectangle(
+ const Eigen::Vector2d & s,
+ const Eigen::Vector2d & d,
+ const Eigen::Vector2d & A,
+ const Eigen::Vector2d & B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "line_segment_in_rectangle.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/linprog.cpp b/xs/src/igl/linprog.cpp
new file mode 100644
index 000000000..b73ffc513
--- /dev/null
+++ b/xs/src/igl/linprog.cpp
@@ -0,0 +1,302 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "linprog.h"
+#include "slice.h"
+#include "slice_into.h"
+#include "find.h"
+#include "colon.h"
+#include <iostream>
+
+//#define IGL_LINPROG_VERBOSE
+IGL_INLINE bool igl::linprog(
+ const Eigen::VectorXd & c,
+ const Eigen::MatrixXd & _A,
+ const Eigen::VectorXd & b,
+ const int k,
+ Eigen::VectorXd & x)
+{
+ // This is a very literal translation of
+ // http://www.mathworks.com/matlabcentral/fileexchange/2166-introduction-to-linear-algebra/content/strang/linprog.m
+ using namespace Eigen;
+ using namespace std;
+ bool success = true;
+ // number of constraints
+ const int m = _A.rows();
+ // number of original variables
+ const int n = _A.cols();
+ // number of iterations
+ int it = 0;
+ // maximum number of iterations
+ //const int MAXIT = 10*m;
+ const int MAXIT = 100*m;
+ // residual tolerance
+ const double tol = 1e-10;
+ const auto & sign = [](const Eigen::VectorXd & B) -> Eigen::VectorXd
+ {
+ Eigen::VectorXd Bsign(B.size());
+ for(int i = 0;i<B.size();i++)
+ {
+ Bsign(i) = B(i)>0?1:(B(i)<0?-1:0);
+ }
+ return Bsign;
+ };
+ // initial (inverse) basis matrix
+ VectorXd Dv = sign(sign(b).array()+0.5);
+ Dv.head(k).setConstant(1.);
+ MatrixXd D = Dv.asDiagonal();
+ // Incorporate slack variables
+ MatrixXd A(_A.rows(),_A.cols()+D.cols());
+ A<<_A,D;
+ // Initial basis
+ VectorXi B = igl::colon<int>(n,n+m-1);
+ // non-basis, may turn out that vector<> would be better here
+ VectorXi N = igl::colon<int>(0,n-1);
+ int j;
+ double bmin = b.minCoeff(&j);
+ int phase;
+ VectorXd xb;
+ VectorXd s;
+ VectorXi J;
+ if(k>0 && bmin<0)
+ {
+ phase = 1;
+ xb = VectorXd::Ones(m);
+ // super cost
+ s.resize(n+m+1);
+ s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k+1);
+ N.resize(n+1);
+ N<<igl::colon<int>(0,n-1),B(j);
+ J.resize(B.size()-1);
+ // [0 1 2 3 4]
+ // ^
+ // [0 1]
+ // [3 4]
+ J.head(j) = B.head(j);
+ J.tail(B.size()-j-1) = B.tail(B.size()-j-1);
+ B(j) = n+m;
+ MatrixXd AJ;
+ igl::slice(A,J,2,AJ);
+ const VectorXd a = b - AJ.rowwise().sum();
+ {
+ MatrixXd old_A = A;
+ A.resize(A.rows(),A.cols()+a.cols());
+ A<<old_A,a;
+ }
+ D.col(j) = -a/a(j);
+ D(j,j) = 1./a(j);
+ }else if(k==m)
+ {
+ phase = 2;
+ xb = b;
+ s.resize(c.size()+m);
+ // cost function
+ s<<c,VectorXd::Zero(m);
+ }else //k = 0 or bmin >=0
+ {
+ phase = 1;
+ xb = b.array().abs();
+ s.resize(n+m);
+ // super cost
+ s<<VectorXd::Zero(n+k),VectorXd::Ones(m-k);
+ }
+ while(phase<3)
+ {
+ double df = -1;
+ int t = std::numeric_limits<int>::max();
+ // Lagrange mutipliers fro Ax=b
+ VectorXd yb = D.transpose() * igl::slice(s,B);
+ while(true)
+ {
+ if(MAXIT>0 && it>=MAXIT)
+ {
+#ifdef IGL_LINPROG_VERBOSE
+ cerr<<"linprog: warning! maximum iterations without convergence."<<endl;
+#endif
+ success = false;
+ break;
+ }
+ // no freedom for minimization
+ if(N.size() == 0)
+ {
+ break;
+ }
+ // reduced costs
+ VectorXd sN = igl::slice(s,N);
+ MatrixXd AN = igl::slice(A,N,2);
+ VectorXd r = sN - AN.transpose() * yb;
+ int q;
+ // determine new basic variable
+ double rmin = r.minCoeff(&q);
+ // optimal! infinity norm
+ if(rmin>=-tol*(sN.array().abs().maxCoeff()+1))
+ {
+ break;
+ }
+ // increment iteration count
+ it++;
+ // apply Bland's rule to avoid cycling
+ if(df>=0)
+ {
+ if(MAXIT == -1)
+ {
+#ifdef IGL_LINPROG_VERBOSE
+ cerr<<"linprog: warning! degenerate vertex"<<endl;
+#endif
+ success = false;
+ }
+ igl::find((r.array()<0).eval(),J);
+ double Nq = igl::slice(N,J).minCoeff();
+ // again seems like q is assumed to be a scalar though matlab code
+ // could produce a vector for multiple matches
+ (N.array()==Nq).cast<int>().maxCoeff(&q);
+ }
+ VectorXd d = D*A.col(N(q));
+ VectorXi I;
+ igl::find((d.array()>tol).eval(),I);
+ if(I.size() == 0)
+ {
+#ifdef IGL_LINPROG_VERBOSE
+ cerr<<"linprog: warning! solution is unbounded"<<endl;
+#endif
+ // This seems dubious:
+ it=-it;
+ success = false;
+ break;
+ }
+ VectorXd xbd = igl::slice(xb,I).array()/igl::slice(d,I).array();
+ // new use of r
+ int p;
+ {
+ double r;
+ r = xbd.minCoeff(&p);
+ p = I(p);
+ // apply Bland's rule to avoid cycling
+ if(df>=0)
+ {
+ igl::find((xbd.array()==r).eval(),J);
+ double Bp = igl::slice(B,igl::slice(I,J)).minCoeff();
+ // idiotic way of finding index in B of Bp
+ // code down the line seems to assume p is a scalar though the matlab
+ // code could find a vector of matches)
+ (B.array()==Bp).cast<int>().maxCoeff(&p);
+ }
+ // update x
+ xb -= r*d;
+ xb(p) = r;
+ // change in f
+ df = r*rmin;
+ }
+ // row vector
+ RowVectorXd v = D.row(p)/d(p);
+ yb += v.transpose() * (s(N(q)) - d.transpose()*igl::slice(s,B));
+ d(p)-=1;
+ // update inverse basis matrix
+ D = D - d*v;
+ t = B(p);
+ B(p) = N(q);
+ if(t>(n+k-1))
+ {
+ // remove qth entry from N
+ VectorXi old_N = N;
+ N.resize(N.size()-1);
+ N.head(q) = old_N.head(q);
+ N.head(q) = old_N.head(q);
+ N.tail(old_N.size()-q-1) = old_N.tail(old_N.size()-q-1);
+ }else
+ {
+ N(q) = t;
+ }
+ }
+ // iterative refinement
+ xb = (xb+D*(b-igl::slice(A,B,2)*xb)).eval();
+ // must be due to rounding
+ VectorXi I;
+ igl::find((xb.array()<0).eval(),I);
+ if(I.size()>0)
+ {
+ // so correct
+ VectorXd Z = VectorXd::Zero(I.size(),1);
+ igl::slice_into(Z,I,xb);
+ }
+ // B, xb,n,m,res=A(:,B)*xb-b
+ if(phase == 2 || it<0)
+ {
+ break;
+ }
+ if(xb.transpose()*igl::slice(s,B) > tol)
+ {
+ it = -it;
+#ifdef IGL_LINPROG_VERBOSE
+ cerr<<"linprog: warning, no feasible solution"<<endl;
+#endif
+ success = false;
+ break;
+ }
+ // re-initialize for Phase 2
+ phase = phase+1;
+ s*=1e6*c.array().abs().maxCoeff();
+ s.head(n) = c;
+ }
+ x.resize(std::max(B.maxCoeff()+1,n));
+ igl::slice_into(xb,B,x);
+ x = x.head(n).eval();
+ return success;
+}
+
+IGL_INLINE bool igl::linprog(
+ const Eigen::VectorXd & f,
+ const Eigen::MatrixXd & A,
+ const Eigen::VectorXd & b,
+ const Eigen::MatrixXd & B,
+ const Eigen::VectorXd & c,
+ Eigen::VectorXd & x)
+{
+ using namespace Eigen;
+ using namespace std;
+ const int m = A.rows();
+ const int n = A.cols();
+ const int p = B.rows();
+ MatrixXd Im = MatrixXd::Identity(m,m);
+ MatrixXd AS(m,n+m);
+ AS<<A,Im;
+ MatrixXd bS = b.array().abs();
+ for(int i = 0;i<m;i++)
+ {
+ const auto & sign = [](double x)->double
+ {
+ return (x<0?-1:(x>0?1:0));
+ };
+ AS.row(i) *= sign(b(i));
+ }
+ MatrixXd In = MatrixXd::Identity(n,n);
+ MatrixXd P(n+m,2*n+m);
+ P<< In, -In, MatrixXd::Zero(n,m),
+ MatrixXd::Zero(m,2*n), Im;
+ MatrixXd ASP = AS*P;
+ MatrixXd BSP(0,2*n+m);
+ if(p>0)
+ {
+ MatrixXd BS(p,2*n);
+ BS<<B,MatrixXd::Zero(p,n);
+ BSP = BS*P;
+ }
+
+ VectorXd fSP = VectorXd::Ones(2*n+m);
+ fSP.head(2*n) = P.block(0,0,n,2*n).transpose()*f;
+ const VectorXd & cc = fSP;
+
+ MatrixXd AA(m+p,2*n+m);
+ AA<<ASP,BSP;
+ VectorXd bb(m+p);
+ bb<<bS,c;
+
+ VectorXd xxs;
+ bool ret = linprog(cc,AA,bb,0,xxs);
+ x = P.block(0,0,n,2*n+m)*xxs;
+ return ret;
+}
diff --git a/xs/src/igl/linprog.h b/xs/src/igl/linprog.h
new file mode 100644
index 000000000..db98435ad
--- /dev/null
+++ b/xs/src/igl/linprog.h
@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LINPROG_H
+#define IGL_LINPROG_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Solve a linear program given in "standard form"
+ //
+ // min f'x
+ // s.t. A( 1:k,:) x <= b(1:k)
+ // A(k+1:end,:) x = b(k+1:end)
+ // ** x >= 0 **
+ //
+ // In contrast to other APIs the entries in b may be negative.
+ //
+ // Inputs:
+ // c #x list of linear coefficients
+ // A #A by #x matrix of linear constraint coefficients
+ // b #A list of linear constraint right-hand sides
+ // k number of inequality constraints as first rows of A,b
+ // Outputs:
+ // x #x solution vector
+ //
+ IGL_INLINE bool linprog(
+ const Eigen::VectorXd & c,
+ const Eigen::MatrixXd & A,
+ const Eigen::VectorXd & b,
+ const int k,
+ Eigen::VectorXd & f);
+
+ // Wrapper in friendlier general form (no implicit bounds on x)
+ //
+ // min f'x
+ // s.t. A x <= b
+ // B x = c
+ //
+ // Inputs:
+ // f #x list of linear coefficients
+ // A #A by #x matrix of linear inequality constraint coefficients
+ // b #A list of linear constraint right-hand sides
+ // B #B by #x matrix of linear equality constraint coefficients
+ // c #B list of linear constraint right-hand sides
+ // Outputs:
+ // x #x solution vector
+ //
+ IGL_INLINE bool linprog(
+ const Eigen::VectorXd & f,
+ const Eigen::MatrixXd & A,
+ const Eigen::VectorXd & b,
+ const Eigen::MatrixXd & B,
+ const Eigen::VectorXd & c,
+ Eigen::VectorXd & x);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "linprog.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/list_to_matrix.cpp b/xs/src/igl/list_to_matrix.cpp
new file mode 100644
index 000000000..a1ca1926b
--- /dev/null
+++ b/xs/src/igl/list_to_matrix.cpp
@@ -0,0 +1,175 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "list_to_matrix.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include <Eigen/Dense>
+
+#include "max_size.h"
+#include "min_size.h"
+
+template <typename T, typename Derived>
+IGL_INLINE bool igl::list_to_matrix(const std::vector<std::vector<T > > & V,Eigen::PlainObjectBase<Derived>& M)
+{
+ // number of rows
+ int m = V.size();
+ if(m == 0)
+ {
+ M.resize(0,0);
+ return true;
+ }
+ // number of columns
+ int n = igl::min_size(V);
+ if(n != igl::max_size(V))
+ {
+ return false;
+ }
+ assert(n != -1);
+ // Resize output
+ M.resize(m,n);
+
+ // Loop over rows
+ for(int i = 0;i<m;i++)
+ {
+ // Loop over cols
+ for(int j = 0;j<n;j++)
+ {
+ M(i,j) = V[i][j];
+ }
+ }
+
+ return true;
+}
+
+template <typename T, typename Derived>
+IGL_INLINE bool igl::list_to_matrix(
+ const std::vector<std::vector<T > > & V,
+ const int n,
+ const T & padding,
+ Eigen::PlainObjectBase<Derived>& M)
+{
+ const int m = V.size();
+ M.resize(m,n);
+ for(int i = 0;i<m;i++)
+ {
+ const auto & row = V[i];
+ if(row.size()>n)
+ {
+ return false;
+ }
+ int j = 0;
+ for(;j<row.size();j++)
+ {
+ M(i,j) = row[j];
+ }
+ for(;j<n;j++)
+ {
+ M(i,j) = padding;
+ }
+ }
+ return true;
+}
+
+template <typename T, typename Derived>
+IGL_INLINE bool igl::list_to_matrix(const std::vector<T > & V,Eigen::PlainObjectBase<Derived>& M)
+{
+ // number of rows
+ int m = V.size();
+ if(m == 0)
+ {
+ //fprintf(stderr,"Error: list_to_matrix() list is empty()\n");
+ //return false;
+ if(Derived::ColsAtCompileTime == 1)
+ {
+ M.resize(0,1);
+ }else if(Derived::RowsAtCompileTime == 1)
+ {
+ M.resize(1,0);
+ }else
+ {
+ M.resize(0,0);
+ }
+ return true;
+ }
+ // Resize output
+ if(Derived::RowsAtCompileTime == 1)
+ {
+ M.resize(1,m);
+ }else
+ {
+ M.resize(m,1);
+ }
+
+ // Loop over rows
+ for(int i = 0;i<m;i++)
+ {
+ M(i) = V[i];
+ }
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<double, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<long, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<bool, Eigen::Array<bool, -1, 3, 0, -1, 3> >(std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<int, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, 4, 1, 0, 4, 1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+// generated by autoexplicit.sh
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, 2, 1, 0, 2, 1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<int, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template bool igl::list_to_matrix<int, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<int, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+template bool igl::list_to_matrix<float, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(std::vector<std::vector<float, std::allocator<float> >, std::allocator<std::vector<float, std::allocator<float> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+template bool igl::list_to_matrix<unsigned int, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
+template bool igl::list_to_matrix<int, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::list_to_matrix<float, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::vector<std::vector<float, std::allocator<float> >, std::allocator<std::vector<float, std::allocator<float> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<bool, Eigen::Array<bool, -1, 1, 0, -1, 1> >(std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
+template bool igl::list_to_matrix<bool, Eigen::Array<bool, -1, -1, 0, -1, -1> >(std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<bool, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<bool, std::allocator<bool> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<bool, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<int, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<int, std::allocator<int> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<int, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+
+#ifdef WIN32
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<double, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::vector<double, std::allocator<double> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::list_to_matrix<unsigned __int64, class Eigen::Matrix<int, -1, -1, 0, -1, -1> >(class std::vector<unsigned __int64, class std::allocator<unsigned __int64> > const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > &);
+template bool igl::list_to_matrix<unsigned __int64,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+template bool igl::list_to_matrix<unsigned __int64,class Eigen::Matrix<long,-1,1,0,-1,1> >(class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<long,-1,1,0,-1,1> > &);
+template bool igl::list_to_matrix<unsigned long long,class Eigen::Matrix<int,-1,1,0,-1,1> >(class std::vector<unsigned long long,class std::allocator<unsigned long long> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &);
+template bool igl::list_to_matrix<unsigned long, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<unsigned long, std::allocator<unsigned long> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
+#endif
diff --git a/xs/src/igl/list_to_matrix.h b/xs/src/igl/list_to_matrix.h
new file mode 100644
index 000000000..1a5881dc1
--- /dev/null
+++ b/xs/src/igl/list_to_matrix.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LIST_TO_MATRIX_H
+#define IGL_LIST_TO_MATRIX_H
+#include "igl_inline.h"
+#include <vector>
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Convert a list (std::vector) of row vectors of the same length to a matrix
+ // Template:
+ // T type that can be safely cast to type in Mat via '='
+ // Mat Matrix type, must implement:
+ // .resize(m,n)
+ // .row(i) = Row
+ // Inputs:
+ // V a m-long list of vectors of size n
+ // Outputs:
+ // M an m by n matrix
+ // Returns true on success, false on errors
+ template <typename T, typename Derived>
+ IGL_INLINE bool list_to_matrix(
+ const std::vector<std::vector<T > > & V,
+ Eigen::PlainObjectBase<Derived>& M);
+ // Convert a list of row vectors of `n` or less to a matrix and pad on
+ // the right with `padding`:
+ //
+ // Inputs:
+ // V a m-long list of vectors of size <=n
+ // n number of columns
+ // padding value to fill in from right for short rows
+ // Outputs:
+ // M an m by n matrix
+ template <typename T, typename Derived>
+ IGL_INLINE bool list_to_matrix(
+ const std::vector<std::vector<T > > & V,
+ const int n,
+ const T & padding,
+ Eigen::PlainObjectBase<Derived>& M);
+ // Vector wrapper
+ template <typename T, typename Derived>
+ IGL_INLINE bool list_to_matrix(const std::vector<T > & V,Eigen::PlainObjectBase<Derived>& M);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "list_to_matrix.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/local_basis.cpp b/xs/src/igl/local_basis.cpp
new file mode 100644
index 000000000..599eca739
--- /dev/null
+++ b/xs/src/igl/local_basis.cpp
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "local_basis.h"
+
+#include <sstream>
+#include <string>
+#include <fstream>
+
+#include <vector>
+#include <Eigen/Geometry>
+
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::local_basis(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedV>& B1,
+ Eigen::PlainObjectBase<DerivedV>& B2,
+ Eigen::PlainObjectBase<DerivedV>& B3
+ )
+{
+ using namespace Eigen;
+ using namespace std;
+ B1.resize(F.rows(),3);
+ B2.resize(F.rows(),3);
+ B3.resize(F.rows(),3);
+
+ for (unsigned i=0;i<F.rows();++i)
+ {
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v1 = (V.row(F(i,1)) - V.row(F(i,0))).normalized();
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> t = V.row(F(i,2)) - V.row(F(i,0));
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v3 = v1.cross(t).normalized();
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v2 = v1.cross(v3).normalized();
+
+ B1.row(i) = v1;
+ B2.row(i) = -v2;
+ B3.row(i) = v3;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::local_basis<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::local_basis<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/local_basis.h b/xs/src/igl/local_basis.h
new file mode 100644
index 000000000..392796c34
--- /dev/null
+++ b/xs/src/igl/local_basis.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LOCALBASIS_H
+#define IGL_LOCALBASIS_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+#include <vector>
+
+namespace igl
+{
+ // Compute a local orthogonal reference system for each triangle in the given mesh
+ // Templates:
+ // DerivedV derived from vertex positions matrix type: i.e. MatrixXd
+ // DerivedF derived from face indices matrix type: i.e. MatrixXi
+ // Inputs:
+ // V eigen matrix #V by 3
+ // F #F by 3 list of mesh faces (must be triangles)
+ // Outputs:
+ // B1 eigen matrix #F by 3, each vector is tangent to the triangle
+ // B2 eigen matrix #F by 3, each vector is tangent to the triangle and perpendicular to B1
+ // B3 eigen matrix #F by 3, normal of the triangle
+ //
+ // See also: adjacency_matrix
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void local_basis(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedV>& B1,
+ Eigen::PlainObjectBase<DerivedV>& B2,
+ Eigen::PlainObjectBase<DerivedV>& B3
+ );
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "local_basis.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/look_at.cpp b/xs/src/igl/look_at.cpp
new file mode 100644
index 000000000..c55c9b2ec
--- /dev/null
+++ b/xs/src/igl/look_at.cpp
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "look_at.h"
+
+template <
+ typename Derivedeye,
+ typename Derivedcenter,
+ typename Derivedup,
+ typename DerivedR>
+IGL_INLINE void igl::look_at(
+ const Eigen::PlainObjectBase<Derivedeye> & eye,
+ const Eigen::PlainObjectBase<Derivedcenter> & center,
+ const Eigen::PlainObjectBase<Derivedup> & up,
+ Eigen::PlainObjectBase<DerivedR> & R)
+{
+ typedef Eigen::Matrix<typename DerivedR::Scalar,3,1> Vector3S;
+ Vector3S f = (center - eye).normalized();
+ Vector3S s = f.cross(up).normalized();
+ Vector3S u = s.cross(f);
+ R = Eigen::Matrix<typename DerivedR::Scalar,4,4>::Identity();
+ R(0,0) = s(0);
+ R(0,1) = s(1);
+ R(0,2) = s(2);
+ R(1,0) = u(0);
+ R(1,1) = u(1);
+ R(1,2) = u(2);
+ R(2,0) =-f(0);
+ R(2,1) =-f(1);
+ R(2,2) =-f(2);
+ R(0,3) =-s.transpose() * eye;
+ R(1,3) =-u.transpose() * eye;
+ R(2,3) = f.transpose() * eye;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::look_at<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> >&);
+#endif
diff --git a/xs/src/igl/look_at.h b/xs/src/igl/look_at.h
new file mode 100644
index 000000000..883cbf94e
--- /dev/null
+++ b/xs/src/igl/look_at.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LOOK_AT_H
+#define IGL_LOOK_AT_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Implementation of the deprecated gluLookAt function.
+ //
+ // Inputs:
+ // eye 3-vector of eye position
+ // center 3-vector of center reference point
+ // up 3-vector of up vector
+ // Outputs:
+ // R 4x4 rotation matrix
+ //
+ template <
+ typename Derivedeye,
+ typename Derivedcenter,
+ typename Derivedup,
+ typename DerivedR >
+ IGL_INLINE void look_at(
+ const Eigen::PlainObjectBase<Derivedeye> & eye,
+ const Eigen::PlainObjectBase<Derivedcenter> & center,
+ const Eigen::PlainObjectBase<Derivedup> & up,
+ Eigen::PlainObjectBase<DerivedR> & R);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "look_at.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/loop.cpp b/xs/src/igl/loop.cpp
new file mode 100644
index 000000000..b4233ca67
--- /dev/null
+++ b/xs/src/igl/loop.cpp
@@ -0,0 +1,173 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "loop.h"
+
+#include <igl/adjacency_list.h>
+#include <igl/triangle_triangle_adjacency.h>
+#include <igl/unique.h>
+
+#include <vector>
+
+template <
+ typename DerivedF,
+ typename SType,
+ typename DerivedNF>
+IGL_INLINE void igl::loop(
+ const int n_verts,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::SparseMatrix<SType>& S,
+ Eigen::PlainObjectBase<DerivedNF> & NF)
+{
+ typedef Eigen::SparseMatrix<SType> SparseMat;
+ typedef Eigen::Triplet<SType> Triplet_t;
+
+ //Ref. https://graphics.stanford.edu/~mdfisher/subdivision.html
+ //Heavily borrowing from igl::upsample
+
+ DerivedF FF, FFi;
+ triangle_triangle_adjacency(F, FF, FFi);
+ std::vector<std::vector<typename DerivedF::Scalar>> adjacencyList;
+ adjacency_list(F, adjacencyList, true);
+
+ //Compute the number and positions of the vertices to insert (on edges)
+ Eigen::MatrixXi NI = Eigen::MatrixXi::Constant(FF.rows(), FF.cols(), -1);
+ Eigen::MatrixXi NIdoubles = Eigen::MatrixXi::Zero(FF.rows(), FF.cols());
+ Eigen::VectorXi vertIsOnBdry = Eigen::VectorXi::Zero(n_verts);
+ int counter = 0;
+ for(int i=0; i<FF.rows(); ++i)
+ {
+ for(int j=0; j<3; ++j)
+ {
+ if(NI(i,j) == -1)
+ {
+ NI(i,j) = counter;
+ NIdoubles(i,j) = 0;
+ if (FF(i,j) != -1)
+ {
+ //If it is not a boundary
+ NI(FF(i,j), FFi(i,j)) = counter;
+ NIdoubles(i,j) = 1;
+ } else
+ {
+ //Mark boundary vertices for later
+ vertIsOnBdry(F(i,j)) = 1;
+ vertIsOnBdry(F(i,(j+1)%3)) = 1;
+ }
+ ++counter;
+ }
+ }
+ }
+
+ const int& n_odd = n_verts;
+ const int& n_even = counter;
+ const int n_newverts = n_odd + n_even;
+
+ //Construct vertex positions
+ std::vector<Triplet_t> tripletList;
+ for(int i=0; i<n_odd; ++i)
+ {
+ //Old vertices
+ const std::vector<int>& localAdjList = adjacencyList[i];
+ if(vertIsOnBdry(i)==1)
+ {
+ //Boundary vertex
+ tripletList.emplace_back(i, localAdjList.front(), 1./8.);
+ tripletList.emplace_back(i, localAdjList.back(), 1./8.);
+ tripletList.emplace_back(i, i, 3./4.);
+ } else
+ {
+ const int n = localAdjList.size();
+ const SType dn = n;
+ SType beta;
+ if(n==3)
+ {
+ beta = 3./16.;
+ } else
+ {
+ beta = 3./8./dn;
+ }
+ for(int j=0; j<n; ++j)
+ {
+ tripletList.emplace_back(i, localAdjList[j], beta);
+ }
+ tripletList.emplace_back(i, i, 1.-dn*beta);
+ }
+ }
+ for(int i=0; i<FF.rows(); ++i)
+ {
+ //New vertices
+ for(int j=0; j<3; ++j)
+ {
+ if(NIdoubles(i,j)==0)
+ {
+ if(FF(i,j)==-1)
+ {
+ //Boundary vertex
+ tripletList.emplace_back(NI(i,j) + n_odd, F(i,j), 1./2.);
+ tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+1)%3), 1./2.);
+ } else
+ {
+ tripletList.emplace_back(NI(i,j) + n_odd, F(i,j), 3./8.);
+ tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+1)%3), 3./8.);
+ tripletList.emplace_back(NI(i,j) + n_odd, F(i, (j+2)%3), 1./8.);
+ tripletList.emplace_back(NI(i,j) + n_odd, F(FF(i,j), (FFi(i,j)+2)%3), 1./8.);
+ }
+ }
+ }
+ }
+ S.resize(n_newverts, n_verts);
+ S.setFromTriplets(tripletList.begin(), tripletList.end());
+
+ // Build the new topology (Every face is replaced by four)
+ NF.resize(F.rows()*4, 3);
+ for(int i=0; i<F.rows();++i)
+ {
+ Eigen::VectorXi VI(6);
+ VI << F(i,0), F(i,1), F(i,2), NI(i,0) + n_odd, NI(i,1) + n_odd, NI(i,2) + n_odd;
+
+ Eigen::VectorXi f0(3), f1(3), f2(3), f3(3);
+ f0 << VI(0), VI(3), VI(5);
+ f1 << VI(1), VI(4), VI(3);
+ f2 << VI(3), VI(4), VI(5);
+ f3 << VI(4), VI(2), VI(5);
+
+ NF.row((i*4)+0) = f0;
+ NF.row((i*4)+1) = f1;
+ NF.row((i*4)+2) = f2;
+ NF.row((i*4)+3) = f3;
+ }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF>
+IGL_INLINE void igl::loop(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedNV>& NV,
+ Eigen::PlainObjectBase<DerivedNF>& NF,
+ const int number_of_subdivs)
+{
+ NV = V;
+ NF = F;
+ for(int i=0; i<number_of_subdivs; ++i)
+ {
+ DerivedNF tempF = NF;
+ Eigen::SparseMatrix<typename DerivedV::Scalar> S;
+ loop(NV.rows(), tempF, S, NF);
+ // This .eval is super important
+ NV = (S*NV).eval();
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::loop<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, int);
+#endif
diff --git a/xs/src/igl/loop.h b/xs/src/igl/loop.h
new file mode 100644
index 000000000..bc1616891
--- /dev/null
+++ b/xs/src/igl/loop.h
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Oded Stein <oded.stein@columbia.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_LOOP_H
+#define IGL_LOOP_H
+
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // LOOP Given the triangle mesh [V, F], where n_verts = V.rows(), computes
+ // newV and a sparse matrix S s.t. [newV, newF] is the subdivided mesh where
+ // newV = S*V.
+ //
+ // Inputs:
+ // n_verts an integer (number of mesh vertices)
+ // F an m by 3 matrix of integers of triangle faces
+ // Outputs:
+ // S a sparse matrix (will become the subdivision matrix)
+ // newF a matrix containing the new faces
+ template <
+ typename DerivedF,
+ typename SType,
+ typename DerivedNF>
+ IGL_INLINE void loop(
+ const int n_verts,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::SparseMatrix<SType>& S,
+ Eigen::PlainObjectBase<DerivedNF> & NF);
+ // LOOP Given the triangle mesh [V, F], computes number_of_subdivs steps of loop subdivision and outputs the new mesh [newV, newF]
+ //
+ // Inputs:
+ // V an n by 3 matrix of vertices
+ // F an m by 3 matrix of integers of triangle faces
+ // number_of_subdivs an integer that specifies how many subdivision steps to do
+ // Outputs:
+ // NV a matrix containing the new vertices
+ // NF a matrix containing the new faces
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF>
+ IGL_INLINE void loop(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedNV>& NV,
+ Eigen::PlainObjectBase<DerivedNF>& NF,
+ const int number_of_subdivs = 1);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "loop.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/lscm.cpp b/xs/src/igl/lscm.cpp
new file mode 100644
index 000000000..6932f94d4
--- /dev/null
+++ b/xs/src/igl/lscm.cpp
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "lscm.h"
+
+#include "vector_area_matrix.h"
+#include "cotmatrix.h"
+#include "repdiag.h"
+#include "min_quad_with_fixed.h"
+#include <iostream>
+
+IGL_INLINE bool igl::lscm(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc,
+ Eigen::MatrixXd & V_uv)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ // Assemble the area matrix (note that A is #Vx2 by #Vx2)
+ SparseMatrix<double> A;
+ igl::vector_area_matrix(F,A);
+
+ // Assemble the cotan laplacian matrix
+ SparseMatrix<double> L;
+ igl::cotmatrix(V,F,L);
+
+ SparseMatrix<double> L_flat;
+ repdiag(L,2,L_flat);
+
+ VectorXi b_flat(b.size()*bc.cols(),1);
+ VectorXd bc_flat(bc.size(),1);
+ for(int c = 0;c<bc.cols();c++)
+ {
+ b_flat.block(c*b.size(),0,b.rows(),1) = c*V.rows() + b.array();
+ bc_flat.block(c*bc.rows(),0,bc.rows(),1) = bc.col(c);
+ }
+
+ // Minimize the LSCM energy
+ SparseMatrix<double> Q = -L_flat + 2.*A;
+ const VectorXd B_flat = VectorXd::Zero(V.rows()*2);
+ igl::min_quad_with_fixed_data<double> data;
+ if(!igl::min_quad_with_fixed_precompute(Q,b_flat,SparseMatrix<double>(),true,data))
+ {
+ return false;
+ }
+
+ MatrixXd W_flat;
+ if(!min_quad_with_fixed_solve(data,B_flat,bc_flat,VectorXd(),W_flat))
+ {
+ return false;
+ }
+
+
+ assert(W_flat.rows() == V.rows()*2);
+ V_uv.resize(V.rows(),2);
+ for (unsigned i=0;i<V_uv.cols();++i)
+ {
+ V_uv.col(V_uv.cols()-i-1) = W_flat.block(V_uv.rows()*i,0,V_uv.rows(),1);
+ }
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/lscm.h b/xs/src/igl/lscm.h
new file mode 100644
index 000000000..2386215df
--- /dev/null
+++ b/xs/src/igl/lscm.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+// 2015 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_LSCM_H
+#define IGL_LSCM_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Compute a Least-squares conformal map parametrization (equivalently
+ // derived in "Intrinsic Parameterizations of Surface Meshes" [Desbrun et al.
+ // 2002] and "Least Squares Conformal Maps for Automatic Texture Atlas
+ // Generation" [Lévy et al. 2002]), though this implementation follows the
+ // derivation in: "Spectral Conformal Parameterization" [Mullen et al. 2008]
+ // (note, this does **not** implement the Eigen-decomposition based method in
+ // [Mullen et al. 2008], which is not equivalent). Input should be a manifold
+ // mesh (also no unreferenced vertices) and "boundary" (fixed vertices) `b`
+ // should contain at least two vertices per connected component.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of mesh faces (must be triangles)
+ // b #b boundary indices into V
+ // bc #b by 3 list of boundary values
+ // Outputs:
+ // UV #V by 2 list of 2D mesh vertex positions in UV space
+ // Returns true only on solver success.
+ //
+ IGL_INLINE bool lscm(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::VectorXi& b,
+ const Eigen::MatrixXd& bc,
+ Eigen::MatrixXd& V_uv);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "lscm.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/map_vertices_to_circle.cpp b/xs/src/igl/map_vertices_to_circle.cpp
new file mode 100755
index 000000000..233613936
--- /dev/null
+++ b/xs/src/igl/map_vertices_to_circle.cpp
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "map_vertices_to_circle.h"
+#include "PI.h"
+
+IGL_INLINE void igl::map_vertices_to_circle(
+ const Eigen::MatrixXd& V,
+ const Eigen::VectorXi& bnd,
+ Eigen::MatrixXd& UV)
+{
+ // Get sorted list of boundary vertices
+ std::vector<int> interior,map_ij;
+ map_ij.resize(V.rows());
+
+ std::vector<bool> isOnBnd(V.rows(),false);
+ for (int i = 0; i < bnd.size(); i++)
+ {
+ isOnBnd[bnd[i]] = true;
+ map_ij[bnd[i]] = i;
+ }
+
+ for (int i = 0; i < (int)isOnBnd.size(); i++)
+ {
+ if (!isOnBnd[i])
+ {
+ map_ij[i] = interior.size();
+ interior.push_back(i);
+ }
+ }
+
+ // Map boundary to unit circle
+ std::vector<double> len(bnd.size());
+ len[0] = 0.;
+
+ for (int i = 1; i < bnd.size(); i++)
+ {
+ len[i] = len[i-1] + (V.row(bnd[i-1]) - V.row(bnd[i])).norm();
+ }
+ double total_len = len[len.size()-1] + (V.row(bnd[0]) - V.row(bnd[bnd.size()-1])).norm();
+
+ UV.resize(bnd.size(),2);
+ for (int i = 0; i < bnd.size(); i++)
+ {
+ double frac = len[i] * 2. * igl::PI / total_len;
+ UV.row(map_ij[bnd[i]]) << cos(frac), sin(frac);
+ }
+
+}
diff --git a/xs/src/igl/map_vertices_to_circle.h b/xs/src/igl/map_vertices_to_circle.h
new file mode 100755
index 000000000..54743717f
--- /dev/null
+++ b/xs/src/igl/map_vertices_to_circle.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MAP_VERTICES_TO_CIRCLE_H
+#define IGL_MAP_VERTICES_TO_CIRCLE_H
+#include "igl_inline.h"
+#include "PI.h"
+
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl
+{
+
+ // Map the vertices whose indices are in a given boundary loop (bnd) on the
+ // unit circle with spacing proportional to the original boundary edge
+ // lengths.
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // b #W list of vertex ids
+ // Outputs:
+ // UV #W by 2 list of 2D position on the unit circle for the vertices in b
+ IGL_INLINE void map_vertices_to_circle(
+ const Eigen::MatrixXd& V,
+ const Eigen::VectorXi& bnd,
+ Eigen::MatrixXd& UV);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "map_vertices_to_circle.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/massmatrix.cpp b/xs/src/igl/massmatrix.cpp
new file mode 100644
index 000000000..b51e11061
--- /dev/null
+++ b/xs/src/igl/massmatrix.cpp
@@ -0,0 +1,166 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "massmatrix.h"
+#include "normalize_row_sums.h"
+#include "sparse.h"
+#include "doublearea.h"
+#include "repmat.h"
+#include <Eigen/Geometry>
+#include <iostream>
+
+template <typename DerivedV, typename DerivedF, typename Scalar>
+IGL_INLINE void igl::massmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const MassMatrixType type,
+ Eigen::SparseMatrix<Scalar>& M)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ const int n = V.rows();
+ const int m = F.rows();
+ const int simplex_size = F.cols();
+
+ MassMatrixType eff_type = type;
+ // Use voronoi of for triangles by default, otherwise barycentric
+ if(type == MASSMATRIX_TYPE_DEFAULT)
+ {
+ eff_type = (simplex_size == 3?MASSMATRIX_TYPE_VORONOI:MASSMATRIX_TYPE_BARYCENTRIC);
+ }
+
+ // Not yet supported
+ assert(type!=MASSMATRIX_TYPE_FULL);
+
+ Matrix<int,Dynamic,1> MI;
+ Matrix<int,Dynamic,1> MJ;
+ Matrix<Scalar,Dynamic,1> MV;
+ if(simplex_size == 3)
+ {
+ // Triangles
+ // edge lengths numbered same as opposite vertices
+ Matrix<Scalar,Dynamic,3> l(m,3);
+ // loop over faces
+ for(int i = 0;i<m;i++)
+ {
+ l(i,0) = (V.row(F(i,1))-V.row(F(i,2))).norm();
+ l(i,1) = (V.row(F(i,2))-V.row(F(i,0))).norm();
+ l(i,2) = (V.row(F(i,0))-V.row(F(i,1))).norm();
+ }
+ Matrix<Scalar,Dynamic,1> dblA;
+ doublearea(l,0.,dblA);
+
+ switch(eff_type)
+ {
+ case MASSMATRIX_TYPE_BARYCENTRIC:
+ // diagonal entries for each face corner
+ MI.resize(m*3,1); MJ.resize(m*3,1); MV.resize(m*3,1);
+ MI.block(0*m,0,m,1) = F.col(0);
+ MI.block(1*m,0,m,1) = F.col(1);
+ MI.block(2*m,0,m,1) = F.col(2);
+ MJ = MI;
+ repmat(dblA,3,1,MV);
+ MV.array() /= 6.0;
+ break;
+ case MASSMATRIX_TYPE_VORONOI:
+ {
+ // diagonal entries for each face corner
+ // http://www.alecjacobson.com/weblog/?p=874
+ MI.resize(m*3,1); MJ.resize(m*3,1); MV.resize(m*3,1);
+ MI.block(0*m,0,m,1) = F.col(0);
+ MI.block(1*m,0,m,1) = F.col(1);
+ MI.block(2*m,0,m,1) = F.col(2);
+ MJ = MI;
+
+ // Holy shit this needs to be cleaned up and optimized
+ Matrix<Scalar,Dynamic,3> cosines(m,3);
+ cosines.col(0) =
+ (l.col(2).array().pow(2)+l.col(1).array().pow(2)-l.col(0).array().pow(2))/(l.col(1).array()*l.col(2).array()*2.0);
+ cosines.col(1) =
+ (l.col(0).array().pow(2)+l.col(2).array().pow(2)-l.col(1).array().pow(2))/(l.col(2).array()*l.col(0).array()*2.0);
+ cosines.col(2) =
+ (l.col(1).array().pow(2)+l.col(0).array().pow(2)-l.col(2).array().pow(2))/(l.col(0).array()*l.col(1).array()*2.0);
+ Matrix<Scalar,Dynamic,3> barycentric = cosines.array() * l.array();
+ normalize_row_sums(barycentric,barycentric);
+ Matrix<Scalar,Dynamic,3> partial = barycentric;
+ partial.col(0).array() *= dblA.array() * 0.5;
+ partial.col(1).array() *= dblA.array() * 0.5;
+ partial.col(2).array() *= dblA.array() * 0.5;
+ Matrix<Scalar,Dynamic,3> quads(partial.rows(),partial.cols());
+ quads.col(0) = (partial.col(1)+partial.col(2))*0.5;
+ quads.col(1) = (partial.col(2)+partial.col(0))*0.5;
+ quads.col(2) = (partial.col(0)+partial.col(1))*0.5;
+
+ quads.col(0) = (cosines.col(0).array()<0).select( 0.25*dblA,quads.col(0));
+ quads.col(1) = (cosines.col(0).array()<0).select(0.125*dblA,quads.col(1));
+ quads.col(2) = (cosines.col(0).array()<0).select(0.125*dblA,quads.col(2));
+
+ quads.col(0) = (cosines.col(1).array()<0).select(0.125*dblA,quads.col(0));
+ quads.col(1) = (cosines.col(1).array()<0).select(0.25*dblA,quads.col(1));
+ quads.col(2) = (cosines.col(1).array()<0).select(0.125*dblA,quads.col(2));
+
+ quads.col(0) = (cosines.col(2).array()<0).select(0.125*dblA,quads.col(0));
+ quads.col(1) = (cosines.col(2).array()<0).select(0.125*dblA,quads.col(1));
+ quads.col(2) = (cosines.col(2).array()<0).select( 0.25*dblA,quads.col(2));
+
+ MV.block(0*m,0,m,1) = quads.col(0);
+ MV.block(1*m,0,m,1) = quads.col(1);
+ MV.block(2*m,0,m,1) = quads.col(2);
+
+ break;
+ }
+ case MASSMATRIX_TYPE_FULL:
+ assert(false && "Implementation incomplete");
+ break;
+ default:
+ assert(false && "Unknown Mass matrix eff_type");
+ }
+
+ }else if(simplex_size == 4)
+ {
+ assert(V.cols() == 3);
+ assert(eff_type == MASSMATRIX_TYPE_BARYCENTRIC);
+ MI.resize(m*4,1); MJ.resize(m*4,1); MV.resize(m*4,1);
+ MI.block(0*m,0,m,1) = F.col(0);
+ MI.block(1*m,0,m,1) = F.col(1);
+ MI.block(2*m,0,m,1) = F.col(2);
+ MI.block(3*m,0,m,1) = F.col(3);
+ MJ = MI;
+ // loop over tets
+ for(int i = 0;i<m;i++)
+ {
+ // http://en.wikipedia.org/wiki/Tetrahedron#Volume
+ Matrix<Scalar,3,1> v0m3,v1m3,v2m3;
+ v0m3.head(V.cols()) = V.row(F(i,0)) - V.row(F(i,3));
+ v1m3.head(V.cols()) = V.row(F(i,1)) - V.row(F(i,3));
+ v2m3.head(V.cols()) = V.row(F(i,2)) - V.row(F(i,3));
+ Scalar v = fabs(v0m3.dot(v1m3.cross(v2m3)))/6.0;
+ MV(i+0*m) = v/4.0;
+ MV(i+1*m) = v/4.0;
+ MV(i+2*m) = v/4.0;
+ MV(i+3*m) = v/4.0;
+ }
+ }else
+ {
+ // Unsupported simplex size
+ assert(false && "Unsupported simplex size");
+ }
+ sparse(MI,MJ,MV,n,n,M);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::massmatrix<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MassMatrixType, Eigen::SparseMatrix<double, 0, int>&);
+// generated by autoexplicit.sh
+template void igl::massmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, igl::MassMatrixType, Eigen::SparseMatrix<double, 0, int>&);
+// generated by autoexplicit.sh
+template void igl::massmatrix<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::MassMatrixType, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::massmatrix<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::MassMatrixType, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::massmatrix<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::MassMatrixType, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/massmatrix.h b/xs/src/igl/massmatrix.h
new file mode 100644
index 000000000..69d8dc960
--- /dev/null
+++ b/xs/src/igl/massmatrix.h
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MASSMATRIX_TYPE_H
+#define IGL_MASSMATRIX_TYPE_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+
+ enum MassMatrixType
+ {
+ MASSMATRIX_TYPE_BARYCENTRIC = 0,
+ MASSMATRIX_TYPE_VORONOI = 1,
+ MASSMATRIX_TYPE_FULL = 2,
+ MASSMATRIX_TYPE_DEFAULT = 3,
+ NUM_MASSMATRIX_TYPE = 4
+ };
+
+ // Constructs the mass (area) matrix for a given mesh (V,F).
+ //
+ // Templates:
+ // DerivedV derived type of eigen matrix for V (e.g. derived from
+ // MatrixXd)
+ // DerivedF derived type of eigen matrix for F (e.g. derived from
+ // MatrixXi)
+ // Scalar scalar type for eigen sparse matrix (e.g. double)
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by simplex_size list of mesh faces (must be triangles)
+ // type one of the following ints:
+ // MASSMATRIX_TYPE_BARYCENTRIC barycentric
+ // MASSMATRIX_TYPE_VORONOI voronoi-hybrid {default}
+ // MASSMATRIX_TYPE_FULL full {not implemented}
+ // Outputs:
+ // M #V by #V mass matrix
+ //
+ // See also: adjacency_matrix
+ //
+ template <typename DerivedV, typename DerivedF, typename Scalar>
+ IGL_INLINE void massmatrix(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const MassMatrixType type,
+ Eigen::SparseMatrix<Scalar>& M);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "massmatrix.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/mat_max.cpp b/xs/src/igl/mat_max.cpp
new file mode 100644
index 000000000..c5da97569
--- /dev/null
+++ b/xs/src/igl/mat_max.cpp
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mat_max.h"
+
+template <typename DerivedX, typename DerivedY, typename DerivedI>
+IGL_INLINE void igl::mat_max(
+ const Eigen::DenseBase<DerivedX> & X,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY> & Y,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ assert(dim==1||dim==2);
+
+ // output size
+ int n = (dim==1?X.cols():X.rows());
+ // resize output
+ Y.resize(n);
+ I.resize(n);
+
+ // loop over dimension opposite of dim
+ for(int j = 0;j<n;j++)
+ {
+ typename DerivedX::Index PHONY,i;
+ typename DerivedX::Scalar m;
+ if(dim==1)
+ {
+ m = X.col(j).maxCoeff(&i,&PHONY);
+ }else
+ {
+ m = X.row(j).maxCoeff(&PHONY,&i);
+ }
+ Y(j) = m;
+ I(j) = i;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::mat_max<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/mat_max.h b/xs/src/igl/mat_max.h
new file mode 100644
index 000000000..ad3ec6e61
--- /dev/null
+++ b/xs/src/igl/mat_max.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MAT_MAX_H
+#define IGL_MAT_MAX_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Ideally this becomes a super overloaded function supporting everything
+ // that matlab's max supports
+
+ // Max function for matrices to act like matlab's max function. Specifically
+ // like [Y,I] = max(X,[],dim);
+ //
+ // Templates:
+ // T should be a eigen matrix primitive type like int or double
+ // Inputs:
+ // X m by n matrix
+ // dim dimension along which to take max
+ // Outputs:
+ // Y n-long vector (if dim == 1)
+ // or
+ // Y m-long vector (if dim == 2)
+ // I vector the same size as Y containing the indices along dim of maximum
+ // entries
+ template <typename DerivedX, typename DerivedY, typename DerivedI>
+ IGL_INLINE void mat_max(
+ const Eigen::DenseBase<DerivedX> & X,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY> & Y,
+ Eigen::PlainObjectBase<DerivedI> & I);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mat_max.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/mat_min.cpp b/xs/src/igl/mat_min.cpp
new file mode 100644
index 000000000..ad50c7014
--- /dev/null
+++ b/xs/src/igl/mat_min.cpp
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mat_min.h"
+
+template <typename DerivedX, typename DerivedY, typename DerivedI>
+IGL_INLINE void igl::mat_min(
+ const Eigen::DenseBase<DerivedX> & X,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY> & Y,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ assert(dim==1||dim==2);
+
+ // output size
+ int n = (dim==1?X.cols():X.rows());
+ // resize output
+ Y.resize(n);
+ I.resize(n);
+
+ // loop over dimension opposite of dim
+ for(int j = 0;j<n;j++)
+ {
+ typename DerivedX::Index PHONY,i;
+ typename DerivedX::Scalar m;
+ if(dim==1)
+ {
+ m = X.col(j).minCoeff(&i,&PHONY);
+ }else
+ {
+ m = X.row(j).minCoeff(&PHONY,&i);
+ }
+ Y(j) = m;
+ I(j) = i;
+ }
+}
+
+//template <typename T>
+//IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> igl::mat_min(
+// const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
+// const int dim)
+//{
+// Eigen::Matrix<T,Eigen::Dynamic,1> Y;
+// Eigen::Matrix<int,Eigen::Dynamic,1> I;
+// mat_min(X,dim,Y,I);
+// return Y;
+//}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::mat_min<Eigen::Array<bool, -1, 3, 0, -1, 3>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Array<bool, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::mat_min<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/mat_min.h b/xs/src/igl/mat_min.h
new file mode 100644
index 000000000..3673aeded
--- /dev/null
+++ b/xs/src/igl/mat_min.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MAT_MIN_H
+#define IGL_MAT_MIN_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Ideally this becomes a super overloaded function supporting everything
+ // that matlab's min supports
+
+ // Min function for matrices to act like matlab's min function. Specifically
+ // like [Y,I] = min(X,[],dim);
+ //
+ // Templates:
+ // T should be a eigen matrix primitive type like int or double
+ // Inputs:
+ // X m by n matrix
+ // dim dimension along which to take min
+ // Outputs:
+ // Y n-long sparse vector (if dim == 1)
+ // or
+ // Y m-long sparse vector (if dim == 2)
+ // I vector the same size as Y containing the indices along dim of minimum
+ // entries
+ //
+ // See also: mat_max
+ template <typename DerivedX, typename DerivedY, typename DerivedI>
+ IGL_INLINE void mat_min(
+ const Eigen::DenseBase<DerivedX> & X,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY> & Y,
+ Eigen::PlainObjectBase<DerivedI> & I);
+ // Use Y = X.colwise().minCoeff() instead
+ //// In-line wrapper
+ //template <typename T>
+ //IGL_INLINE Eigen::Matrix<T,Eigen::Dynamic,1> mat_min(
+ // const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
+ // const int dim);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mat_min.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/mat_to_quat.cpp b/xs/src/igl/mat_to_quat.cpp
new file mode 100644
index 000000000..5c8e04b1f
--- /dev/null
+++ b/xs/src/igl/mat_to_quat.cpp
@@ -0,0 +1,141 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mat_to_quat.h"
+#include <cmath>
+
+// This could be replaced by something fast
+template <typename Q_type>
+static inline Q_type ReciprocalSqrt( const Q_type x )
+{
+ return 1.0/sqrt(x);
+}
+
+//// Converts row major order matrix to quat
+//// http://software.intel.com/sites/default/files/m/d/4/1/d/8/293748.pdf
+//template <typename Q_type>
+//IGL_INLINE void igl::mat4_to_quat(const Q_type * m, Q_type * q)
+//{
+// Q_type t = + m[0 * 4 + 0] + m[1 * 4 + 1] + m[2 * 4 + 2] + 1.0f;
+// Q_type s = ReciprocalSqrt( t ) * 0.5f;
+// q[3] = s * t;
+// q[2] = ( m[0 * 4 + 1] - m[1 * 4 + 0] ) * s;
+// q[1] = ( m[2 * 4 + 0] - m[0 * 4 + 2] ) * s;
+// q[0] = ( m[1 * 4 + 2] - m[2 * 4 + 1] ) * s;
+//}
+
+// https://bmgame.googlecode.com/svn/idlib/math/Simd_AltiVec.cpp
+template <typename Q_type>
+IGL_INLINE void igl::mat4_to_quat(const Q_type * mat, Q_type * q)
+{
+ Q_type trace;
+ Q_type s;
+ Q_type t;
+ int i;
+ int j;
+ int k;
+
+ static int next[3] = { 1, 2, 0 };
+
+ trace = mat[0 * 4 + 0] + mat[1 * 4 + 1] + mat[2 * 4 + 2];
+
+ if ( trace > 0.0f ) {
+
+ t = trace + 1.0f;
+ s = ReciprocalSqrt( t ) * 0.5f;
+
+ q[3] = s * t;
+ q[0] = ( mat[1 * 4 + 2] - mat[2 * 4 + 1] ) * s;
+ q[1] = ( mat[2 * 4 + 0] - mat[0 * 4 + 2] ) * s;
+ q[2] = ( mat[0 * 4 + 1] - mat[1 * 4 + 0] ) * s;
+
+ } else {
+
+ i = 0;
+ if ( mat[1 * 4 + 1] > mat[0 * 4 + 0] ) {
+ i = 1;
+ }
+ if ( mat[2 * 4 + 2] > mat[i * 4 + i] ) {
+ i = 2;
+ }
+ j = next[i];
+ k = next[j];
+
+ t = ( mat[i * 4 + i] - ( mat[j * 4 + j] + mat[k * 4 + k] ) ) + 1.0f;
+ s = ReciprocalSqrt( t ) * 0.5f;
+
+ q[i] = s * t;
+ q[3] = ( mat[j * 4 + k] - mat[k * 4 + j] ) * s;
+ q[j] = ( mat[i * 4 + j] + mat[j * 4 + i] ) * s;
+ q[k] = ( mat[i * 4 + k] + mat[k * 4 + i] ) * s;
+ }
+
+ //// Unused translation
+ //jq.t[0] = mat[0 * 4 + 3];
+ //jq.t[1] = mat[1 * 4 + 3];
+ //jq.t[2] = mat[2 * 4 + 3];
+}
+
+template <typename Q_type>
+IGL_INLINE void igl::mat3_to_quat(const Q_type * mat, Q_type * q)
+{
+ Q_type trace;
+ Q_type s;
+ Q_type t;
+ int i;
+ int j;
+ int k;
+
+ static int next[3] = { 1, 2, 0 };
+
+ trace = mat[0 * 3 + 0] + mat[1 * 3 + 1] + mat[2 * 3 + 2];
+
+ if ( trace > 0.0f ) {
+
+ t = trace + 1.0f;
+ s = ReciprocalSqrt( t ) * 0.5f;
+
+ q[3] = s * t;
+ q[0] = ( mat[1 * 3 + 2] - mat[2 * 3 + 1] ) * s;
+ q[1] = ( mat[2 * 3 + 0] - mat[0 * 3 + 2] ) * s;
+ q[2] = ( mat[0 * 3 + 1] - mat[1 * 3 + 0] ) * s;
+
+ } else {
+
+ i = 0;
+ if ( mat[1 * 3 + 1] > mat[0 * 3 + 0] ) {
+ i = 1;
+ }
+ if ( mat[2 * 3 + 2] > mat[i * 3 + i] ) {
+ i = 2;
+ }
+ j = next[i];
+ k = next[j];
+
+ t = ( mat[i * 3 + i] - ( mat[j * 3 + j] + mat[k * 3 + k] ) ) + 1.0f;
+ s = ReciprocalSqrt( t ) * 0.5f;
+
+ q[i] = s * t;
+ q[3] = ( mat[j * 3 + k] - mat[k * 3 + j] ) * s;
+ q[j] = ( mat[i * 3 + j] + mat[j * 3 + i] ) * s;
+ q[k] = ( mat[i * 3 + k] + mat[k * 3 + i] ) * s;
+ }
+
+ //// Unused translation
+ //jq.t[0] = mat[0 * 4 + 3];
+ //jq.t[1] = mat[1 * 4 + 3];
+ //jq.t[2] = mat[2 * 4 + 3];
+}
+
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::mat4_to_quat<double>(double const*, double*);
+template void igl::mat4_to_quat<float>(float const*, float*);
+template void igl::mat3_to_quat<double>(double const*, double*);
+#endif
diff --git a/xs/src/igl/mat_to_quat.h b/xs/src/igl/mat_to_quat.h
new file mode 100644
index 000000000..acea683f7
--- /dev/null
+++ b/xs/src/igl/mat_to_quat.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MAT_TO_QUAT_H
+#define IGL_MAT_TO_QUAT_H
+#include "igl_inline.h"
+namespace igl
+{
+ // Convert a OpenGL (rotation) matrix to a quaternion
+ //
+ // Input:
+ // m 16-element opengl rotation matrix
+ // Output:
+ // q 4-element quaternion (not normalized)
+ template <typename Q_type>
+ IGL_INLINE void mat4_to_quat(const Q_type * m, Q_type * q);
+ // Input:
+ // m 9-element opengl rotation matrix
+ template <typename Q_type>
+ IGL_INLINE void mat3_to_quat(const Q_type * m, Q_type * q);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mat_to_quat.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/material_colors.h b/xs/src/igl/material_colors.h
new file mode 100644
index 000000000..1927fa42d
--- /dev/null
+++ b/xs/src/igl/material_colors.h
@@ -0,0 +1,57 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATERIAL_COLORS_H
+#define IGL_MATERIAL_COLORS_H
+#include <Eigen/Core>
+// Define constant material colors for use with opengl glMaterialfv
+// Most of these colors come from IGL publications
+namespace igl
+{
+ // Gold/Silver used in BBW/MONO/STBS/FAST
+ const float GOLD_AMBIENT[4] = { 51.0/255.0, 43.0/255.0,33.3/255.0,1.0f };
+ const float GOLD_DIFFUSE[4] = { 255.0/255.0,228.0/255.0,58.0/255.0,1.0f };
+ const float GOLD_SPECULAR[4] = { 255.0/255.0,235.0/255.0,80.0/255.0,1.0f };
+ const float SILVER_AMBIENT[4] = { 0.2f, 0.2f, 0.2f, 1.0f };
+ const float SILVER_DIFFUSE[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ const float SILVER_SPECULAR[4] = { 1.0f, 1.0f, 1.0f, 1.0f };
+ // Blue/Cyan more similar to Jovan Popovic's blue than to Mario Botsch's blue
+ const float CYAN_AMBIENT[4] = { 59.0/255.0, 68.0/255.0,255.0/255.0,1.0f };
+ const float CYAN_DIFFUSE[4] = { 94.0/255.0,185.0/255.0,238.0/255.0,1.0f };
+ const float CYAN_SPECULAR[4] = { 163.0/255.0,221.0/255.0,255.0/255.0,1.0f };
+ const float DENIS_PURPLE_DIFFUSE[4] = { 80.0/255.0,64.0/255.0,255.0/255.0,1.0f };
+ const float LADISLAV_ORANGE_DIFFUSE[4] = {1.0f, 125.0f / 255.0f, 19.0f / 255.0f, 0.0f};
+ // FAST armadillos colors
+ const float FAST_GREEN_DIFFUSE[4] = { 113.0f/255.0f, 239.0f/255.0f, 46.0f/255.0f, 1.0f};
+ const float FAST_RED_DIFFUSE[4] = { 255.0f/255.0f, 65.0f/255.0f, 46.0f/255.0f, 1.0f};
+ const float FAST_BLUE_DIFFUSE[4] = { 106.0f/255.0f, 106.0f/255.0f, 255.0f/255.0f, 1.0f};
+ const float FAST_GRAY_DIFFUSE[4] = { 150.0f/255.0f, 150.0f/255.0f, 150.0f/255.0f, 1.0f};
+ // Basic colors
+ const float WHITE[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
+ const float BLACK[4] = { 0.0/255.0,0.0/255.0,0.0/255.0,1.0f };
+ const float WHITE_AMBIENT[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
+ const float WHITE_DIFFUSE[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
+ const float WHITE_SPECULAR[4] = { 255.0/255.0,255.0/255.0,255.0/255.0,1.0f };
+ const float BBW_POINT_COLOR[4] = {239./255.,213./255.,46./255.,255.0/255.0};
+ const float BBW_LINE_COLOR[4] = {106./255.,106./255.,255./255.,255./255.};
+ const float MIDNIGHT_BLUE_DIFFUSE[4] = { 21.0f/255.0f, 27.0f/255.0f, 84.0f/255.0f, 1.0f};
+ // Winding number colors
+ const float EASTER_RED_DIFFUSE[4] = {0.603922,0.494118f,0.603922f,1.0f};
+ const float WN_OPEN_BOUNDARY_COLOR[4] = {154./255.,0./255.,0./255.,1.0f};
+ const float WN_NON_MANIFOLD_EDGE_COLOR[4] = {201./255., 51./255.,255./255.,1.0f};
+ const Eigen::Vector4f
+ MAYA_GREEN(128./255.,242./255.,0./255.,1.),
+ MAYA_YELLOW(255./255.,247./255.,50./255.,1.),
+ MAYA_RED(234./255.,63./255.,52./255.,1.),
+ MAYA_BLUE(0./255.,73./255.,252./255.,1.),
+ MAYA_PURPLE(180./255.,73./255.,200./255.,1.),
+ MAYA_VIOLET(31./255.,15./255.,66./255.,1.),
+ MAYA_GREY(0.5,0.5,0.5,1.0),
+ MAYA_CYAN(131./255.,219./255.,252./255.,1.),
+ MAYA_SEA_GREEN(70./255.,252./255.,167./255.,1.);
+}
+#endif
diff --git a/xs/src/igl/matlab/MatlabWorkspace.h b/xs/src/igl/matlab/MatlabWorkspace.h
new file mode 100644
index 000000000..c8dcaf9ed
--- /dev/null
+++ b/xs/src/igl/matlab/MatlabWorkspace.h
@@ -0,0 +1,579 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATLAB_MATLAB_WORKSPACE_H
+#define IGL_MATLAB_MATLAB_WORKSPACE_H
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+#include <mat.h>
+
+#include <string>
+#include <vector>
+
+namespace igl
+{
+ namespace matlab
+ {
+ // It would be really great to replicate this for a simple XML-based
+ // workspace.
+ //
+ // Class which contains data of a matlab workspace which can be written to a
+ // .mat file and loaded from matlab
+ //
+ // This depends on matlab at compile time (though it shouldn't necessarily
+ // have to) but it does not depend on running the matlab engine at run-time.
+ //
+ // Known bugs: Treats all matrices as doubles (this may actually be desired
+ // for some "index" matrices since matlab's sparse command takes doubles
+ // rather than int class matrices). It is of course not desired when dealing
+ // with logicals or uint's for images.
+ class MatlabWorkspace
+ {
+ private:
+ // KNOWN BUG: Why not use a map? Any reason to allow duplicate names?
+ //
+ // List of names
+ std::vector<std::string> names;
+ // List of data pointers
+ std::vector<mxArray*> data;
+ public:
+ MatlabWorkspace();
+ ~MatlabWorkspace();
+ // Clear names and data of variables in workspace
+ inline void clear();
+ // Save current list of variables
+ //
+ // Inputs:
+ // path path to .mat file
+ // Returns true on success, false on failure
+ inline bool write(const std::string & path) const;
+ // Load list of variables from .mat file
+ //
+ // Inputs:
+ // path path to .mat file
+ // Returns true on success, false on failure
+ inline bool read(const std::string & path);
+ // Assign data to a variable name in the workspace
+ //
+ // Template:
+ // DerivedM eigen matrix (e.g. MatrixXd)
+ // Inputs:
+ // M data (usually a matrix)
+ // name variable name to save into work space
+ // Returns true on success, false on failure
+ //
+ // Known Bugs: Assumes Eigen is using column major ordering
+ template <typename DerivedM>
+ inline MatlabWorkspace& save(
+ const Eigen::PlainObjectBase<DerivedM>& M,
+ const std::string & name);
+ // Template:
+ // MT sparse matrix type (e.g. double)
+ template <typename MT>
+ inline MatlabWorkspace& save(
+ const Eigen::SparseMatrix<MT>& M,
+ const std::string & name);
+ // Templates:
+ // ScalarM scalar type, e.g. double
+ template <typename ScalarM>
+ inline MatlabWorkspace& save(
+ const std::vector<std::vector<ScalarM> > & vM,
+ const std::string & name);
+ // Templates:
+ // ScalarV scalar type, e.g. double
+ template <typename ScalarV>
+ inline MatlabWorkspace& save(
+ const std::vector<ScalarV> & vV,
+ const std::string & name);
+ // NOTE: Eigen stores quaternions coefficients as (i,j,k,1), but most of
+ // our matlab code stores them as (1,i,j,k) This takes a quaternion and
+ // saves it as a (1,i,j,k) row vector
+ //
+ // Templates:
+ // Q quaternion type
+ template <typename Q>
+ inline MatlabWorkspace& save(
+ const Eigen::Quaternion<Q> & q,
+ const std::string & name);
+ inline MatlabWorkspace& save(
+ const double d,
+ const std::string & name);
+ // Same as save() but adds 1 to each element, useful for saving "index"
+ // matrices like lists of faces or elements
+ template <typename DerivedM>
+ inline MatlabWorkspace& save_index(
+ const Eigen::DenseBase<DerivedM>& M,
+ const std::string & name);
+ template <typename ScalarM>
+ inline MatlabWorkspace& save_index(
+ const std::vector<std::vector<ScalarM> > & vM,
+ const std::string & name);
+ template <typename ScalarV>
+ inline MatlabWorkspace& save_index(
+ const std::vector<ScalarV> & vV,
+ const std::string & name);
+ // Find a certain matrix by name.
+ //
+ // KNOWN BUG: Outputs the first found (not necessarily unique lists).
+ //
+ // Template:
+ // DerivedM eigen matrix (e.g. MatrixXd)
+ // Inputs:
+ // name exact name of matrix as string
+ // Outputs:
+ // M matrix
+ // Returns true only if found.
+ template <typename DerivedM>
+ inline bool find(
+ const std::string & name,
+ Eigen::PlainObjectBase<DerivedM>& M);
+ template <typename MT>
+ inline bool find(
+ const std::string & name,
+ Eigen::SparseMatrix<MT>& M);
+ inline bool find(
+ const std::string & name,
+ double & d);
+ inline bool find(
+ const std::string & name,
+ int & v);
+ // Subtracts 1 from all entries
+ template <typename DerivedM>
+ inline bool find_index(
+ const std::string & name,
+ Eigen::PlainObjectBase<DerivedM>& M);
+ };
+ }
+}
+
+// Implementation
+
+// Be sure that this is not compiled into libigl.a
+// http://stackoverflow.com/a/3318993/148668
+
+// IGL
+#include "igl/list_to_matrix.h"
+
+// MATLAB
+#include "mat.h"
+
+// STL
+#include <iostream>
+#include <algorithm>
+#include <vector>
+
+inline igl::matlab::MatlabWorkspace::MatlabWorkspace():
+ names(),
+ data()
+{
+}
+
+inline igl::matlab::MatlabWorkspace::~MatlabWorkspace()
+{
+ // clean up data
+ clear();
+}
+
+inline void igl::matlab::MatlabWorkspace::clear()
+{
+ for_each(data.begin(),data.end(),&mxDestroyArray);
+ data.clear();
+ names.clear();
+}
+
+inline bool igl::matlab::MatlabWorkspace::write(const std::string & path) const
+{
+ using namespace std;
+ MATFile * mat_file = matOpen(path.c_str(), "w");
+ if(mat_file == NULL)
+ {
+ fprintf(stderr,"Error opening file %s\n",path.c_str());
+ return false;
+ }
+ assert(names.size() == data.size());
+ // loop over names and data
+ for(int i = 0;i < (int)names.size(); i++)
+ {
+ // Put variable as LOCAL variable
+ int status = matPutVariable(mat_file,names[i].c_str(), data[i]);
+ if(status != 0)
+ {
+ cerr<<"^MatlabWorkspace::save Error: matPutVariable ("<<names[i]<<
+ ") failed"<<endl;
+ return false;
+ }
+ }
+ if(matClose(mat_file) != 0)
+ {
+ fprintf(stderr,"Error closing file %s\n",path.c_str());
+ return false;
+ }
+ return true;
+}
+
+inline bool igl::matlab::MatlabWorkspace::read(const std::string & path)
+{
+ using namespace std;
+
+ MATFile * mat_file;
+
+ mat_file = matOpen(path.c_str(), "r");
+ if (mat_file == NULL)
+ {
+ cerr<<"Error: failed to open "<<path<<endl;
+ return false;
+ }
+
+ int ndir;
+ const char ** dir = (const char **)matGetDir(mat_file, &ndir);
+ if (dir == NULL) {
+ cerr<<"Error reading directory of file "<< path<<endl;
+ return false;
+ }
+ mxFree(dir);
+
+ // Must close and reopen
+ if(matClose(mat_file) != 0)
+ {
+ cerr<<"Error: failed to close file "<<path<<endl;
+ return false;
+ }
+ mat_file = matOpen(path.c_str(), "r");
+ if (mat_file == NULL)
+ {
+ cerr<<"Error: failed to open "<<path<<endl;
+ return false;
+ }
+
+
+ /* Read in each array. */
+ for (int i=0; i<ndir; i++)
+ {
+ const char * name;
+ mxArray * mx_data = matGetNextVariable(mat_file, &name);
+ if (mx_data == NULL)
+ {
+ cerr<<"Error: matGetNextVariable failed in "<<path<<endl;
+ return false;
+ }
+ const int dims = mxGetNumberOfDimensions(mx_data);
+ assert(dims == 2);
+ if(dims != 2)
+ {
+ fprintf(stderr,"Variable '%s' has %d ≠ 2 dimensions. Skipping\n",
+ name,dims);
+ mxDestroyArray(mx_data);
+ continue;
+ }
+ // don't destroy
+ names.push_back(name);
+ data.push_back(mx_data);
+ }
+
+ if(matClose(mat_file) != 0)
+ {
+ cerr<<"Error: failed to close file "<<path<<endl;
+ return false;
+ }
+
+ return true;
+}
+
+// Treat everything as a double
+template <typename DerivedM>
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
+ const Eigen::PlainObjectBase<DerivedM>& M,
+ const std::string & name)
+{
+ using namespace std;
+ const int m = M.rows();
+ const int n = M.cols();
+ mxArray * mx_data = mxCreateDoubleMatrix(m,n,mxREAL);
+ data.push_back(mx_data);
+ names.push_back(name);
+ // Copy data immediately
+ // Use Eigen's map and cast to copy
+ Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
+ map(mxGetPr(mx_data),m,n);
+ map = M.template cast<double>();
+ return *this;
+}
+
+// Treat everything as a double
+template <typename MT>
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
+ const Eigen::SparseMatrix<MT>& M,
+ const std::string & name)
+{
+ using namespace std;
+ const int m = M.rows();
+ const int n = M.cols();
+ // THIS WILL NOT WORK FOR ROW-MAJOR
+ assert(n==M.outerSize());
+ const int nzmax = M.nonZeros();
+ mxArray * mx_data = mxCreateSparse(m, n, nzmax, mxREAL);
+ data.push_back(mx_data);
+ names.push_back(name);
+ // Copy data immediately
+ double * pr = mxGetPr(mx_data);
+ mwIndex * ir = mxGetIr(mx_data);
+ mwIndex * jc = mxGetJc(mx_data);
+
+ // Iterate over outside
+ int k = 0;
+ for(int j=0; j<M.outerSize();j++)
+ {
+ jc[j] = k;
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<MT>::InnerIterator it (M,j); it; ++it)
+ {
+ pr[k] = it.value();
+ ir[k] = it.row();
+ k++;
+ }
+ }
+ jc[M.outerSize()] = k;
+
+ return *this;
+}
+
+template <typename ScalarM>
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
+ const std::vector<std::vector<ScalarM> > & vM,
+ const std::string & name)
+{
+ Eigen::MatrixXd M;
+ list_to_matrix(vM,M);
+ return this->save(M,name);
+}
+
+template <typename ScalarV>
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
+ const std::vector<ScalarV> & vV,
+ const std::string & name)
+{
+ Eigen::MatrixXd V;
+ list_to_matrix(vV,V);
+ return this->save(V,name);
+}
+
+template <typename Q>
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
+ const Eigen::Quaternion<Q> & q,
+ const std::string & name)
+{
+ Eigen::Matrix<Q,1,4> qm;
+ qm(0,0) = q.w();
+ qm(0,1) = q.x();
+ qm(0,2) = q.y();
+ qm(0,3) = q.z();
+ return save(qm,name);
+}
+
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save(
+ const double d,
+ const std::string & name)
+{
+ Eigen::VectorXd v(1);
+ v(0) = d;
+ return save(v,name);
+}
+
+template <typename DerivedM>
+inline igl::matlab::MatlabWorkspace&
+ igl::matlab::MatlabWorkspace::save_index(
+ const Eigen::DenseBase<DerivedM>& M,
+ const std::string & name)
+{
+ DerivedM Mp1 = M;
+ Mp1.array() += 1;
+ return this->save(Mp1,name);
+}
+
+template <typename ScalarM>
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save_index(
+ const std::vector<std::vector<ScalarM> > & vM,
+ const std::string & name)
+{
+ Eigen::MatrixXd M;
+ list_to_matrix(vM,M);
+ return this->save_index(M,name);
+}
+
+template <typename ScalarV>
+inline igl::matlab::MatlabWorkspace& igl::matlab::MatlabWorkspace::save_index(
+ const std::vector<ScalarV> & vV,
+ const std::string & name)
+{
+ Eigen::MatrixXd V;
+ list_to_matrix(vV,V);
+ return this->save_index(V,name);
+}
+
+template <typename DerivedM>
+inline bool igl::matlab::MatlabWorkspace::find(
+ const std::string & name,
+ Eigen::PlainObjectBase<DerivedM>& M)
+{
+ using namespace std;
+ const int i = std::find(names.begin(), names.end(), name)-names.begin();
+ if(i>=(int)names.size())
+ {
+ return false;
+ }
+ assert(i<=(int)data.size());
+ mxArray * mx_data = data[i];
+ assert(!mxIsSparse(mx_data));
+ assert(mxGetNumberOfDimensions(mx_data) == 2);
+ //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
+ const int m = mxGetM(mx_data);
+ const int n = mxGetN(mx_data);
+ // Handle vectors: in the sense that anything found becomes a column vector,
+ // whether it was column vector, row vector or matrix
+ if(DerivedM::IsVectorAtCompileTime)
+ {
+ assert(m==1 || n==1 || (m==0 && n==0));
+ M.resize(m*n,1);
+ }else
+ {
+ M.resize(m,n);
+ }
+ assert(mxGetNumberOfElements(mx_data) == M.size());
+ // Use Eigen's map and cast to copy
+ M = Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
+ (mxGetPr(mx_data),M.rows(),M.cols()).cast<typename DerivedM::Scalar>();
+ return true;
+}
+
+template <typename MT>
+inline bool igl::matlab::MatlabWorkspace::find(
+ const std::string & name,
+ Eigen::SparseMatrix<MT>& M)
+{
+ using namespace std;
+ using namespace Eigen;
+ const int i = std::find(names.begin(), names.end(), name)-names.begin();
+ if(i>=(int)names.size())
+ {
+ return false;
+ }
+ assert(i<=(int)data.size());
+ mxArray * mx_data = data[i];
+ // Handle boring case where matrix is actually an empty dense matrix
+ if(mxGetNumberOfElements(mx_data) == 0)
+ {
+ M.resize(0,0);
+ return true;
+ }
+ assert(mxIsSparse(mx_data));
+ assert(mxGetNumberOfDimensions(mx_data) == 2);
+ //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
+ const int m = mxGetM(mx_data);
+ const int n = mxGetN(mx_data);
+ // TODO: It should be possible to directly load the data into the sparse
+ // matrix without going through the triplets
+ // Copy data immediately
+ double * pr = mxGetPr(mx_data);
+ mwIndex * ir = mxGetIr(mx_data);
+ mwIndex * jc = mxGetJc(mx_data);
+ vector<Triplet<MT> > MIJV;
+ const int nnz = mxGetNzmax(mx_data);
+ MIJV.reserve(nnz);
+ // Iterate over outside
+ int k = 0;
+ for(int j=0; j<n;j++)
+ {
+ // Iterate over inside
+ while(k<(int)jc[j+1])
+ {
+ //cout<<ir[k]<<" "<<j<<" "<<pr[k]<<endl;
+ assert((int)ir[k]<m);
+ assert((int)j<n);
+ MIJV.push_back(Triplet<MT >(ir[k],j,pr[k]));
+ k++;
+ }
+ }
+ M.resize(m,n);
+ M.setFromTriplets(MIJV.begin(),MIJV.end());
+
+ return true;
+}
+
+inline bool igl::matlab::MatlabWorkspace::find(
+ const std::string & name,
+ int & v)
+{
+ using namespace std;
+ const int i = std::find(names.begin(), names.end(), name)-names.begin();
+ if(i>=(int)names.size())
+ {
+ return false;
+ }
+ assert(i<=(int)data.size());
+ mxArray * mx_data = data[i];
+ assert(!mxIsSparse(mx_data));
+ assert(mxGetNumberOfDimensions(mx_data) == 2);
+ //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
+ assert(mxGetNumberOfElements(mx_data) == 1);
+ copy(
+ mxGetPr(mx_data),
+ mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
+ &v);
+ return true;
+}
+
+inline bool igl::matlab::MatlabWorkspace::find(
+ const std::string & name,
+ double & d)
+{
+ using namespace std;
+ const int i = std::find(names.begin(), names.end(), name)-names.begin();
+ if(i>=(int)names.size())
+ {
+ return false;
+ }
+ assert(i<=(int)data.size());
+ mxArray * mx_data = data[i];
+ assert(!mxIsSparse(mx_data));
+ assert(mxGetNumberOfDimensions(mx_data) == 2);
+ //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
+ assert(mxGetNumberOfElements(mx_data) == 1);
+ copy(
+ mxGetPr(mx_data),
+ mxGetPr(mx_data)+mxGetNumberOfElements(mx_data),
+ &d);
+ return true;
+}
+
+template <typename DerivedM>
+inline bool igl::matlab::MatlabWorkspace::find_index(
+ const std::string & name,
+ Eigen::PlainObjectBase<DerivedM>& M)
+{
+ if(!find(name,M))
+ {
+ return false;
+ }
+ M.array() -= 1;
+ return true;
+}
+
+
+//template <typename Data>
+//bool igl::matlab::MatlabWorkspace::save(const Data & M, const std::string & name)
+//{
+// using namespace std;
+// // If I don't know the type then I can't save it
+// cerr<<"^MatlabWorkspace::save Error: Unknown data type. "<<
+// name<<" not saved."<<endl;
+// return false;
+//}
+
+#endif
+
diff --git a/xs/src/igl/matlab/MexStream.h b/xs/src/igl/matlab/MexStream.h
new file mode 100644
index 000000000..69a0f2f70
--- /dev/null
+++ b/xs/src/igl/matlab/MexStream.h
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATLAB_MEX_STREAM_H
+#define IGL_MATLAB_MEX_STREAM_H
+#include <iostream>
+namespace igl
+{
+ namespace matlab
+ {
+ // http://stackoverflow.com/a/249008/148668
+
+ // Class to implement "cout" for mex files to print to the matlab terminal
+ // window.
+ //
+ // Insert at the beginning of mexFunction():
+ // MexStream mout;
+ // std::streambuf *outbuf = std::cout.rdbuf(&mout);
+ // ...
+ // ALWAYS restore original buffer to avoid memory leak problems in matlab
+ // std::cout.rdbuf(outbuf);
+ //
+ class MexStream : public std::streambuf
+ {
+ public:
+ protected:
+ inline virtual std::streamsize xsputn(const char *s, std::streamsize n);
+ inline virtual int overflow(int c = EOF);
+ };
+ }
+}
+
+// Implementation
+#include <mex.h>
+inline std::streamsize igl::matlab::MexStream::xsputn(
+ const char *s,
+ std::streamsize n)
+{
+ mexPrintf("%.*s",n,s);
+ mexEvalString("drawnow;"); // to dump string.
+ return n;
+}
+
+inline int igl::matlab::MexStream::overflow(int c)
+{
+ if (c != EOF) {
+ mexPrintf("%.1s",&c);
+ mexEvalString("drawnow;"); // to dump string.
+ }
+ return 1;
+}
+#endif
diff --git a/xs/src/igl/matlab/matlabinterface.cpp b/xs/src/igl/matlab/matlabinterface.cpp
new file mode 100644
index 000000000..6c03485de
--- /dev/null
+++ b/xs/src/igl/matlab/matlabinterface.cpp
@@ -0,0 +1,330 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include <igl/matlab/matlabinterface.h>
+
+// Implementation
+
+// Init the MATLAB engine
+// (no need to call it directly since it is automatically invoked by any other command)
+IGL_INLINE void igl::matlab::mlinit(Engine** mlengine)
+{
+ *mlengine = engOpen("\0");
+}
+
+// Closes the MATLAB engine
+IGL_INLINE void igl::matlab::mlclose(Engine** mlengine)
+{
+ engClose(*mlengine);
+ *mlengine = 0;
+}
+
+// Send a matrix to MATLAB
+IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::MatrixXd& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
+ double *pM = mxGetPr(A);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ pM[c++] = double(M(i,j));
+
+ engPutVariable(*mlengine, name.c_str(), A);
+ mxDestroyArray(A);
+}
+
+// Send a matrix to MATLAB
+IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::MatrixXf& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
+ double *pM = mxGetPr(A);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ pM[c++] = double(M(i,j));
+
+ engPutVariable(*mlengine, name.c_str(), A);
+ mxDestroyArray(A);
+}
+
+// Send a matrix to MATLAB
+IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::MatrixXi& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
+ double *pM = mxGetPr(A);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ pM[c++] = double(M(i,j))+1;
+
+ engPutVariable(*mlengine, name.c_str(), A);
+ mxDestroyArray(A);
+}
+
+// Send a matrix to MATLAB
+IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ mxArray *A = mxCreateDoubleMatrix(M.rows(), M.cols(), mxREAL);
+ double *pM = mxGetPr(A);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ pM[c++] = double(M(i,j))+1;
+
+ engPutVariable(*mlengine, name.c_str(), A);
+ mxDestroyArray(A);
+}
+
+// Receive a matrix from MATLAB
+IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::MatrixXd& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ unsigned long m = 0;
+ unsigned long n = 0;
+ std::vector<double> t;
+
+ mxArray *ary = engGetVariable(*mlengine, name.c_str());
+ if (ary == NULL)
+ {
+ m = 0;
+ n = 0;
+ M = Eigen::MatrixXd(0,0);
+ }
+ else
+ {
+ m = mxGetM(ary);
+ n = mxGetN(ary);
+ M = Eigen::MatrixXd(m,n);
+
+ double *pM = mxGetPr(ary);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ M(i,j) = pM[c++];
+ }
+
+ mxDestroyArray(ary);
+}
+
+IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::MatrixXf& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ unsigned long m = 0;
+ unsigned long n = 0;
+ std::vector<double> t;
+
+ mxArray *ary = engGetVariable(*mlengine, name.c_str());
+ if (ary == NULL)
+ {
+ m = 0;
+ n = 0;
+ M = Eigen::MatrixXf(0,0);
+ }
+ else
+ {
+ m = mxGetM(ary);
+ n = mxGetN(ary);
+ M = Eigen::MatrixXf(m,n);
+
+ double *pM = mxGetPr(ary);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ M(i,j) = pM[c++];
+ }
+
+ mxDestroyArray(ary);
+}
+
+// Receive a matrix from MATLAB
+IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::MatrixXi& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ unsigned long m = 0;
+ unsigned long n = 0;
+ std::vector<double> t;
+
+ mxArray *ary = engGetVariable(*mlengine, name.c_str());
+ if (ary == NULL)
+ {
+ m = 0;
+ n = 0;
+ M = Eigen::MatrixXi(0,0);
+ }
+ else
+ {
+ m = mxGetM(ary);
+ n = mxGetN(ary);
+ M = Eigen::MatrixXi(m,n);
+
+ double *pM = mxGetPr(ary);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ M(i,j) = int(pM[c++])-1;
+ }
+
+ mxDestroyArray(ary);
+}
+
+// Receive a matrix from MATLAB
+IGL_INLINE void igl::matlab::mlgetmatrix(Engine** mlengine, std::string name, Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ unsigned long m = 0;
+ unsigned long n = 0;
+ std::vector<double> t;
+
+ mxArray *ary = engGetVariable(*mlengine, name.c_str());
+ if (ary == NULL)
+ {
+ m = 0;
+ n = 0;
+ M = Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >(0,0);
+ }
+ else
+ {
+ m = mxGetM(ary);
+ n = mxGetN(ary);
+ M = Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >(m,n);
+
+ double *pM = mxGetPr(ary);
+
+ int c = 0;
+ for(int j=0; j<M.cols();++j)
+ for(int i=0; i<M.rows();++i)
+ M(i,j) = (unsigned int)(pM[c++])-1;
+ }
+
+ mxDestroyArray(ary);
+}
+
+
+// Send a single scalar to MATLAB
+IGL_INLINE void igl::matlab::mlsetscalar(Engine** mlengine, std::string name, double s)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ Eigen::MatrixXd M(1,1);
+ M(0,0) = s;
+ mlsetmatrix(mlengine, name, M);
+}
+
+// Receive a single scalar from MATLAB
+IGL_INLINE double igl::matlab::mlgetscalar(Engine** mlengine, std::string name)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ Eigen::MatrixXd M;
+ mlgetmatrix(mlengine, name,M);
+ return M(0,0);
+}
+
+// Execute arbitrary MATLAB code and return the MATLAB output
+IGL_INLINE std::string igl::matlab::mleval(Engine** mlengine, std::string code)
+{
+ if (*mlengine == 0)
+ mlinit(mlengine);
+
+ const char *matlab_code = code.c_str();
+ const int BUF_SIZE = 4096*4096;
+ // allocate on the heap to avoid running out of stack
+ std::string bufauto(BUF_SIZE+1, '\0');
+ char *buf = &bufauto[0];
+
+ assert(matlab_code != NULL);
+
+ // Use RAII ensure that on leaving this scope, the output buffer is
+ // always nullified (to prevent Matlab from accessing memory that might
+ // have already been deallocated).
+ struct cleanup {
+ Engine *m_ep;
+ cleanup(Engine *ep) : m_ep(ep) { }
+ ~cleanup() { engOutputBuffer(m_ep, NULL, 0); }
+ } cleanup_obj(*mlengine);
+
+ if (buf != NULL)
+ engOutputBuffer(*mlengine, buf, BUF_SIZE);
+
+ int res = engEvalString(*mlengine, matlab_code);
+
+ if (res != 0) {
+ std::ostringstream oss;
+ oss << "ERROR: Matlab command failed with error code " << res << ".\n";
+ return oss.str();
+ }
+
+ if (buf[0] == '>' && buf[1] == '>' && buf[2] == ' ')
+ buf += 3;
+ if (buf[0] == '\n') ++buf;
+
+ return std::string(buf);
+}
+
+// Send a sparse matrix
+IGL_INLINE void igl::matlab::mlsetmatrix(Engine** mlengine, std::string name, const Eigen::SparseMatrix<double>& M)
+{
+ int count = 0;
+// // Count non-zero
+// for (unsigned k=0; k<M.outerSize(); ++k)
+// for (Eigen::SparseMatrix<double>::InnerIterator it(M,k); it; ++it)
+// if (it.value() != 0)
+// ++count;
+
+ Eigen::MatrixXd T(M.nonZeros(),3);
+ for (unsigned k=0; k<(unsigned)M.outerSize(); ++k)
+ {
+ for (Eigen::SparseMatrix<double>::InnerIterator it(M,k); it; ++it)
+ {
+ T(count,0) = it.row();
+ T(count,1) = it.col();
+ T(count,2) = it.value();
+ ++count;
+ }
+ }
+
+ T.col(0) = T.col(0).array()+1;
+ T.col(1) = T.col(1).array()+1;
+
+ mlsetmatrix(mlengine,"temp93765",T);
+
+ std::string temp = name + " = sparse(temp93765(:,1),temp93765(:,2),temp93765(:,3),"
+ + std::to_string(M.rows()) + ","
+ + std::to_string(M.cols()) + ");";
+
+ mleval(mlengine,temp);
+ mleval(mlengine,"clear temp93765");
+}
diff --git a/xs/src/igl/matlab/matlabinterface.h b/xs/src/igl/matlab/matlabinterface.h
new file mode 100644
index 000000000..63d72c74e
--- /dev/null
+++ b/xs/src/igl/matlab/matlabinterface.h
@@ -0,0 +1,90 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATLAB_MATLAB_INTERFACE_H
+#define IGL_MATLAB_MATLAB_INTERFACE_H
+#include "../igl_inline.h"
+// WARNING: These functions require matlab installed
+// Additional header folder required:
+// /Applications/MATLAB_R2011a.app/extern/include
+// Additional binary lib to be linked with:
+// /Applications/MATLAB_R2011a.app/bin/maci64/libeng.dylib
+// /Applications/MATLAB_R2011a.app/bin/maci64/libmx.dylib
+
+// MAC ONLY:
+// Add to the environment variables:
+// DYLD_LIBRARY_PATH = /Applications/MATLAB_R2011a.app/bin/maci64/
+// PATH = /opt/local/bin:/opt/local/sbin:/Applications/MATLAB_R2011a.app/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/texbin:/usr/X11/bin
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+#include <string>
+
+#include <complex>
+#include <cassert>
+#include <map>
+#include <string>
+#include <vector>
+
+#include <engine.h> // Matlab engine header
+
+namespace igl
+{
+ namespace matlab
+ {
+ // Init the MATLAB engine
+ // (no need to call it directly since it is automatically invoked by any other command)
+ IGL_INLINE void mlinit(Engine** engine);
+
+ // Closes the MATLAB engine
+ IGL_INLINE void mlclose(Engine** engine);
+
+ // Send a matrix to MATLAB
+ IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXd& M);
+
+ // Send a matrix to MATLAB
+ IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXf& M);
+
+ // Send a matrix to MATLAB
+ IGL_INLINE void mlsetmatrix(Engine** engine, std::string name, const Eigen::MatrixXi& M);
+
+ // Send a matrix to MATLAB
+ IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M);
+
+ // Receive a matrix from MATLAB
+ IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXd& M);
+
+ // Receive a matrix from MATLAB
+ IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXf& M);
+
+ // Receive a matrix from MATLAB
+ IGL_INLINE void mlgetmatrix(Engine** engine, std::string name, Eigen::MatrixXi& M);
+
+ // Receive a matrix from MATLAB
+ IGL_INLINE void mlgetmatrix(Engine** mlengine, std::string name, Eigen::Matrix<unsigned int, Eigen::Dynamic, Eigen::Dynamic >& M);
+
+ // Send a single scalar to MATLAB
+ IGL_INLINE void mlsetscalar(Engine** engine, std::string name, double s);
+
+ // Receive a single scalar from MATLAB
+ IGL_INLINE double mlgetscalar(Engine** engine, std::string name);
+
+ // Execute arbitrary MATLAB code and return the MATLAB output
+ IGL_INLINE std::string mleval(Engine** engine, std::string code);
+
+ // Send a sparse matrix to MATLAB
+ IGL_INLINE void mlsetmatrix(Engine** mlengine, std::string name, const Eigen::SparseMatrix<double>& M);
+
+ }
+}
+
+// Be sure that this is not compiled into libigl.a
+#ifndef IGL_STATIC_LIBRARY
+# include "matlabinterface.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/matlab/mexErrMsgTxt.cpp b/xs/src/igl/matlab/mexErrMsgTxt.cpp
new file mode 100644
index 000000000..89dda1fa3
--- /dev/null
+++ b/xs/src/igl/matlab/mexErrMsgTxt.cpp
@@ -0,0 +1,17 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mexErrMsgTxt.h"
+
+IGL_INLINE void igl::matlab::mexErrMsgTxt(bool assertion, const char * text)
+{
+ if(!assertion)
+ {
+ ::mexErrMsgTxt(text);
+ }
+}
+
diff --git a/xs/src/igl/matlab/mexErrMsgTxt.h b/xs/src/igl/matlab/mexErrMsgTxt.h
new file mode 100644
index 000000000..61b838e6e
--- /dev/null
+++ b/xs/src/igl/matlab/mexErrMsgTxt.h
@@ -0,0 +1,25 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATLAB_MEXERRMSGTXT_H
+#define IGL_MATLAB_MEXERRMSGTXT_H
+#include "../igl_inline.h"
+// Overload mexErrMsgTxt to check an assertion then print text only if
+// assertion fails
+#include "mex.h"
+namespace igl
+{
+ namespace matlab
+ {
+ // Wrapper for mexErrMsgTxt that only calls error if test fails
+ IGL_INLINE void mexErrMsgTxt(bool test, const char * message);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "mexErrMsgTxt.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/matlab/parse_rhs.cpp b/xs/src/igl/matlab/parse_rhs.cpp
new file mode 100644
index 000000000..dafc8ba48
--- /dev/null
+++ b/xs/src/igl/matlab/parse_rhs.cpp
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "parse_rhs.h"
+#include <algorithm>
+
+template <typename DerivedV>
+IGL_INLINE void igl::matlab::parse_rhs_double(
+ const mxArray *prhs[],
+ Eigen::PlainObjectBase<DerivedV> & V)
+{
+ using namespace Eigen;
+ // Use Eigen's map and cast to copy
+ V = Map< Matrix<double,Dynamic,Dynamic> >
+ (mxGetPr(prhs[0]),mxGetM(prhs[0]),mxGetN(prhs[0]))
+ .cast<typename DerivedV::Scalar>();
+}
+
+template <typename DerivedV>
+IGL_INLINE void igl::matlab::parse_rhs_index(
+ const mxArray *prhs[],
+ Eigen::PlainObjectBase<DerivedV> & V)
+{
+ parse_rhs_double(prhs,V);
+ V.array() -= 1;
+}
+
+template <typename MT>
+IGL_INLINE void igl::matlab::parse_rhs(
+ const mxArray *prhs[],
+ Eigen::SparseMatrix<MT> & M)
+{
+ using namespace Eigen;
+ using namespace std;
+ const mxArray * mx_data = prhs[0];
+ // Handle boring case where matrix is actually an empty dense matrix
+ if(mxGetNumberOfElements(mx_data) == 0)
+ {
+ M.resize(0,0);
+ return;
+ }
+ assert(mxIsSparse(mx_data));
+ assert(mxGetNumberOfDimensions(mx_data) == 2);
+ //cout<<name<<": "<<mxGetM(mx_data)<<" "<<mxGetN(mx_data)<<endl;
+ const int m = mxGetM(mx_data);
+ const int n = mxGetN(mx_data);
+ // TODO: It should be possible to directly load the data into the sparse
+ // matrix without going through the triplets
+ // Copy data immediately
+ double * pr = mxGetPr(mx_data);
+ mwIndex * ir = mxGetIr(mx_data);
+ mwIndex * jc = mxGetJc(mx_data);
+ vector<Triplet<MT> > MIJV;
+ MIJV.reserve(mxGetNumberOfElements(mx_data));
+ // Iterate over outside
+ int k = 0;
+ for(int j=0; j<n;j++)
+ {
+ // Iterate over inside
+ while(k<(int)jc[j+1])
+ {
+ //cout<<ir[k]<<" "<<j<<" "<<pr[k]<<endl;
+ assert((int)ir[k]<m);
+ assert((int)j<n);
+ MIJV.push_back(Triplet<MT >(ir[k],j,pr[k]));
+ k++;
+ }
+ }
+ M.resize(m,n);
+ M.setFromTriplets(MIJV.begin(),MIJV.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::matlab::parse_rhs_index<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(mxArray_tag const**, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::matlab::parse_rhs_index<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(mxArray_tag const**, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::matlab::parse_rhs_double<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(mxArray_tag const**, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::matlab::parse_rhs_index<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(mxArray_tag const**, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+template void igl::matlab::parse_rhs_double<Eigen::Matrix<double, -1, 3, 1, -1, 3> >(mxArray_tag const**, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/matlab/parse_rhs.h b/xs/src/igl/matlab/parse_rhs.h
new file mode 100644
index 000000000..3cabec734
--- /dev/null
+++ b/xs/src/igl/matlab/parse_rhs.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATLAB_PARSE_RHS_H
+#define IGL_MATLAB_PARSE_RHS_H
+#include <igl/igl_inline.h>
+#include <mex.h>
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ namespace matlab
+ {
+ // Reads in a matrix as a double
+ //
+ // Inputs:
+ // prhs points to rhs argument
+ // Outputs:
+ // V M by N matrix
+ template <typename DerivedV>
+ IGL_INLINE void parse_rhs_double(
+ const mxArray *prhs[],
+ Eigen::PlainObjectBase<DerivedV> & V);
+ // Reads in a matrix and subtracts 1
+ template <typename DerivedV>
+ IGL_INLINE void parse_rhs_index(
+ const mxArray *prhs[],
+ Eigen::PlainObjectBase<DerivedV> & V);
+ template <typename VType>
+ IGL_INLINE void parse_rhs(
+ const mxArray *prhs[],
+ Eigen::SparseMatrix<VType> & M);
+ }
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "parse_rhs.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/matlab/prepare_lhs.cpp b/xs/src/igl/matlab/prepare_lhs.cpp
new file mode 100644
index 000000000..93593685e
--- /dev/null
+++ b/xs/src/igl/matlab/prepare_lhs.cpp
@@ -0,0 +1,99 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "prepare_lhs.h"
+#include <algorithm>
+template <typename DerivedV>
+IGL_INLINE void igl::matlab::prepare_lhs_double(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ mxArray *plhs[])
+{
+ using namespace std;
+ using namespace Eigen;
+ const int m = V.rows();
+ const int n = V.cols();
+ plhs[0] = mxCreateDoubleMatrix(m,n, mxREAL);
+ Eigen::Map< Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> >
+ map(mxGetPr(plhs[0]),m,n);
+ map = V.template cast<double>();
+}
+
+template <typename DerivedV>
+IGL_INLINE void igl::matlab::prepare_lhs_logical(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ mxArray *plhs[])
+{
+ using namespace std;
+ using namespace Eigen;
+ const int m = V.rows();
+ const int n = V.cols();
+ plhs[0] = mxCreateLogicalMatrix(m,n);
+ mxLogical * Vp = static_cast<mxLogical*>(mxGetData(plhs[0]));
+ Eigen::Map< Eigen::Matrix<mxLogical,Eigen::Dynamic,Eigen::Dynamic> >
+ map(static_cast<mxLogical*>(mxGetData(plhs[0])),m,n);
+ map = V.template cast<mxLogical>();
+}
+
+template <typename DerivedV>
+IGL_INLINE void igl::matlab::prepare_lhs_index(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ mxArray *plhs[])
+{
+ // Treat indices as reals
+ const auto Vd = (V.template cast<double>().array()+1).eval();
+ return prepare_lhs_double(Vd,plhs);
+}
+
+template <typename Vtype>
+IGL_INLINE void igl::matlab::prepare_lhs_double(
+ const Eigen::SparseMatrix<Vtype> & M,
+ mxArray *plhs[])
+{
+ using namespace std;
+ const int m = M.rows();
+ const int n = M.cols();
+ // THIS WILL NOT WORK FOR ROW-MAJOR
+ assert(n==M.outerSize());
+ const int nzmax = M.nonZeros();
+ plhs[0] = mxCreateSparse(m, n, nzmax, mxREAL);
+ mxArray * mx_data = plhs[0];
+ // Copy data immediately
+ double * pr = mxGetPr(mx_data);
+ mwIndex * ir = mxGetIr(mx_data);
+ mwIndex * jc = mxGetJc(mx_data);
+
+ // Iterate over outside
+ int k = 0;
+ for(int j=0; j<M.outerSize();j++)
+ {
+ jc[j] = k;
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<Vtype>::InnerIterator it (M,j); it; ++it)
+ {
+ // copy (cast to double)
+ pr[k] = it.value();
+ ir[k] = it.row();
+ k++;
+ }
+ }
+ jc[M.outerSize()] = k;
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::matlab::prepare_lhs_index<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_index<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_double<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_index<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_logical<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_double<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_logical<Eigen::Matrix<bool, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<bool, -1, 1, 0, -1, 1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_index<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_double<Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_double<Eigen::Matrix<int, 1, -1, 1, 1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, 1, -1, 1, 1, -1> > const&, mxArray_tag**);
+template void igl::matlab::prepare_lhs_double<Eigen::Matrix<int, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, mxArray_tag**);
+#endif
diff --git a/xs/src/igl/matlab/prepare_lhs.h b/xs/src/igl/matlab/prepare_lhs.h
new file mode 100644
index 000000000..0ac0ca6ce
--- /dev/null
+++ b/xs/src/igl/matlab/prepare_lhs.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATLAB_PREPARE_LHS_H
+#define IGL_MATLAB_PREPARE_LHS_H
+#include <igl/igl_inline.h>
+#include <mex.h>
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ namespace matlab
+ {
+ // Writes out a matrix as a double
+ //
+ // Inputs:
+ // prhs points to rhs argument
+ // Outputs:
+ // V M by N matrix
+ template <typename DerivedV>
+ IGL_INLINE void prepare_lhs_double(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ mxArray *plhs[]);
+ // Casts to logical
+ template <typename DerivedV>
+ IGL_INLINE void prepare_lhs_logical(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ mxArray *plhs[]);
+ // Writes out a matrix and adds 1
+ template <typename DerivedV>
+ IGL_INLINE void prepare_lhs_index(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ mxArray *plhs[]);
+ // SparseMatrix
+ template <typename Vtype>
+ IGL_INLINE void prepare_lhs_double(
+ const Eigen::SparseMatrix<Vtype> & V,
+ mxArray *plhs[]);
+ };
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "prepare_lhs.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/matlab/requires_arg.cpp b/xs/src/igl/matlab/requires_arg.cpp
new file mode 100644
index 000000000..a03469183
--- /dev/null
+++ b/xs/src/igl/matlab/requires_arg.cpp
@@ -0,0 +1,16 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "requires_arg.h"
+#include "mexErrMsgTxt.h"
+#include "../C_STR.h"
+
+IGL_INLINE void igl::matlab::requires_arg(const int i, const int nrhs, const char *name)
+{
+ mexErrMsgTxt((i+1)<nrhs,
+ C_STR("Parameter '"<<name<<"' requires argument"));
+}
diff --git a/xs/src/igl/matlab/requires_arg.h b/xs/src/igl/matlab/requires_arg.h
new file mode 100644
index 000000000..65531b2f2
--- /dev/null
+++ b/xs/src/igl/matlab/requires_arg.h
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REQUIRES_ARG_H
+#define IGL_REQUIRES_ARG_H
+#include "../igl_inline.h"
+#include <mex.h>
+namespace igl
+{
+ namespace matlab
+ {
+ // Simply throw an error if (i+1)<rhs
+ //
+ // Input:
+ // i index of current arg
+ // nrhs total number of args
+ // name of current arg
+ IGL_INLINE void requires_arg(const int i, const int nrhs, const char *name);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "requires_arg.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/matlab/validate_arg.cpp b/xs/src/igl/matlab/validate_arg.cpp
new file mode 100644
index 000000000..903c9984d
--- /dev/null
+++ b/xs/src/igl/matlab/validate_arg.cpp
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "validate_arg.h"
+#include "requires_arg.h"
+#include "mexErrMsgTxt.h"
+#include "../C_STR.h"
+
+IGL_INLINE void igl::matlab::validate_arg_scalar(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name)
+{
+ requires_arg(i,nrhs,name);
+ mexErrMsgTxt(mxGetN(prhs[i+1])==1 && mxGetM(prhs[i+1])==1,
+ C_STR("Parameter '"<<name<<"' requires scalar argument"));
+}
+
+IGL_INLINE void igl::matlab::validate_arg_logical(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name)
+{
+ requires_arg(i,nrhs,name);
+ mexErrMsgTxt(mxIsLogical(prhs[i+1]),
+ C_STR("Parameter '"<<name<<"' requires Logical argument"));
+}
+
+IGL_INLINE void igl::matlab::validate_arg_char(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name)
+{
+ requires_arg(i,nrhs,name);
+ mexErrMsgTxt(mxIsChar(prhs[i+1]),
+ C_STR("Parameter '"<<name<<"' requires char argument"));
+}
+
+IGL_INLINE void igl::matlab::validate_arg_double(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name)
+{
+ requires_arg(i,nrhs,name);
+ mexErrMsgTxt(mxIsDouble(prhs[i+1]),
+ C_STR("Parameter '"<<name<<"' requires double argument"));
+}
+IGL_INLINE void igl::matlab::validate_arg_function_handle(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name)
+{
+ requires_arg(i,nrhs,name);
+ mexErrMsgTxt(mxIsClass(prhs[i+1],"function_handle"),
+ C_STR("Parameter '"<<name<<"' requires function handle argument"));
+}
diff --git a/xs/src/igl/matlab/validate_arg.h b/xs/src/igl/matlab/validate_arg.h
new file mode 100644
index 000000000..db52c68d1
--- /dev/null
+++ b/xs/src/igl/matlab/validate_arg.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VALIDATE_ARG_H
+#define IGL_VALIDATE_ARG_H
+#include "../igl_inline.h"
+#include <mex.h>
+namespace igl
+{
+ namespace matlab
+ {
+ // Throw an error if arg i+1 is not a scalar
+ //
+ // Inputs:
+ // i index of current argument
+ // nrhs total number of arguments
+ // prhs pointer to arguments array
+ // name name of current argument
+ IGL_INLINE void validate_arg_scalar(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name);
+ IGL_INLINE void validate_arg_logical(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name);
+ IGL_INLINE void validate_arg_char(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name);
+ IGL_INLINE void validate_arg_double(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name);
+ IGL_INLINE void validate_arg_function_handle(
+ const int i, const int nrhs, const mxArray * prhs[], const char * name);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "validate_arg.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/matlab_format.cpp b/xs/src/igl/matlab_format.cpp
new file mode 100644
index 000000000..ceb5d6db7
--- /dev/null
+++ b/xs/src/igl/matlab_format.cpp
@@ -0,0 +1,155 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "matlab_format.h"
+#include "STR.h"
+#include "find.h"
+
+template <typename DerivedM>
+IGL_INLINE const Eigen::WithFormat< DerivedM > igl::matlab_format(
+ const Eigen::DenseBase<DerivedM> & M,
+ const std::string name)
+{
+ using namespace std;
+ string prefix = "";
+ if(!name.empty())
+ {
+ prefix = name + " = ";
+ }
+
+ return M.format(Eigen::IOFormat(
+ Eigen::FullPrecision,
+ 0,
+ " ",
+ "\n",
+ "",
+ "",
+ // This seems like a bit of a hack since I would expect the rows to align
+ // with out this extra spacing on the first line
+ prefix + "[\n ",
+ "\n];"));
+}
+
+template <typename DerivedS>
+IGL_INLINE const std::string
+igl::matlab_format(
+ const Eigen::SparseMatrix<DerivedS> & S,
+ const std::string name)
+{
+ using namespace Eigen;
+ using namespace std;
+ Matrix<typename Eigen::SparseMatrix<DerivedS>::Scalar,Dynamic,1> I,J,V;
+ Matrix<DerivedS,Dynamic,Dynamic> SIJV;
+ find(S,I,J,V);
+ I.array() += 1;
+ J.array() += 1;
+ SIJV.resize(V.rows(),3);
+ SIJV << I,J,V;
+ string prefix = "";
+ string suffix = "";
+ if(!name.empty())
+ {
+ prefix = name + "IJV = ";
+ suffix = "\n"+name + " = sparse("+name+"IJV(:,1),"+name+"IJV(:,2),"+name+"IJV(:,3),"+std::to_string(S.rows())+","+std::to_string(S.cols())+" );";
+ }
+ return STR(""<<
+ SIJV.format(Eigen::IOFormat(
+ Eigen::FullPrecision,
+ 0,
+ " ",
+ "\n",
+ "",
+ "",
+ // This seems like a bit of a hack since I would expect the rows to align
+ // with out this extra spacing on the first line
+ prefix + "[\n ",
+ "\n];"))<<suffix);
+}
+
+IGL_INLINE Eigen::IOFormat igl::matlab_format()
+{
+ // M = [1 2 3;4 5 6];
+ // M.format(matlab_format()) produces:
+ // [
+ // 1 2 3
+ // 4 5 6
+ // ];
+ return Eigen::IOFormat(
+ Eigen::FullPrecision,
+ 0,
+ " ",
+ "\n",
+ "",
+ "",
+ // This seems like a bit of a hack since I would expect the rows to align
+ // with out this extra spacing on the first line
+ "[\n ",
+ "\n];");
+}
+
+IGL_INLINE const std::string igl::matlab_format(
+ const double v,
+ const std::string name)
+{
+ using namespace std;
+ string prefix = "";
+ if(!name.empty())
+ {
+ prefix = name + " = ";
+ }
+ return STR(prefix<<v<<";");
+}
+
+IGL_INLINE const std::string igl::matlab_format(
+ const float v,
+ const std::string name)
+{
+ return matlab_format(double(v),name);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::WithFormat<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const igl::matlab_format<Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::DenseBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+// generated by autoexplicit.sh
+template Eigen::WithFormat<Eigen::Matrix<int, 4, 1, 0, 4, 1> > const igl::matlab_format<Eigen::Matrix<int, 4, 1, 0, 4, 1> >(Eigen::DenseBase<Eigen::Matrix<int, 4, 1, 0, 4, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template std::basic_string<char, std::char_traits<char>, std::allocator<char> > const igl::matlab_format<double>(Eigen::SparseMatrix<double, 0, int> const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const igl::matlab_format<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::string);
+template Eigen::WithFormat<Eigen::Array<int, -1, -1, 0, -1, -1> > const igl::matlab_format<Eigen::Array<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Array<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const igl::matlab_format<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const igl::matlab_format<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const igl::matlab_format<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Array<int, -1, 1, 0, -1, 1> > const igl::matlab_format<Eigen::Array<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Array<int, -1, 1, 0, -1, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 4, 4, 0, 4, 4> > const igl::matlab_format<Eigen::Matrix<double, 4, 4, 0, 4, 4> >(Eigen::DenseBase<Eigen::Matrix<double, 4, 4, 0, 4, 4> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const igl::matlab_format<Eigen::Matrix<double, -1, 4, 0, -1, 4> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const igl::matlab_format<Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const igl::matlab_format<Eigen::Matrix<double, 2, 1, 0, 2, 1> >(Eigen::DenseBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, 1, -1, 1, 1, -1> > const igl::matlab_format<Eigen::Matrix<int, 1, -1, 1, 1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, 1, -1, 1, 1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const igl::matlab_format<Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 3, 3, 0, 3, 3> > const igl::matlab_format<Eigen::Matrix<double, 3, 3, 0, 3, 3> >(Eigen::DenseBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 2, 2, 0, 2, 2> > const igl::matlab_format<Eigen::Matrix<double, 2, 2, 0, 2, 2> >(Eigen::DenseBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<float, 2, 2, 0, 2, 2> > const igl::matlab_format<Eigen::Matrix<float, 2, 2, 0, 2, 2> >(Eigen::DenseBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 2, 2, 1, 2, 2> > const igl::matlab_format<Eigen::Matrix<double, 2, 2, 1, 2, 2> >(Eigen::DenseBase<Eigen::Matrix<double, 2, 2, 1, 2, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const igl::matlab_format<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::DenseBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<float, 2, 1, 0, 2, 1> > const igl::matlab_format<Eigen::Matrix<float, 2, 1, 0, 2, 1> >(Eigen::DenseBase<Eigen::Matrix<float, 2, 1, 0, 2, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<float, 2, 2, 1, 2, 2> > const igl::matlab_format<Eigen::Matrix<float, 2, 2, 1, 2, 2> >(Eigen::DenseBase<Eigen::Matrix<float, 2, 2, 1, 2, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const igl::matlab_format<Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 3, 3, 1, 3, 3> > const igl::matlab_format<Eigen::Matrix<double, 3, 3, 1, 3, 3> >(Eigen::DenseBase<Eigen::Matrix<double, 3, 3, 1, 3, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const igl::matlab_format<Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const igl::matlab_format<Eigen::Matrix<int, -1, -1, 1, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Array<double, -1, 1, 0, -1, 1> > const igl::matlab_format<Eigen::Array<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Array<double, -1, 1, 0, -1, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const igl::matlab_format<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::DenseBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const igl::matlab_format<Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::DenseBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const igl::matlab_format<Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const igl::matlab_format<Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const igl::matlab_format<Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const igl::matlab_format<Eigen::Matrix<double, 2, 3, 0, 2, 3> >(Eigen::DenseBase<Eigen::Matrix<double, 2, 3, 0, 2, 3> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<double, 3, 2, 0, 3, 2> > const igl::matlab_format<Eigen::Matrix<double, 3, 2, 0, 3, 2> >(Eigen::DenseBase<Eigen::Matrix<double, 3, 2, 0, 3, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const igl::matlab_format<Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<int, 2, 2, 0, 2, 2> > const igl::matlab_format<Eigen::Matrix<int, 2, 2, 0, 2, 2> >(Eigen::DenseBase<Eigen::Matrix<int, 2, 2, 0, 2, 2> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+template Eigen::WithFormat<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const igl::matlab_format<Eigen::Matrix<float, 4, 4, 0, 4, 4> >(Eigen::DenseBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >);
+#endif
diff --git a/xs/src/igl/matlab_format.h b/xs/src/igl/matlab_format.h
new file mode 100644
index 000000000..e1f3ff830
--- /dev/null
+++ b/xs/src/igl/matlab_format.h
@@ -0,0 +1,89 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATLAB_FORMAT_H
+#define IGL_MATLAB_FORMAT_H
+
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+#include <string>
+
+namespace igl
+{
+ // This is a routine to print a matrix using format suitable for pasting into
+ // the matlab IDE
+ //
+ // Templates:
+ // DerivedM e.g. derived from MatrixXd
+ // Input:
+ // input some matrix to be formatted
+ // name name of matrix
+ // Returns Formatted matrix
+ //
+ // Example:
+ // // M := [1 2 3;4 5 6];
+ // cout<<matlab_format(M)<<endl;
+ // // Prints:
+ // // [
+ // // 1 2 3
+ // // 4 5 6
+ // // ];
+ // cout<<matlab_format(M,"M")<<endl;
+ // // Prints:
+ // // M = [
+ // // 1 2 3
+ // // 4 5 6
+ // // ];
+ template <typename DerivedM>
+ IGL_INLINE const Eigen::WithFormat< DerivedM > matlab_format(
+ const Eigen::DenseBase<DerivedM> & M,
+ const std::string name = "");
+ // Same but for sparse matrices. Print IJV format into an auxiliary variable
+ // and then print a call to sparse which will construct the sparse matrix
+ // Example:
+ // // S := [0 2 3;4 5 0];
+ // cout<<matlab_format(S,"S")<<endl;
+ // // Prints:
+ // // SIJV = [
+ // // 2 1 4
+ // // 1 2 2
+ // // 2 2 5
+ // // 1 3 3
+ // // ];
+ // // S = sparse(SIJV(:,1),SIJV(:,2),SIJV(:,3));
+ //
+ template <typename DerivedS>
+ IGL_INLINE const std::string matlab_format(
+ const Eigen::SparseMatrix<DerivedS> & S,
+ const std::string name = "");
+ IGL_INLINE const std::string matlab_format(
+ const double v,
+ const std::string name = "");
+ IGL_INLINE const std::string matlab_format(
+ const float v,
+ const std::string name = "");
+ // Return just IOFormat
+ //
+ // Example:
+ // // M := [1 2 3;4 5 6];
+ // cout<<M.format(matlab_format())<<endl;
+ // // Prints:
+ // // [
+ // // 1 2 3
+ // // 4 5 6
+ // // ];
+ IGL_INLINE Eigen::IOFormat matlab_format();
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "matlab_format.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/matrix_to_list.cpp b/xs/src/igl/matrix_to_list.cpp
new file mode 100644
index 000000000..1c30dff91
--- /dev/null
+++ b/xs/src/igl/matrix_to_list.cpp
@@ -0,0 +1,79 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "matrix_to_list.h"
+
+#include <Eigen/Dense>
+
+template <typename DerivedM>
+IGL_INLINE void igl::matrix_to_list(
+ const Eigen::DenseBase<DerivedM> & M,
+ std::vector<std::vector<typename DerivedM::Scalar > > & V)
+{
+ using namespace std;
+ V.resize(M.rows(),vector<typename DerivedM::Scalar >(M.cols()));
+ // loop over rows
+ for(int i = 0;i<M.rows();i++)
+ {
+ // loop over cols
+ for(int j = 0;j<M.cols();j++)
+ {
+ V[i][j] = M(i,j);
+ }
+ }
+}
+
+template <typename DerivedM>
+IGL_INLINE void igl::matrix_to_list(
+ const Eigen::DenseBase<DerivedM> & M,
+ std::vector<typename DerivedM::Scalar > & V)
+{
+ using namespace std;
+ V.resize(M.size());
+ // loop over cols then rows
+ for(int j = 0;j<M.cols();j++)
+ {
+ for(int i = 0;i<M.rows();i++)
+ {
+ V[i+j*M.rows()] = M(i,j);
+ }
+ }
+}
+
+template <typename DerivedM>
+IGL_INLINE std::vector<typename DerivedM::Scalar > igl::matrix_to_list(
+ const Eigen::DenseBase<DerivedM> & M)
+{
+ std::vector<typename DerivedM::Scalar> V;
+ matrix_to_list(M,V);
+ return V;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::matrix_to_list<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1>, -1, 1, true> >(Eigen::DenseBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1>, -1, 1, true> > const&, std::vector<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1>, -1, 1, true>::Scalar, std::allocator<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1>, -1, 1, true>::Scalar> >&);
+// generated by autoexplicit.sh
+template void igl::matrix_to_list<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, 1, true> >(Eigen::DenseBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, 1, true> > const&, std::vector<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, 1, true>::Scalar, std::allocator<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, 1, true>::Scalar> >&);
+// generated by autoexplicit.sh
+template void igl::matrix_to_list<Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, std::vector<Eigen::Matrix<int, -1, 2, 0, -1, 2>::Scalar, std::allocator<Eigen::Matrix<int, -1, 2, 0, -1, 2>::Scalar> >&);
+// generated by autoexplicit.sh
+template std::vector<Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar> > igl::matrix_to_list<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&);
+// generated by autoexplicit.sh
+template std::vector<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar> > igl::matrix_to_list<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&);
+//template void igl::matrix_to_list<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&);
+//template void igl::matrix_to_list<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::matrix_to_list<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar> >, std::allocator<std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar> > > >&);
+template void igl::matrix_to_list<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar> >, std::allocator<std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar> > > >&);
+template void igl::matrix_to_list<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, std::vector<Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar> >&);
+template void igl::matrix_to_list<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar> >&);
+template void igl::matrix_to_list<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar> >&);
+template void igl::matrix_to_list<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar> >, std::allocator<std::vector<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar, std::allocator<Eigen::Matrix<int, -1, 1, 0, -1, 1>::Scalar> > > >&);
+template void igl::matrix_to_list<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar> >&);
+template void igl::matrix_to_list<Eigen::Matrix<int, 1, -1, 1, 1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, 1, -1, 1, 1, -1> > const&, std::vector<Eigen::Matrix<int, 1, -1, 1, 1, -1>::Scalar, std::allocator<Eigen::Matrix<int, 1, -1, 1, 1, -1>::Scalar> >&);
+template std::vector<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, std::allocator<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar> > igl::matrix_to_list<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/matrix_to_list.h b/xs/src/igl/matrix_to_list.h
new file mode 100644
index 000000000..a84281127
--- /dev/null
+++ b/xs/src/igl/matrix_to_list.h
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MATRIX_TO_LIST_H
+#define IGL_MATRIX_TO_LIST_H
+#include "igl_inline.h"
+#include <vector>
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Convert a matrix to a list (std::vector) of row vectors of the same size
+ //
+ // Template:
+ // Mat Matrix type, must implement:
+ // .resize(m,n)
+ // .row(i) = Row
+ // T type that can be safely cast to type in Mat via '='
+ // Inputs:
+ // M an m by n matrix
+ // Outputs:
+ // V a m-long list of vectors of size n
+ //
+ // See also: list_to_matrix
+ template <typename DerivedM>
+ IGL_INLINE void matrix_to_list(
+ const Eigen::DenseBase<DerivedM> & M,
+ std::vector<std::vector<typename DerivedM::Scalar > > & V);
+ // Convert a matrix to a list (std::vector) of elements in column-major
+ // ordering.
+ //
+ // Inputs:
+ // M an m by n matrix
+ // Outputs:
+ // V an m*n list of elements
+ template <typename DerivedM>
+ IGL_INLINE void matrix_to_list(
+ const Eigen::DenseBase<DerivedM> & M,
+ std::vector<typename DerivedM::Scalar > & V);
+ // Return wrapper
+ template <typename DerivedM>
+ IGL_INLINE std::vector<typename DerivedM::Scalar > matrix_to_list(
+ const Eigen::DenseBase<DerivedM> & M);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "matrix_to_list.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/max.cpp b/xs/src/igl/max.cpp
new file mode 100644
index 000000000..e451c3b15
--- /dev/null
+++ b/xs/src/igl/max.cpp
@@ -0,0 +1,46 @@
+#include "max.h"
+#include "for_each.h"
+#include "find_zero.h"
+
+template <typename AType, typename DerivedB, typename DerivedI>
+IGL_INLINE void igl::max(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ const int n = A.cols();
+ const int m = A.rows();
+ B.resize(dim==1?n:m);
+ B.setConstant(std::numeric_limits<typename DerivedB::Scalar>::lowest());
+ I.resize(dim==1?n:m);
+ for_each(A,[&B,&I,&dim](int i, int j,const typename DerivedB::Scalar v)
+ {
+ if(dim == 2)
+ {
+ std::swap(i,j);
+ }
+ // Coded as if dim == 1, assuming swap for dim == 2
+ if(v > B(j))
+ {
+ B(j) = v;
+ I(j) = i;
+ }
+ });
+ Eigen::VectorXi Z;
+ find_zero(A,dim,Z);
+ for(int j = 0;j<I.size();j++)
+ {
+ if(Z(j) != (dim==1?m:n) && 0 > B(j))
+ {
+ B(j) = 0;
+ I(j) = Z(j);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::max<bool, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/max.h b/xs/src/igl/max.h
new file mode 100644
index 000000000..554a19b13
--- /dev/null
+++ b/xs/src/igl/max.h
@@ -0,0 +1,27 @@
+#ifndef IGL_MAX_H
+#define IGL_MAX_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Inputs:
+ // X m by n matrix
+ // dim dimension along which to take max
+ // Outputs:
+ // Y n-long vector (if dim == 1)
+ // or
+ // Y m-long vector (if dim == 2)
+ // I vector the same size as Y containing the indices along dim of maximum
+ // entries
+ template <typename AType, typename DerivedB, typename DerivedI>
+ IGL_INLINE void max(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedI> & I);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "max.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/max_faces_stopping_condition.cpp b/xs/src/igl/max_faces_stopping_condition.cpp
new file mode 100644
index 000000000..adc4fc96e
--- /dev/null
+++ b/xs/src/igl/max_faces_stopping_condition.cpp
@@ -0,0 +1,93 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "max_faces_stopping_condition.h"
+
+IGL_INLINE void igl::max_faces_stopping_condition(
+ int & m,
+ const int orig_m,
+ const int max_m,
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> & stopping_condition)
+{
+ stopping_condition =
+ [orig_m,max_m,&m](
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int f1,
+ const int f2)->bool
+ {
+ // Only subtract if we're collapsing a real face
+ if(f1 < orig_m) m-=1;
+ if(f2 < orig_m) m-=1;
+ return m<=(int)max_m;
+ };
+}
+
+IGL_INLINE
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)>
+ igl::max_faces_stopping_condition(
+ int & m,
+ const int orig_m,
+ const int max_m)
+{
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> stopping_condition;
+ max_faces_stopping_condition(
+ m,orig_m,max_m,stopping_condition);
+ return stopping_condition;
+}
diff --git a/xs/src/igl/max_faces_stopping_condition.h b/xs/src/igl/max_faces_stopping_condition.h
new file mode 100644
index 000000000..e886a1f5c
--- /dev/null
+++ b/xs/src/igl/max_faces_stopping_condition.h
@@ -0,0 +1,75 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MAX_FACES_STOPPING_CONDITION_H
+#define IGL_MAX_FACES_STOPPING_CONDITION_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include <set>
+#include <functional>
+namespace igl
+{
+ // Stopping condition function compatible with igl::decimate. The outpute
+ // function handle will return true if number of faces is less than max_m
+ //
+ // Inputs:
+ // m reference to working variable initially should be set to current
+ // number of faces.
+ // orig_m number (size) of original face list _**not**_ including any
+ // faces added to handle phony boundary faces connecting to point at
+ // infinity. For closed meshes it's safe to set this to F.rows()
+ // max_m maximum number of faces
+ // Outputs:
+ // stopping_condition
+ //
+ IGL_INLINE void max_faces_stopping_condition(
+ int & m,
+ const int orig_m,
+ const int max_m,
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)> & stopping_condition);
+ IGL_INLINE
+ std::function<bool(
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const std::set<std::pair<double,int> > &,
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,
+ const Eigen::MatrixXd &,
+ const int,
+ const int,
+ const int,
+ const int,
+ const int)>
+ max_faces_stopping_condition(
+ int & m,
+ const int orign_m,
+ const int max_m);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "max_faces_stopping_condition.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/max_size.cpp b/xs/src/igl/max_size.cpp
new file mode 100644
index 000000000..f3b9a07f2
--- /dev/null
+++ b/xs/src/igl/max_size.cpp
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "max_size.h"
+
+
+template <typename T>
+IGL_INLINE int igl::max_size(const std::vector<T> & V)
+{
+ int max_size = -1;
+ for(
+ typename std::vector<T>::const_iterator iter = V.begin();
+ iter != V.end();
+ iter++)
+ {
+ int size = (int)iter->size();
+ max_size = (max_size > size ? max_size : size);
+ }
+ return max_size;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template int igl::max_size<std::vector<long, std::allocator<long> > >(std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&);
+// generated by autoexplicit.sh
+template int igl::max_size<std::vector<unsigned int, std::allocator<unsigned int> > >(std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > > const&);
+// generated by autoexplicit.sh
+template int igl::max_size<std::vector<int, std::allocator<int> > >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&);
+// generated by autoexplicit.sh
+template int igl::max_size<std::vector<double, std::allocator<double> > >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&);
+template int igl::max_size<std::vector<bool, std::allocator<bool> > >(std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > > const&);
+template int igl::max_size<std::vector<float, std::allocator<float> > >(std::vector<std::vector<float, std::allocator<float> >, std::allocator<std::vector<float, std::allocator<float> > > > const&);
+#endif
diff --git a/xs/src/igl/max_size.h b/xs/src/igl/max_size.h
new file mode 100644
index 000000000..58035d4ce
--- /dev/null
+++ b/xs/src/igl/max_size.h
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MAX_SIZE_H
+#define IGL_MAX_SIZE_H
+#include "igl_inline.h"
+#include <vector>
+
+namespace igl
+{
+ // Determine max size of lists in a vector
+ // Template:
+ // T some list type object that implements .size()
+ // Inputs:
+ // V vector of list types T
+ // Returns max .size() found in V, returns -1 if V is empty
+ template <typename T>
+ IGL_INLINE int max_size(const std::vector<T> & V);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "max_size.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/median.cpp b/xs/src/igl/median.cpp
new file mode 100644
index 000000000..718b9acc9
--- /dev/null
+++ b/xs/src/igl/median.cpp
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "median.h"
+#include "matrix_to_list.h"
+
+#include <vector>
+#include <algorithm>
+
+template <typename DerivedV, typename mType>
+IGL_INLINE bool igl::median(
+ const Eigen::MatrixBase<DerivedV> & V, mType & m)
+{
+ using namespace std;
+ if(V.size() == 0)
+ {
+ return false;
+ }
+ vector<typename DerivedV::Scalar> vV;
+ matrix_to_list(V,vV);
+ // http://stackoverflow.com/a/1719155/148668
+ size_t n = vV.size()/2;
+ nth_element(vV.begin(),vV.begin()+n,vV.end());
+ if(vV.size()%2==0)
+ {
+ nth_element(vV.begin(),vV.begin()+n-1,vV.end());
+ m = 0.5*(vV[n]+vV[n-1]);
+ }else
+ {
+ m = vV[n];
+ }
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::median<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1>, -1, 1, true>, float>(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1>, -1, 1, true> > const&, float&);
+// generated by autoexplicit.sh
+template bool igl::median<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, 1, true>, double>(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, 1, true> > const&, double&);
+#endif
diff --git a/xs/src/igl/median.h b/xs/src/igl/median.h
new file mode 100644
index 000000000..7986dfda4
--- /dev/null
+++ b/xs/src/igl/median.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MEDIAN_H
+#define IGL_MEDIAN_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Compute the median of an eigen vector
+ //
+ // Inputs:
+ // V #V list of unsorted values
+ // Outputs:
+ // m median of those values
+ // Returns true on success, false on failure
+ template <typename DerivedV, typename mType>
+ IGL_INLINE bool median(
+ const Eigen::MatrixBase<DerivedV> & V, mType & m);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "median.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/min.cpp b/xs/src/igl/min.cpp
new file mode 100644
index 000000000..ce8ba328e
--- /dev/null
+++ b/xs/src/igl/min.cpp
@@ -0,0 +1,41 @@
+#include "min.h"
+#include "for_each.h"
+#include "find_zero.h"
+
+template <typename AType, typename DerivedB, typename DerivedI>
+IGL_INLINE void igl::min(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ const int n = A.cols();
+ const int m = A.rows();
+ B.resize(dim==1?n:m);
+ B.setConstant(std::numeric_limits<typename DerivedB::Scalar>::max());
+ I.resize(dim==1?n:m);
+ for_each(A,[&B,&I,&dim](int i, int j,const typename DerivedB::Scalar v)
+ {
+ if(dim == 2)
+ {
+ std::swap(i,j);
+ }
+ // Coded as if dim == 1, assuming swap for dim == 2
+ if(v < B(j))
+ {
+ B(j) = v;
+ I(j) = i;
+ }
+ });
+ Eigen::VectorXi Z;
+ find_zero(A,dim,Z);
+ for(int j = 0;j<I.size();j++)
+ {
+ if(Z(j) != (dim==1?m:n) && 0 < B(j))
+ {
+ B(j) = 0;
+ I(j) = Z(j);
+ }
+ }
+}
+
diff --git a/xs/src/igl/min.h b/xs/src/igl/min.h
new file mode 100644
index 000000000..bbe5b494a
--- /dev/null
+++ b/xs/src/igl/min.h
@@ -0,0 +1,28 @@
+#ifndef IGL_MIN_H
+#define IGL_MIN_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Inputs:
+ // X m by n matrix
+ // dim dimension along which to take min
+ // Outputs:
+ // Y n-long vector (if dim == 1)
+ // or
+ // Y m-long vector (if dim == 2)
+ // I vector the same size as Y containing the indices along dim of minimum
+ // entries
+ template <typename AType, typename DerivedB, typename DerivedI>
+ IGL_INLINE void min(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedI> & I);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "min.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/min_quad_dense.cpp b/xs/src/igl/min_quad_dense.cpp
new file mode 100644
index 000000000..f489d996c
--- /dev/null
+++ b/xs/src/igl/min_quad_dense.cpp
@@ -0,0 +1,97 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "min_quad_dense.h"
+
+#include <Eigen/Core>
+#include <Eigen/LU>
+#include "EPS.h"
+#include <cstdio>
+
+template <typename T>
+IGL_INLINE void igl::min_quad_dense_precompute(
+ const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& A,
+ const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& Aeq,
+ const bool use_lu_decomposition,
+ Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& S)
+{
+ typedef Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> Mat;
+ // This threshold seems to matter a lot but I'm not sure how to
+ // set it
+ const T treshold = igl::FLOAT_EPS;
+ //const T treshold = igl::DOUBLE_EPS;
+
+ const int n = A.rows();
+ assert(A.cols() == n);
+ const int m = Aeq.rows();
+ assert(Aeq.cols() == n);
+
+ // Lagrange multipliers method:
+ Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> LM(n + m, n + m);
+ LM.block(0, 0, n, n) = A;
+ LM.block(0, n, n, m) = Aeq.transpose();
+ LM.block(n, 0, m, n) = Aeq;
+ LM.block(n, n, m, m).setZero();
+
+ Mat LMpinv;
+ if(use_lu_decomposition)
+ {
+ // if LM is close to singular, use at your own risk :)
+ LMpinv = LM.inverse();
+ }else
+ {
+ // use SVD
+ typedef Eigen::Matrix<T, Eigen::Dynamic, 1> Vec;
+ Vec singValues;
+ Eigen::JacobiSVD<Mat> svd;
+ svd.compute(LM, Eigen::ComputeFullU | Eigen::ComputeFullV );
+ const Mat& u = svd.matrixU();
+ const Mat& v = svd.matrixV();
+ const Vec& singVals = svd.singularValues();
+
+ Vec pi_singVals(n + m);
+ int zeroed = 0;
+ for (int i=0; i<n + m; i++)
+ {
+ T sv = singVals(i, 0);
+ assert(sv >= 0);
+ // printf("sv: %lg ? %lg\n",(double) sv,(double)treshold);
+ if (sv > treshold) pi_singVals(i, 0) = T(1) / sv;
+ else
+ {
+ pi_singVals(i, 0) = T(0);
+ zeroed++;
+ }
+ }
+
+ printf("min_quad_dense_precompute: %i singular values zeroed (threshold = %e)\n", zeroed, treshold);
+ Eigen::DiagonalMatrix<T, Eigen::Dynamic> pi_diag(pi_singVals);
+
+ LMpinv = v * pi_diag * u.transpose();
+ }
+ S = LMpinv.block(0, 0, n, n + m);
+
+ //// debug:
+ //mlinit(&g_pEngine);
+ //
+ //mlsetmatrix(&g_pEngine, "A", A);
+ //mlsetmatrix(&g_pEngine, "Aeq", Aeq);
+ //mlsetmatrix(&g_pEngine, "LM", LM);
+ //mlsetmatrix(&g_pEngine, "u", u);
+ //mlsetmatrix(&g_pEngine, "v", v);
+ //MatrixXd svMat = singVals;
+ //mlsetmatrix(&g_pEngine, "singVals", svMat);
+ //mlsetmatrix(&g_pEngine, "LMpinv", LMpinv);
+ //mlsetmatrix(&g_pEngine, "S", S);
+
+ //int hu = 1;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::min_quad_dense_precompute<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, bool, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+#endif
diff --git a/xs/src/igl/min_quad_dense.h b/xs/src/igl/min_quad_dense.h
new file mode 100644
index 000000000..3d115168a
--- /dev/null
+++ b/xs/src/igl/min_quad_dense.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MIN_QUAD_DENSE_H
+#define IGL_MIN_QUAD_DENSE_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+//// debug
+//#include <matlabinterface.h>
+//Engine *g_pEngine;
+
+
+namespace igl
+{
+ // MIN_QUAD_WITH_FIXED Minimize quadratic energy Z'*A*Z + Z'*B + C
+ // subject to linear constraints Aeq*Z = Beq
+ //
+ // Templates:
+ // T should be a eigen matrix primitive type like float or double
+ // Inputs:
+ // A n by n matrix of quadratic coefficients
+ // B n by 1 column of linear coefficients
+ // Aeq m by n list of linear equality constraint coefficients
+ // Beq m by 1 list of linear equality constraint constant values
+ // use_lu_decomposition use lu rather than SVD
+ // Outputs:
+ // S n by (n + m) "solve" matrix, such that S*[B', Beq'] is a solution
+ // Returns true on success, false on error
+ template <typename T>
+ IGL_INLINE void min_quad_dense_precompute(
+ const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& A,
+ const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& Aeq,
+ const bool use_lu_decomposition,
+ Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic>& S);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "min_quad_dense.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/min_quad_with_fixed.cpp b/xs/src/igl/min_quad_with_fixed.cpp
new file mode 100644
index 000000000..ffb1322c7
--- /dev/null
+++ b/xs/src/igl/min_quad_with_fixed.cpp
@@ -0,0 +1,597 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "min_quad_with_fixed.h"
+
+#include "slice.h"
+#include "is_symmetric.h"
+#include "find.h"
+#include "sparse.h"
+#include "repmat.h"
+#include "matlab_format.h"
+#include "EPS.h"
+#include "cat.h"
+
+//#include <Eigen/SparseExtra>
+// Bug in unsupported/Eigen/SparseExtra needs iostream first
+#include <iostream>
+#include <unsupported/Eigen/SparseExtra>
+#include <cassert>
+#include <cstdio>
+#include <iostream>
+
+template <typename T, typename Derivedknown>
+IGL_INLINE bool igl::min_quad_with_fixed_precompute(
+ const Eigen::SparseMatrix<T>& A2,
+ const Eigen::MatrixBase<Derivedknown> & known,
+ const Eigen::SparseMatrix<T>& Aeq,
+ const bool pd,
+ min_quad_with_fixed_data<T> & data
+ )
+{
+//#define MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ using namespace Eigen;
+ using namespace std;
+ const Eigen::SparseMatrix<T> A = 0.5*A2;
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" pre"<<endl;
+#endif
+ // number of rows
+ int n = A.rows();
+ // cache problem size
+ data.n = n;
+
+ int neq = Aeq.rows();
+ // default is to have 0 linear equality constraints
+ if(Aeq.size() != 0)
+ {
+ assert(n == Aeq.cols() && "#Aeq.cols() should match A.rows()");
+ }
+
+ assert(A.rows() == n && "A should be square");
+ assert(A.cols() == n && "A should be square");
+
+ // number of known rows
+ int kr = known.size();
+
+ assert((kr == 0 || known.minCoeff() >= 0)&& "known indices should be in [0,n)");
+ assert((kr == 0 || known.maxCoeff() < n) && "known indices should be in [0,n)");
+ assert(neq <= n && "Number of equality constraints should be less than DOFs");
+
+
+ // cache known
+ data.known = known;
+ // get list of unknown indices
+ data.unknown.resize(n-kr);
+ std::vector<bool> unknown_mask;
+ unknown_mask.resize(n,true);
+ for(int i = 0;i<kr;i++)
+ {
+ unknown_mask[known(i)] = false;
+ }
+ int u = 0;
+ for(int i = 0;i<n;i++)
+ {
+ if(unknown_mask[i])
+ {
+ data.unknown(u) = i;
+ u++;
+ }
+ }
+ // get list of lagrange multiplier indices
+ data.lagrange.resize(neq);
+ for(int i = 0;i<neq;i++)
+ {
+ data.lagrange(i) = n + i;
+ }
+ // cache unknown followed by lagrange indices
+ data.unknown_lagrange.resize(data.unknown.size()+data.lagrange.size());
+ // Would like to do:
+ //data.unknown_lagrange << data.unknown, data.lagrange;
+ // but Eigen can't handle empty vectors in comma initialization
+ // https://forum.kde.org/viewtopic.php?f=74&t=107974&p=364947#p364947
+ if(data.unknown.size() > 0)
+ {
+ data.unknown_lagrange.head(data.unknown.size()) = data.unknown;
+ }
+ if(data.lagrange.size() > 0)
+ {
+ data.unknown_lagrange.tail(data.lagrange.size()) = data.lagrange;
+ }
+
+ SparseMatrix<T> Auu;
+ slice(A,data.unknown,data.unknown,Auu);
+ assert(Auu.size() != 0 && Auu.rows() > 0 && "There should be at least one unknown.");
+
+ // Positive definiteness is *not* determined, rather it is given as a
+ // parameter
+ data.Auu_pd = pd;
+ if(data.Auu_pd)
+ {
+ // PD implies symmetric
+ data.Auu_sym = true;
+ // This is an annoying assertion unless EPS can be chosen in a nicer way.
+ //assert(is_symmetric(Auu,EPS<double>()));
+ assert(is_symmetric(Auu,1.0) &&
+ "Auu should be symmetric if positive definite");
+ }else
+ {
+ // determine if A(unknown,unknown) is symmetric and/or positive definite
+ VectorXi AuuI,AuuJ;
+ MatrixXd AuuV;
+ find(Auu,AuuI,AuuJ,AuuV);
+ data.Auu_sym = is_symmetric(Auu,EPS<double>()*AuuV.maxCoeff());
+ }
+
+ // Determine number of linearly independent constraints
+ int nc = 0;
+ if(neq>0)
+ {
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" qr"<<endl;
+#endif
+ // QR decomposition to determine row rank in Aequ
+ slice(Aeq,data.unknown,2,data.Aequ);
+ assert(data.Aequ.rows() == neq &&
+ "#Rows in Aequ should match #constraints");
+ assert(data.Aequ.cols() == data.unknown.size() &&
+ "#cols in Aequ should match #unknowns");
+ data.AeqTQR.compute(data.Aequ.transpose().eval());
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<endl<<matlab_format(SparseMatrix<T>(data.Aequ.transpose().eval()),"AeqT")<<endl<<endl;
+#endif
+ switch(data.AeqTQR.info())
+ {
+ case Eigen::Success:
+ break;
+ case Eigen::NumericalIssue:
+ cerr<<"Error: Numerical issue."<<endl;
+ return false;
+ case Eigen::InvalidInput:
+ cerr<<"Error: Invalid input."<<endl;
+ return false;
+ default:
+ cerr<<"Error: Other."<<endl;
+ return false;
+ }
+ nc = data.AeqTQR.rank();
+ assert(nc<=neq &&
+ "Rank of reduced constraints should be <= #original constraints");
+ data.Aeq_li = nc == neq;
+ //cout<<"data.Aeq_li: "<<data.Aeq_li<<endl;
+ }else
+ {
+ data.Aeq_li = true;
+ }
+
+ if(data.Aeq_li)
+ {
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" Aeq_li=true"<<endl;
+#endif
+ // Append lagrange multiplier quadratic terms
+ SparseMatrix<T> new_A;
+ SparseMatrix<T> AeqT = Aeq.transpose();
+ SparseMatrix<T> Z(neq,neq);
+ // This is a bit slower. But why isn't cat fast?
+ new_A = cat(1, cat(2, A, AeqT ),
+ cat(2, Aeq, Z ));
+
+ // precompute RHS builders
+ if(kr > 0)
+ {
+ SparseMatrix<T> Aulk,Akul;
+ // Slow
+ slice(new_A,data.unknown_lagrange,data.known,Aulk);
+ //// This doesn't work!!!
+ //data.preY = Aulk + Akul.transpose();
+ // Slow
+ if(data.Auu_sym)
+ {
+ data.preY = Aulk*2;
+ }else
+ {
+ slice(new_A,data.known,data.unknown_lagrange,Akul);
+ SparseMatrix<T> AkulT = Akul.transpose();
+ data.preY = Aulk + AkulT;
+ }
+ }else
+ {
+ data.preY.resize(data.unknown_lagrange.size(),0);
+ }
+
+ // Positive definite and no equality constraints (Positive definiteness
+ // implies symmetric)
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" factorize"<<endl;
+#endif
+ if(data.Auu_pd && neq == 0)
+ {
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" llt"<<endl;
+#endif
+ data.llt.compute(Auu);
+ switch(data.llt.info())
+ {
+ case Eigen::Success:
+ break;
+ case Eigen::NumericalIssue:
+ cerr<<"Error: Numerical issue."<<endl;
+ return false;
+ default:
+ cerr<<"Error: Other."<<endl;
+ return false;
+ }
+ data.solver_type = min_quad_with_fixed_data<T>::LLT;
+ }else
+ {
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" ldlt"<<endl;
+#endif
+ // Either not PD or there are equality constraints
+ SparseMatrix<T> NA;
+ slice(new_A,data.unknown_lagrange,data.unknown_lagrange,NA);
+ data.NA = NA;
+ // Ideally we'd use LDLT but Eigen doesn't support positive semi-definite
+ // matrices:
+ // http://forum.kde.org/viewtopic.php?f=74&t=106962&p=291990#p291990
+ if(data.Auu_sym && false)
+ {
+ data.ldlt.compute(NA);
+ switch(data.ldlt.info())
+ {
+ case Eigen::Success:
+ break;
+ case Eigen::NumericalIssue:
+ cerr<<"Error: Numerical issue."<<endl;
+ return false;
+ default:
+ cerr<<"Error: Other."<<endl;
+ return false;
+ }
+ data.solver_type = min_quad_with_fixed_data<T>::LDLT;
+ }else
+ {
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" lu"<<endl;
+#endif
+ // Resort to LU
+ // Bottleneck >1/2
+ data.lu.compute(NA);
+ //std::cout<<"NA=["<<std::endl<<NA<<std::endl<<"];"<<std::endl;
+ switch(data.lu.info())
+ {
+ case Eigen::Success:
+ break;
+ case Eigen::NumericalIssue:
+ cerr<<"Error: Numerical issue."<<endl;
+ return false;
+ case Eigen::InvalidInput:
+ cerr<<"Error: Invalid Input."<<endl;
+ return false;
+ default:
+ cerr<<"Error: Other."<<endl;
+ return false;
+ }
+ data.solver_type = min_quad_with_fixed_data<T>::LU;
+ }
+ }
+ }else
+ {
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" Aeq_li=false"<<endl;
+#endif
+ data.neq = neq;
+ const int nu = data.unknown.size();
+ //cout<<"nu: "<<nu<<endl;
+ //cout<<"neq: "<<neq<<endl;
+ //cout<<"nc: "<<nc<<endl;
+ //cout<<" matrixR"<<endl;
+ SparseMatrix<T> AeqTR,AeqTQ;
+ AeqTR = data.AeqTQR.matrixR();
+ // This shouldn't be necessary
+ AeqTR.prune(0.0);
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" matrixQ"<<endl;
+#endif
+ // THIS IS ESSENTIALLY DENSE AND THIS IS BY FAR THE BOTTLENECK
+ // http://forum.kde.org/viewtopic.php?f=74&t=117500
+ AeqTQ = data.AeqTQR.matrixQ();
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" prune"<<endl;
+ cout<<" nnz: "<<AeqTQ.nonZeros()<<endl;
+#endif
+ // This shouldn't be necessary
+ AeqTQ.prune(0.0);
+ //cout<<"AeqTQ: "<<AeqTQ.rows()<<" "<<AeqTQ.cols()<<endl;
+ //cout<<matlab_format(AeqTQ,"AeqTQ")<<endl;
+ //cout<<" perms"<<endl;
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" nnz: "<<AeqTQ.nonZeros()<<endl;
+ cout<<" perm"<<endl;
+#endif
+ SparseMatrix<double> I(neq,neq);
+ I.setIdentity();
+ data.AeqTE = data.AeqTQR.colsPermutation() * I;
+ data.AeqTET = data.AeqTQR.colsPermutation().transpose() * I;
+ assert(AeqTR.rows() == nu && "#rows in AeqTR should match #unknowns");
+ assert(AeqTR.cols() == neq && "#cols in AeqTR should match #constraints");
+ assert(AeqTQ.rows() == nu && "#rows in AeqTQ should match #unknowns");
+ assert(AeqTQ.cols() == nu && "#cols in AeqTQ should match #unknowns");
+ //cout<<" slice"<<endl;
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" slice"<<endl;
+#endif
+ data.AeqTQ1 = AeqTQ.topLeftCorner(nu,nc);
+ data.AeqTQ1T = data.AeqTQ1.transpose().eval();
+ // ALREADY TRIM (Not 100% sure about this)
+ data.AeqTR1 = AeqTR.topLeftCorner(nc,nc);
+ data.AeqTR1T = data.AeqTR1.transpose().eval();
+ //cout<<"AeqTR1T.size() "<<data.AeqTR1T.rows()<<" "<<data.AeqTR1T.cols()<<endl;
+ // Null space
+ data.AeqTQ2 = AeqTQ.bottomRightCorner(nu,nu-nc);
+ data.AeqTQ2T = data.AeqTQ2.transpose().eval();
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" proj"<<endl;
+#endif
+ // Projected hessian
+ SparseMatrix<T> QRAuu = data.AeqTQ2T * Auu * data.AeqTQ2;
+ {
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" factorize"<<endl;
+#endif
+ // QRAuu should always be PD
+ data.llt.compute(QRAuu);
+ switch(data.llt.info())
+ {
+ case Eigen::Success:
+ break;
+ case Eigen::NumericalIssue:
+ cerr<<"Error: Numerical issue."<<endl;
+ return false;
+ default:
+ cerr<<"Error: Other."<<endl;
+ return false;
+ }
+ data.solver_type = min_quad_with_fixed_data<T>::QR_LLT;
+ }
+#ifdef MIN_QUAD_WITH_FIXED_CPP_DEBUG
+ cout<<" smash"<<endl;
+#endif
+ // Known value multiplier
+ SparseMatrix<T> Auk;
+ slice(A,data.unknown,data.known,Auk);
+ SparseMatrix<T> Aku;
+ slice(A,data.known,data.unknown,Aku);
+ SparseMatrix<T> AkuT = Aku.transpose();
+ data.preY = Auk + AkuT;
+ // Needed during solve
+ data.Auu = Auu;
+ slice(Aeq,data.known,2,data.Aeqk);
+ assert(data.Aeqk.rows() == neq);
+ assert(data.Aeqk.cols() == data.known.size());
+ }
+ return true;
+}
+
+
+template <
+ typename T,
+ typename DerivedB,
+ typename DerivedY,
+ typename DerivedBeq,
+ typename DerivedZ,
+ typename Derivedsol>
+IGL_INLINE bool igl::min_quad_with_fixed_solve(
+ const min_quad_with_fixed_data<T> & data,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedY> & Y,
+ const Eigen::MatrixBase<DerivedBeq> & Beq,
+ Eigen::PlainObjectBase<DerivedZ> & Z,
+ Eigen::PlainObjectBase<Derivedsol> & sol)
+{
+ using namespace std;
+ using namespace Eigen;
+ typedef Matrix<T,Dynamic,1> VectorXT;
+ typedef Matrix<T,Dynamic,Dynamic> MatrixXT;
+ // number of known rows
+ int kr = data.known.size();
+ if(kr!=0)
+ {
+ assert(kr == Y.rows());
+ }
+ // number of columns to solve
+ int cols = Y.cols();
+ assert(B.cols() == 1 || B.cols() == cols);
+ assert(Beq.size() == 0 || Beq.cols() == 1 || Beq.cols() == cols);
+
+ // resize output
+ Z.resize(data.n,cols);
+ // Set known values
+ for(int i = 0;i < kr;i++)
+ {
+ for(int j = 0;j < cols;j++)
+ {
+ Z(data.known(i),j) = Y(i,j);
+ }
+ }
+
+ if(data.Aeq_li)
+ {
+ // number of lagrange multipliers aka linear equality constraints
+ int neq = data.lagrange.size();
+ // append lagrange multiplier rhs's
+ MatrixXT BBeq(B.rows() + Beq.rows(),cols);
+ if(B.size() > 0)
+ {
+ BBeq.topLeftCorner(B.rows(),cols) = B.replicate(1,B.cols()==cols?1:cols);
+ }
+ if(Beq.size() > 0)
+ {
+ BBeq.bottomLeftCorner(Beq.rows(),cols) = -2.0*Beq.replicate(1,Beq.cols()==cols?1:cols);
+ }
+
+ // Build right hand side
+ MatrixXT BBequlcols;
+ igl::slice(BBeq,data.unknown_lagrange,1,BBequlcols);
+ MatrixXT NB;
+ if(kr == 0)
+ {
+ NB = BBequlcols;
+ }else
+ {
+ NB = data.preY * Y + BBequlcols;
+ }
+
+ //std::cout<<"NB=["<<std::endl<<NB<<std::endl<<"];"<<std::endl;
+ //cout<<matlab_format(NB,"NB")<<endl;
+ switch(data.solver_type)
+ {
+ case igl::min_quad_with_fixed_data<T>::LLT:
+ sol = data.llt.solve(NB);
+ break;
+ case igl::min_quad_with_fixed_data<T>::LDLT:
+ sol = data.ldlt.solve(NB);
+ break;
+ case igl::min_quad_with_fixed_data<T>::LU:
+ // Not a bottleneck
+ sol = data.lu.solve(NB);
+ break;
+ default:
+ cerr<<"Error: invalid solver type"<<endl;
+ return false;
+ }
+ //std::cout<<"sol=["<<std::endl<<sol<<std::endl<<"];"<<std::endl;
+ // Now sol contains sol/-0.5
+ sol *= -0.5;
+ // Now sol contains solution
+ // Place solution in Z
+ for(int i = 0;i<(sol.rows()-neq);i++)
+ {
+ for(int j = 0;j<sol.cols();j++)
+ {
+ Z(data.unknown_lagrange(i),j) = sol(i,j);
+ }
+ }
+ }else
+ {
+ assert(data.solver_type == min_quad_with_fixed_data<T>::QR_LLT);
+ MatrixXT eff_Beq;
+ // Adjust Aeq rhs to include known parts
+ eff_Beq =
+ //data.AeqTQR.colsPermutation().transpose() * (-data.Aeqk * Y + Beq);
+ data.AeqTET * (-data.Aeqk * Y + Beq.replicate(1,Beq.cols()==cols?1:cols));
+ // Where did this -0.5 come from? Probably the same place as above.
+ MatrixXT Bu;
+ slice(B,data.unknown,1,Bu);
+ MatrixXT NB;
+ NB = -0.5*(Bu.replicate(1,B.cols()==cols?1:cols) + data.preY * Y);
+ // Trim eff_Beq
+ const int nc = data.AeqTQR.rank();
+ const int neq = Beq.rows();
+ eff_Beq = eff_Beq.topLeftCorner(nc,cols).eval();
+ data.AeqTR1T.template triangularView<Lower>().solveInPlace(eff_Beq);
+ // Now eff_Beq = (data.AeqTR1T \ (data.AeqTET * (-data.Aeqk * Y + Beq)))
+ MatrixXT lambda_0;
+ lambda_0 = data.AeqTQ1 * eff_Beq;
+ //cout<<matlab_format(lambda_0,"lambda_0")<<endl;
+ MatrixXT QRB;
+ QRB = -data.AeqTQ2T * (data.Auu * lambda_0) + data.AeqTQ2T * NB;
+ Derivedsol lambda;
+ lambda = data.llt.solve(QRB);
+ // prepare output
+ Derivedsol solu;
+ solu = data.AeqTQ2 * lambda + lambda_0;
+ // http://www.math.uh.edu/~rohop/fall_06/Chapter3.pdf
+ Derivedsol solLambda;
+ {
+ Derivedsol temp1,temp2;
+ temp1 = (data.AeqTQ1T * NB - data.AeqTQ1T * data.Auu * solu);
+ data.AeqTR1.template triangularView<Upper>().solveInPlace(temp1);
+ //cout<<matlab_format(temp1,"temp1")<<endl;
+ temp2 = Derivedsol::Zero(neq,cols);
+ temp2.topLeftCorner(nc,cols) = temp1;
+ //solLambda = data.AeqTQR.colsPermutation() * temp2;
+ solLambda = data.AeqTE * temp2;
+ }
+ // sol is [Z(unknown);Lambda]
+ assert(data.unknown.size() == solu.rows());
+ assert(cols == solu.cols());
+ assert(data.neq == neq);
+ assert(data.neq == solLambda.rows());
+ assert(cols == solLambda.cols());
+ sol.resize(data.unknown.size()+data.neq,cols);
+ sol.block(0,0,solu.rows(),solu.cols()) = solu;
+ sol.block(solu.rows(),0,solLambda.rows(),solLambda.cols()) = solLambda;
+ for(int u = 0;u<data.unknown.size();u++)
+ {
+ for(int j = 0;j<Z.cols();j++)
+ {
+ Z(data.unknown(u),j) = solu(u,j);
+ }
+ }
+ }
+ return true;
+}
+
+template <
+ typename T,
+ typename DerivedB,
+ typename DerivedY,
+ typename DerivedBeq,
+ typename DerivedZ>
+IGL_INLINE bool igl::min_quad_with_fixed_solve(
+ const min_quad_with_fixed_data<T> & data,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedY> & Y,
+ const Eigen::MatrixBase<DerivedBeq> & Beq,
+ Eigen::PlainObjectBase<DerivedZ> & Z)
+{
+ Eigen::Matrix<typename DerivedZ::Scalar, Eigen::Dynamic, Eigen::Dynamic> sol;
+ return min_quad_with_fixed_solve(data,B,Y,Beq,Z,sol);
+}
+
+template <
+ typename T,
+ typename Derivedknown,
+ typename DerivedB,
+ typename DerivedY,
+ typename DerivedBeq,
+ typename DerivedZ>
+IGL_INLINE bool igl::min_quad_with_fixed(
+ const Eigen::SparseMatrix<T>& A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<Derivedknown> & known,
+ const Eigen::MatrixBase<DerivedY> & Y,
+ const Eigen::SparseMatrix<T>& Aeq,
+ const Eigen::MatrixBase<DerivedBeq> & Beq,
+ const bool pd,
+ Eigen::PlainObjectBase<DerivedZ> & Z)
+{
+ min_quad_with_fixed_data<T> data;
+ if(!min_quad_with_fixed_precompute(A,known,Aeq,pd,data))
+ {
+ return false;
+ }
+ return min_quad_with_fixed_solve(data,B,Y,Beq,Z);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::min_quad_with_fixed<double, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template bool igl::min_quad_with_fixed_precompute<double, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, bool, igl::min_quad_with_fixed_data<double>&);
+template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::min_quad_with_fixed_precompute<double, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, bool, igl::min_quad_with_fixed_data<double>&);
+template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::min_quad_with_fixed_solve<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(igl::min_quad_with_fixed_data<double> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::min_quad_with_fixed<double, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/min_quad_with_fixed.h b/xs/src/igl/min_quad_with_fixed.h
new file mode 100644
index 000000000..269623313
--- /dev/null
+++ b/xs/src/igl/min_quad_with_fixed.h
@@ -0,0 +1,179 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MIN_QUAD_WITH_FIXED_H
+#define IGL_MIN_QUAD_WITH_FIXED_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Core>
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+// Bug in unsupported/Eigen/SparseExtra needs iostream first
+#include <iostream>
+#include <unsupported/Eigen/SparseExtra>
+
+namespace igl
+{
+ template <typename T>
+ struct min_quad_with_fixed_data;
+ // Known Bugs: rows of Aeq **should probably** be linearly independent.
+ // During precomputation, the rows of a Aeq are checked via QR. But in case
+ // they're not then resulting probably will no longer be sparse: it will be
+ // slow.
+ //
+ // MIN_QUAD_WITH_FIXED Minimize a quadratic energy of the form
+ //
+ // trace( 0.5*Z'*A*Z + Z'*B + constant )
+ //
+ // subject to
+ //
+ // Z(known,:) = Y, and
+ // Aeq*Z = Beq
+ //
+ // Templates:
+ // T should be a eigen matrix primitive type like int or double
+ // Inputs:
+ // A n by n matrix of quadratic coefficients
+ // known list of indices to known rows in Z
+ // Y list of fixed values corresponding to known rows in Z
+ // Aeq m by n list of linear equality constraint coefficients
+ // pd flag specifying whether A(unknown,unknown) is positive definite
+ // Outputs:
+ // data factorization struct with all necessary information to solve
+ // using min_quad_with_fixed_solve
+ // 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
+ //
+ template <typename T, typename Derivedknown>
+ IGL_INLINE bool min_quad_with_fixed_precompute(
+ const Eigen::SparseMatrix<T>& A,
+ const Eigen::MatrixBase<Derivedknown> & known,
+ const Eigen::SparseMatrix<T>& Aeq,
+ const bool pd,
+ min_quad_with_fixed_data<T> & data
+ );
+ // Solves a system previously factored using min_quad_with_fixed_precompute
+ //
+ // Template:
+ // T type of sparse matrix (e.g. double)
+ // DerivedY type of Y (e.g. derived from VectorXd or MatrixXd)
+ // DerivedZ type of Z (e.g. derived from VectorXd or MatrixXd)
+ // Inputs:
+ // data factorization struct with all necessary precomputation to solve
+ // B n by k column of linear coefficients
+ // Y b by k list of constant fixed values
+ // Beq m by k list of linear equality constraint constant values
+ // Outputs:
+ // Z n by k solution
+ // sol #unknowns+#lagrange by k solution to linear system
+ // Returns true on success, false on error
+ template <
+ typename T,
+ typename DerivedB,
+ typename DerivedY,
+ typename DerivedBeq,
+ typename DerivedZ,
+ typename Derivedsol>
+ IGL_INLINE bool min_quad_with_fixed_solve(
+ const min_quad_with_fixed_data<T> & data,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedY> & Y,
+ const Eigen::MatrixBase<DerivedBeq> & Beq,
+ Eigen::PlainObjectBase<DerivedZ> & Z,
+ Eigen::PlainObjectBase<Derivedsol> & sol);
+ // Wrapper without sol
+ template <
+ typename T,
+ typename DerivedB,
+ typename DerivedY,
+ typename DerivedBeq,
+ typename DerivedZ>
+ IGL_INLINE bool min_quad_with_fixed_solve(
+ const min_quad_with_fixed_data<T> & data,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedY> & Y,
+ const Eigen::MatrixBase<DerivedBeq> & Beq,
+ Eigen::PlainObjectBase<DerivedZ> & Z);
+ template <
+ typename T,
+ typename Derivedknown,
+ typename DerivedB,
+ typename DerivedY,
+ typename DerivedBeq,
+ typename DerivedZ>
+ IGL_INLINE bool min_quad_with_fixed(
+ const Eigen::SparseMatrix<T>& A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<Derivedknown> & known,
+ const Eigen::MatrixBase<DerivedY> & Y,
+ const Eigen::SparseMatrix<T>& Aeq,
+ const Eigen::MatrixBase<DerivedBeq> & Beq,
+ const bool pd,
+ Eigen::PlainObjectBase<DerivedZ> & Z);
+}
+
+template <typename T>
+struct igl::min_quad_with_fixed_data
+{
+ // Size of original system: number of unknowns + number of knowns
+ int n;
+ // Whether A(unknown,unknown) is positive definite
+ bool Auu_pd;
+ // Whether A(unknown,unknown) is symmetric
+ bool Auu_sym;
+ // Indices of known variables
+ Eigen::VectorXi known;
+ // Indices of unknown variables
+ Eigen::VectorXi unknown;
+ // Indices of lagrange variables
+ Eigen::VectorXi lagrange;
+ // Indices of unknown variable followed by Indices of lagrange variables
+ Eigen::VectorXi unknown_lagrange;
+ // Matrix multiplied against Y when constructing right hand side
+ Eigen::SparseMatrix<T> preY;
+ enum SolverType
+ {
+ LLT = 0,
+ LDLT = 1,
+ LU = 2,
+ QR_LLT = 3,
+ NUM_SOLVER_TYPES = 4
+ } solver_type;
+ // Solvers
+ Eigen::SimplicialLLT <Eigen::SparseMatrix<T > > llt;
+ Eigen::SimplicialLDLT<Eigen::SparseMatrix<T > > ldlt;
+ Eigen::SparseLU<Eigen::SparseMatrix<T, Eigen::ColMajor>, Eigen::COLAMDOrdering<int> > lu;
+ // QR factorization
+ // Are rows of Aeq linearly independent?
+ bool Aeq_li;
+ // Columns of Aeq corresponding to unknowns
+ int neq;
+ Eigen::SparseQR<Eigen::SparseMatrix<T>, Eigen::COLAMDOrdering<int> > AeqTQR;
+ Eigen::SparseMatrix<T> Aeqk;
+ Eigen::SparseMatrix<T> Aequ;
+ Eigen::SparseMatrix<T> Auu;
+ Eigen::SparseMatrix<T> AeqTQ1;
+ Eigen::SparseMatrix<T> AeqTQ1T;
+ Eigen::SparseMatrix<T> AeqTQ2;
+ Eigen::SparseMatrix<T> AeqTQ2T;
+ Eigen::SparseMatrix<T> AeqTR1;
+ Eigen::SparseMatrix<T> AeqTR1T;
+ Eigen::SparseMatrix<T> AeqTE;
+ Eigen::SparseMatrix<T> AeqTET;
+ // Debug
+ Eigen::SparseMatrix<T> NA;
+ Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> NB;
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "min_quad_with_fixed.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/min_size.cpp b/xs/src/igl/min_size.cpp
new file mode 100644
index 000000000..0b0cfa9e2
--- /dev/null
+++ b/xs/src/igl/min_size.cpp
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "min_size.h"
+
+template <typename T>
+IGL_INLINE int igl::min_size(const std::vector<T> & V)
+{
+ int min_size = -1;
+ for(
+ typename std::vector<T>::const_iterator iter = V.begin();
+ iter != V.end();
+ iter++)
+ {
+ int size = (int)iter->size();
+ // have to handle base case
+ if(min_size == -1)
+ {
+ min_size = size;
+ }else{
+ min_size = (min_size < size ? min_size : size);
+ }
+ }
+ return min_size;
+}
+
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template int igl::min_size<std::vector<long, std::allocator<long> > >(std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&);
+// generated by autoexplicit.sh
+template int igl::min_size<std::vector<unsigned int, std::allocator<unsigned int> > >(std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > > const&);
+// generated by autoexplicit.sh
+template int igl::min_size<std::vector<int, std::allocator<int> > >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&);
+// generated by autoexplicit.sh
+template int igl::min_size<std::vector<double, std::allocator<double> > >(std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&);
+template int igl::min_size<std::vector<bool, std::allocator<bool> > >(std::vector<std::vector<bool, std::allocator<bool> >, std::allocator<std::vector<bool, std::allocator<bool> > > > const&);
+template int igl::min_size<std::vector<float, std::allocator<float> > >(std::vector<std::vector<float, std::allocator<float> >, std::allocator<std::vector<float, std::allocator<float> > > > const&);
+#endif
diff --git a/xs/src/igl/min_size.h b/xs/src/igl/min_size.h
new file mode 100644
index 000000000..e44036279
--- /dev/null
+++ b/xs/src/igl/min_size.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MIN_SIZE_H
+#define IGL_MIN_SIZE_H
+#include "igl_inline.h"
+#include <vector>
+
+namespace igl
+{
+ // Determine min size of lists in a vector
+ // Template:
+ // T some list type object that implements .size()
+ // Inputs:
+ // V vector of list types T
+ // Returns min .size() found in V, returns -1 if V is empty
+ template <typename T>
+ IGL_INLINE int min_size(const std::vector<T> & V);
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "min_size.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/mod.cpp b/xs/src/igl/mod.cpp
new file mode 100644
index 000000000..2064fe6a4
--- /dev/null
+++ b/xs/src/igl/mod.cpp
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mod.h"
+
+template <typename DerivedA, typename DerivedB>
+IGL_INLINE void igl::mod(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ const int base,
+ Eigen::PlainObjectBase<DerivedB> & B)
+{
+ B.resizeLike(A);
+ for(int i = 0;i<A.rows();i++)
+ {
+ for(int j = 0;j<A.cols();j++)
+ {
+ B(i,j) = A(i,j)%base;
+ }
+ }
+}
+template <typename DerivedA>
+IGL_INLINE DerivedA igl::mod(
+ const Eigen::PlainObjectBase<DerivedA> & A, const int base)
+{
+ DerivedA B;
+ mod(A,base,B);
+ return B;
+}
+#ifdef IGL_STATIC_LIBRARY
+#endif
diff --git a/xs/src/igl/mod.h b/xs/src/igl/mod.h
new file mode 100644
index 000000000..3ff58a231
--- /dev/null
+++ b/xs/src/igl/mod.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MOD_H
+#define IGL_MOD_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute elementwise mod: B = A % base
+ //
+ // Inputs:
+ // A m by n matrix
+ // base number to mod against
+ // Outputs:
+ // B m by n matrix
+ template <typename DerivedA, typename DerivedB>
+ IGL_INLINE void mod(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ const int base,
+ Eigen::PlainObjectBase<DerivedB> & B);
+ template <typename DerivedA>
+ IGL_INLINE DerivedA mod(
+ const Eigen::PlainObjectBase<DerivedA> & A, const int base);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "mod.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/mode.cpp b/xs/src/igl/mode.cpp
new file mode 100644
index 000000000..89df6be66
--- /dev/null
+++ b/xs/src/igl/mode.cpp
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mode.h"
+
+// Implementation
+#include <vector>
+
+template <typename T>
+IGL_INLINE void igl::mode(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
+ const int d,
+ Eigen::Matrix<T,Eigen::Dynamic,1> & M)
+{
+ assert(d==1 || d==2);
+ using namespace std;
+ int m = X.rows();
+ int n = X.cols();
+ M.resize((d==1)?n:m,1);
+ for(int i = 0;i<((d==2)?m:n);i++)
+ {
+ vector<int> counts(((d==2)?n:m),0);
+ for(int j = 0;j<((d==2)?n:m);j++)
+ {
+ T v = (d==2)?X(i,j):X(j,i);
+ for(int k = 0;k<((d==2)?n:m);k++)
+ {
+ T u = (d==2)?X(i,k):X(k,i);
+ if(v == u)
+ {
+ counts[k]++;
+ }
+ }
+ }
+ assert(counts.size() > 0);
+ int max_count = -1;
+ int max_count_j = -1;
+ int j =0;
+ for(vector<int>::iterator it = counts.begin();it<counts.end();it++)
+ {
+ if(max_count < *it)
+ {
+ max_count = *it;
+ max_count_j = j;
+ }
+ j++;
+ }
+ M(i,0) = (d==2)?X(i,max_count_j):X(max_count_j,i);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::mode<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, int, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
+// generated by autoexplicit.sh
+template void igl::mode<int>(Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+#endif
diff --git a/xs/src/igl/mode.h b/xs/src/igl/mode.h
new file mode 100644
index 000000000..4d0943881
--- /dev/null
+++ b/xs/src/igl/mode.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MODE_H
+#define IGL_MODE_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Takes mode of coefficients in a matrix along a given dension
+ //
+ // Templates:
+ // T should be a eigen matrix primitive type like int or double
+ // Inputs:
+ // X m by n original matrix
+ // d dension along which to take mode, m or n
+ // Outputs:
+ // M vector containing mode along dension d, if d==1 then this will be a
+ // n-long vector if d==2 then this will be a m-long vector
+ template <typename T>
+ IGL_INLINE void mode(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & X,
+ const int d,
+ Eigen::Matrix<T,Eigen::Dynamic,1> & M);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mode.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/mosek/bbw.cpp b/xs/src/igl/mosek/bbw.cpp
new file mode 100644
index 000000000..99d28ab15
--- /dev/null
+++ b/xs/src/igl/mosek/bbw.cpp
@@ -0,0 +1,88 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "bbw.h"
+#include "mosek_quadprog.h"
+#include "../harmonic.h"
+#include "../slice_into.h"
+#include <Eigen/Sparse>
+#include <iostream>
+#include <cstdio>
+
+
+template <
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+IGL_INLINE bool igl::mosek::bbw(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedEle> & Ele,
+ const Eigen::PlainObjectBase<Derivedb> & b,
+ const Eigen::PlainObjectBase<Derivedbc> & bc,
+ igl::BBWData & data,
+ igl::mosek::MosekData & mosek_data,
+ Eigen::PlainObjectBase<DerivedW> & W
+ )
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(!data.partition_unity && "partition_unity not implemented yet");
+ // number of domain vertices
+ int n = V.rows();
+ // number of handles
+ int m = bc.cols();
+ // Build biharmonic operator
+ Eigen::SparseMatrix<typename DerivedV::Scalar> Q;
+ harmonic(V,Ele,2,Q);
+ W.derived().resize(n,m);
+ // No linear terms
+ VectorXd c = VectorXd::Zero(n);
+ // No linear constraints
+ SparseMatrix<typename DerivedW::Scalar> A(0,n);
+ VectorXd uc(0,1),lc(0,1);
+ // Upper and lower box constraints (Constant bounds)
+ VectorXd ux = VectorXd::Ones(n);
+ VectorXd lx = VectorXd::Zero(n);
+ // Loop over handles
+ for(int i = 0;i<m;i++)
+ {
+ if(data.verbosity >= 1)
+ {
+ cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
+ "."<<endl;
+ }
+ VectorXd bci = bc.col(i);
+ VectorXd Wi;
+ // impose boundary conditions via bounds
+ slice_into(bci,b,ux);
+ slice_into(bci,b,lx);
+ bool r = mosek_quadprog(Q,c,0,A,lc,uc,lx,ux,mosek_data,Wi);
+ if(!r)
+ {
+ return false;
+ }
+ W.col(i) = Wi;
+ }
+#ifndef NDEBUG
+ const double min_rowsum = W.rowwise().sum().array().abs().minCoeff();
+ if(min_rowsum < 0.1)
+ {
+ cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
+ "active set iterations or enforcing partition of unity."<<endl;
+ }
+#endif
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::mosek::bbw<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::BBWData&, igl::mosek::MosekData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
+
diff --git a/xs/src/igl/mosek/bbw.h b/xs/src/igl/mosek/bbw.h
new file mode 100644
index 000000000..5dcae0fed
--- /dev/null
+++ b/xs/src/igl/mosek/bbw.h
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MOSEK_BBW_H
+#define IGL_MOSEK_BBW_H
+#include "../igl_inline.h"
+#include "mosek_quadprog.h"
+#include "../bbw.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ namespace mosek
+ {
+ // 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
+ // mosek_data object containing mosek options
+ // 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
+ template <
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedb,
+ typename Derivedbc,
+ typename DerivedW>
+ IGL_INLINE bool bbw(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedEle> & Ele,
+ const Eigen::PlainObjectBase<Derivedb> & b,
+ const Eigen::PlainObjectBase<Derivedbc> & bc,
+ igl::BBWData & data,
+ igl::mosek::MosekData & mosek_data,
+ Eigen::PlainObjectBase<DerivedW> & W);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "bbw.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/mosek/mosek_guarded.cpp b/xs/src/igl/mosek/mosek_guarded.cpp
new file mode 100644
index 000000000..242d928f6
--- /dev/null
+++ b/xs/src/igl/mosek/mosek_guarded.cpp
@@ -0,0 +1,24 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mosek_guarded.h"
+#include <iostream>
+
+IGL_INLINE MSKrescodee igl::mosek::mosek_guarded(const MSKrescodee r)
+{
+ using namespace std;
+ if(r != MSK_RES_OK)
+ {
+ /* In case of an error print error code and description. */
+ char symname[MSK_MAX_STR_LEN];
+ char desc[MSK_MAX_STR_LEN];
+ MSK_getcodedesc(r,symname,desc);
+ cerr<<"MOSEK ERROR ("<<r<<"): "<<symname<<" - '"<<desc<<"'"<<endl;
+ }
+ return r;
+}
+
diff --git a/xs/src/igl/mosek/mosek_guarded.h b/xs/src/igl/mosek/mosek_guarded.h
new file mode 100644
index 000000000..1c9e0cbf9
--- /dev/null
+++ b/xs/src/igl/mosek/mosek_guarded.h
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MOSEK_MOSEK_GUARDED_H
+#define IGL_MOSEK_MOSEK_GUARDED_H
+#include "../igl_inline.h"
+
+#include "mosek.h"
+namespace igl
+{
+ namespace mosek
+ {
+ // Little function to wrap around mosek call to handle errors
+ //
+ // Inputs:
+ // r mosek error code returned from mosek call
+ // Returns r untouched
+ IGL_INLINE MSKrescodee mosek_guarded(const MSKrescodee r);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mosek_guarded.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/mosek/mosek_linprog.cpp b/xs/src/igl/mosek/mosek_linprog.cpp
new file mode 100644
index 000000000..fe09d5adb
--- /dev/null
+++ b/xs/src/igl/mosek/mosek_linprog.cpp
@@ -0,0 +1,164 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mosek_linprog.h"
+#include "../mosek/mosek_guarded.h"
+#include "../harwell_boeing.h"
+#include <limits>
+#include <cmath>
+#include <vector>
+
+IGL_INLINE bool igl::mosek::mosek_linprog(
+ const Eigen::VectorXd & c,
+ const Eigen::SparseMatrix<double> & A,
+ const Eigen::VectorXd & lc,
+ const Eigen::VectorXd & uc,
+ const Eigen::VectorXd & lx,
+ const Eigen::VectorXd & ux,
+ Eigen::VectorXd & x)
+{
+ // variables for mosek task, env and result code
+ MSKenv_t env;
+ // Create the MOSEK environment
+ mosek_guarded(MSK_makeenv(&env,NULL));
+ // initialize mosek environment
+#if MSK_VERSION_MAJOR <= 7
+ mosek_guarded(MSK_initenv(env));
+#endif
+ const bool ret = mosek_linprog(c,A,lc,uc,lx,ux,env,x);
+ MSK_deleteenv(&env);
+ return ret;
+}
+
+IGL_INLINE bool igl::mosek::mosek_linprog(
+ const Eigen::VectorXd & c,
+ const Eigen::SparseMatrix<double> & A,
+ const Eigen::VectorXd & lc,
+ const Eigen::VectorXd & uc,
+ const Eigen::VectorXd & lx,
+ const Eigen::VectorXd & ux,
+ const MSKenv_t & env,
+ Eigen::VectorXd & x)
+{
+ // following http://docs.mosek.com/7.1/capi/Linear_optimization.html
+ using namespace std;
+ // number of constraints
+ const int m = A.rows();
+ // number of variables
+ const int n = A.cols();
+
+
+ vector<double> vAv;
+ vector<int> vAri,vAcp;
+ int nr;
+ harwell_boeing(A,nr,vAv,vAri,vAcp);
+
+ MSKtask_t task;
+ // Create the optimization task
+ mosek_guarded(MSK_maketask(env,m,n,&task));
+ // no threads
+ mosek_guarded(MSK_putintparam(task,MSK_IPAR_NUM_THREADS,1));
+ if(m>0)
+ {
+ // Append 'm' empty constraints, the constrainst will initially have no
+ // bounds
+ mosek_guarded(MSK_appendcons(task,m));
+ }
+ mosek_guarded(MSK_appendvars(task,n));
+
+
+ const auto & key = [](const double lxj, const double uxj) ->
+ MSKboundkeye
+ {
+ MSKboundkeye k = MSK_BK_FR;
+ if(isfinite(lxj) && isfinite(uxj))
+ {
+ if(lxj == uxj)
+ {
+ k = MSK_BK_FX;
+ }else{
+ k = MSK_BK_RA;
+ }
+ }else if(isfinite(lxj))
+ {
+ k = MSK_BK_LO;
+ }else if(isfinite(uxj))
+ {
+ k = MSK_BK_UP;
+ }
+ return k;
+ };
+
+ // loop over variables
+ for(int j = 0;j<n;j++)
+ {
+ if(c.size() > 0)
+ {
+ // Set linear term c_j in the objective
+ mosek_guarded(MSK_putcj(task,j,c(j)));
+ }
+
+ // Set constant bounds on variable j
+ const double lxj = lx.size()>0?lx[j]:-numeric_limits<double>::infinity();
+ const double uxj = ux.size()>0?ux[j]: numeric_limits<double>::infinity();
+ mosek_guarded(MSK_putvarbound(task,j,key(lxj,uxj),lxj,uxj));
+
+ if(m>0)
+ {
+ // Input column j of A
+ mosek_guarded(
+ MSK_putacol(
+ task,
+ j,
+ vAcp[j+1]-vAcp[j],
+ &vAri[vAcp[j]],
+ &vAv[vAcp[j]])
+ );
+ }
+ }
+ // loop over constraints
+ for(int i = 0;i<m;i++)
+ {
+ // Set constraint bounds for row i
+ const double lci = lc.size()>0?lc[i]:-numeric_limits<double>::infinity();
+ const double uci = uc.size()>0?uc[i]: numeric_limits<double>::infinity();
+ mosek_guarded(MSK_putconbound(task,i,key(lci,uci),lci,uci));
+ }
+
+ // Now the optimizer has been prepared
+ MSKrescodee trmcode;
+ // run the optimizer
+ mosek_guarded(MSK_optimizetrm(task,&trmcode));
+ // Get status
+ MSKsolstae solsta;
+ MSK_getsolsta (task,MSK_SOL_ITR,&solsta);
+ bool success = false;
+ switch(solsta)
+ {
+ case MSK_SOL_STA_OPTIMAL:
+ case MSK_SOL_STA_NEAR_OPTIMAL:
+ x.resize(n);
+ /* Request the basic solution. */
+ MSK_getxx(task,MSK_SOL_BAS,x.data());
+ success = true;
+ break;
+ case MSK_SOL_STA_DUAL_INFEAS_CER:
+ case MSK_SOL_STA_PRIM_INFEAS_CER:
+ case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
+ case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:
+ //printf("Primal or dual infeasibility certificate found.\n");
+ break;
+ case MSK_SOL_STA_UNKNOWN:
+ //printf("The status of the solution could not be determined.\n");
+ break;
+ default:
+ //printf("Other solution status.");
+ break;
+ }
+ MSK_deletetask(&task);
+ return success;
+}
diff --git a/xs/src/igl/mosek/mosek_linprog.h b/xs/src/igl/mosek/mosek_linprog.h
new file mode 100644
index 000000000..57791cd60
--- /dev/null
+++ b/xs/src/igl/mosek/mosek_linprog.h
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MOSEK_MOSEK_LINPROG_H
+#define IGL_MOSEK_MOSEK_LINPROG_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+#include <mosek.h>
+namespace igl
+{
+ namespace mosek
+ {
+ // Solve a linear program using mosek:
+ //
+ // min c'x
+ // s.t. lc <= A x <= uc
+ // lx <= x <= ux
+ //
+ // Inputs:
+ // c #x list of linear objective coefficients
+ // A #A by #x matrix of linear inequality constraint coefficients
+ // lc #A list of lower constraint bounds
+ // uc #A list of upper constraint bounds
+ // lx #x list of lower variable bounds
+ // ux #x list of upper variable bounds
+ // Outputs:
+ // x #x list of solution values
+ // Returns true iff success.
+ IGL_INLINE bool mosek_linprog(
+ const Eigen::VectorXd & c,
+ const Eigen::SparseMatrix<double> & A,
+ const Eigen::VectorXd & lc,
+ const Eigen::VectorXd & uc,
+ const Eigen::VectorXd & lx,
+ const Eigen::VectorXd & ux,
+ Eigen::VectorXd & x);
+ // Wrapper that keeps mosek environment alive (if licence checking is
+ // becoming a bottleneck)
+ IGL_INLINE bool mosek_linprog(
+ const Eigen::VectorXd & c,
+ const Eigen::SparseMatrix<double> & A,
+ const Eigen::VectorXd & lc,
+ const Eigen::VectorXd & uc,
+ const Eigen::VectorXd & lx,
+ const Eigen::VectorXd & ux,
+ const MSKenv_t & env,
+ Eigen::VectorXd & x);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mosek_linprog.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/mosek/mosek_quadprog.cpp b/xs/src/igl/mosek/mosek_quadprog.cpp
new file mode 100644
index 000000000..36d9e873b
--- /dev/null
+++ b/xs/src/igl/mosek/mosek_quadprog.cpp
@@ -0,0 +1,343 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mosek_quadprog.h"
+#include "mosek_guarded.h"
+#include <cstdio>
+#include "../find.h"
+#include "../verbose.h"
+#include "../speye.h"
+#include "../matrix_to_list.h"
+#include "../list_to_matrix.h"
+#include "../harwell_boeing.h"
+#include "../EPS.h"
+
+
+igl::mosek::MosekData::MosekData()
+{
+ // These are the default settings that worked well for BBW. Your miles may
+ // very well be kilometers.
+
+ // >1e0 NONSOLUTION
+ // 1e-1 artifacts in deformation
+ // 1e-3 artifacts in isolines
+ // 1e-4 seems safe
+ // 1e-8 MOSEK DEFAULT SOLUTION
+ douparam[MSK_DPAR_INTPNT_TOL_REL_GAP]=1e-8;
+#if MSK_VERSION_MAJOR >= 8
+ douparam[MSK_DPAR_INTPNT_QO_TOL_REL_GAP]=1e-12;
+#endif
+ // Force using multiple threads, not sure if MOSEK is properly destroying
+ //extra threads...
+#if MSK_VERSION_MAJOR >= 7
+ intparam[MSK_IPAR_NUM_THREADS] = 6;
+#elif MSK_VERSION_MAJOR == 6
+ intparam[MSK_IPAR_INTPNT_NUM_THREADS] = 6;
+#endif
+#if MSK_VERSION_MAJOR == 6
+ // Force turn off data check
+ intparam[MSK_IPAR_DATA_CHECK]=MSK_OFF;
+#endif
+ // Turn off presolving
+ // intparam[MSK_IPAR_PRESOLVE_USE] = MSK_PRESOLVE_MODE_OFF;
+ // Force particular matrix reordering method
+ // MSK_ORDER_METHOD_NONE cuts time in half roughly, since half the time is
+ // usually spent reordering the matrix
+ // !! WARNING Setting this parameter to anything but MSK_ORDER_METHOD_FREE
+ // seems to have the effect of setting it to MSK_ORDER_METHOD_NONE
+ // *Or maybe Mosek is spending a bunch of time analyzing the matrix to
+ // choose the right ordering method when really any of them are
+ // instantaneous
+ intparam[MSK_IPAR_INTPNT_ORDER_METHOD] = MSK_ORDER_METHOD_NONE;
+ // 1.0 means optimizer is very lenient about declaring model infeasible
+ douparam[MSK_DPAR_INTPNT_TOL_INFEAS] = 1e-8;
+ // Hard to say if this is doing anything, probably nothing dramatic
+ douparam[MSK_DPAR_INTPNT_TOL_PSAFE]= 1e2;
+ // Turn off convexity check
+ intparam[MSK_IPAR_CHECK_CONVEXITY] = MSK_CHECK_CONVEXITY_NONE;
+}
+
+template <typename Index, typename Scalar>
+IGL_INLINE bool igl::mosek::mosek_quadprog(
+ const Index n,
+ std::vector<Index> & Qi,
+ std::vector<Index> & Qj,
+ std::vector<Scalar> & Qv,
+ const std::vector<Scalar> & c,
+ const Scalar cf,
+ const Index m,
+ std::vector<Scalar> & Av,
+ std::vector<Index> & Ari,
+ const std::vector<Index> & Acp,
+ const std::vector<Scalar> & lc,
+ const std::vector<Scalar> & uc,
+ const std::vector<Scalar> & lx,
+ const std::vector<Scalar> & ux,
+ MosekData & mosek_data,
+ std::vector<Scalar> & x)
+{
+ // I J V vectors of Q should all be same length
+ assert(Qv.size() == Qi.size());
+ assert(Qv.size() == Qj.size());
+ // number of columns in linear constraint matrix must be ≤ number of
+ // variables
+ assert( (int)Acp.size() == (n+1));
+ // linear bound vectors must be size of number of constraints or empty
+ assert( ((int)lc.size() == m) || ((int)lc.size() == 0));
+ assert( ((int)uc.size() == m) || ((int)uc.size() == 0));
+ // constant bound vectors must be size of number of variables or empty
+ assert( ((int)lx.size() == n) || ((int)lx.size() == 0));
+ assert( ((int)ux.size() == n) || ((int)ux.size() == 0));
+
+ // allocate space for solution in x
+ x.resize(n);
+
+ // variables for mosek task, env and result code
+ MSKenv_t env;
+ MSKtask_t task;
+
+ // Create the MOSEK environment
+#if MSK_VERSION_MAJOR >= 7
+ mosek_guarded(MSK_makeenv(&env,NULL));
+#elif MSK_VERSION_MAJOR == 6
+ mosek_guarded(MSK_makeenv(&env,NULL,NULL,NULL,NULL));
+#endif
+ ///* Directs the log stream to the 'printstr' function. */
+ //// Little function mosek needs in order to know how to print to std out
+ //const auto & printstr = [](void *handle, char str[])
+ //{
+ // printf("%s",str);
+ //}
+ //mosek_guarded(MSK_linkfunctoenvstream(env,MSK_STREAM_LOG,NULL,printstr));
+ // initialize mosek environment
+#if MSK_VERSION_MAJOR <= 7
+ mosek_guarded(MSK_initenv(env));
+#endif
+ // Create the optimization task
+ mosek_guarded(MSK_maketask(env,m,n,&task));
+ verbose("Creating task with %ld linear constraints and %ld variables...\n",m,n);
+ //// Tell mosek how to print to std out
+ //mosek_guarded(MSK_linkfunctotaskstream(task,MSK_STREAM_LOG,NULL,printstr));
+ // Give estimate of number of variables
+ mosek_guarded(MSK_putmaxnumvar(task,n));
+ if(m>0)
+ {
+ // Give estimate of number of constraints
+ mosek_guarded(MSK_putmaxnumcon(task,m));
+ // Give estimate of number of non zeros in A
+ mosek_guarded(MSK_putmaxnumanz(task,Av.size()));
+ }
+ // Give estimate of number of non zeros in Q
+ mosek_guarded(MSK_putmaxnumqnz(task,Qv.size()));
+ if(m>0)
+ {
+ // Append 'm' empty constraints, the constrainst will initially have no
+ // bounds
+#if MSK_VERSION_MAJOR >= 7
+ mosek_guarded(MSK_appendcons(task,m));
+#elif MSK_VERSION_MAJOR == 6
+ mosek_guarded(MSK_append(task,MSK_ACC_CON,m));
+#endif
+ }
+ // Append 'n' variables
+#if MSK_VERSION_MAJOR >= 7
+ mosek_guarded(MSK_appendvars(task,n));
+#elif MSK_VERSION_MAJOR == 6
+ mosek_guarded(MSK_append(task,MSK_ACC_VAR,n));
+#endif
+ // add a contant term to the objective
+ mosek_guarded(MSK_putcfix(task,cf));
+
+ // loop over variables
+ for(int j = 0;j<n;j++)
+ {
+ if(c.size() > 0)
+ {
+ // Set linear term c_j in the objective
+ mosek_guarded(MSK_putcj(task,j,c[j]));
+ }
+
+ // Set constant bounds on variable j
+ if(lx[j] == ux[j])
+ {
+ mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_FX,lx[j],ux[j]));
+ }else
+ {
+ mosek_guarded(MSK_putbound(task,MSK_ACC_VAR,j,MSK_BK_RA,lx[j],ux[j]));
+ }
+
+ if(m>0)
+ {
+ // Input column j of A
+#if MSK_VERSION_MAJOR >= 7
+ mosek_guarded(
+ MSK_putacol(
+ task,
+ j,
+ Acp[j+1]-Acp[j],
+ &Ari[Acp[j]],
+ &Av[Acp[j]])
+ );
+#elif MSK_VERSION_MAJOR == 6
+ mosek_guarded(
+ MSK_putavec(
+ task,
+ MSK_ACC_VAR,
+ j,
+ Acp[j+1]-Acp[j],
+ &Ari[Acp[j]],
+ &Av[Acp[j]])
+ );
+#endif
+ }
+ }
+
+ // loop over constraints
+ for(int i = 0;i<m;i++)
+ {
+ // put bounds on constraints
+ mosek_guarded(MSK_putbound(task,MSK_ACC_CON,i,MSK_BK_RA,lc[i],uc[i]));
+ }
+
+ // Input Q for the objective (REMEMBER Q SHOULD ONLY BE LOWER TRIANGLE)
+ mosek_guarded(MSK_putqobj(task,Qv.size(),&Qi[0],&Qj[0],&Qv[0]));
+
+ // Set up task parameters
+ for(
+ std::map<MSKiparame,int>::iterator pit = mosek_data.intparam.begin();
+ pit != mosek_data.intparam.end();
+ pit++)
+ {
+ mosek_guarded(MSK_putintparam(task,pit->first,pit->second));
+ }
+ for(
+ std::map<MSKdparame,double>::iterator pit = mosek_data.douparam.begin();
+ pit != mosek_data.douparam.end();
+ pit++)
+ {
+ mosek_guarded(MSK_putdouparam(task,pit->first,pit->second));
+ }
+
+ // Now the optimizer has been prepared
+ MSKrescodee trmcode;
+ // run the optimizer
+ mosek_guarded(MSK_optimizetrm(task,&trmcode));
+
+ //// Print a summary containing information about the solution for debugging
+ //// purposes
+ //MSK_solutionsummary(task,MSK_STREAM_LOG);
+
+ // Get status of solution
+ MSKsolstae solsta;
+#if MSK_VERSION_MAJOR >= 7
+ MSK_getsolsta (task,MSK_SOL_ITR,&solsta);
+#elif MSK_VERSION_MAJOR == 6
+ MSK_getsolutionstatus(task,MSK_SOL_ITR,NULL,&solsta);
+#endif
+
+ bool success = false;
+ switch(solsta)
+ {
+ case MSK_SOL_STA_OPTIMAL:
+ case MSK_SOL_STA_NEAR_OPTIMAL:
+ MSK_getsolutionslice(task,MSK_SOL_ITR,MSK_SOL_ITEM_XX,0,n,&x[0]);
+ //printf("Optimal primal solution\n");
+ //for(size_t j=0; j<n; ++j)
+ //{
+ // printf("x[%ld]: %g\n",j,x[j]);
+ //}
+ success = true;
+ break;
+ case MSK_SOL_STA_DUAL_INFEAS_CER:
+ case MSK_SOL_STA_PRIM_INFEAS_CER:
+ case MSK_SOL_STA_NEAR_DUAL_INFEAS_CER:
+ case MSK_SOL_STA_NEAR_PRIM_INFEAS_CER:
+ //printf("Primal or dual infeasibility certificate found.\n");
+ break;
+ case MSK_SOL_STA_UNKNOWN:
+ //printf("The status of the solution could not be determined.\n");
+ break;
+ default:
+ //printf("Other solution status.");
+ break;
+ }
+
+ MSK_deletetask(&task);
+ MSK_deleteenv(&env);
+
+ return success;
+}
+
+IGL_INLINE bool igl::mosek::mosek_quadprog(
+ const Eigen::SparseMatrix<double> & Q,
+ const Eigen::VectorXd & c,
+ const double cf,
+ const Eigen::SparseMatrix<double> & A,
+ const Eigen::VectorXd & lc,
+ const Eigen::VectorXd & uc,
+ const Eigen::VectorXd & lx,
+ const Eigen::VectorXd & ux,
+ MosekData & mosek_data,
+ Eigen::VectorXd & x)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ typedef int Index;
+ typedef double Scalar;
+ // Q should be square
+ assert(Q.rows() == Q.cols());
+ // Q should be symmetric
+#ifdef EIGEN_HAS_A_BUG_AND_FAILS_TO_LET_ME_COMPUTE_Q_MINUS_Q_TRANSPOSE
+ assert( (Q-Q.transpose()).sum() < FLOAT_EPS);
+#endif
+ // Only keep lower triangular part of Q
+ SparseMatrix<Scalar> QL;
+ //QL = Q.template triangularView<Lower>();
+ QL = Q.triangularView<Lower>();
+ VectorXi Qi,Qj;
+ VectorXd Qv;
+ find(QL,Qi,Qj,Qv);
+ vector<Index> vQi = matrix_to_list(Qi);
+ vector<Index> vQj = matrix_to_list(Qj);
+ vector<Scalar> vQv = matrix_to_list(Qv);
+
+ // Convert linear term
+ vector<Scalar> vc = matrix_to_list(c);
+
+ assert(lc.size() == A.rows());
+ assert(uc.size() == A.rows());
+ // Convert A to harwell boeing format
+ vector<Scalar> vAv;
+ vector<Index> vAr,vAc;
+ Index nr;
+ harwell_boeing(A,nr,vAv,vAr,vAc);
+
+ assert(lx.size() == Q.rows());
+ assert(ux.size() == Q.rows());
+ vector<Scalar> vlc = matrix_to_list(lc);
+ vector<Scalar> vuc = matrix_to_list(uc);
+ vector<Scalar> vlx = matrix_to_list(lx);
+ vector<Scalar> vux = matrix_to_list(ux);
+
+ vector<Scalar> vx;
+ bool ret = mosek_quadprog<Index,Scalar>(
+ Q.rows(),vQi,vQj,vQv,
+ vc,
+ cf,
+ nr,
+ vAv, vAr, vAc,
+ vlc,vuc,
+ vlx,vux,
+ mosek_data,
+ vx);
+ list_to_matrix(vx,x);
+ return ret;
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template declarations
+#endif
diff --git a/xs/src/igl/mosek/mosek_quadprog.h b/xs/src/igl/mosek/mosek_quadprog.h
new file mode 100644
index 000000000..38343318a
--- /dev/null
+++ b/xs/src/igl/mosek/mosek_quadprog.h
@@ -0,0 +1,145 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MOSEK_MOSEK_QUADPROG_H
+#define IGL_MOSEK_MOSEK_QUADPROG_H
+#include "../igl_inline.h"
+#include <vector>
+#include <map>
+#include <mosek.h>
+
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ namespace mosek
+ {
+ struct MosekData
+ {
+ // Integer parameters
+ std::map<MSKiparame,int> intparam;
+ // Double parameters
+ std::map<MSKdparame,double> douparam;
+ // Default values
+ IGL_INLINE MosekData();
+ };
+ // Solve a convex quadratic optimization problem with linear and constant
+ // bounds, that is:
+ //
+ // Minimize: ½ * xT * Q⁰ * x + cT * x + cf
+ //
+ // Subject to: lc ≤ Ax ≤ uc
+ // lx ≤ x ≤ ux
+ //
+ // where we are trying to find the optimal vector of values x.
+ //
+ // Note: Q⁰ must be symmetric and the ½ is a convention of MOSEK
+ //
+ // Note: Because of how MOSEK accepts different parts of the system, Q
+ // should be stored in IJV (aka Coordinate) format and should only include
+ // entries in the lower triangle. A should be stored in Column compressed
+ // (aka Harwell Boeing) format. As described:
+ // http://netlib.org/linalg/html_templates/node92.html
+ // or
+ // http://en.wikipedia.org/wiki/Sparse_matrix
+ // #Compressed_sparse_column_.28CSC_or_CCS.29
+ //
+ //
+ // Templates:
+ // Index type for index variables
+ // Scalar type for floating point variables (gets cast to double?)
+ // Input:
+ // n number of variables, i.e. size of x
+ // Qi vector of qnnz row indices of non-zeros in LOWER TRIANGLE ONLY of
+ // Q⁰
+ // Qj vector of qnnz column indices of non-zeros in LOWER TRIANGLE ONLY
+ // of Q⁰
+ // Qv vector of qnnz values of non-zeros in LOWER TRIANGLE ONLY of Q⁰,
+ // such that:
+ //
+ // Q⁰(Qi[k],Qj[k]) = Qv[k] for k ∈ [0,Qnnz-1], where Qnnz is the
+ //
+ // number of non-zeros in Q⁰
+ // c (optional) vector of n values of c, transpose of coefficient row
+ // vector of linear terms, EMPTY means c == 0
+ // cf (ignored) value of constant term in objective, 0 means cf == 0, so
+ // optional only in the sense that it is mandatory
+ // m number of constraints, therefore also number of rows in linear
+ // constraint coefficient matrix A, and in linear constraint bound
+ // vectors lc and uc
+ // Av vector of non-zero values of A, in column compressed order
+ // Ari vector of row indices corresponding to non-zero values of A,
+ // Acp vector of indices into Ari and Av of the first entry for each
+ // column of A, size(Acp) = (# columns of A) + 1 = n + 1
+ // lc vector of m linear constraint lower bounds
+ // uc vector of m linear constraint upper bounds
+ // lx vector of n constant lower bounds
+ // ux vector of n constant upper bounds
+ // Output:
+ // x vector of size n to hold output of optimization
+ // Return:
+ // true only if optimization was successful with no errors
+ //
+ // Note: All indices are 0-based
+ //
+ template <typename Index, typename Scalar>
+ IGL_INLINE bool mosek_quadprog(
+ const Index n,
+ /* mosek won't allow this to be const*/ std::vector<Index> & Qi,
+ /* mosek won't allow this to be const*/ std::vector<Index> & Qj,
+ /* mosek won't allow this to be const*/ std::vector<Scalar> & Qv,
+ const std::vector<Scalar> & c,
+ const Scalar cf,
+ const Index m,
+ /* mosek won't allow this to be const*/ std::vector<Scalar> & Av,
+ /* mosek won't allow this to be const*/ std::vector<Index> & Ari,
+ const std::vector<Index> & Acp,
+ const std::vector<Scalar> & lc,
+ const std::vector<Scalar> & uc,
+ const std::vector<Scalar> & lx,
+ const std::vector<Scalar> & ux,
+ MosekData & mosek_data,
+ std::vector<Scalar> & x);
+ // Wrapper with Eigen elements
+ //
+ // Inputs:
+ // Q n by n square quadratic coefficients matrix **only lower triangle
+ // is used**.
+ // c n-long vector of linear coefficients
+ // cf constant coefficient
+ // A m by n square linear coefficienst matrix of inequality constraints
+ // lc m-long vector of lower bounds for linear inequality constraints
+ // uc m-long vector of upper bounds for linear inequality constraints
+ // lx n-long vector of lower bounds
+ // ux n-long vector of upper bounds
+ // mosek_data parameters struct
+ // Outputs:
+ // x n-long solution vector
+ // Returns true only if optimization finishes without error
+ //
+ IGL_INLINE bool mosek_quadprog(
+ const Eigen::SparseMatrix<double> & Q,
+ const Eigen::VectorXd & c,
+ const double cf,
+ const Eigen::SparseMatrix<double> & A,
+ const Eigen::VectorXd & lc,
+ const Eigen::VectorXd & uc,
+ const Eigen::VectorXd & lx,
+ const Eigen::VectorXd & ux,
+ MosekData & mosek_data,
+ Eigen::VectorXd & x);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mosek_quadprog.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/mvc.cpp b/xs/src/igl/mvc.cpp
new file mode 100644
index 000000000..a6fed49d8
--- /dev/null
+++ b/xs/src/igl/mvc.cpp
@@ -0,0 +1,196 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "mvc.h"
+#include <vector>
+#include <cassert>
+#include <iostream>
+
+// Broken Implementation
+IGL_INLINE void igl::mvc(const Eigen::MatrixXd &V, const Eigen::MatrixXd &C, Eigen::MatrixXd &W)
+{
+
+ // at least three control points
+ assert(C.rows()>2);
+
+ // dimension of points
+ assert(C.cols() == 3 || C.cols() == 2);
+ assert(V.cols() == 3 || V.cols() == 2);
+
+ // number of polygon points
+ int num = C.rows();
+
+ Eigen::MatrixXd V1,C1;
+ int i_prev, i_next;
+
+ // check if either are 3D but really all z's are 0
+ bool V_flat = (V.cols() == 3) && (std::sqrt( (V.col(3)).dot(V.col(3)) ) < 1e-10);
+ bool C_flat = (C.cols() == 3) && (std::sqrt( (C.col(3)).dot(C.col(3)) ) < 1e-10);
+
+ // if both are essentially 2D then ignore z-coords
+ if((C.cols() == 2 || C_flat) && (V.cols() == 2 || V_flat))
+ {
+ // ignore z coordinate
+ V1 = V.block(0,0,V.rows(),2);
+ C1 = C.block(0,0,C.rows(),2);
+ }
+ else
+ {
+ // give dummy z coordinate to either mesh or poly
+ if(V.rows() == 2)
+ {
+ V1 = Eigen::MatrixXd(V.rows(),3);
+ V1.block(0,0,V.rows(),2) = V;
+ }
+ else
+ V1 = V;
+
+ if(C.rows() == 2)
+ {
+ C1 = Eigen::MatrixXd(C.rows(),3);
+ C1.block(0,0,C.rows(),2) = C;
+ }
+ else
+ C1 = C;
+
+ // check that C is planar
+ // average normal around poly corners
+
+ Eigen::Vector3d n = Eigen::Vector3d::Zero();
+ // take centroid as point on plane
+ Eigen::Vector3d p = Eigen::Vector3d::Zero();
+ for (int i = 0; i<num; ++i)
+ {
+ i_prev = (i>0)?(i-1):(num-1);
+ i_next = (i<num-1)?(i+1):0;
+ Eigen::Vector3d vnext = (C1.row(i_next) - C1.row(i)).transpose();
+ Eigen::Vector3d vprev = (C1.row(i_prev) - C1.row(i)).transpose();
+ n += vnext.cross(vprev);
+ p += C1.row(i);
+ }
+ p/=num;
+ n/=num;
+ // normalize n
+ n /= std::sqrt(n.dot(n));
+
+ // check that poly is really coplanar
+#ifndef NDEBUG
+ for (int i = 0; i<num; ++i)
+ {
+ double dist_to_plane_C = std::abs((C1.row(i)-p.transpose()).dot(n));
+ assert(dist_to_plane_C<1e-10);
+ }
+#endif
+
+ // check that poly is really coplanar
+ for (int i = 0; i<V1.rows(); ++i)
+ {
+ double dist_to_plane_V = std::abs((V1.row(i)-p.transpose()).dot(n));
+ if(dist_to_plane_V>1e-10)
+ std::cerr<<"Distance from V to plane of C is large..."<<std::endl;
+ }
+
+ // change of basis
+ Eigen::Vector3d b1 = C1.row(1)-C1.row(0);
+ Eigen::Vector3d b2 = n.cross(b1);
+ // normalize basis rows
+ b1 /= std::sqrt(b1.dot(b1));
+ b2 /= std::sqrt(b2.dot(b2));
+ n /= std::sqrt(n.dot(n));
+
+ //transpose of the basis matrix in the m-file
+ Eigen::Matrix3d basis = Eigen::Matrix3d::Zero();
+ basis.col(0) = b1;
+ basis.col(1) = b2;
+ basis.col(2) = n;
+
+ // change basis of rows vectors by right multiplying with inverse of matrix
+ // with basis vectors as rows
+ Eigen::ColPivHouseholderQR<Eigen::Matrix3d> solver = basis.colPivHouseholderQr();
+ // Throw away coordinates in normal direction
+ V1 = solver.solve(V1.transpose()).transpose().block(0,0,V1.rows(),2);
+ C1 = solver.solve(C1.transpose()).transpose().block(0,0,C1.rows(),2);
+
+ }
+
+ // vectors from V to every C, where CmV(i,j,:) is the vector from domain
+ // vertex j to handle i
+ double EPS = 1e-10;
+ Eigen::MatrixXd WW = Eigen::MatrixXd(C1.rows(), V1.rows());
+ Eigen::MatrixXd dist_C_V (C1.rows(), V1.rows());
+ std::vector< std::pair<int,int> > on_corner(0);
+ std::vector< std::pair<int,int> > on_segment(0);
+ for (int i = 0; i<C1.rows(); ++i)
+ {
+ i_prev = (i>0)?(i-1):(num-1);
+ i_next = (i<num-1)?(i+1):0;
+ // distance from each corner in C to the next corner so that edge_length(i)
+ // is the distance from C(i,:) to C(i+1,:) defined cyclically
+ double edge_length = std::sqrt((C1.row(i) - C1.row(i_next)).dot(C1.row(i) - C1.row(i_next)));
+ for (int j = 0; j<V1.rows(); ++j)
+ {
+ Eigen::VectorXd v = C1.row(i) - V1.row(j);
+ Eigen::VectorXd vnext = C1.row(i_next) - V1.row(j);
+ Eigen::VectorXd vprev = C1.row(i_prev) - V1.row(j);
+ // distance from V to every C, where dist_C_V(i,j) is the distance from domain
+ // vertex j to handle i
+ dist_C_V(i,j) = std::sqrt(v.dot(v));
+ double dist_C_V_next = std::sqrt(vnext.dot(vnext));
+ double a_prev = std::atan2(vprev[1],vprev[0]) - std::atan2(v[1],v[0]);
+ double a_next = std::atan2(v[1],v[0]) - std::atan2(vnext[1],vnext[0]);
+ // mean value coordinates
+ WW(i,j) = (std::tan(a_prev/2.0) + std::tan(a_next/2.0)) / dist_C_V(i,j);
+
+ if (dist_C_V(i,j) < EPS)
+ on_corner.push_back(std::make_pair(j,i));
+ else
+ // only in case of no-corner (no need for checking for multiple segments afterwards --
+ // should only be on one segment (otherwise must be on a corner and we already
+ // handled that)
+ // domain vertex j is on the segment from i to i+1 if the distances from vj to
+ // pi and pi+1 are about
+ if(std::abs((dist_C_V(i,j) + dist_C_V_next) / edge_length - 1) < EPS)
+ on_segment.push_back(std::make_pair(j,i));
+
+ }
+ }
+
+ // handle degenerate cases
+ // snap vertices close to corners
+ for (unsigned i = 0; i<on_corner.size(); ++i)
+ {
+ int vi = on_corner[i].first;
+ int ci = on_corner[i].second;
+ for (int ii = 0; ii<C.rows(); ++ii)
+ WW(ii,vi) = (ii==ci)?1:0;
+ }
+
+ // snap vertices close to segments
+ for (unsigned i = 0; i<on_segment.size(); ++i)
+ {
+ int vi = on_segment[i].first;
+ int ci = on_segment[i].second;
+ int ci_next = (ci<num-1)?(ci+1):0;
+ for (int ii = 0; ii<C.rows(); ++ii)
+ if (ii == ci)
+ WW(ii,vi) = dist_C_V(ci_next,vi);
+ else
+ {
+ if ( ii == ci_next)
+ WW(ii,vi) = dist_C_V(ci,vi);
+ else
+ WW(ii,vi) = 0;
+ }
+ }
+
+ // normalize W
+ for (int i = 0; i<V.rows(); ++i)
+ WW.col(i) /= WW.col(i).sum();
+
+ // we've made W transpose
+ W = WW.transpose();
+}
diff --git a/xs/src/igl/mvc.h b/xs/src/igl/mvc.h
new file mode 100644
index 000000000..3c7c2abcc
--- /dev/null
+++ b/xs/src/igl/mvc.h
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_MVC_H
+#define IGL_MVC_H
+
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // MVC - MEAN VALUE COORDINATES
+ //
+ // mvc(V,C,W)
+ //
+ // Inputs:
+ // V #V x dim list of vertex positions (dim = 2 or dim = 3)
+ // C #C x dim list of polygon vertex positions in counter-clockwise order
+ // (dim = 2 or dim = 3)
+ //
+ // Outputs:
+ // W weights, #V by #C matrix of weights
+ //
+ // Known Bugs: implementation is listed as "Broken"
+ IGL_INLINE void mvc(
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXd &C,
+ Eigen::MatrixXd &W);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "mvc.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/nchoosek.cpp b/xs/src/igl/nchoosek.cpp
new file mode 100644
index 000000000..88ab5449d
--- /dev/null
+++ b/xs/src/igl/nchoosek.cpp
@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti, Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "nchoosek.h"
+#include <cmath>
+#include <cassert>
+
+IGL_INLINE double igl::nchoosek(const int n, const int k)
+{
+ if(k>n/2)
+ {
+ return nchoosek(n,n-k);
+ }else if(k==1)
+ {
+ return n;
+ }else
+ {
+ double c = 1;
+ for(int i = 1;i<=k;i++)
+ {
+ c *= (((double)n-k+i)/((double)i));
+ }
+ return std::round(c);
+ }
+}
+
+template < typename DerivedV, typename DerivedU>
+IGL_INLINE void igl::nchoosek(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const int k,
+ Eigen::PlainObjectBase<DerivedU> & U)
+{
+ using namespace Eigen;
+ if(V.size() == 0)
+ {
+ U.resize(0,k);
+ return;
+ }
+ assert((V.cols() == 1 || V.rows() == 1) && "V must be a vector");
+ U.resize(nchoosek(V.size(),k),k);
+ int running_i = 0;
+ int running_j = 0;
+ Matrix<typename DerivedU::Scalar,1,Dynamic> running(1,k);
+ int N = V.size();
+ const std::function<void(int,int)> doCombs =
+ [&running,&N,&doCombs,&running_i,&running_j,&U,&V](int offset, int k)
+ {
+ if(k==0)
+ {
+ U.row(running_i) = running;
+ running_i++;
+ return;
+ }
+ for (int i = offset; i <= N - k; ++i)
+ {
+ running(running_j) = V(i);
+ running_j++;
+ doCombs(i+1,k-1);
+ running_j--;
+ }
+ };
+ doCombs(0,k);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::nchoosek<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+#else
+template void igl::nchoosek<Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<int, true>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<int, true>, Eigen::Matrix<int, -1, 1, 0, -1, 1> > > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
+
+#endif
diff --git a/xs/src/igl/nchoosek.h b/xs/src/igl/nchoosek.h
new file mode 100644
index 000000000..ec882e6c6
--- /dev/null
+++ b/xs/src/igl/nchoosek.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti, Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_NCHOOSEK
+#define IGL_NCHOOSEK
+#include "igl_inline.h"
+#include "deprecated.h"
+#include <vector>
+
+#include <Eigen/Core>
+
+namespace igl
+{
+ // NCHOOSEK Like matlab's nchoosek.
+ //
+ // Inputs:
+ // n total number elements
+ // k size of sub-set to consider
+ // Returns number of k-size combinations out of the set [1,...,n]
+ IGL_INLINE double nchoosek(const int n, const int k);
+ //
+ // Inputs:
+ // V n-long vector of elements
+ // k size of sub-set to consider
+ // Outputs:
+ // U nchoosek by k long matrix where each row is a unique k-size
+ // combination
+ template < typename DerivedV, typename DerivedU>
+ IGL_INLINE void nchoosek(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const int k,
+ Eigen::PlainObjectBase<DerivedU> & U);
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "nchoosek.cpp"
+#endif
+
+
+#endif /* defined(IGL_NCHOOSEK) */
diff --git a/xs/src/igl/next_filename.cpp b/xs/src/igl/next_filename.cpp
new file mode 100644
index 000000000..b453a149a
--- /dev/null
+++ b/xs/src/igl/next_filename.cpp
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "next_filename.h"
+#include "STR.h"
+#include "file_exists.h"
+#include <cmath>
+#include <iomanip>
+
+bool igl::next_filename(
+ const std::string & prefix,
+ const int zeros,
+ const std::string & suffix,
+ std::string & next)
+{
+ using namespace std;
+ // O(n), for huge lists could at least find bounds with exponential search
+ // and then narrow with binary search O(log(n))
+ int i = 0;
+ while(true)
+ {
+ next = STR(prefix << setfill('0') << setw(zeros)<<i<<suffix);
+ if(!file_exists(next))
+ {
+ return true;
+ }
+ i++;
+ if(zeros > 0 && i >= pow(10,zeros))
+ {
+ return false;
+ }
+ }
+}
+
diff --git a/xs/src/igl/next_filename.h b/xs/src/igl/next_filename.h
new file mode 100644
index 000000000..2aa3094da
--- /dev/null
+++ b/xs/src/igl/next_filename.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NEXT_FILENAME_H
+#define IGL_NEXT_FILENAME_H
+#include "igl_inline.h"
+#include <string>
+namespace igl
+{
+ // Find the file with the first filename of the form
+ // "prefix%0[zeros]dsuffix"
+ //
+ // Inputs:
+ // prefix path to containing dir and filename prefix
+ // zeros number of leading zeros as if digit printed with printf
+ // suffix suffix of filename and extension (should included dot)
+ // Outputs:
+ // next path to next file
+ // Returns true if found, false if exceeding range in zeros
+ IGL_INLINE bool next_filename(
+ const std::string & prefix,
+ const int zeros,
+ const std::string & suffix,
+ std::string & next);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "next_filename.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/normal_derivative.cpp b/xs/src/igl/normal_derivative.cpp
new file mode 100644
index 000000000..d943fe0e2
--- /dev/null
+++ b/xs/src/igl/normal_derivative.cpp
@@ -0,0 +1,118 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "LinSpaced.h"
+#include "normal_derivative.h"
+#include "cotmatrix_entries.h"
+#include "slice.h"
+#include <cassert>
+
+template <
+ typename DerivedV,
+ typename DerivedEle,
+ typename Scalar>
+IGL_INLINE void igl::normal_derivative(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedEle> & Ele,
+ Eigen::SparseMatrix<Scalar>& DD)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Element simplex-size
+ const size_t ss = Ele.cols();
+ assert( ((ss==3) || (ss==4)) && "Only triangles or tets");
+ // cotangents
+ Matrix<Scalar,Dynamic,Dynamic> C;
+ cotmatrix_entries(V,Ele,C);
+ vector<Triplet<Scalar> > IJV;
+ // Number of elements
+ const size_t m = Ele.rows();
+ // Number of vertices
+ const size_t n = V.rows();
+ switch(ss)
+ {
+ default:
+ assert(false);
+ return;
+ case 4:
+ {
+ const MatrixXi DDJ =
+ slice(
+ Ele,
+ (VectorXi(24)<<
+ 1,0,2,0,3,0,2,1,3,1,0,1,3,2,0,2,1,2,0,3,1,3,2,3).finished(),
+ 2);
+ MatrixXi DDI(m,24);
+ for(size_t f = 0;f<4;f++)
+ {
+ const auto & I = (igl::LinSpaced<VectorXi >(m,0,m-1).array()+f*m).eval();
+ for(size_t r = 0;r<6;r++)
+ {
+ DDI.col(f*6+r) = I;
+ }
+ }
+ const DiagonalMatrix<Scalar,24,24> S =
+ (Matrix<Scalar,2,1>(1,-1).template replicate<12,1>()).asDiagonal();
+ Matrix<Scalar,Dynamic,Dynamic> DDV =
+ slice(
+ C,
+ (VectorXi(24)<<
+ 2,2,1,1,3,3,0,0,4,4,2,2,5,5,1,1,0,0,3,3,4,4,5,5).finished(),
+ 2);
+ DDV *= S;
+
+ IJV.reserve(DDV.size());
+ for(size_t f = 0;f<6*4;f++)
+ {
+ for(size_t e = 0;e<m;e++)
+ {
+ IJV.push_back(Triplet<Scalar>(DDI(e,f),DDJ(e,f),DDV(e,f)));
+ }
+ }
+ DD.resize(m*4,n);
+ DD.setFromTriplets(IJV.begin(),IJV.end());
+ break;
+ }
+ case 3:
+ {
+ const MatrixXi DDJ =
+ slice(Ele,(VectorXi(12)<<2,0,1,0,0,1,2,1,1,2,0,2).finished(),2);
+ MatrixXi DDI(m,12);
+ for(size_t f = 0;f<3;f++)
+ {
+ const auto & I = (igl::LinSpaced<VectorXi >(m,0,m-1).array()+f*m).eval();
+ for(size_t r = 0;r<4;r++)
+ {
+ DDI.col(f*4+r) = I;
+ }
+ }
+ const DiagonalMatrix<Scalar,12,12> S =
+ (Matrix<Scalar,2,1>(1,-1).template replicate<6,1>()).asDiagonal();
+ Matrix<Scalar,Dynamic,Dynamic> DDV =
+ slice(C,(VectorXi(12)<<1,1,2,2,2,2,0,0,0,0,1,1).finished(),2);
+ DDV *= S;
+
+ IJV.reserve(DDV.size());
+ for(size_t f = 0;f<12;f++)
+ {
+ for(size_t e = 0;e<m;e++)
+ {
+ IJV.push_back(Triplet<Scalar>(DDI(e,f),DDJ(e,f),DDV(e,f)));
+ }
+ }
+ DD.resize(m*3,n);
+ DD.setFromTriplets(IJV.begin(),IJV.end());
+ break;
+ }
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::normal_derivative<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/normal_derivative.h b/xs/src/igl/normal_derivative.h
new file mode 100644
index 000000000..861b55555
--- /dev/null
+++ b/xs/src/igl/normal_derivative.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NORMAL_DERIVATIVE_H
+#define IGL_NORMAL_DERIVATIVE_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // NORMAL_DERIVATIVE Computes the directional derivative **normal** to
+ // **all** (half-)edges of a triangle mesh (not just boundary edges). These
+ // are integrated along the edge: they're the per-face constant gradient dot
+ // the rotated edge vector (unit rotated edge vector for direction then
+ // magnitude for integration).
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by 3|4 list of triangle|tetrahedron indices into V
+ // Outputs:
+ // DD #F*3|4 by #V sparse matrix representing operator to compute
+ // directional derivative with respect to each facet of each element.
+ //
+ template <
+ typename DerivedV,
+ typename DerivedEle,
+ typename Scalar>
+ IGL_INLINE void normal_derivative(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedEle> & Ele,
+ Eigen::SparseMatrix<Scalar>& DD);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "normal_derivative.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/normalize_quat.cpp b/xs/src/igl/normalize_quat.cpp
new file mode 100644
index 000000000..f110d6b75
--- /dev/null
+++ b/xs/src/igl/normalize_quat.cpp
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "normalize_quat.h"
+
+#include "EPS.h"
+#include <cmath>
+
+template <typename Q_type>
+IGL_INLINE bool igl::normalize_quat(
+ const Q_type *q,
+ Q_type *out)
+{
+ // Get length
+ Q_type len = sqrt(
+ q[0]*q[0]+
+ q[1]*q[1]+
+ q[2]*q[2]+
+ q[3]*q[3]);
+
+ // Noramlize each coordinate
+ out[0] = q[0]/len;
+ out[1] = q[1]/len;
+ out[2] = q[2]/len;
+ out[3] = q[3]/len;
+
+ // Test whether length was below Epsilon
+ return (len > igl::EPS<Q_type>());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::normalize_quat<double>(double const*, double*);
+// generated by autoexplicit.sh
+template bool igl::normalize_quat<float>(float const*, float*);
+#endif
diff --git a/xs/src/igl/normalize_quat.h b/xs/src/igl/normalize_quat.h
new file mode 100644
index 000000000..e97759b17
--- /dev/null
+++ b/xs/src/igl/normalize_quat.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NORMALIZE_QUAT_H
+#define IGL_NORMALIZE_QUAT_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Normalize 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:
+ // q input quaternion
+ // Outputs:
+ // out result of normalization, allowed to be same as q
+ // Returns true on success, false if len(q) < EPS
+ template <typename Q_type>
+ IGL_INLINE bool normalize_quat(
+ const Q_type *q,
+ Q_type *out);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "normalize_quat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/normalize_row_lengths.cpp b/xs/src/igl/normalize_row_lengths.cpp
new file mode 100644
index 000000000..3d7e566e8
--- /dev/null
+++ b/xs/src/igl/normalize_row_lengths.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "normalize_row_lengths.h"
+
+template <typename DerivedV>
+IGL_INLINE void igl::normalize_row_lengths(
+ const Eigen::PlainObjectBase<DerivedV>& A,
+ Eigen::PlainObjectBase<DerivedV> & B)
+{
+ // Resize output
+ B.resizeLike(A);
+
+ // loop over rows
+ for(int i = 0; i < A.rows();i++)
+ {
+ B.row(i) = A.row(i).normalized();
+ }
+ //// Or just:
+ //B = A;
+ //B.rowwise().normalize();
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::normalize_row_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::normalize_row_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template void igl::normalize_row_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/normalize_row_lengths.h b/xs/src/igl/normalize_row_lengths.h
new file mode 100644
index 000000000..c305c0f65
--- /dev/null
+++ b/xs/src/igl/normalize_row_lengths.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NORMALIZE_ROW_LENGTHS_H
+#define IGL_NORMALIZE_ROW_LENGTHS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+// History:
+// March 24, 2012: Alec changed function name from normalize_rows to
+// normalize_row_lengths to avoid confusion with normalize_row_sums
+
+namespace igl
+{
+ // Obsolete: just use A.rowwise().normalize() or B=A.rowwise().normalized();
+ //
+ // Normalize the rows in A so that their lengths are each 1 and place the new
+ // entries in B
+ // Inputs:
+ // A #rows by k input matrix
+ // Outputs:
+ // B #rows by k input matrix, can be the same as A
+ template <typename DerivedV>
+ IGL_INLINE void normalize_row_lengths(
+ const Eigen::PlainObjectBase<DerivedV>& A,
+ Eigen::PlainObjectBase<DerivedV> & B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "normalize_row_lengths.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/normalize_row_sums.cpp b/xs/src/igl/normalize_row_sums.cpp
new file mode 100644
index 000000000..1204e073d
--- /dev/null
+++ b/xs/src/igl/normalize_row_sums.cpp
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "normalize_row_sums.h"
+
+template <typename DerivedA, typename DerivedB>
+IGL_INLINE void igl::normalize_row_sums(
+ const Eigen::MatrixBase<DerivedA>& A,
+ Eigen::MatrixBase<DerivedB> & B)
+{
+#ifndef NDEBUG
+ // loop over rows
+ for(int i = 0; i < A.rows();i++)
+ {
+ typename DerivedB::Scalar sum = A.row(i).sum();
+ assert(sum != 0);
+ }
+#endif
+ B = (A.array().colwise() / A.rowwise().sum().array()).eval();
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::normalize_row_sums<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::normalize_row_sums<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/normalize_row_sums.h b/xs/src/igl/normalize_row_sums.h
new file mode 100644
index 000000000..a832e82a6
--- /dev/null
+++ b/xs/src/igl/normalize_row_sums.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NORMALIZE_ROW_SUMS_H
+#define IGL_NORMALIZE_ROW_SUMS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Normalize the rows in A so that their sums are each 1 and place the new
+ // entries in B
+ // Inputs:
+ // A #rows by k input matrix
+ // Outputs:
+ // B #rows by k input matrix, can be the same as A
+ //
+ // Note: This is just calling an Eigen one-liner.
+ template <typename DerivedA, typename DerivedB>
+ IGL_INLINE void normalize_row_sums(
+ const Eigen::MatrixBase<DerivedA>& A,
+ Eigen::MatrixBase<DerivedB> & B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "normalize_row_sums.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/null.cpp b/xs/src/igl/null.cpp
new file mode 100644
index 000000000..b2291f454
--- /dev/null
+++ b/xs/src/igl/null.cpp
@@ -0,0 +1,21 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "null.h"
+#include "EPS.h"
+
+template <typename DerivedA, typename DerivedN>
+IGL_INLINE void igl::null(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ using namespace Eigen;
+ typedef typename DerivedA::Scalar Scalar;
+ JacobiSVD<MatrixXd> svd(A, ComputeFullV);
+ svd.setThreshold(A.cols() * svd.singularValues().maxCoeff() * EPS<Scalar>());
+ N = svd.matrixV().rightCols(A.cols()-svd.rank());
+}
diff --git a/xs/src/igl/null.h b/xs/src/igl/null.h
new file mode 100644
index 000000000..2349217fb
--- /dev/null
+++ b/xs/src/igl/null.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_NULL_H
+#define IGL_NULL_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Like MATLAB's null
+ //
+ // Compute a basis for the null space for the given matrix A: the columns of
+ // the output N form a basis for the space orthogonal to that spanned by the
+ // rows of A.
+ //
+ // Inputs:
+ // A m by n matrix
+ // Outputs:
+ // N n by r matrix, where r is the row rank of A
+ template <typename DerivedA, typename DerivedN>
+ IGL_INLINE void null(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedN> & N);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "null.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/octree.cpp b/xs/src/igl/octree.cpp
new file mode 100644
index 000000000..6ed95d846
--- /dev/null
+++ b/xs/src/igl/octree.cpp
@@ -0,0 +1,176 @@
+#include "octree.h"
+#include <vector>
+#include <queue>
+
+namespace igl {
+ template <typename DerivedP, typename IndexType, typename DerivedCH,
+ typename DerivedCN, typename DerivedW>
+ IGL_INLINE void octree(const Eigen::MatrixBase<DerivedP>& P,
+ std::vector<std::vector<IndexType> > & point_indices,
+ Eigen::PlainObjectBase<DerivedCH>& CH,
+ Eigen::PlainObjectBase<DerivedCN>& CN,
+ Eigen::PlainObjectBase<DerivedW>& W)
+ {
+
+
+
+ const int MAX_DEPTH = 30000;
+
+ typedef typename DerivedCH::Scalar ChildrenType;
+ typedef typename DerivedCN::Scalar CentersType;
+ typedef typename DerivedW::Scalar WidthsType;
+ typedef Eigen::Matrix<ChildrenType,8,1> Vector8i;
+ typedef Eigen::Matrix<typename DerivedP::Scalar, 1, 3> RowVector3PType;
+ typedef Eigen::Matrix<CentersType, 1, 3> RowVector3CentersType;
+
+ std::vector<Eigen::Matrix<ChildrenType,8,1>,
+ Eigen::aligned_allocator<Eigen::Matrix<ChildrenType,8,1> > > children;
+ std::vector<Eigen::Matrix<CentersType,1,3>,
+ Eigen::aligned_allocator<Eigen::Matrix<CentersType,1,3> > > centers;
+ std::vector<WidthsType> widths;
+
+ auto get_octant = [](RowVector3PType location,
+ RowVector3CentersType center){
+ // We use a binary numbering of children. Treating the parent cell's
+ // center as the origin, we number the octants in the following manner:
+ // The first bit is 1 iff the octant's x coordinate is positive
+ // The second bit is 1 iff the octant's y coordinate is positive
+ // The third bit is 1 iff the octant's z coordinate is positive
+ //
+ // For example, the octant with negative x, positive y, positive z is:
+ // 110 binary = 6 decimal
+ IndexType index = 0;
+ if( location(0) >= center(0)){
+ index = index + 1;
+ }
+ if( location(1) >= center(1)){
+ index = index + 2;
+ }
+ if( location(2) >= center(2)){
+ index = index + 4;
+ }
+ return index;
+ };
+
+
+ std::function< RowVector3CentersType(const RowVector3CentersType,
+ const CentersType,
+ const ChildrenType) >
+ translate_center =
+ [](const RowVector3CentersType & parent_center,
+ const CentersType h,
+ const ChildrenType child_index){
+ RowVector3CentersType change_vector;
+ change_vector << -h,-h,-h;
+
+ //positive x chilren are 1,3,4,7
+ if(child_index % 2){
+ change_vector(0) = h;
+ }
+ //positive y children are 2,3,6,7
+ if(child_index == 2 || child_index == 3 ||
+ child_index == 6 || child_index == 7){
+ change_vector(1) = h;
+ }
+ //positive z children are 4,5,6,7
+ if(child_index > 3){
+ change_vector(2) = h;
+ }
+ RowVector3CentersType output = parent_center + change_vector;
+ return output;
+ };
+
+ // How many cells do we have so far?
+ IndexType m = 0;
+
+ // Useful list of number 0..7
+ const Vector8i zero_to_seven = (Vector8i()<<0,1,2,3,4,5,6,7).finished();
+ const Vector8i neg_ones = (Vector8i()<<-1,-1,-1,-1,-1,-1,-1,-1).finished();
+
+ std::function< void(const ChildrenType, const int) > helper;
+ helper = [&helper,&translate_center,&get_octant,&m,
+ &zero_to_seven,&neg_ones,&P,
+ &point_indices,&children,&centers,&widths]
+ (const ChildrenType index, const int depth)-> void
+ {
+ if(point_indices.at(index).size() > 1 && depth < MAX_DEPTH){
+ //give the parent access to the children
+ children.at(index) = zero_to_seven.array() + m;
+ //make the children's data in our arrays
+
+ //Add the children to the lists, as default children
+ CentersType h = widths.at(index)/2;
+ RowVector3CentersType curr_center = centers.at(index);
+
+
+ for(ChildrenType i = 0; i < 8; i++){
+ children.emplace_back(neg_ones);
+ point_indices.emplace_back(std::vector<IndexType>());
+ centers.emplace_back(translate_center(curr_center,h,i));
+ widths.emplace_back(h);
+ }
+
+
+ //Split up the points into the corresponding children
+ for(int j = 0; j < point_indices.at(index).size(); j++){
+ IndexType curr_point_index = point_indices.at(index).at(j);
+ IndexType cell_of_curr_point =
+ get_octant(P.row(curr_point_index),curr_center)+m;
+ point_indices.at(cell_of_curr_point).emplace_back(curr_point_index);
+ }
+
+ //Now increase m
+ m += 8;
+
+
+ // Look ma, I'm calling myself.
+ for(int i = 0; i < 8; i++){
+ helper(children.at(index)(i),depth+1);
+ }
+ }
+ };
+
+ {
+ std::vector<IndexType> all(P.rows());
+ for(IndexType i = 0;i<all.size();i++) all[i]=i;
+ point_indices.emplace_back(all);
+ }
+ children.emplace_back(neg_ones);
+
+ //Get the minimum AABB for the points
+ RowVector3PType backleftbottom(P.col(0).minCoeff(),
+ P.col(1).minCoeff(),
+ P.col(2).minCoeff());
+ RowVector3PType frontrighttop(P.col(0).maxCoeff(),
+ P.col(1).maxCoeff(),
+ P.col(2).maxCoeff());
+ RowVector3CentersType aabb_center = (backleftbottom+frontrighttop)/2.0;
+ WidthsType aabb_width = std::max(std::max(
+ frontrighttop(0) - backleftbottom(0),
+ frontrighttop(1) - backleftbottom(1)),
+ frontrighttop(2) - backleftbottom(2));
+ centers.emplace_back( aabb_center );
+
+ //Widths are the side length of the cube, (not half the side length):
+ widths.emplace_back( aabb_width );
+ m++;
+ // then you have to actually call the function
+ helper(0,0);
+
+ //Now convert from vectors to Eigen matricies:
+ CH.resize(children.size(),8);
+ CN.resize(centers.size(),3);
+ W.resize(widths.size(),1);
+
+ for(int i = 0; i < children.size(); i++){
+ CH.row(i) = children.at(i);
+ }
+ for(int i = 0; i < centers.size(); i++){
+ CN.row(i) = centers.at(i);
+ }
+ for(int i = 0; i < widths.size(); i++){
+ W(i) = widths.at(i);
+ }
+ }
+}
+
diff --git a/xs/src/igl/octree.h b/xs/src/igl/octree.h
new file mode 100644
index 000000000..425d86b2d
--- /dev/null
+++ b/xs/src/igl/octree.h
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Gavin Barill <gavinpcb@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/
+
+#ifndef IGL_OCTREE
+#define IGL_OCTREE
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+
+
+
+namespace igl
+{
+ // Given a set of 3D points P, generate data structures for a pointerless
+ // octree. Each cell stores its points, children, center location and width.
+ // Our octree is not dense. We use the following rule: if the current cell
+ // has any number of points, it will have all 8 children. A leaf cell will
+ // have -1's as its list of child indices.
+ //
+ // We use a binary numbering of children. Treating the parent cell's center
+ // as the origin, we number the octants in the following manner:
+ // The first bit is 1 iff the octant's x coordinate is positive
+ // The second bit is 1 iff the octant's y coordinate is positive
+ // The third bit is 1 iff the octant's z coordinate is positive
+ //
+ // For example, the octant with negative x, positive y, positive z is:
+ // 110 binary = 6 decimal
+ //
+ // Inputs:
+ // P #P by 3 list of point locations
+ //
+ // Outputs:
+ // point_indices a vector of vectors, where the ith entry is a vector of
+ // the indices into P that are the ith octree cell's points
+ // CH #OctreeCells by 8, where the ith row is the indices of
+ // the ith octree cell's children
+ // CN #OctreeCells by 3, where the ith row is a 3d row vector
+ // representing the position of the ith cell's center
+ // W #OctreeCells, a vector where the ith entry is the width
+ // of the ith octree cell
+ //
+ template <typename DerivedP, typename IndexType, typename DerivedCH,
+ typename DerivedCN, typename DerivedW>
+ IGL_INLINE void octree(const Eigen::MatrixBase<DerivedP>& P,
+ std::vector<std::vector<IndexType> > & point_indices,
+ Eigen::PlainObjectBase<DerivedCH>& CH,
+ Eigen::PlainObjectBase<DerivedCN>& CN,
+ Eigen::PlainObjectBase<DerivedW>& W);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "octree.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/on_boundary.cpp b/xs/src/igl/on_boundary.cpp
new file mode 100644
index 000000000..3fb70ec59
--- /dev/null
+++ b/xs/src/igl/on_boundary.cpp
@@ -0,0 +1,141 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "on_boundary.h"
+
+// IGL includes
+#include "sort.h"
+#include "face_occurrences.h"
+
+// STL includes
+
+template <typename IntegerT>
+IGL_INLINE void igl::on_boundary(
+ const std::vector<std::vector<IntegerT> > & T,
+ std::vector<bool> & I,
+ std::vector<std::vector<bool> > & C)
+{
+ using namespace std;
+ if(T.empty())
+ {
+ I.clear();
+ C.clear();
+ return;
+ }
+
+ switch(T[0].size())
+ {
+ case 3:
+ {
+ // Get a list of all faces
+ vector<vector<IntegerT> > F(T.size()*3,vector<IntegerT>(2));
+ // Gather faces, loop over tets
+ for(int i = 0; i< (int)T.size();i++)
+ {
+ assert(T[i].size() == 3);
+ // get face in correct order
+ F[i*3+0][0] = T[i][1];
+ F[i*3+0][1] = T[i][2];
+ F[i*3+1][0] = T[i][2];
+ F[i*3+1][1] = T[i][0];
+ F[i*3+2][0] = T[i][0];
+ F[i*3+2][1] = T[i][1];
+ }
+ // Counts
+ vector<int> FC;
+ face_occurrences(F,FC);
+ C.resize(T.size(),vector<bool>(3));
+ I.resize(T.size(),false);
+ for(int i = 0; i< (int)T.size();i++)
+ {
+ for(int j = 0;j<3;j++)
+ {
+ assert(FC[i*3+j] == 2 || FC[i*3+j] == 1);
+ C[i][j] = FC[i*3+j]==1;
+ // if any are on boundary set to true
+ I[i] = I[i] || C[i][j];
+ }
+ }
+ return;
+ }
+ case 4:
+ {
+ // Get a list of all faces
+ vector<vector<IntegerT> > F(T.size()*4,vector<IntegerT>(3));
+ // Gather faces, loop over tets
+ for(int i = 0; i< (int)T.size();i++)
+ {
+ assert(T[i].size() == 4);
+ // get face in correct order
+ F[i*4+0][0] = T[i][1];
+ F[i*4+0][1] = T[i][3];
+ F[i*4+0][2] = T[i][2];
+ // get face in correct order
+ F[i*4+1][0] = T[i][0];
+ F[i*4+1][1] = T[i][2];
+ F[i*4+1][2] = T[i][3];
+ // get face in correct order
+ F[i*4+2][0] = T[i][0];
+ F[i*4+2][1] = T[i][3];
+ F[i*4+2][2] = T[i][1];
+ // get face in correct order
+ F[i*4+3][0] = T[i][0];
+ F[i*4+3][1] = T[i][1];
+ F[i*4+3][2] = T[i][2];
+ }
+ // Counts
+ vector<int> FC;
+ face_occurrences(F,FC);
+ C.resize(T.size(),vector<bool>(4));
+ I.resize(T.size(),false);
+ for(int i = 0; i< (int)T.size();i++)
+ {
+ for(int j = 0;j<4;j++)
+ {
+ assert(FC[i*4+j] == 2 || FC[i*4+j] == 1);
+ C[i][j] = FC[i*4+j]==1;
+ // if any are on boundary set to true
+ I[i] = I[i] || C[i][j];
+ }
+ }
+ return;
+ }
+ }
+
+
+}
+
+#include "list_to_matrix.h"
+#include "matrix_to_list.h"
+
+template <typename DerivedT, typename DerivedI, typename DerivedC>
+IGL_INLINE void igl::on_boundary(
+ const Eigen::MatrixBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedI>& I,
+ Eigen::PlainObjectBase<DerivedC>& C)
+{
+ assert(T.cols() == 0 || T.cols() == 4 || T.cols() == 3);
+ using namespace std;
+ using namespace Eigen;
+ // Cop out: use vector of vectors version
+ vector<vector<typename DerivedT::Scalar> > vT;
+ matrix_to_list(T,vT);
+ vector<bool> vI;
+ vector<vector<bool> > vC;
+ on_boundary(vT,vI,vC);
+ list_to_matrix(vI,I);
+ list_to_matrix(vC,C);
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::on_boundary<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Array<bool, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 3, 0, -1, 3> >&);
+template void igl::on_boundary<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::on_boundary<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Array<bool, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Array<bool, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/on_boundary.h b/xs/src/igl/on_boundary.h
new file mode 100644
index 000000000..c4dab1706
--- /dev/null
+++ b/xs/src/igl/on_boundary.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ON_BOUNDARY_H
+#define IGL_ON_BOUNDARY_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+#include <vector>
+
+namespace igl
+{
+ // ON_BOUNDARY Determine boundary facets of mesh elements stored in T
+ //
+ // Templates:
+ // IntegerT integer-value: i.e. int
+ // IntegerF integer-value: i.e. int
+ // Input:
+ // T triangle|tetrahedron index list, m by 3|4, where m is the number of
+ // elements
+ // Output:
+ // I m long list of bools whether tet is on boundary
+ // C m by 3|4 list of bools whether opposite facet is on boundary
+ //
+ template <typename IntegerT>
+ IGL_INLINE void on_boundary(
+ const std::vector<std::vector<IntegerT> > & T,
+ std::vector<bool> & I,
+ std::vector<std::vector<bool> > & C);
+ // Templates:
+ // DerivedT integer-value: i.e. from MatrixXi
+ // DerivedI bool-value: i.e. from MatrixXi
+ // DerivedC bool-value: i.e. from MatrixXi
+ template <typename DerivedT, typename DerivedI, typename DerivedC>
+ IGL_INLINE void on_boundary(
+ const Eigen::MatrixBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedI>& I,
+ Eigen::PlainObjectBase<DerivedC>& C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "on_boundary.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/opengl/MeshGL.cpp b/xs/src/igl/opengl/MeshGL.cpp
new file mode 100644
index 000000000..f49924324
--- /dev/null
+++ b/xs/src/igl/opengl/MeshGL.cpp
@@ -0,0 +1,313 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "MeshGL.h"
+#include "bind_vertex_attrib_array.h"
+#include "create_shader_program.h"
+#include "destroy_shader_program.h"
+#include <iostream>
+
+IGL_INLINE void igl::opengl::MeshGL::init_buffers()
+{
+ // Mesh: Vertex Array Object & Buffer objects
+ glGenVertexArrays(1, &vao_mesh);
+ glBindVertexArray(vao_mesh);
+ glGenBuffers(1, &vbo_V);
+ glGenBuffers(1, &vbo_V_normals);
+ glGenBuffers(1, &vbo_V_ambient);
+ glGenBuffers(1, &vbo_V_diffuse);
+ glGenBuffers(1, &vbo_V_specular);
+ glGenBuffers(1, &vbo_V_uv);
+ glGenBuffers(1, &vbo_F);
+ glGenTextures(1, &vbo_tex);
+
+ // Line overlay
+ glGenVertexArrays(1, &vao_overlay_lines);
+ glBindVertexArray(vao_overlay_lines);
+ glGenBuffers(1, &vbo_lines_F);
+ glGenBuffers(1, &vbo_lines_V);
+ glGenBuffers(1, &vbo_lines_V_colors);
+
+ // Point overlay
+ glGenVertexArrays(1, &vao_overlay_points);
+ glBindVertexArray(vao_overlay_points);
+ glGenBuffers(1, &vbo_points_F);
+ glGenBuffers(1, &vbo_points_V);
+ glGenBuffers(1, &vbo_points_V_colors);
+
+ dirty = MeshGL::DIRTY_ALL;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::free_buffers()
+{
+ if (is_initialized)
+ {
+ glDeleteVertexArrays(1, &vao_mesh);
+ glDeleteVertexArrays(1, &vao_overlay_lines);
+ glDeleteVertexArrays(1, &vao_overlay_points);
+
+ glDeleteBuffers(1, &vbo_V);
+ glDeleteBuffers(1, &vbo_V_normals);
+ glDeleteBuffers(1, &vbo_V_ambient);
+ glDeleteBuffers(1, &vbo_V_diffuse);
+ glDeleteBuffers(1, &vbo_V_specular);
+ glDeleteBuffers(1, &vbo_V_uv);
+ glDeleteBuffers(1, &vbo_F);
+ glDeleteBuffers(1, &vbo_lines_F);
+ glDeleteBuffers(1, &vbo_lines_V);
+ glDeleteBuffers(1, &vbo_lines_V_colors);
+ glDeleteBuffers(1, &vbo_points_F);
+ glDeleteBuffers(1, &vbo_points_V);
+ glDeleteBuffers(1, &vbo_points_V_colors);
+
+ glDeleteTextures(1, &vbo_tex);
+ }
+}
+
+IGL_INLINE void igl::opengl::MeshGL::bind_mesh()
+{
+ glBindVertexArray(vao_mesh);
+ glUseProgram(shader_mesh);
+ bind_vertex_attrib_array(shader_mesh,"position", vbo_V, V_vbo, dirty & MeshGL::DIRTY_POSITION);
+ bind_vertex_attrib_array(shader_mesh,"normal", vbo_V_normals, V_normals_vbo, dirty & MeshGL::DIRTY_NORMAL);
+ bind_vertex_attrib_array(shader_mesh,"Ka", vbo_V_ambient, V_ambient_vbo, dirty & MeshGL::DIRTY_AMBIENT);
+ bind_vertex_attrib_array(shader_mesh,"Kd", vbo_V_diffuse, V_diffuse_vbo, dirty & MeshGL::DIRTY_DIFFUSE);
+ bind_vertex_attrib_array(shader_mesh,"Ks", vbo_V_specular, V_specular_vbo, dirty & MeshGL::DIRTY_SPECULAR);
+ bind_vertex_attrib_array(shader_mesh,"texcoord", vbo_V_uv, V_uv_vbo, dirty & MeshGL::DIRTY_UV);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_F);
+ if (dirty & MeshGL::DIRTY_FACE)
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*F_vbo.size(), F_vbo.data(), GL_DYNAMIC_DRAW);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, vbo_tex);
+ if (dirty & MeshGL::DIRTY_TEXTURE)
+ {
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_u, tex_v, 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.data());
+ }
+ glUniform1i(glGetUniformLocation(shader_mesh,"tex"), 0);
+ dirty &= ~MeshGL::DIRTY_MESH;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::bind_overlay_lines()
+{
+ bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_LINES;
+
+ glBindVertexArray(vao_overlay_lines);
+ glUseProgram(shader_overlay_lines);
+ bind_vertex_attrib_array(shader_overlay_lines,"position", vbo_lines_V, lines_V_vbo, is_dirty);
+ bind_vertex_attrib_array(shader_overlay_lines,"color", vbo_lines_V_colors, lines_V_colors_vbo, is_dirty);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_lines_F);
+ if (is_dirty)
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*lines_F_vbo.size(), lines_F_vbo.data(), GL_DYNAMIC_DRAW);
+
+ dirty &= ~MeshGL::DIRTY_OVERLAY_LINES;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::bind_overlay_points()
+{
+ bool is_dirty = dirty & MeshGL::DIRTY_OVERLAY_POINTS;
+
+ glBindVertexArray(vao_overlay_points);
+ glUseProgram(shader_overlay_points);
+ bind_vertex_attrib_array(shader_overlay_points,"position", vbo_points_V, points_V_vbo, is_dirty);
+ bind_vertex_attrib_array(shader_overlay_points,"color", vbo_points_V_colors, points_V_colors_vbo, is_dirty);
+
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, vbo_points_F);
+ if (is_dirty)
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned)*points_F_vbo.size(), points_F_vbo.data(), GL_DYNAMIC_DRAW);
+
+ dirty &= ~MeshGL::DIRTY_OVERLAY_POINTS;
+}
+
+IGL_INLINE void igl::opengl::MeshGL::draw_mesh(bool solid)
+{
+ glPolygonMode(GL_FRONT_AND_BACK, solid ? GL_FILL : GL_LINE);
+
+ /* Avoid Z-buffer fighting between filled triangles & wireframe lines */
+ if (solid)
+ {
+ glEnable(GL_POLYGON_OFFSET_FILL);
+ glPolygonOffset(1.0, 1.0);
+ }
+ glDrawElements(GL_TRIANGLES, 3*F_vbo.rows(), GL_UNSIGNED_INT, 0);
+
+ glDisable(GL_POLYGON_OFFSET_FILL);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::draw_overlay_lines()
+{
+ glDrawElements(GL_LINES, lines_F_vbo.rows(), GL_UNSIGNED_INT, 0);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::draw_overlay_points()
+{
+ glDrawElements(GL_POINTS, points_F_vbo.rows(), GL_UNSIGNED_INT, 0);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::init()
+{
+ if(is_initialized)
+ {
+ return;
+ }
+ is_initialized = true;
+ std::string mesh_vertex_shader_string =
+R"(#version 150
+ uniform mat4 view;
+ uniform mat4 proj;
+ uniform mat4 normal_matrix;
+ in vec3 position;
+ in vec3 normal;
+ out vec3 position_eye;
+ out vec3 normal_eye;
+ in vec4 Ka;
+ in vec4 Kd;
+ in vec4 Ks;
+ in vec2 texcoord;
+ out vec2 texcoordi;
+ out vec4 Kai;
+ out vec4 Kdi;
+ out vec4 Ksi;
+
+ void main()
+ {
+ position_eye = vec3 (view * vec4 (position, 1.0));
+ normal_eye = vec3 (normal_matrix * vec4 (normal, 0.0));
+ normal_eye = normalize(normal_eye);
+ gl_Position = proj * vec4 (position_eye, 1.0); //proj * view * vec4(position, 1.0);"
+ Kai = Ka;
+ Kdi = Kd;
+ Ksi = Ks;
+ texcoordi = texcoord;
+ }
+)";
+
+ std::string mesh_fragment_shader_string =
+R"(#version 150
+ uniform mat4 view;
+ uniform mat4 proj;
+ uniform vec4 fixed_color;
+ in vec3 position_eye;
+ in vec3 normal_eye;
+ uniform vec3 light_position_eye;
+ vec3 Ls = vec3 (1, 1, 1);
+ vec3 Ld = vec3 (1, 1, 1);
+ vec3 La = vec3 (1, 1, 1);
+ in vec4 Ksi;
+ in vec4 Kdi;
+ in vec4 Kai;
+ in vec2 texcoordi;
+ uniform sampler2D tex;
+ uniform float specular_exponent;
+ uniform float lighting_factor;
+ uniform float texture_factor;
+ out vec4 outColor;
+ void main()
+ {
+ vec3 Ia = La * vec3(Kai); // ambient intensity
+
+ vec3 vector_to_light_eye = light_position_eye - position_eye;
+ vec3 direction_to_light_eye = normalize (vector_to_light_eye);
+ float dot_prod = dot (direction_to_light_eye, normalize(normal_eye));
+ float clamped_dot_prod = max (dot_prod, 0.0);
+ vec3 Id = Ld * vec3(Kdi) * clamped_dot_prod; // Diffuse intensity
+
+ vec3 reflection_eye = reflect (-direction_to_light_eye, normalize(normal_eye));
+ vec3 surface_to_viewer_eye = normalize (-position_eye);
+ float dot_prod_specular = dot (reflection_eye, surface_to_viewer_eye);
+ dot_prod_specular = float(abs(dot_prod)==dot_prod) * max (dot_prod_specular, 0.0);
+ float specular_factor = pow (dot_prod_specular, specular_exponent);
+ vec3 Is = Ls * vec3(Ksi) * specular_factor; // specular intensity
+ vec4 color = vec4(lighting_factor * (Is + Id) + Ia + (1.0-lighting_factor) * vec3(Kdi),(Kai.a+Ksi.a+Kdi.a)/3);
+ outColor = mix(vec4(1,1,1,1), texture(tex, texcoordi), texture_factor) * color;
+ if (fixed_color != vec4(0.0)) outColor = fixed_color;
+ }
+)";
+
+ std::string overlay_vertex_shader_string =
+R"(#version 150
+ uniform mat4 view;
+ uniform mat4 proj;
+ in vec3 position;
+ in vec3 color;
+ out vec3 color_frag;
+
+ void main()
+ {
+ gl_Position = proj * view * vec4 (position, 1.0);
+ color_frag = color;
+ }
+)";
+
+ std::string overlay_fragment_shader_string =
+R"(#version 150
+ in vec3 color_frag;
+ out vec4 outColor;
+ void main()
+ {
+ outColor = vec4(color_frag, 1.0);
+ }
+)";
+
+ std::string overlay_point_fragment_shader_string =
+R"(#version 150
+ in vec3 color_frag;
+ out vec4 outColor;
+ void main()
+ {
+ if (length(gl_PointCoord - vec2(0.5)) > 0.5)
+ discard;
+ outColor = vec4(color_frag, 1.0);
+ }
+)";
+
+ init_buffers();
+ create_shader_program(
+ mesh_vertex_shader_string,
+ mesh_fragment_shader_string,
+ {},
+ shader_mesh);
+ create_shader_program(
+ overlay_vertex_shader_string,
+ overlay_fragment_shader_string,
+ {},
+ shader_overlay_lines);
+ create_shader_program(
+ overlay_vertex_shader_string,
+ overlay_point_fragment_shader_string,
+ {},
+ shader_overlay_points);
+}
+
+IGL_INLINE void igl::opengl::MeshGL::free()
+{
+ const auto free = [](GLuint & id)
+ {
+ if(id)
+ {
+ destroy_shader_program(id);
+ id = 0;
+ }
+ };
+
+ if (is_initialized)
+ {
+ free(shader_mesh);
+ free(shader_overlay_lines);
+ free(shader_overlay_points);
+ free_buffers();
+ }
+}
diff --git a/xs/src/igl/opengl/MeshGL.h b/xs/src/igl/opengl/MeshGL.h
new file mode 100644
index 000000000..74c358903
--- /dev/null
+++ b/xs/src/igl/opengl/MeshGL.h
@@ -0,0 +1,133 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_MESHGL_H
+#define IGL_OPENGL_MESHGL_H
+
+// Coverts mesh data inside a igl::ViewerData class in an OpenGL
+// compatible format The class includes a shader and the opengl calls to plot
+// the data
+
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+
+namespace igl
+{
+namespace opengl
+{
+
+class MeshGL
+{
+public:
+ typedef unsigned int GLuint;
+
+ enum DirtyFlags
+ {
+ DIRTY_NONE = 0x0000,
+ DIRTY_POSITION = 0x0001,
+ DIRTY_UV = 0x0002,
+ DIRTY_NORMAL = 0x0004,
+ DIRTY_AMBIENT = 0x0008,
+ DIRTY_DIFFUSE = 0x0010,
+ DIRTY_SPECULAR = 0x0020,
+ DIRTY_TEXTURE = 0x0040,
+ DIRTY_FACE = 0x0080,
+ DIRTY_MESH = 0x00FF,
+ DIRTY_OVERLAY_LINES = 0x0100,
+ DIRTY_OVERLAY_POINTS = 0x0200,
+ DIRTY_ALL = 0x03FF
+ };
+
+ bool is_initialized = false;
+ GLuint vao_mesh;
+ GLuint vao_overlay_lines;
+ GLuint vao_overlay_points;
+ GLuint shader_mesh;
+ GLuint shader_overlay_lines;
+ GLuint shader_overlay_points;
+
+ GLuint vbo_V; // Vertices of the current mesh (#V x 3)
+ GLuint vbo_V_uv; // UV coordinates for the current mesh (#V x 2)
+ GLuint vbo_V_normals; // Vertices of the current mesh (#V x 3)
+ GLuint vbo_V_ambient; // Ambient material (#V x 3)
+ GLuint vbo_V_diffuse; // Diffuse material (#V x 3)
+ GLuint vbo_V_specular; // Specular material (#V x 3)
+
+ GLuint vbo_F; // Faces of the mesh (#F x 3)
+ GLuint vbo_tex; // Texture
+
+ GLuint vbo_lines_F; // Indices of the line overlay
+ GLuint vbo_lines_V; // Vertices of the line overlay
+ GLuint vbo_lines_V_colors; // Color values of the line overlay
+ GLuint vbo_points_F; // Indices of the point overlay
+ GLuint vbo_points_V; // Vertices of the point overlay
+ GLuint vbo_points_V_colors; // Color values of the point overlay
+
+ // Temporary copy of the content of each VBO
+ typedef Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> RowMatrixXf;
+ RowMatrixXf V_vbo;
+ RowMatrixXf V_normals_vbo;
+ RowMatrixXf V_ambient_vbo;
+ RowMatrixXf V_diffuse_vbo;
+ RowMatrixXf V_specular_vbo;
+ RowMatrixXf V_uv_vbo;
+ RowMatrixXf lines_V_vbo;
+ RowMatrixXf lines_V_colors_vbo;
+ RowMatrixXf points_V_vbo;
+ RowMatrixXf points_V_colors_vbo;
+
+ int tex_u;
+ int tex_v;
+ Eigen::Matrix<char,Eigen::Dynamic,1> tex;
+
+ Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> F_vbo;
+ Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> lines_F_vbo;
+ Eigen::Matrix<unsigned, Eigen::Dynamic, Eigen::Dynamic, Eigen::RowMajor> points_F_vbo;
+
+ // Marks dirty buffers that need to be uploaded to OpenGL
+ uint32_t dirty;
+
+ // Initialize shaders and buffers
+ IGL_INLINE void init();
+
+ // Release all resources
+ IGL_INLINE void free();
+
+ // Create a new set of OpenGL buffer objects
+ IGL_INLINE void init_buffers();
+
+ // Bind the underlying OpenGL buffer objects for subsequent mesh draw calls
+ IGL_INLINE void bind_mesh();
+
+ /// Draw the currently buffered mesh (either solid or wireframe)
+ IGL_INLINE void draw_mesh(bool solid);
+
+ // Bind the underlying OpenGL buffer objects for subsequent line overlay draw calls
+ IGL_INLINE void bind_overlay_lines();
+
+ /// Draw the currently buffered line overlay
+ IGL_INLINE void draw_overlay_lines();
+
+ // Bind the underlying OpenGL buffer objects for subsequent point overlay draw calls
+ IGL_INLINE void bind_overlay_points();
+
+ /// Draw the currently buffered point overlay
+ IGL_INLINE void draw_overlay_points();
+
+ // Release the OpenGL buffer objects
+ IGL_INLINE void free_buffers();
+
+};
+
+}
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "MeshGL.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/ViewerCore.cpp b/xs/src/igl/opengl/ViewerCore.cpp
new file mode 100644
index 000000000..fc5f4664b
--- /dev/null
+++ b/xs/src/igl/opengl/ViewerCore.cpp
@@ -0,0 +1,391 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "ViewerCore.h"
+#include "gl.h"
+#include "../quat_to_mat.h"
+#include "../snap_to_fixed_up.h"
+#include "../look_at.h"
+#include "../frustum.h"
+#include "../ortho.h"
+#include "../massmatrix.h"
+#include "../barycenter.h"
+#include "../PI.h"
+#include <Eigen/Geometry>
+#include <iostream>
+
+IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F)
+{
+ if(V.rows() == 0)
+ return;
+
+ get_scale_and_shift_to_fit_mesh(V,F,camera_base_zoom,camera_base_translation);
+ // Rather than crash on empty mesh...
+ if(V.size() > 0)
+ {
+ object_scale = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm();
+ }
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ float& zoom,
+ Eigen::Vector3f& shift)
+{
+ if (V.rows() == 0)
+ return;
+
+ Eigen::MatrixXd BC;
+ if (F.rows() <= 1)
+ {
+ BC = V;
+ } else
+ {
+ igl::barycenter(V,F,BC);
+ }
+ return get_scale_and_shift_to_fit_mesh(BC,zoom,shift);
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::align_camera_center(
+ const Eigen::MatrixXd& V)
+{
+ if(V.rows() == 0)
+ return;
+
+ get_scale_and_shift_to_fit_mesh(V,camera_base_zoom,camera_base_translation);
+ // Rather than crash on empty mesh...
+ if(V.size() > 0)
+ {
+ object_scale = (V.colwise().maxCoeff() - V.colwise().minCoeff()).norm();
+ }
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::get_scale_and_shift_to_fit_mesh(
+ const Eigen::MatrixXd& V,
+ float& zoom,
+ Eigen::Vector3f& shift)
+{
+ if (V.rows() == 0)
+ return;
+
+ auto min_point = V.colwise().minCoeff();
+ auto max_point = V.colwise().maxCoeff();
+ auto centroid = (0.5*(min_point + max_point)).eval();
+ shift.setConstant(0);
+ shift.head(centroid.size()) = -centroid.cast<float>();
+ zoom = 2.0 / (max_point-min_point).array().abs().maxCoeff();
+}
+
+
+IGL_INLINE void igl::opengl::ViewerCore::clear_framebuffers()
+{
+ glClearColor(background_color[0],
+ background_color[1],
+ background_color[2],
+ background_color[3]);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::draw(
+ ViewerData& data,
+ bool update_matrices)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ if (depth_test)
+ glEnable(GL_DEPTH_TEST);
+ else
+ glDisable(GL_DEPTH_TEST);
+
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ /* Bind and potentially refresh mesh/line/point data */
+ if (data.dirty)
+ {
+ data.updateGL(data, data.invert_normals,data.meshgl);
+ data.dirty = MeshGL::DIRTY_NONE;
+ }
+ data.meshgl.bind_mesh();
+
+ // Initialize uniform
+ glViewport(viewport(0), viewport(1), viewport(2), viewport(3));
+
+ if(update_matrices)
+ {
+ view = Eigen::Matrix4f::Identity();
+ proj = Eigen::Matrix4f::Identity();
+ norm = Eigen::Matrix4f::Identity();
+
+ float width = viewport(2);
+ float height = viewport(3);
+
+ // Set view
+ look_at( camera_eye, camera_center, camera_up, view);
+ view = view
+ * (trackball_angle * Eigen::Scaling(camera_zoom * camera_base_zoom)
+ * Eigen::Translation3f(camera_translation + camera_base_translation)).matrix();
+
+ norm = view.inverse().transpose();
+
+ // Set projection
+ if (orthographic)
+ {
+ float length = (camera_eye - camera_center).norm();
+ float h = tan(camera_view_angle/360.0 * igl::PI) * (length);
+ ortho(-h*width/height, h*width/height, -h, h, camera_dnear, camera_dfar,proj);
+ }
+ else
+ {
+ float fH = tan(camera_view_angle / 360.0 * igl::PI) * camera_dnear;
+ float fW = fH * (double)width/(double)height;
+ frustum(-fW, fW, -fH, fH, camera_dnear, camera_dfar,proj);
+ }
+ }
+
+ // Send transformations to the GPU
+ GLint viewi = glGetUniformLocation(data.meshgl.shader_mesh,"view");
+ GLint proji = glGetUniformLocation(data.meshgl.shader_mesh,"proj");
+ GLint normi = glGetUniformLocation(data.meshgl.shader_mesh,"normal_matrix");
+ glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
+ glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+ glUniformMatrix4fv(normi, 1, GL_FALSE, norm.data());
+
+ // Light parameters
+ GLint specular_exponenti = glGetUniformLocation(data.meshgl.shader_mesh,"specular_exponent");
+ GLint light_position_eyei = glGetUniformLocation(data.meshgl.shader_mesh,"light_position_eye");
+ GLint lighting_factori = glGetUniformLocation(data.meshgl.shader_mesh,"lighting_factor");
+ GLint fixed_colori = glGetUniformLocation(data.meshgl.shader_mesh,"fixed_color");
+ GLint texture_factori = glGetUniformLocation(data.meshgl.shader_mesh,"texture_factor");
+
+ glUniform1f(specular_exponenti, data.shininess);
+ glUniform3fv(light_position_eyei, 1, light_position.data());
+ glUniform1f(lighting_factori, lighting_factor); // enables lighting
+ glUniform4f(fixed_colori, 0.0, 0.0, 0.0, 0.0);
+
+ if (data.V.rows()>0)
+ {
+ // Render fill
+ if (data.show_faces)
+ {
+ // Texture
+ glUniform1f(texture_factori, data.show_texture ? 1.0f : 0.0f);
+ data.meshgl.draw_mesh(true);
+ glUniform1f(texture_factori, 0.0f);
+ }
+
+ // Render wireframe
+ if (data.show_lines)
+ {
+ glLineWidth(data.line_width);
+ glUniform4f(fixed_colori,
+ data.line_color[0],
+ data.line_color[1],
+ data.line_color[2], 1.0f);
+ data.meshgl.draw_mesh(false);
+ glUniform4f(fixed_colori, 0.0f, 0.0f, 0.0f, 0.0f);
+ }
+ }
+
+ if (data.show_overlay)
+ {
+ if (data.show_overlay_depth)
+ glEnable(GL_DEPTH_TEST);
+ else
+ glDisable(GL_DEPTH_TEST);
+
+ if (data.lines.rows() > 0)
+ {
+ data.meshgl.bind_overlay_lines();
+ viewi = glGetUniformLocation(data.meshgl.shader_overlay_lines,"view");
+ proji = glGetUniformLocation(data.meshgl.shader_overlay_lines,"proj");
+
+ glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
+ glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+ // This must be enabled, otherwise glLineWidth has no effect
+ glEnable(GL_LINE_SMOOTH);
+ glLineWidth(data.line_width);
+
+ data.meshgl.draw_overlay_lines();
+ }
+
+ if (data.points.rows() > 0)
+ {
+ data.meshgl.bind_overlay_points();
+ viewi = glGetUniformLocation(data.meshgl.shader_overlay_points,"view");
+ proji = glGetUniformLocation(data.meshgl.shader_overlay_points,"proj");
+
+ glUniformMatrix4fv(viewi, 1, GL_FALSE, view.data());
+ glUniformMatrix4fv(proji, 1, GL_FALSE, proj.data());
+ glPointSize(data.point_size);
+
+ data.meshgl.draw_overlay_points();
+ }
+
+ glEnable(GL_DEPTH_TEST);
+ }
+
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::draw_buffer(ViewerData& data,
+ bool update_matrices,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A)
+{
+ assert(R.rows() == G.rows() && G.rows() == B.rows() && B.rows() == A.rows());
+ assert(R.cols() == G.cols() && G.cols() == B.cols() && B.cols() == A.cols());
+
+ unsigned width = R.rows();
+ unsigned height = R.cols();
+
+ // https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing
+ unsigned int framebuffer;
+ glGenFramebuffers(1, &framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+ // create a multisampled color attachment texture
+ unsigned int textureColorBufferMultiSampled;
+ glGenTextures(1, &textureColorBufferMultiSampled);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled);
+ glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, 4, GL_RGBA, width, height, GL_TRUE);
+ glBindTexture(GL_TEXTURE_2D_MULTISAMPLE, 0);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, textureColorBufferMultiSampled, 0);
+ // create a (also multisampled) renderbuffer object for depth and stencil attachments
+ unsigned int rbo;
+ glGenRenderbuffers(1, &rbo);
+ glBindRenderbuffer(GL_RENDERBUFFER, rbo);
+ glRenderbufferStorageMultisample(GL_RENDERBUFFER, 4, GL_DEPTH24_STENCIL8, width, height);
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, rbo);
+ assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ // configure second post-processing framebuffer
+ unsigned int intermediateFBO;
+ glGenFramebuffers(1, &intermediateFBO);
+ glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
+ // create a color attachment texture
+ unsigned int screenTexture;
+ glGenTextures(1, &screenTexture);
+ glBindTexture(GL_TEXTURE_2D, screenTexture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, screenTexture, 0); // we only need a color buffer
+ assert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
+
+ // Clear the buffer
+ glClearColor(background_color(0), background_color(1), background_color(2), 0.f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ // Save old viewport
+ Eigen::Vector4f viewport_ori = viewport;
+ viewport << 0,0,width,height;
+ // Draw
+ draw(data,update_matrices);
+ // Restore viewport
+ viewport = viewport_ori;
+
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, framebuffer);
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, intermediateFBO);
+ glBlitFramebuffer(0, 0, width, height, 0, 0, width, height, GL_COLOR_BUFFER_BIT, GL_NEAREST);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, intermediateFBO);
+ // Copy back in the given Eigen matrices
+ GLubyte* pixels = (GLubyte*)calloc(width*height*4,sizeof(GLubyte));
+ glReadPixels(0, 0,width, height,GL_RGBA, GL_UNSIGNED_BYTE, pixels);
+
+ // Clean up
+ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteTextures(1, &screenTexture);
+ glDeleteTextures(1, &textureColorBufferMultiSampled);
+ glDeleteFramebuffers(1, &framebuffer);
+ glDeleteFramebuffers(1, &intermediateFBO);
+ glDeleteRenderbuffers(1, &rbo);
+
+ int count = 0;
+ for (unsigned j=0; j<height; ++j)
+ {
+ for (unsigned i=0; i<width; ++i)
+ {
+ R(i,j) = pixels[count*4+0];
+ G(i,j) = pixels[count*4+1];
+ B(i,j) = pixels[count*4+2];
+ A(i,j) = pixels[count*4+3];
+ ++count;
+ }
+ }
+ // Clean up
+ free(pixels);
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::set_rotation_type(
+ const igl::opengl::ViewerCore::RotationType & value)
+{
+ using namespace Eigen;
+ using namespace std;
+ const RotationType old_rotation_type = rotation_type;
+ rotation_type = value;
+ if(rotation_type == ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP &&
+ old_rotation_type != ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP)
+ {
+ snap_to_fixed_up(Quaternionf(trackball_angle),trackball_angle);
+ }
+}
+
+
+IGL_INLINE igl::opengl::ViewerCore::ViewerCore()
+{
+ // Default colors
+ background_color << 0.3f, 0.3f, 0.5f, 1.0f;
+
+ // Default lights settings
+ light_position << 0.0f, 0.3f, 0.0f;
+ lighting_factor = 1.0f; //on
+
+ // Default trackball
+ trackball_angle = Eigen::Quaternionf::Identity();
+ set_rotation_type(ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP);
+
+ // Camera parameters
+ camera_base_zoom = 1.0f;
+ camera_zoom = 1.0f;
+ orthographic = false;
+ camera_view_angle = 45.0;
+ camera_dnear = 1.0;
+ camera_dfar = 100.0;
+ camera_base_translation << 0, 0, 0;
+ camera_translation << 0, 0, 0;
+ camera_eye << 0, 0, 5;
+ camera_center << 0, 0, 0;
+ camera_up << 0, 1, 0;
+
+ depth_test = true;
+
+ is_animating = false;
+ animation_max_fps = 30.;
+
+ viewport.setZero();
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::init()
+{
+}
+
+IGL_INLINE void igl::opengl::ViewerCore::shut()
+{
+}
diff --git a/xs/src/igl/opengl/ViewerCore.h b/xs/src/igl/opengl/ViewerCore.h
new file mode 100644
index 000000000..94d3367e0
--- /dev/null
+++ b/xs/src/igl/opengl/ViewerCore.h
@@ -0,0 +1,199 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_VIEWERCORE_H
+#define IGL_OPENGL_VIEWERCORE_H
+
+#include <igl/opengl/MeshGL.h>
+#include <igl/opengl/ViewerData.h>
+
+#include <igl/igl_inline.h>
+#include <Eigen/Geometry>
+#include <Eigen/Core>
+
+namespace igl
+{
+namespace opengl
+{
+
+// Basic class of the 3D mesh viewer
+// TODO: write documentation
+
+class ViewerCore
+{
+public:
+ IGL_INLINE ViewerCore();
+
+ // Initialization
+ IGL_INLINE void init();
+
+ // Shutdown
+ IGL_INLINE void shut();
+
+ // Serialization code
+ IGL_INLINE void InitSerialization();
+
+
+ // ------------------- Camera control functions
+
+ // Adjust the view to see the entire model
+ IGL_INLINE void align_camera_center(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F);
+
+ // Determines how much to zoom and shift such that the mesh fills the unit
+ // box (centered at the origin)
+ IGL_INLINE void get_scale_and_shift_to_fit_mesh(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ float & zoom,
+ Eigen::Vector3f& shift);
+
+ // Adjust the view to see the entire model
+ IGL_INLINE void align_camera_center(
+ const Eigen::MatrixXd& V);
+
+ // Determines how much to zoom and shift such that the mesh fills the unit
+ // box (centered at the origin)
+ IGL_INLINE void get_scale_and_shift_to_fit_mesh(
+ const Eigen::MatrixXd& V,
+ float & zoom,
+ Eigen::Vector3f& shift);
+
+ // ------------------- Drawing functions
+
+ // Clear the frame buffers
+ IGL_INLINE void clear_framebuffers();
+
+ // Draw everything
+ //
+ // data cannot be const because it is being set to "clean"
+ IGL_INLINE void draw(ViewerData& data, bool update_matrices = true);
+ IGL_INLINE void draw_buffer(
+ ViewerData& data,
+ bool update_matrices,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A);
+
+ // Trackball angle (quaternion)
+ enum RotationType
+ {
+ ROTATION_TYPE_TRACKBALL = 0,
+ ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP = 1,
+ ROTATION_TYPE_NO_ROTATION = 2,
+ NUM_ROTATION_TYPES = 3
+ };
+ IGL_INLINE void set_rotation_type(const RotationType & value);
+
+ // ------------------- Properties
+
+ // Colors
+ Eigen::Vector4f background_color;
+
+ // Lighting
+ Eigen::Vector3f light_position;
+ float lighting_factor;
+
+ RotationType rotation_type;
+ Eigen::Quaternionf trackball_angle;
+
+ // Camera parameters
+ float camera_base_zoom;
+ float camera_zoom;
+ bool orthographic;
+ Eigen::Vector3f camera_base_translation;
+ Eigen::Vector3f camera_translation;
+ Eigen::Vector3f camera_eye;
+ Eigen::Vector3f camera_up;
+ Eigen::Vector3f camera_center;
+ float camera_view_angle;
+ float camera_dnear;
+ float camera_dfar;
+
+ bool depth_test;
+
+ // Animation
+ bool is_animating;
+ double animation_max_fps;
+
+ // Caches the two-norm between the min/max point of the bounding box
+ float object_scale;
+
+ // Viewport size
+ Eigen::Vector4f viewport;
+
+ // Save the OpenGL transformation matrices used for the previous rendering pass
+ Eigen::Matrix4f view;
+ Eigen::Matrix4f proj;
+ Eigen::Matrix4f norm;
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+};
+
+}
+}
+
+#include <igl/serialize.h>
+namespace igl {
+ namespace serialization {
+
+ inline void serialization(bool s, igl::opengl::ViewerCore& obj, std::vector<char>& buffer)
+ {
+
+ SERIALIZE_MEMBER(background_color);
+
+ SERIALIZE_MEMBER(light_position);
+ SERIALIZE_MEMBER(lighting_factor);
+
+ SERIALIZE_MEMBER(trackball_angle);
+ SERIALIZE_MEMBER(rotation_type);
+
+ SERIALIZE_MEMBER(camera_base_zoom);
+ SERIALIZE_MEMBER(camera_zoom);
+ SERIALIZE_MEMBER(orthographic);
+ SERIALIZE_MEMBER(camera_base_translation);
+ SERIALIZE_MEMBER(camera_translation);
+ SERIALIZE_MEMBER(camera_view_angle);
+ SERIALIZE_MEMBER(camera_dnear);
+ SERIALIZE_MEMBER(camera_dfar);
+ SERIALIZE_MEMBER(camera_eye);
+ SERIALIZE_MEMBER(camera_center);
+ SERIALIZE_MEMBER(camera_up);
+
+ SERIALIZE_MEMBER(depth_test);
+ SERIALIZE_MEMBER(is_animating);
+ SERIALIZE_MEMBER(animation_max_fps);
+
+ SERIALIZE_MEMBER(object_scale);
+
+ SERIALIZE_MEMBER(viewport);
+ SERIALIZE_MEMBER(view);
+ SERIALIZE_MEMBER(proj);
+ SERIALIZE_MEMBER(norm);
+ }
+
+ template<>
+ inline void serialize(const igl::opengl::ViewerCore& obj, std::vector<char>& buffer)
+ {
+ serialization(true, const_cast<igl::opengl::ViewerCore&>(obj), buffer);
+ }
+
+ template<>
+ inline void deserialize(igl::opengl::ViewerCore& obj, const std::vector<char>& buffer)
+ {
+ serialization(false, obj, const_cast<std::vector<char>&>(buffer));
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "ViewerCore.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/ViewerData.cpp b/xs/src/igl/opengl/ViewerData.cpp
new file mode 100644
index 000000000..0a7f2c44b
--- /dev/null
+++ b/xs/src/igl/opengl/ViewerData.cpp
@@ -0,0 +1,691 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "ViewerData.h"
+
+#include "../per_face_normals.h"
+#include "../material_colors.h"
+#include "../parula.h"
+#include "../per_vertex_normals.h"
+
+#include <iostream>
+
+
+IGL_INLINE igl::opengl::ViewerData::ViewerData()
+: dirty(MeshGL::DIRTY_ALL),
+ show_faces(true),
+ show_lines(true),
+ invert_normals(false),
+ show_overlay(true),
+ show_overlay_depth(true),
+ show_vertid(false),
+ show_faceid(false),
+ show_texture(false),
+ point_size(30),
+ line_width(0.5f),
+ line_color(0,0,0,1),
+ shininess(35.0f),
+ id(-1)
+{
+ clear();
+};
+
+IGL_INLINE void igl::opengl::ViewerData::set_face_based(bool newvalue)
+{
+ if (face_based != newvalue)
+ {
+ face_based = newvalue;
+ dirty = MeshGL::DIRTY_ALL;
+ }
+}
+
+// Helpers that draws the most common meshes
+IGL_INLINE void igl::opengl::ViewerData::set_mesh(
+ const Eigen::MatrixXd& _V, const Eigen::MatrixXi& _F)
+{
+ using namespace std;
+
+ Eigen::MatrixXd V_temp;
+
+ // If V only has two columns, pad with a column of zeros
+ if (_V.cols() == 2)
+ {
+ V_temp = Eigen::MatrixXd::Zero(_V.rows(),3);
+ V_temp.block(0,0,_V.rows(),2) = _V;
+ }
+ else
+ V_temp = _V;
+
+ if (V.rows() == 0 && F.rows() == 0)
+ {
+ V = V_temp;
+ F = _F;
+
+ compute_normals();
+ uniform_colors(
+ Eigen::Vector3d(GOLD_AMBIENT[0], GOLD_AMBIENT[1], GOLD_AMBIENT[2]),
+ Eigen::Vector3d(GOLD_DIFFUSE[0], GOLD_DIFFUSE[1], GOLD_DIFFUSE[2]),
+ Eigen::Vector3d(GOLD_SPECULAR[0], GOLD_SPECULAR[1], GOLD_SPECULAR[2]));
+
+ grid_texture();
+ }
+ else
+ {
+ if (_V.rows() == V.rows() && _F.rows() == F.rows())
+ {
+ V = V_temp;
+ F = _F;
+ }
+ else
+ cerr << "ERROR (set_mesh): The new mesh has a different number of vertices/faces. Please clear the mesh before plotting."<<endl;
+ }
+ dirty |= MeshGL::DIRTY_FACE | MeshGL::DIRTY_POSITION;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_vertices(const Eigen::MatrixXd& _V)
+{
+ V = _V;
+ assert(F.size() == 0 || F.maxCoeff() < V.rows());
+ dirty |= MeshGL::DIRTY_POSITION;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_normals(const Eigen::MatrixXd& N)
+{
+ using namespace std;
+ if (N.rows() == V.rows())
+ {
+ set_face_based(false);
+ V_normals = N;
+ }
+ else if (N.rows() == F.rows() || N.rows() == F.rows()*3)
+ {
+ set_face_based(true);
+ F_normals = N;
+ }
+ else
+ cerr << "ERROR (set_normals): Please provide a normal per face, per corner or per vertex."<<endl;
+ dirty |= MeshGL::DIRTY_NORMAL;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_colors(const Eigen::MatrixXd &C)
+{
+ using namespace std;
+ using namespace Eigen;
+ if(C.rows()>0 && C.cols() == 1)
+ {
+ Eigen::MatrixXd C3;
+ igl::parula(C,true,C3);
+ return set_colors(C3);
+ }
+ // Ambient color should be darker color
+ const auto ambient = [](const MatrixXd & C)->MatrixXd
+ {
+ MatrixXd T = 0.1*C;
+ T.col(3) = C.col(3);
+ return T;
+ };
+ // Specular color should be a less saturated and darker color: dampened
+ // highlights
+ const auto specular = [](const MatrixXd & C)->MatrixXd
+ {
+ const double grey = 0.3;
+ MatrixXd T = grey+0.1*(C.array()-grey);
+ T.col(3) = C.col(3);
+ return T;
+ };
+ if (C.rows() == 1)
+ {
+ for (unsigned i=0;i<V_material_diffuse.rows();++i)
+ {
+ if (C.cols() == 3)
+ V_material_diffuse.row(i) << C.row(0),1;
+ else if (C.cols() == 4)
+ V_material_diffuse.row(i) << C.row(0);
+ }
+ V_material_ambient = ambient(V_material_diffuse);
+ V_material_specular = specular(V_material_diffuse);
+
+ for (unsigned i=0;i<F_material_diffuse.rows();++i)
+ {
+ if (C.cols() == 3)
+ F_material_diffuse.row(i) << C.row(0),1;
+ else if (C.cols() == 4)
+ F_material_diffuse.row(i) << C.row(0);
+ }
+ F_material_ambient = ambient(F_material_diffuse);
+ F_material_specular = specular(F_material_diffuse);
+ }
+ else if (C.rows() == V.rows())
+ {
+ set_face_based(false);
+ for (unsigned i=0;i<V_material_diffuse.rows();++i)
+ {
+ if (C.cols() == 3)
+ V_material_diffuse.row(i) << C.row(i), 1;
+ else if (C.cols() == 4)
+ V_material_diffuse.row(i) << C.row(i);
+ }
+ V_material_ambient = ambient(V_material_diffuse);
+ V_material_specular = specular(V_material_diffuse);
+ }
+ else if (C.rows() == F.rows())
+ {
+ set_face_based(true);
+ for (unsigned i=0;i<F_material_diffuse.rows();++i)
+ {
+ if (C.cols() == 3)
+ F_material_diffuse.row(i) << C.row(i), 1;
+ else if (C.cols() == 4)
+ F_material_diffuse.row(i) << C.row(i);
+ }
+ F_material_ambient = ambient(F_material_diffuse);
+ F_material_specular = specular(F_material_diffuse);
+ }
+ else
+ cerr << "ERROR (set_colors): Please provide a single color, or a color per face or per vertex."<<endl;
+ dirty |= MeshGL::DIRTY_DIFFUSE;
+
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_uv(const Eigen::MatrixXd& UV)
+{
+ using namespace std;
+ if (UV.rows() == V.rows())
+ {
+ set_face_based(false);
+ V_uv = UV;
+ }
+ else
+ cerr << "ERROR (set_UV): Please provide uv per vertex."<<endl;;
+ dirty |= MeshGL::DIRTY_UV;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F)
+{
+ set_face_based(true);
+ V_uv = UV_V.block(0,0,UV_V.rows(),2);
+ F_uv = UV_F;
+ dirty |= MeshGL::DIRTY_UV;
+}
+
+
+IGL_INLINE void igl::opengl::ViewerData::set_texture(
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B)
+{
+ texture_R = R;
+ texture_G = G;
+ texture_B = B;
+ texture_A = Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>::Constant(R.rows(),R.cols(),255);
+ dirty |= MeshGL::DIRTY_TEXTURE;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_texture(
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A)
+{
+ texture_R = R;
+ texture_G = G;
+ texture_B = B;
+ texture_A = A;
+ dirty |= MeshGL::DIRTY_TEXTURE;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_points(
+ const Eigen::MatrixXd& P,
+ const Eigen::MatrixXd& C)
+{
+ // clear existing points
+ points.resize(0,0);
+ add_points(P,C);
+}
+
+IGL_INLINE void igl::opengl::ViewerData::add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C)
+{
+ Eigen::MatrixXd P_temp;
+
+ // If P only has two columns, pad with a column of zeros
+ if (P.cols() == 2)
+ {
+ P_temp = Eigen::MatrixXd::Zero(P.rows(),3);
+ P_temp.block(0,0,P.rows(),2) = P;
+ }
+ else
+ P_temp = P;
+
+ int lastid = points.rows();
+ points.conservativeResize(points.rows() + P_temp.rows(),6);
+ for (unsigned i=0; i<P_temp.rows(); ++i)
+ points.row(lastid+i) << P_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
+
+ dirty |= MeshGL::DIRTY_OVERLAY_POINTS;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::set_edges(
+ const Eigen::MatrixXd& P,
+ const Eigen::MatrixXi& E,
+ const Eigen::MatrixXd& C)
+{
+ using namespace Eigen;
+ lines.resize(E.rows(),9);
+ assert(C.cols() == 3);
+ for(int e = 0;e<E.rows();e++)
+ {
+ RowVector3d color;
+ if(C.size() == 3)
+ {
+ color<<C;
+ }else if(C.rows() == E.rows())
+ {
+ color<<C.row(e);
+ }
+ lines.row(e)<< P.row(E(e,0)), P.row(E(e,1)), color;
+ }
+ dirty |= MeshGL::DIRTY_OVERLAY_LINES;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::add_edges(const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C)
+{
+ Eigen::MatrixXd P1_temp,P2_temp;
+
+ // If P1 only has two columns, pad with a column of zeros
+ if (P1.cols() == 2)
+ {
+ P1_temp = Eigen::MatrixXd::Zero(P1.rows(),3);
+ P1_temp.block(0,0,P1.rows(),2) = P1;
+ P2_temp = Eigen::MatrixXd::Zero(P2.rows(),3);
+ P2_temp.block(0,0,P2.rows(),2) = P2;
+ }
+ else
+ {
+ P1_temp = P1;
+ P2_temp = P2;
+ }
+
+ int lastid = lines.rows();
+ lines.conservativeResize(lines.rows() + P1_temp.rows(),9);
+ for (unsigned i=0; i<P1_temp.rows(); ++i)
+ lines.row(lastid+i) << P1_temp.row(i), P2_temp.row(i), i<C.rows() ? C.row(i) : C.row(C.rows()-1);
+
+ dirty |= MeshGL::DIRTY_OVERLAY_LINES;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::add_label(const Eigen::VectorXd& P, const std::string& str)
+{
+ Eigen::RowVectorXd P_temp;
+
+ // If P only has two columns, pad with a column of zeros
+ if (P.size() == 2)
+ {
+ P_temp = Eigen::RowVectorXd::Zero(3);
+ P_temp << P.transpose(), 0;
+ }
+ else
+ P_temp = P;
+
+ int lastid = labels_positions.rows();
+ labels_positions.conservativeResize(lastid+1, 3);
+ labels_positions.row(lastid) = P_temp;
+ labels_strings.push_back(str);
+}
+
+IGL_INLINE void igl::opengl::ViewerData::clear()
+{
+ V = Eigen::MatrixXd (0,3);
+ F = Eigen::MatrixXi (0,3);
+
+ F_material_ambient = Eigen::MatrixXd (0,4);
+ F_material_diffuse = Eigen::MatrixXd (0,4);
+ F_material_specular = Eigen::MatrixXd (0,4);
+
+ V_material_ambient = Eigen::MatrixXd (0,4);
+ V_material_diffuse = Eigen::MatrixXd (0,4);
+ V_material_specular = Eigen::MatrixXd (0,4);
+
+ F_normals = Eigen::MatrixXd (0,3);
+ V_normals = Eigen::MatrixXd (0,3);
+
+ V_uv = Eigen::MatrixXd (0,2);
+ F_uv = Eigen::MatrixXi (0,3);
+
+ lines = Eigen::MatrixXd (0,9);
+ points = Eigen::MatrixXd (0,6);
+ labels_positions = Eigen::MatrixXd (0,3);
+ labels_strings.clear();
+
+ face_based = false;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::compute_normals()
+{
+ igl::per_face_normals(V, F, F_normals);
+ igl::per_vertex_normals(V, F, F_normals, V_normals);
+ dirty |= MeshGL::DIRTY_NORMAL;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
+ const Eigen::Vector3d& ambient,
+ const Eigen::Vector3d& diffuse,
+ const Eigen::Vector3d& specular)
+{
+ Eigen::Vector4d ambient4;
+ Eigen::Vector4d diffuse4;
+ Eigen::Vector4d specular4;
+
+ ambient4 << ambient, 1;
+ diffuse4 << diffuse, 1;
+ specular4 << specular, 1;
+
+ uniform_colors(ambient4,diffuse4,specular4);
+}
+
+IGL_INLINE void igl::opengl::ViewerData::uniform_colors(
+ const Eigen::Vector4d& ambient,
+ const Eigen::Vector4d& diffuse,
+ const Eigen::Vector4d& specular)
+{
+ V_material_ambient.resize(V.rows(),4);
+ V_material_diffuse.resize(V.rows(),4);
+ V_material_specular.resize(V.rows(),4);
+
+ for (unsigned i=0; i<V.rows();++i)
+ {
+ V_material_ambient.row(i) = ambient;
+ V_material_diffuse.row(i) = diffuse;
+ V_material_specular.row(i) = specular;
+ }
+
+ F_material_ambient.resize(F.rows(),4);
+ F_material_diffuse.resize(F.rows(),4);
+ F_material_specular.resize(F.rows(),4);
+
+ for (unsigned i=0; i<F.rows();++i)
+ {
+ F_material_ambient.row(i) = ambient;
+ F_material_diffuse.row(i) = diffuse;
+ F_material_specular.row(i) = specular;
+ }
+ dirty |= MeshGL::DIRTY_SPECULAR | MeshGL::DIRTY_DIFFUSE | MeshGL::DIRTY_AMBIENT;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::grid_texture()
+{
+ // Don't do anything for an empty mesh
+ if(V.rows() == 0)
+ {
+ V_uv.resize(V.rows(),2);
+ return;
+ }
+ if (V_uv.rows() == 0)
+ {
+ V_uv = V.block(0, 0, V.rows(), 2);
+ V_uv.col(0) = V_uv.col(0).array() - V_uv.col(0).minCoeff();
+ V_uv.col(0) = V_uv.col(0).array() / V_uv.col(0).maxCoeff();
+ V_uv.col(1) = V_uv.col(1).array() - V_uv.col(1).minCoeff();
+ V_uv.col(1) = V_uv.col(1).array() / V_uv.col(1).maxCoeff();
+ V_uv = V_uv.array() * 10;
+ dirty |= MeshGL::DIRTY_TEXTURE;
+ }
+
+ unsigned size = 128;
+ unsigned size2 = size/2;
+ texture_R.resize(size, size);
+ for (unsigned i=0; i<size; ++i)
+ {
+ for (unsigned j=0; j<size; ++j)
+ {
+ texture_R(i,j) = 0;
+ if ((i<size2 && j<size2) || (i>=size2 && j>=size2))
+ texture_R(i,j) = 255;
+ }
+ }
+
+ texture_G = texture_R;
+ texture_B = texture_R;
+ texture_A = Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>::Constant(texture_R.rows(),texture_R.cols(),255);
+ dirty |= MeshGL::DIRTY_TEXTURE;
+}
+
+IGL_INLINE void igl::opengl::ViewerData::updateGL(
+ const igl::opengl::ViewerData& data,
+ const bool invert_normals,
+ igl::opengl::MeshGL& meshgl
+ )
+{
+ if (!meshgl.is_initialized)
+ {
+ meshgl.init();
+ }
+
+ bool per_corner_uv = (data.F_uv.rows() == data.F.rows());
+ bool per_corner_normals = (data.F_normals.rows() == 3 * data.F.rows());
+
+ meshgl.dirty |= data.dirty;
+
+ // Input:
+ // X #F by dim quantity
+ // Output:
+ // X_vbo #F*3 by dim scattering per corner
+ const auto per_face = [&data](
+ const Eigen::MatrixXd & X,
+ MeshGL::RowMatrixXf & X_vbo)
+ {
+ assert(X.cols() == 4);
+ X_vbo.resize(data.F.rows()*3,4);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ X_vbo.row(i*3+j) = X.row(i).cast<float>();
+ };
+
+ // Input:
+ // X #V by dim quantity
+ // Output:
+ // X_vbo #F*3 by dim scattering per corner
+ const auto per_corner = [&data](
+ const Eigen::MatrixXd & X,
+ MeshGL::RowMatrixXf & X_vbo)
+ {
+ X_vbo.resize(data.F.rows()*3,X.cols());
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ X_vbo.row(i*3+j) = X.row(data.F(i,j)).cast<float>();
+ };
+
+ if (!data.face_based)
+ {
+ if (!(per_corner_uv || per_corner_normals))
+ {
+ // Vertex positions
+ if (meshgl.dirty & MeshGL::DIRTY_POSITION)
+ meshgl.V_vbo = data.V.cast<float>();
+
+ // Vertex normals
+ if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
+ {
+ meshgl.V_normals_vbo = data.V_normals.cast<float>();
+ if (invert_normals)
+ meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
+ }
+
+ // Per-vertex material settings
+ if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
+ meshgl.V_ambient_vbo = data.V_material_ambient.cast<float>();
+ if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
+ meshgl.V_diffuse_vbo = data.V_material_diffuse.cast<float>();
+ if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
+ meshgl.V_specular_vbo = data.V_material_specular.cast<float>();
+
+ // Face indices
+ if (meshgl.dirty & MeshGL::DIRTY_FACE)
+ meshgl.F_vbo = data.F.cast<unsigned>();
+
+ // Texture coordinates
+ if (meshgl.dirty & MeshGL::DIRTY_UV)
+ {
+ meshgl.V_uv_vbo = data.V_uv.cast<float>();
+ }
+ }
+ else
+ {
+
+ // Per vertex properties with per corner UVs
+ if (meshgl.dirty & MeshGL::DIRTY_POSITION)
+ {
+ per_corner(data.V,meshgl.V_vbo);
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
+ {
+ meshgl.V_ambient_vbo.resize(data.F.rows()*3,4);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ meshgl.V_ambient_vbo.row(i*3+j) = data.V_material_ambient.row(data.F(i,j)).cast<float>();
+ }
+ if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
+ {
+ meshgl.V_diffuse_vbo.resize(data.F.rows()*3,4);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ meshgl.V_diffuse_vbo.row(i*3+j) = data.V_material_diffuse.row(data.F(i,j)).cast<float>();
+ }
+ if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
+ {
+ meshgl.V_specular_vbo.resize(data.F.rows()*3,4);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ meshgl.V_specular_vbo.row(i*3+j) = data.V_material_specular.row(data.F(i,j)).cast<float>();
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
+ {
+ meshgl.V_normals_vbo.resize(data.F.rows()*3,3);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ meshgl.V_normals_vbo.row(i*3+j) =
+ per_corner_normals ?
+ data.F_normals.row(i*3+j).cast<float>() :
+ data.V_normals.row(data.F(i,j)).cast<float>();
+
+
+ if (invert_normals)
+ meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_FACE)
+ {
+ meshgl.F_vbo.resize(data.F.rows(),3);
+ for (unsigned i=0; i<data.F.rows();++i)
+ meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_UV)
+ {
+ meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ meshgl.V_uv_vbo.row(i*3+j) =
+ data.V_uv.row(per_corner_uv ?
+ data.F_uv(i,j) : data.F(i,j)).cast<float>();
+ }
+ }
+ }
+ else
+ {
+ if (meshgl.dirty & MeshGL::DIRTY_POSITION)
+ {
+ per_corner(data.V,meshgl.V_vbo);
+ }
+ if (meshgl.dirty & MeshGL::DIRTY_AMBIENT)
+ {
+ per_face(data.F_material_ambient,meshgl.V_ambient_vbo);
+ }
+ if (meshgl.dirty & MeshGL::DIRTY_DIFFUSE)
+ {
+ per_face(data.F_material_diffuse,meshgl.V_diffuse_vbo);
+ }
+ if (meshgl.dirty & MeshGL::DIRTY_SPECULAR)
+ {
+ per_face(data.F_material_specular,meshgl.V_specular_vbo);
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_NORMAL)
+ {
+ meshgl.V_normals_vbo.resize(data.F.rows()*3,3);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ meshgl.V_normals_vbo.row(i*3+j) =
+ per_corner_normals ?
+ data.F_normals.row(i*3+j).cast<float>() :
+ data.F_normals.row(i).cast<float>();
+
+ if (invert_normals)
+ meshgl.V_normals_vbo = -meshgl.V_normals_vbo;
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_FACE)
+ {
+ meshgl.F_vbo.resize(data.F.rows(),3);
+ for (unsigned i=0; i<data.F.rows();++i)
+ meshgl.F_vbo.row(i) << i*3+0, i*3+1, i*3+2;
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_UV)
+ {
+ meshgl.V_uv_vbo.resize(data.F.rows()*3,2);
+ for (unsigned i=0; i<data.F.rows();++i)
+ for (unsigned j=0;j<3;++j)
+ meshgl.V_uv_vbo.row(i*3+j) = data.V_uv.row(per_corner_uv ? data.F_uv(i,j) : data.F(i,j)).cast<float>();
+ }
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_TEXTURE)
+ {
+ meshgl.tex_u = data.texture_R.rows();
+ meshgl.tex_v = data.texture_R.cols();
+ meshgl.tex.resize(data.texture_R.size()*4);
+ for (unsigned i=0;i<data.texture_R.size();++i)
+ {
+ meshgl.tex(i*4+0) = data.texture_R(i);
+ meshgl.tex(i*4+1) = data.texture_G(i);
+ meshgl.tex(i*4+2) = data.texture_B(i);
+ meshgl.tex(i*4+3) = data.texture_A(i);
+ }
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_OVERLAY_LINES)
+ {
+ meshgl.lines_V_vbo.resize(data.lines.rows()*2,3);
+ meshgl.lines_V_colors_vbo.resize(data.lines.rows()*2,3);
+ meshgl.lines_F_vbo.resize(data.lines.rows()*2,1);
+ for (unsigned i=0; i<data.lines.rows();++i)
+ {
+ meshgl.lines_V_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 0).cast<float>();
+ meshgl.lines_V_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 3).cast<float>();
+ meshgl.lines_V_colors_vbo.row(2*i+0) = data.lines.block<1, 3>(i, 6).cast<float>();
+ meshgl.lines_V_colors_vbo.row(2*i+1) = data.lines.block<1, 3>(i, 6).cast<float>();
+ meshgl.lines_F_vbo(2*i+0) = 2*i+0;
+ meshgl.lines_F_vbo(2*i+1) = 2*i+1;
+ }
+ }
+
+ if (meshgl.dirty & MeshGL::DIRTY_OVERLAY_POINTS)
+ {
+ meshgl.points_V_vbo.resize(data.points.rows(),3);
+ meshgl.points_V_colors_vbo.resize(data.points.rows(),3);
+ meshgl.points_F_vbo.resize(data.points.rows(),1);
+ for (unsigned i=0; i<data.points.rows();++i)
+ {
+ meshgl.points_V_vbo.row(i) = data.points.block<1, 3>(i, 0).cast<float>();
+ meshgl.points_V_colors_vbo.row(i) = data.points.block<1, 3>(i, 3).cast<float>();
+ meshgl.points_F_vbo(i) = i;
+ }
+ }
+}
diff --git a/xs/src/igl/opengl/ViewerData.h b/xs/src/igl/opengl/ViewerData.h
new file mode 100644
index 000000000..b3ec9178c
--- /dev/null
+++ b/xs/src/igl/opengl/ViewerData.h
@@ -0,0 +1,276 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VIEWERDATA_H
+#define IGL_VIEWERDATA_H
+
+#include "../igl_inline.h"
+#include "MeshGL.h"
+#include <cassert>
+#include <cstdint>
+#include <Eigen/Core>
+#include <memory>
+#include <vector>
+
+// Alec: This is a mesh class containing a variety of data types (normals,
+// overlays, material colors, etc.)
+//
+namespace igl
+{
+
+// TODO: write documentation
+namespace opengl
+{
+
+class ViewerData
+{
+public:
+ ViewerData();
+
+ // Empty all fields
+ IGL_INLINE void clear();
+
+ // Change the visualization mode, invalidating the cache if necessary
+ IGL_INLINE void set_face_based(bool newvalue);
+
+ // Helpers that can draw the most common meshes
+ IGL_INLINE void set_mesh(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
+ IGL_INLINE void set_vertices(const Eigen::MatrixXd& V);
+ IGL_INLINE void set_normals(const Eigen::MatrixXd& N);
+
+ // Set the color of the mesh
+ //
+ // Inputs:
+ // C #V|#F|1 by 3 list of colors
+ IGL_INLINE void set_colors(const Eigen::MatrixXd &C);
+ // Set per-vertex UV coordinates
+ //
+ // Inputs:
+ // UV #V by 2 list of UV coordinates (indexed by F)
+ IGL_INLINE void set_uv(const Eigen::MatrixXd& UV);
+ // Set per-corner UV coordinates
+ //
+ // Inputs:
+ // UV_V #UV by 2 list of UV coordinates
+ // UV_F #F by 3 list of UV indices into UV_V
+ IGL_INLINE void set_uv(const Eigen::MatrixXd& UV_V, const Eigen::MatrixXi& UV_F);
+ // Set the texture associated with the mesh.
+ //
+ // Inputs:
+ // R width by height image matrix of red channel
+ // G width by height image matrix of green channel
+ // B width by height image matrix of blue channel
+ //
+ IGL_INLINE void set_texture(
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B);
+
+ // Set the texture associated with the mesh.
+ //
+ // Inputs:
+ // R width by height image matrix of red channel
+ // G width by height image matrix of green channel
+ // B width by height image matrix of blue channel
+ // A width by height image matrix of alpha channel
+ //
+ IGL_INLINE void set_texture(
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A);
+
+ // Sets points given a list of point vertices. In constrast to `set_points`
+ // this will (purposefully) clober existing points.
+ //
+ // Inputs:
+ // P #P by 3 list of vertex positions
+ // C #P|1 by 3 color(s)
+ IGL_INLINE void set_points(
+ const Eigen::MatrixXd& P,
+ const Eigen::MatrixXd& C);
+ IGL_INLINE void add_points(const Eigen::MatrixXd& P, const Eigen::MatrixXd& C);
+ // Sets edges given a list of edge vertices and edge indices. In constrast
+ // to `add_edges` this will (purposefully) clober existing edges.
+ //
+ // Inputs:
+ // P #P by 3 list of vertex positions
+ // E #E by 2 list of edge indices into P
+ // C #E|1 by 3 color(s)
+ IGL_INLINE void set_edges (const Eigen::MatrixXd& P, const Eigen::MatrixXi& E, const Eigen::MatrixXd& C);
+ // Alec: This is very confusing. Why does add_edges have a different API from
+ // set_edges?
+ IGL_INLINE void add_edges (const Eigen::MatrixXd& P1, const Eigen::MatrixXd& P2, const Eigen::MatrixXd& C);
+ IGL_INLINE void add_label (const Eigen::VectorXd& P, const std::string& str);
+
+ // Computes the normals of the mesh
+ IGL_INLINE void compute_normals();
+
+ // Assigns uniform colors to all faces/vertices
+ IGL_INLINE void uniform_colors(
+ const Eigen::Vector3d& diffuse,
+ const Eigen::Vector3d& ambient,
+ const Eigen::Vector3d& specular);
+
+ // Assigns uniform colors to all faces/vertices
+ IGL_INLINE void uniform_colors(
+ const Eigen::Vector4d& ambient,
+ const Eigen::Vector4d& diffuse,
+ const Eigen::Vector4d& specular);
+
+ // Generates a default grid texture
+ IGL_INLINE void grid_texture();
+
+ Eigen::MatrixXd V; // Vertices of the current mesh (#V x 3)
+ Eigen::MatrixXi F; // Faces of the mesh (#F x 3)
+
+ // Per face attributes
+ Eigen::MatrixXd F_normals; // One normal per face
+
+ Eigen::MatrixXd F_material_ambient; // Per face ambient color
+ Eigen::MatrixXd F_material_diffuse; // Per face diffuse color
+ Eigen::MatrixXd F_material_specular; // Per face specular color
+
+ // Per vertex attributes
+ Eigen::MatrixXd V_normals; // One normal per vertex
+
+ Eigen::MatrixXd V_material_ambient; // Per vertex ambient color
+ Eigen::MatrixXd V_material_diffuse; // Per vertex diffuse color
+ Eigen::MatrixXd V_material_specular; // Per vertex specular color
+
+ // UV parametrization
+ Eigen::MatrixXd V_uv; // UV vertices
+ Eigen::MatrixXi F_uv; // optional faces for UVs
+
+ // Texture
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_R;
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_G;
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_B;
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic> texture_A;
+
+ // Overlays
+
+ // Lines plotted over the scene
+ // (Every row contains 9 doubles in the following format S_x, S_y, S_z, T_x, T_y, T_z, C_r, C_g, C_b),
+ // with S and T the coordinates of the two vertices of the line in global coordinates, and C the color in floating point rgb format
+ Eigen::MatrixXd lines;
+
+ // Points plotted over the scene
+ // (Every row contains 6 doubles in the following format P_x, P_y, P_z, C_r, C_g, C_b),
+ // with P the position in global coordinates of the center of the point, and C the color in floating point rgb format
+ Eigen::MatrixXd points;
+
+ // Text labels plotted over the scene
+ // Textp contains, in the i-th row, the position in global coordinates where the i-th label should be anchored
+ // Texts contains in the i-th position the text of the i-th label
+ Eigen::MatrixXd labels_positions;
+ std::vector<std::string> labels_strings;
+
+ // Marks dirty buffers that need to be uploaded to OpenGL
+ uint32_t dirty;
+
+ // Enable per-face or per-vertex properties
+ bool face_based;
+
+ // Visualization options
+ bool show_overlay;
+ bool show_overlay_depth;
+ bool show_texture;
+ bool show_faces;
+ bool show_lines;
+ bool show_vertid;
+ bool show_faceid;
+ bool invert_normals;
+
+ // Point size / line width
+ float point_size;
+ float line_width;
+ Eigen::Vector4f line_color;
+
+ // Shape material
+ float shininess;
+
+ // Unique identifier
+ int id;
+
+ // OpenGL representation of the mesh
+ igl::opengl::MeshGL meshgl;
+
+ // Update contents from a 'Data' instance
+ IGL_INLINE void updateGL(
+ const igl::opengl::ViewerData& data,
+ const bool invert_normals,
+ igl::opengl::MeshGL& meshgl);
+};
+
+} // namespace opengl
+} // namespace igl
+
+////////////////////////////////////////////////////////////////////////////////
+
+#include <igl/serialize.h>
+namespace igl
+{
+ namespace serialization
+ {
+ inline void serialization(bool s, igl::opengl::ViewerData& obj, std::vector<char>& buffer)
+ {
+ SERIALIZE_MEMBER(V);
+ SERIALIZE_MEMBER(F);
+ SERIALIZE_MEMBER(F_normals);
+ SERIALIZE_MEMBER(F_material_ambient);
+ SERIALIZE_MEMBER(F_material_diffuse);
+ SERIALIZE_MEMBER(F_material_specular);
+ SERIALIZE_MEMBER(V_normals);
+ SERIALIZE_MEMBER(V_material_ambient);
+ SERIALIZE_MEMBER(V_material_diffuse);
+ SERIALIZE_MEMBER(V_material_specular);
+ SERIALIZE_MEMBER(V_uv);
+ SERIALIZE_MEMBER(F_uv);
+ SERIALIZE_MEMBER(texture_R);
+ SERIALIZE_MEMBER(texture_G);
+ SERIALIZE_MEMBER(texture_B);
+ SERIALIZE_MEMBER(texture_A);
+ SERIALIZE_MEMBER(lines);
+ SERIALIZE_MEMBER(points);
+ SERIALIZE_MEMBER(labels_positions);
+ SERIALIZE_MEMBER(labels_strings);
+ SERIALIZE_MEMBER(dirty);
+ SERIALIZE_MEMBER(face_based);
+ SERIALIZE_MEMBER(show_faces);
+ SERIALIZE_MEMBER(show_lines);
+ SERIALIZE_MEMBER(invert_normals);
+ SERIALIZE_MEMBER(show_overlay);
+ SERIALIZE_MEMBER(show_overlay_depth);
+ SERIALIZE_MEMBER(show_vertid);
+ SERIALIZE_MEMBER(show_faceid);
+ SERIALIZE_MEMBER(show_texture);
+ SERIALIZE_MEMBER(point_size);
+ SERIALIZE_MEMBER(line_width);
+ SERIALIZE_MEMBER(line_color);
+ SERIALIZE_MEMBER(shininess);
+ SERIALIZE_MEMBER(id);
+ }
+ template<>
+ inline void serialize(const igl::opengl::ViewerData& obj, std::vector<char>& buffer)
+ {
+ serialization(true, const_cast<igl::opengl::ViewerData&>(obj), buffer);
+ }
+ template<>
+ inline void deserialize(igl::opengl::ViewerData& obj, const std::vector<char>& buffer)
+ {
+ serialization(false, obj, const_cast<std::vector<char>&>(buffer));
+ obj.dirty = igl::opengl::MeshGL::DIRTY_ALL;
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "ViewerData.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/bind_vertex_attrib_array.cpp b/xs/src/igl/opengl/bind_vertex_attrib_array.cpp
new file mode 100644
index 000000000..4aa807c18
--- /dev/null
+++ b/xs/src/igl/opengl/bind_vertex_attrib_array.cpp
@@ -0,0 +1,24 @@
+#include "bind_vertex_attrib_array.h"
+
+IGL_INLINE GLint igl::opengl::bind_vertex_attrib_array(
+ const GLuint program_shader,
+ const std::string &name,
+ GLuint bufferID,
+ const Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> &M,
+ bool refresh)
+{
+ GLint id = glGetAttribLocation(program_shader, name.c_str());
+ if (id < 0)
+ return id;
+ if (M.size() == 0)
+ {
+ glDisableVertexAttribArray(id);
+ return id;
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, bufferID);
+ if (refresh)
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*M.size(), M.data(), GL_DYNAMIC_DRAW);
+ glVertexAttribPointer(id, M.cols(), GL_FLOAT, GL_FALSE, 0, 0);
+ glEnableVertexAttribArray(id);
+ return id;
+}
diff --git a/xs/src/igl/opengl/bind_vertex_attrib_array.h b/xs/src/igl/opengl/bind_vertex_attrib_array.h
new file mode 100644
index 000000000..4e9443136
--- /dev/null
+++ b/xs/src/igl/opengl/bind_vertex_attrib_array.h
@@ -0,0 +1,32 @@
+#ifndef IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H
+#define IGL_OPENGL_BIND_VERTEX_ATTRIB_ARRAY_H
+#include "gl.h"
+#include "../igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+namespace igl
+{
+ namespace opengl
+ {
+ // Bind a per-vertex array attribute and refresh its contents from an Eigen
+ // matrix
+ //
+ // Inputs:
+ // program_shader id of shader program
+ // name name of attribute in vertex shader
+ // bufferID id of buffer to bind to
+ // M #V by dim matrix of per-vertex data
+ // refresh whether to actually call glBufferData or just bind the buffer
+ // Returns id of named attribute in shader
+ IGL_INLINE GLint bind_vertex_attrib_array(
+ const GLuint program_shader,
+ const std::string &name,
+ GLuint bufferID,
+ const Eigen::Matrix<float,Eigen::Dynamic,Eigen::Dynamic,Eigen::RowMajor> &M,
+ bool refresh);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "bind_vertex_attrib_array.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl/create_index_vbo.cpp b/xs/src/igl/opengl/create_index_vbo.cpp
new file mode 100644
index 000000000..76f6248c0
--- /dev/null
+++ b/xs/src/igl/opengl/create_index_vbo.cpp
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "create_index_vbo.h"
+
+// http://www.songho.ca/opengl/gl_vbo.html#create
+IGL_INLINE void igl::opengl::create_index_vbo(
+ const Eigen::MatrixXi & F,
+ GLuint & F_vbo_id)
+{
+ // Generate Buffers
+ glGenBuffers(1,&F_vbo_id);
+ // Bind Buffers
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,F_vbo_id);
+ // Copy data to buffers
+ // We expect a matrix with each vertex position on a row, we then want to
+ // pass this data to OpenGL reading across rows (row-major)
+ if(F.Options & Eigen::RowMajor)
+ {
+ glBufferData(
+ GL_ELEMENT_ARRAY_BUFFER,
+ sizeof(int)*F.size(),
+ F.data(),
+ GL_STATIC_DRAW);
+ }else
+ {
+ // Create temporary copy of transpose
+ Eigen::MatrixXi FT = F.transpose();
+ // If its column major then we need to temporarily store a transpose
+ glBufferData(
+ GL_ELEMENT_ARRAY_BUFFER,
+ sizeof(int)*F.size(),
+ FT.data(),
+ GL_STATIC_DRAW);
+ }
+ // bind with 0, so, switch back to normal pointer operation
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/opengl/create_index_vbo.h b/xs/src/igl/opengl/create_index_vbo.h
new file mode 100644
index 000000000..e48f3a489
--- /dev/null
+++ b/xs/src/igl/opengl/create_index_vbo.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_CREATE_INDEX_VBO_H
+#define IGL_OPENGL_CREATE_INDEX_VBO_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <Eigen/Core>
+
+// Create a VBO (Vertex Buffer Object) for a list of indices:
+// GL_ELEMENT_ARRAY_BUFFER_ARB for the triangle indices (F)
+namespace igl
+{
+ namespace opengl
+ {
+ // Inputs:
+ // F #F by 3 eigen Matrix of face (triangle) indices
+ // Outputs:
+ // F_vbo_id buffer id for face indices
+ //
+ IGL_INLINE void create_index_vbo(
+ const Eigen::MatrixXi & F,
+ GLuint & F_vbo_id);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "create_index_vbo.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/create_mesh_vbo.cpp b/xs/src/igl/opengl/create_mesh_vbo.cpp
new file mode 100644
index 000000000..3876e1dfa
--- /dev/null
+++ b/xs/src/igl/opengl/create_mesh_vbo.cpp
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "create_mesh_vbo.h"
+
+#include "create_vector_vbo.h"
+#include "create_index_vbo.h"
+
+// http://www.songho.ca/opengl/gl_vbo.html#create
+IGL_INLINE void igl::opengl::create_mesh_vbo(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ GLuint & V_vbo_id,
+ GLuint & F_vbo_id)
+{
+ // Create VBO for vertex position vectors
+ create_vector_vbo(V,V_vbo_id);
+ // Create VBO for face index lists
+ create_index_vbo(F,F_vbo_id);
+}
+
+// http://www.songho.ca/opengl/gl_vbo.html#create
+IGL_INLINE void igl::opengl::create_mesh_vbo(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ GLuint & V_vbo_id,
+ GLuint & F_vbo_id,
+ GLuint & N_vbo_id)
+{
+ // Create VBOs for faces and vertices
+ create_mesh_vbo(V,F,V_vbo_id,F_vbo_id);
+ // Create VBO for normal vectors
+ create_vector_vbo(N,N_vbo_id);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/opengl/create_mesh_vbo.h b/xs/src/igl/opengl/create_mesh_vbo.h
new file mode 100644
index 000000000..ecb303b09
--- /dev/null
+++ b/xs/src/igl/opengl/create_mesh_vbo.h
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_CREATE_MESH_VBO_H
+#define IGL_OPENGL_CREATE_MESH_VBO_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <Eigen/Core>
+
+// Create a VBO (Vertex Buffer Object) for a mesh. Actually two VBOs: one
+// GL_ARRAY_BUFFER for the vertex positions (V) and one
+// GL_ELEMENT_ARRAY_BUFFER for the triangle indices (F)
+namespace igl
+{
+ namespace opengl
+ {
+
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigen Matrix of face (triangle) indices
+ // Outputs:
+ // V_vbo_id buffer id for vertex positions
+ // F_vbo_id buffer id for face indices
+ //
+ // NOTE: when using glDrawElements VBOs for V and F using MatrixXd and
+ // MatrixXi will have types GL_DOUBLE and GL_UNSIGNED_INT respectively
+ //
+ IGL_INLINE void create_mesh_vbo(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ GLuint & V_vbo_id,
+ GLuint & F_vbo_id);
+
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigen Matrix of face (triangle) indices
+ // N #V by 3 eigen Matrix of mesh vertex 3D normals
+ // Outputs:
+ // V_vbo_id buffer id for vertex positions
+ // F_vbo_id buffer id for face indices
+ // N_vbo_id buffer id for vertex positions
+ IGL_INLINE void create_mesh_vbo(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ GLuint & V_vbo_id,
+ GLuint & F_vbo_id,
+ GLuint & N_vbo_id);
+ }
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "create_mesh_vbo.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/create_shader_program.cpp b/xs/src/igl/opengl/create_shader_program.cpp
new file mode 100644
index 000000000..6c4b31a2f
--- /dev/null
+++ b/xs/src/igl/opengl/create_shader_program.cpp
@@ -0,0 +1,141 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "create_shader_program.h"
+
+#include "load_shader.h"
+#include "print_program_info_log.h"
+#include <iostream>
+#include <cstdio>
+
+IGL_INLINE bool igl::opengl::create_shader_program(
+ const std::string & geom_source,
+ const std::string & vert_source,
+ const std::string & frag_source,
+ const std::map<std::string,GLuint> & attrib,
+ GLuint & id)
+{
+ using namespace std;
+ if(vert_source == "" && frag_source == "")
+ {
+ cerr<<
+ "create_shader_program() could not create shader program,"
+ " both .vert and .frag source given were empty"<<endl;
+ return false;
+ }
+
+ // create program
+ id = glCreateProgram();
+ if(id == 0)
+ {
+ cerr<<"create_shader_program() could not create shader program."<<endl;
+ return false;
+ }
+ GLuint g = 0,f = 0,v = 0;
+
+ if(geom_source != "")
+ {
+ // load vertex shader
+ g = igl::opengl::load_shader(geom_source.c_str(),GL_GEOMETRY_SHADER);
+ if(g == 0)
+ {
+ cerr<<"geometry shader failed to compile."<<endl;
+ return false;
+ }
+ glAttachShader(id,g);
+ }
+
+ if(vert_source != "")
+ {
+ // load vertex shader
+ v = igl::opengl::load_shader(vert_source.c_str(),GL_VERTEX_SHADER);
+ if(v == 0)
+ {
+ cerr<<"vertex shader failed to compile."<<endl;
+ return false;
+ }
+ glAttachShader(id,v);
+ }
+
+ if(frag_source != "")
+ {
+ // load fragment shader
+ f = igl::opengl::load_shader(frag_source.c_str(),GL_FRAGMENT_SHADER);
+ if(f == 0)
+ {
+ cerr<<"fragment shader failed to compile."<<endl;
+ return false;
+ }
+ glAttachShader(id,f);
+ }
+
+ // loop over attributes
+ for(
+ std::map<std::string,GLuint>::const_iterator ait = attrib.begin();
+ ait != attrib.end();
+ ait++)
+ {
+ glBindAttribLocation(
+ id,
+ (*ait).second,
+ (*ait).first.c_str());
+ }
+ // Link program
+ glLinkProgram(id);
+ const auto & detach = [&id](const GLuint shader)
+ {
+ if(shader)
+ {
+ glDetachShader(id,shader);
+ glDeleteShader(shader);
+ }
+ };
+ detach(g);
+ detach(f);
+ detach(v);
+
+ // print log if any
+ igl::opengl::print_program_info_log(id);
+
+ return true;
+}
+
+IGL_INLINE bool igl::opengl::create_shader_program(
+ const std::string & vert_source,
+ const std::string & frag_source,
+ const std::map<std::string,GLuint> & attrib,
+ GLuint & prog_id)
+{
+ return create_shader_program("",vert_source,frag_source,attrib,prog_id);
+}
+
+
+IGL_INLINE GLuint igl::opengl::create_shader_program(
+ const std::string & geom_source,
+ const std::string & vert_source,
+ const std::string & frag_source,
+ const std::map<std::string,GLuint> & attrib)
+{
+ GLuint prog_id = 0;
+ create_shader_program(geom_source,vert_source,frag_source,attrib,prog_id);
+ return prog_id;
+}
+
+IGL_INLINE GLuint igl::opengl::create_shader_program(
+ const std::string & vert_source,
+ const std::string & frag_source,
+ const std::map<std::string,GLuint> & attrib)
+{
+ GLuint prog_id = 0;
+ create_shader_program(vert_source,frag_source,attrib,prog_id);
+ return prog_id;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
+
diff --git a/xs/src/igl/opengl/create_shader_program.h b/xs/src/igl/opengl/create_shader_program.h
new file mode 100644
index 000000000..5dfdc701d
--- /dev/null
+++ b/xs/src/igl/opengl/create_shader_program.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_CREATE_SHADER_PROGRAM_H
+#define IGL_OPENGL_CREATE_SHADER_PROGRAM_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <string>
+#include <map>
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Create a shader program with a vertex and fragments shader loading from
+ // source strings and vertex attributes assigned from a map before linking the
+ // shaders to the program, making it ready to use with glUseProgram(id)
+ // Inputs:
+ // geom_source string containing source code of geometry shader (can be
+ // "" to mean use default pass-through)
+ // vert_source string containing source code of vertex shader
+ // frag_source string containing source code of fragment shader
+ // attrib map containing table of vertex attribute strings add their
+ // correspondingly ids (generated previously using glBindAttribLocation)
+ // Outputs:
+ // id index id of created shader, set to 0 on error
+ // Returns true on success, false on error
+ //
+ // Note: Caller is responsible for making sure that current value of id is not
+ // leaking a shader (since it will be overwritten)
+ //
+ // See also: destroy_shader_program
+ IGL_INLINE bool create_shader_program(
+ const std::string &geom_source,
+ const std::string &vert_source,
+ const std::string &frag_source,
+ const std::map<std::string,GLuint> &attrib,
+ GLuint & id);
+ IGL_INLINE bool create_shader_program(
+ const std::string &vert_source,
+ const std::string &frag_source,
+ const std::map<std::string,GLuint> &attrib,
+ GLuint & id);
+ IGL_INLINE GLuint create_shader_program(
+ const std::string & geom_source,
+ const std::string & vert_source,
+ const std::string & frag_source,
+ const std::map<std::string,GLuint> &attrib);
+ IGL_INLINE GLuint create_shader_program(
+ const std::string & vert_source,
+ const std::string & frag_source,
+ const std::map<std::string,GLuint> &attrib);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "create_shader_program.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/create_vector_vbo.cpp b/xs/src/igl/opengl/create_vector_vbo.cpp
new file mode 100644
index 000000000..8690359b7
--- /dev/null
+++ b/xs/src/igl/opengl/create_vector_vbo.cpp
@@ -0,0 +1,57 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "create_vector_vbo.h"
+
+#include <cassert>
+
+// http://www.songho.ca/opengl/gl_vbo.html#create
+template <typename T>
+IGL_INLINE void igl::opengl::create_vector_vbo(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & V,
+ GLuint & V_vbo_id)
+{
+ //// Expects that input is list of 3D vectors along rows
+ //assert(V.cols() == 3);
+
+ // Generate Buffers
+ glGenBuffers(1,&V_vbo_id);
+ // Bind Buffers
+ glBindBuffer(GL_ARRAY_BUFFER,V_vbo_id);
+ // Copy data to buffers
+ // We expect a matrix with each vertex position on a row, we then want to
+ // pass this data to OpenGL reading across rows (row-major)
+ if(V.Options & Eigen::RowMajor)
+ {
+ glBufferData(
+ GL_ARRAY_BUFFER,
+ sizeof(T)*V.size(),
+ V.data(),
+ GL_STATIC_DRAW);
+ }else
+ {
+ // Create temporary copy of transpose
+ Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> VT = V.transpose();
+ // If its column major then we need to temporarily store a transpose
+ glBufferData(
+ GL_ARRAY_BUFFER,
+ sizeof(T)*V.size(),
+ VT.data(),
+ GL_STATIC_DRAW);
+ }
+ // bind with 0, so, switch back to normal pointer operation
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::opengl::create_vector_vbo<int>(Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, unsigned int&);
+// generated by autoexplicit.sh
+template void igl::opengl::create_vector_vbo<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, unsigned int&);
+#endif
+
diff --git a/xs/src/igl/opengl/create_vector_vbo.h b/xs/src/igl/opengl/create_vector_vbo.h
new file mode 100644
index 000000000..757c1a199
--- /dev/null
+++ b/xs/src/igl/opengl/create_vector_vbo.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_CREATE_VECTOR_VBO_H
+#define IGL_OPENGL_CREATE_VECTOR_VBO_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <Eigen/Core>
+
+// Create a VBO (Vertex Buffer Object) for a list of vectors:
+// GL_ARRAY_BUFFER for the vectors (V)
+namespace igl
+{
+ namespace opengl
+ {
+ // Templates:
+ // T should be a eigen matrix primitive type like int or double
+ // Inputs:
+ // V m by n eigen Matrix of type T values
+ // Outputs:
+ // V_vbo_id buffer id for vectors
+ //
+ template <typename T>
+ IGL_INLINE void create_vector_vbo(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & V,
+ GLuint & V_vbo_id);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "create_vector_vbo.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/destroy_shader_program.cpp b/xs/src/igl/opengl/destroy_shader_program.cpp
new file mode 100644
index 000000000..2ceace7c2
--- /dev/null
+++ b/xs/src/igl/opengl/destroy_shader_program.cpp
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "destroy_shader_program.h"
+#include "report_gl_error.h"
+#include <cstdio>
+
+IGL_INLINE bool igl::opengl::destroy_shader_program(const GLuint id)
+{
+ // Don't try to destroy id == 0 (no shader program)
+ if(id == 0)
+ {
+ fprintf(stderr,"Error: destroy_shader_program() id = %d"
+ " but must should be positive\n",id);
+ return false;
+ }
+ // Get each attached shader one by one and detach and delete it
+ GLsizei count;
+ // shader id
+ GLuint s;
+ do
+ {
+ // Try to get at most *1* attached shader
+ glGetAttachedShaders(id,1,&count,&s);
+ GLenum err = igl::opengl::report_gl_error();
+ if (GL_NO_ERROR != err)
+ {
+ return false;
+ }
+ // Check that we actually got *1*
+ if(count == 1)
+ {
+ // Detach and delete this shader
+ glDetachShader(id,s);
+ glDeleteShader(s);
+ }
+ }while(count > 0);
+ // Now that all of the shaders are gone we can just delete the program
+ glDeleteProgram(id);
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
+
diff --git a/xs/src/igl/opengl/destroy_shader_program.h b/xs/src/igl/opengl/destroy_shader_program.h
new file mode 100644
index 000000000..5d53d8c3e
--- /dev/null
+++ b/xs/src/igl/opengl/destroy_shader_program.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_DESTROY_SHADER_PROGRAM_H
+#define IGL_OPENGL_DESTROY_SHADER_PROGRAM_H
+#include "../igl_inline.h"
+#include "gl.h"
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Properly destroy a shader program. Detach and delete each of its shaders
+ // and delete it
+ // Inputs:
+ // id index id of created shader, set to 0 on error
+ // Returns true on success, false on error
+ //
+ // Note: caller is responsible for making sure he doesn't foolishly continue
+ // to use id as if it still contains a program
+ //
+ // See also: create_shader_program
+ IGL_INLINE bool destroy_shader_program(const GLuint id);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "destroy_shader_program.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/gl.h b/xs/src/igl/opengl/gl.h
new file mode 100644
index 000000000..fc037c198
--- /dev/null
+++ b/xs/src/igl/opengl/gl.h
@@ -0,0 +1,25 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013, 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GL_H
+#define IGL_OPENGL_GL_H
+
+#ifdef IGL_OPENGL2_GL_H
+# error "igl/opengl2/gl.h already included"
+#endif
+
+// Always use this:
+// #include "gl.h"
+// Instead of:
+// #include <OpenGL/gl3.h>
+// or
+// #include <GL/gl.h>
+//
+
+#include <glad/glad.h>
+
+#endif
diff --git a/xs/src/igl/opengl/gl_type_size.cpp b/xs/src/igl/opengl/gl_type_size.cpp
new file mode 100644
index 000000000..0fd02bf05
--- /dev/null
+++ b/xs/src/igl/opengl/gl_type_size.cpp
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "gl_type_size.h"
+#include <cassert>
+
+IGL_INLINE int igl::opengl::gl_type_size(const GLenum type)
+{
+ switch(type)
+ {
+ case GL_DOUBLE:
+ return 8;
+ break;
+ case GL_FLOAT:
+ return 4;
+ break;
+ case GL_INT:
+ return 4;
+ break;
+ default:
+ // should handle all other GL_[types]
+ assert(false && "Implementation incomplete.");
+ break;
+ }
+ return -1;
+}
diff --git a/xs/src/igl/opengl/gl_type_size.h b/xs/src/igl/opengl/gl_type_size.h
new file mode 100644
index 000000000..a74119549
--- /dev/null
+++ b/xs/src/igl/opengl/gl_type_size.h
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GL_TYPE_SIZE_H
+#define IGL_OPENGL_GL_TYPE_SIZE_H
+#include "../igl_inline.h"
+#include "gl.h"
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Return the number of bytes for a given OpenGL type // Inputs:
+ // type enum value of opengl type
+ // Returns size in bytes of type
+ IGL_INLINE int gl_type_size(const GLenum type);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "gl_type_size.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/glfw/Viewer.cpp b/xs/src/igl/opengl/glfw/Viewer.cpp
new file mode 100644
index 000000000..76d1604a0
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/Viewer.cpp
@@ -0,0 +1,950 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "Viewer.h"
+
+#include <chrono>
+#include <thread>
+
+#include <Eigen/LU>
+
+#include "../gl.h"
+#include <GLFW/glfw3.h>
+
+#include <cmath>
+#include <cstdio>
+#include <sstream>
+#include <iomanip>
+#include <iostream>
+#include <fstream>
+#include <algorithm>
+#include <limits>
+#include <cassert>
+
+#include <igl/project.h>
+#include <igl/get_seconds.h>
+#include <igl/readOBJ.h>
+#include <igl/readOFF.h>
+#include <igl/adjacency_list.h>
+#include <igl/writeOBJ.h>
+#include <igl/writeOFF.h>
+#include <igl/massmatrix.h>
+#include <igl/file_dialog_open.h>
+#include <igl/file_dialog_save.h>
+#include <igl/quat_mult.h>
+#include <igl/axis_angle_to_quat.h>
+#include <igl/trackball.h>
+#include <igl/two_axis_valuator_fixed_up.h>
+#include <igl/snap_to_canonical_view_quat.h>
+#include <igl/unproject.h>
+#include <igl/serialize.h>
+
+// Internal global variables used for glfw event handling
+static igl::opengl::glfw::Viewer * __viewer;
+static double highdpi = 1;
+static double scroll_x = 0;
+static double scroll_y = 0;
+
+static void glfw_mouse_press(GLFWwindow* window, int button, int action, int modifier)
+{
+
+ igl::opengl::glfw::Viewer::MouseButton mb;
+
+ if (button == GLFW_MOUSE_BUTTON_1)
+ mb = igl::opengl::glfw::Viewer::MouseButton::Left;
+ else if (button == GLFW_MOUSE_BUTTON_2)
+ mb = igl::opengl::glfw::Viewer::MouseButton::Right;
+ else //if (button == GLFW_MOUSE_BUTTON_3)
+ mb = igl::opengl::glfw::Viewer::MouseButton::Middle;
+
+ if (action == GLFW_PRESS)
+ __viewer->mouse_down(mb,modifier);
+ else
+ __viewer->mouse_up(mb,modifier);
+}
+
+static void glfw_error_callback(int error, const char* description)
+{
+ fputs(description, stderr);
+}
+
+static void glfw_char_mods_callback(GLFWwindow* window, unsigned int codepoint, int modifier)
+{
+ __viewer->key_pressed(codepoint, modifier);
+}
+
+static void glfw_key_callback(GLFWwindow* window, int key, int scancode, int action, int modifier)
+{
+ if (key == GLFW_KEY_ESCAPE && action == GLFW_PRESS)
+ glfwSetWindowShouldClose(window, GL_TRUE);
+
+ if (action == GLFW_PRESS)
+ __viewer->key_down(key, modifier);
+ else if(action == GLFW_RELEASE)
+ __viewer->key_up(key, modifier);
+}
+
+static void glfw_window_size(GLFWwindow* window, int width, int height)
+{
+ int w = width*highdpi;
+ int h = height*highdpi;
+
+ __viewer->post_resize(w, h);
+
+}
+
+static void glfw_mouse_move(GLFWwindow* window, double x, double y)
+{
+ __viewer->mouse_move(x*highdpi, y*highdpi);
+}
+
+static void glfw_mouse_scroll(GLFWwindow* window, double x, double y)
+{
+ using namespace std;
+ scroll_x += x;
+ scroll_y += y;
+
+ __viewer->mouse_scroll(y);
+}
+
+static void glfw_drop_callback(GLFWwindow *window,int count,const char **filenames)
+{
+}
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+
+ IGL_INLINE int Viewer::launch(bool resizable,bool fullscreen)
+ {
+ // TODO return values are being ignored...
+ launch_init(resizable,fullscreen);
+ launch_rendering(true);
+ launch_shut();
+ return EXIT_SUCCESS;
+ }
+
+ IGL_INLINE int Viewer::launch_init(bool resizable,bool fullscreen)
+ {
+ glfwSetErrorCallback(glfw_error_callback);
+ if (!glfwInit())
+ {
+ return EXIT_FAILURE;
+ }
+ glfwWindowHint(GLFW_SAMPLES, 8);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3);
+ #ifdef __APPLE__
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+ #endif
+ if(fullscreen)
+ {
+ GLFWmonitor *monitor = glfwGetPrimaryMonitor();
+ const GLFWvidmode *mode = glfwGetVideoMode(monitor);
+ window = glfwCreateWindow(mode->width,mode->height,"libigl viewer",monitor,nullptr);
+ }
+ else
+ {
+ if (core.viewport.tail<2>().any()) {
+ window = glfwCreateWindow(core.viewport(2),core.viewport(3),"libigl viewer",nullptr,nullptr);
+ } else {
+ window = glfwCreateWindow(1280,800,"libigl viewer",nullptr,nullptr);
+ }
+ }
+ if (!window)
+ {
+ glfwTerminate();
+ return EXIT_FAILURE;
+ }
+ glfwMakeContextCurrent(window);
+ // Load OpenGL and its extensions
+ if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
+ {
+ printf("Failed to load OpenGL and its extensions\n");
+ return(-1);
+ }
+ #if defined(DEBUG) || defined(_DEBUG)
+ printf("OpenGL Version %d.%d loaded\n", GLVersion.major, GLVersion.minor);
+ int major, minor, rev;
+ major = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR);
+ minor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR);
+ rev = glfwGetWindowAttrib(window, GLFW_CONTEXT_REVISION);
+ printf("OpenGL version received: %d.%d.%d\n", major, minor, rev);
+ printf("Supported OpenGL is %s\n", (const char*)glGetString(GL_VERSION));
+ printf("Supported GLSL is %s\n", (const char*)glGetString(GL_SHADING_LANGUAGE_VERSION));
+ #endif
+ glfwSetInputMode(window,GLFW_CURSOR,GLFW_CURSOR_NORMAL);
+ // Initialize FormScreen
+ __viewer = this;
+ // Register callbacks
+ glfwSetKeyCallback(window, glfw_key_callback);
+ glfwSetCursorPosCallback(window,glfw_mouse_move);
+ glfwSetWindowSizeCallback(window,glfw_window_size);
+ glfwSetMouseButtonCallback(window,glfw_mouse_press);
+ glfwSetScrollCallback(window,glfw_mouse_scroll);
+ glfwSetCharModsCallback(window,glfw_char_mods_callback);
+ glfwSetDropCallback(window,glfw_drop_callback);
+ // Handle retina displays (windows and mac)
+ int width, height;
+ glfwGetFramebufferSize(window, &width, &height);
+ int width_window, height_window;
+ glfwGetWindowSize(window, &width_window, &height_window);
+ highdpi = width/width_window;
+ glfw_window_size(window,width_window,height_window);
+ //opengl.init();
+ core.align_camera_center(data().V,data().F);
+ // Initialize IGL viewer
+ init();
+ return EXIT_SUCCESS;
+ }
+
+
+
+ IGL_INLINE bool Viewer::launch_rendering(bool loop)
+ {
+ // glfwMakeContextCurrent(window);
+ // Rendering loop
+ const int num_extra_frames = 5;
+ int frame_counter = 0;
+ while (!glfwWindowShouldClose(window))
+ {
+ double tic = get_seconds();
+ draw();
+ glfwSwapBuffers(window);
+ if(core.is_animating || frame_counter++ < num_extra_frames)
+ {
+ glfwPollEvents();
+ // In microseconds
+ double duration = 1000000.*(get_seconds()-tic);
+ const double min_duration = 1000000./core.animation_max_fps;
+ if(duration<min_duration)
+ {
+ std::this_thread::sleep_for(std::chrono::microseconds((int)(min_duration-duration)));
+ }
+ }
+ else
+ {
+ glfwWaitEvents();
+ frame_counter = 0;
+ }
+ if (!loop)
+ return !glfwWindowShouldClose(window);
+ }
+ return EXIT_SUCCESS;
+ }
+
+ IGL_INLINE void Viewer::launch_shut()
+ {
+ for(auto & data : data_list)
+ {
+ data.meshgl.free();
+ }
+ core.shut();
+ shutdown_plugins();
+ glfwDestroyWindow(window);
+ glfwTerminate();
+ return;
+ }
+
+ IGL_INLINE void Viewer::init()
+ {
+ core.init();
+
+ if (callback_init)
+ if (callback_init(*this))
+ return;
+
+ init_plugins();
+ }
+
+ IGL_INLINE void Viewer::init_plugins()
+ {
+ // Init all plugins
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ {
+ plugins[i]->init(this);
+ }
+ }
+
+ IGL_INLINE void Viewer::shutdown_plugins()
+ {
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ {
+ plugins[i]->shutdown();
+ }
+ }
+
+ IGL_INLINE Viewer::Viewer():
+ data_list(1),
+ selected_data_index(0),
+ next_data_id(1)
+ {
+ window = nullptr;
+ data_list.front().id = 0;
+
+ // Temporary variables initialization
+ down = false;
+ hack_never_moved = true;
+ scroll_position = 0.0f;
+
+ // Per face
+ data().set_face_based(false);
+
+ // C-style callbacks
+ callback_init = nullptr;
+ callback_pre_draw = nullptr;
+ callback_post_draw = nullptr;
+ callback_mouse_down = nullptr;
+ callback_mouse_up = nullptr;
+ callback_mouse_move = nullptr;
+ callback_mouse_scroll = nullptr;
+ callback_key_down = nullptr;
+ callback_key_up = nullptr;
+
+ callback_init_data = nullptr;
+ callback_pre_draw_data = nullptr;
+ callback_post_draw_data = nullptr;
+ callback_mouse_down_data = nullptr;
+ callback_mouse_up_data = nullptr;
+ callback_mouse_move_data = nullptr;
+ callback_mouse_scroll_data = nullptr;
+ callback_key_down_data = nullptr;
+ callback_key_up_data = nullptr;
+
+#ifndef IGL_VIEWER_VIEWER_QUIET
+ const std::string usage(R"(igl::opengl::glfw::Viewer usage:
+ [drag] Rotate scene
+ A,a Toggle animation (tight draw loop)
+ F,f Toggle face based
+ I,i Toggle invert normals
+ L,l Toggle wireframe
+ O,o Toggle orthographic/perspective projection
+ T,t Toggle filled faces
+ Z Snap to canonical view
+ [,] Toggle between rotation control types (trackball, two-axis
+ valuator with fixed up, 2D mode with no rotation))
+ <,> Toggle between models
+ ; Toggle vertex labels
+ : Toggle face labels)"
+);
+ std::cout<<usage<<std::endl;
+#endif
+ }
+
+ IGL_INLINE Viewer::~Viewer()
+ {
+ }
+
+ IGL_INLINE bool Viewer::load_mesh_from_file(
+ const std::string & mesh_file_name_string)
+ {
+
+ // first try to load it with a plugin
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ {
+ if (plugins[i]->load(mesh_file_name_string))
+ {
+ return true;
+ }
+ }
+
+ // Create new data slot and set to selected
+ if(!(data().F.rows() == 0 && data().V.rows() == 0))
+ {
+ append_mesh();
+ }
+ data().clear();
+
+ size_t last_dot = mesh_file_name_string.rfind('.');
+ if (last_dot == std::string::npos)
+ {
+ std::cerr<<"Error: No file extension found in "<<
+ mesh_file_name_string<<std::endl;
+ return false;
+ }
+
+ std::string extension = mesh_file_name_string.substr(last_dot+1);
+
+ if (extension == "off" || extension =="OFF")
+ {
+ Eigen::MatrixXd V;
+ Eigen::MatrixXi F;
+ if (!igl::readOFF(mesh_file_name_string, V, F))
+ return false;
+ data().set_mesh(V,F);
+ }
+ else if (extension == "obj" || extension =="OBJ")
+ {
+ Eigen::MatrixXd corner_normals;
+ Eigen::MatrixXi fNormIndices;
+
+ Eigen::MatrixXd UV_V;
+ Eigen::MatrixXi UV_F;
+ Eigen::MatrixXd V;
+ Eigen::MatrixXi F;
+
+ if (!(
+ igl::readOBJ(
+ mesh_file_name_string,
+ V, UV_V, corner_normals, F, UV_F, fNormIndices)))
+ {
+ return false;
+ }
+
+ data().set_mesh(V,F);
+ data().set_uv(UV_V,UV_F);
+
+ }
+ else
+ {
+ // unrecognized file type
+ printf("Error: %s is not a recognized file type.\n",extension.c_str());
+ return false;
+ }
+
+ data().compute_normals();
+ data().uniform_colors(Eigen::Vector3d(51.0/255.0,43.0/255.0,33.3/255.0),
+ Eigen::Vector3d(255.0/255.0,228.0/255.0,58.0/255.0),
+ Eigen::Vector3d(255.0/255.0,235.0/255.0,80.0/255.0));
+
+ // Alec: why?
+ if (data().V_uv.rows() == 0)
+ {
+ data().grid_texture();
+ }
+
+ core.align_camera_center(data().V,data().F);
+
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if (plugins[i]->post_load())
+ return true;
+
+ return true;
+ }
+
+ IGL_INLINE bool Viewer::save_mesh_to_file(
+ const std::string & mesh_file_name_string)
+ {
+ // first try to load it with a plugin
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if (plugins[i]->save(mesh_file_name_string))
+ return true;
+
+ size_t last_dot = mesh_file_name_string.rfind('.');
+ if (last_dot == std::string::npos)
+ {
+ // No file type determined
+ std::cerr<<"Error: No file extension found in "<<
+ mesh_file_name_string<<std::endl;
+ return false;
+ }
+ std::string extension = mesh_file_name_string.substr(last_dot+1);
+ if (extension == "off" || extension =="OFF")
+ {
+ return igl::writeOFF(
+ mesh_file_name_string,data().V,data().F);
+ }
+ else if (extension == "obj" || extension =="OBJ")
+ {
+ Eigen::MatrixXd corner_normals;
+ Eigen::MatrixXi fNormIndices;
+
+ Eigen::MatrixXd UV_V;
+ Eigen::MatrixXi UV_F;
+
+ return igl::writeOBJ(mesh_file_name_string,
+ data().V,
+ data().F,
+ corner_normals, fNormIndices, UV_V, UV_F);
+ }
+ else
+ {
+ // unrecognized file type
+ printf("Error: %s is not a recognized file type.\n",extension.c_str());
+ return false;
+ }
+ return true;
+ }
+
+ IGL_INLINE bool Viewer::key_pressed(unsigned int unicode_key,int modifiers)
+ {
+ if (callback_key_pressed)
+ if (callback_key_pressed(*this,unicode_key,modifiers))
+ return true;
+
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ {
+ if (plugins[i]->key_pressed(unicode_key, modifiers))
+ {
+ return true;
+ }
+ }
+
+ switch(unicode_key)
+ {
+ case 'A':
+ case 'a':
+ {
+ core.is_animating = !core.is_animating;
+ return true;
+ }
+ case 'F':
+ case 'f':
+ {
+ data().set_face_based(!data().face_based);
+ return true;
+ }
+ case 'I':
+ case 'i':
+ {
+ data().dirty |= MeshGL::DIRTY_NORMAL;
+ data().invert_normals = !data().invert_normals;
+ return true;
+ }
+ case 'L':
+ case 'l':
+ {
+ data().show_lines = !data().show_lines;
+ return true;
+ }
+ case 'O':
+ case 'o':
+ {
+ core.orthographic = !core.orthographic;
+ return true;
+ }
+ case 'T':
+ case 't':
+ {
+ data().show_faces = !data().show_faces;
+ return true;
+ }
+ case 'Z':
+ {
+ snap_to_canonical_quaternion();
+ return true;
+ }
+ case '[':
+ case ']':
+ {
+ if(core.rotation_type == ViewerCore::ROTATION_TYPE_TRACKBALL)
+ core.set_rotation_type(ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP);
+ else
+ core.set_rotation_type(ViewerCore::ROTATION_TYPE_TRACKBALL);
+
+ return true;
+ }
+ case '<':
+ case '>':
+ {
+ selected_data_index =
+ (selected_data_index + data_list.size() + (unicode_key=='>'?1:-1))%data_list.size();
+ return true;
+ }
+ case ';':
+ data().show_vertid = !data().show_vertid;
+ return true;
+ case ':':
+ data().show_faceid = !data().show_faceid;
+ return true;
+ default: break;//do nothing
+ }
+ return false;
+ }
+
+ IGL_INLINE bool Viewer::key_down(int key,int modifiers)
+ {
+ if (callback_key_down)
+ if (callback_key_down(*this,key,modifiers))
+ return true;
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if (plugins[i]->key_down(key, modifiers))
+ return true;
+ return false;
+ }
+
+ IGL_INLINE bool Viewer::key_up(int key,int modifiers)
+ {
+ if (callback_key_up)
+ if (callback_key_up(*this,key,modifiers))
+ return true;
+
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if (plugins[i]->key_up(key, modifiers))
+ return true;
+
+ return false;
+ }
+
+ IGL_INLINE bool Viewer::mouse_down(MouseButton button,int modifier)
+ {
+ // Remember mouse location at down even if used by callback/plugin
+ down_mouse_x = current_mouse_x;
+ down_mouse_y = current_mouse_y;
+
+ if (callback_mouse_down)
+ if (callback_mouse_down(*this,static_cast<int>(button),modifier))
+ return true;
+
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if(plugins[i]->mouse_down(static_cast<int>(button),modifier))
+ return true;
+
+ down = true;
+
+ down_translation = core.camera_translation;
+
+
+ // Initialization code for the trackball
+ Eigen::RowVector3d center;
+ if (data().V.rows() == 0)
+ {
+ center << 0,0,0;
+ }else
+ {
+ center = data().V.colwise().sum()/data().V.rows();
+ }
+
+ Eigen::Vector3f coord =
+ igl::project(
+ Eigen::Vector3f(center(0),center(1),center(2)),
+ core.view,
+ core.proj,
+ core.viewport);
+ down_mouse_z = coord[2];
+ down_rotation = core.trackball_angle;
+
+ mouse_mode = MouseMode::Rotation;
+
+ switch (button)
+ {
+ case MouseButton::Left:
+ if (core.rotation_type == ViewerCore::ROTATION_TYPE_NO_ROTATION) {
+ mouse_mode = MouseMode::Translation;
+ } else {
+ mouse_mode = MouseMode::Rotation;
+ }
+ break;
+
+ case MouseButton::Right:
+ mouse_mode = MouseMode::Translation;
+ break;
+
+ default:
+ mouse_mode = MouseMode::None;
+ break;
+ }
+
+ return true;
+ }
+
+ IGL_INLINE bool Viewer::mouse_up(MouseButton button,int modifier)
+ {
+ down = false;
+
+ if (callback_mouse_up)
+ if (callback_mouse_up(*this,static_cast<int>(button),modifier))
+ return true;
+
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if(plugins[i]->mouse_up(static_cast<int>(button),modifier))
+ return true;
+
+ mouse_mode = MouseMode::None;
+
+ return true;
+ }
+
+ IGL_INLINE bool Viewer::mouse_move(int mouse_x,int mouse_y)
+ {
+ if(hack_never_moved)
+ {
+ down_mouse_x = mouse_x;
+ down_mouse_y = mouse_y;
+ hack_never_moved = false;
+ }
+ current_mouse_x = mouse_x;
+ current_mouse_y = mouse_y;
+
+ if (callback_mouse_move)
+ if (callback_mouse_move(*this,mouse_x,mouse_y))
+ return true;
+
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if (plugins[i]->mouse_move(mouse_x, mouse_y))
+ return true;
+
+ if (down)
+ {
+ switch (mouse_mode)
+ {
+ case MouseMode::Rotation:
+ {
+ switch(core.rotation_type)
+ {
+ default:
+ assert(false && "Unknown rotation type");
+ case ViewerCore::ROTATION_TYPE_NO_ROTATION:
+ break;
+ case ViewerCore::ROTATION_TYPE_TRACKBALL:
+ igl::trackball(
+ core.viewport(2),
+ core.viewport(3),
+ 2.0f,
+ down_rotation,
+ down_mouse_x,
+ down_mouse_y,
+ mouse_x,
+ mouse_y,
+ core.trackball_angle);
+ break;
+ case ViewerCore::ROTATION_TYPE_TWO_AXIS_VALUATOR_FIXED_UP:
+ igl::two_axis_valuator_fixed_up(
+ core.viewport(2),core.viewport(3),
+ 2.0,
+ down_rotation,
+ down_mouse_x, down_mouse_y, mouse_x, mouse_y,
+ core.trackball_angle);
+ break;
+ }
+ //Eigen::Vector4f snapq = core.trackball_angle;
+
+ break;
+ }
+
+ case MouseMode::Translation:
+ {
+ //translation
+ Eigen::Vector3f pos1 = igl::unproject(Eigen::Vector3f(mouse_x, core.viewport[3] - mouse_y, down_mouse_z), core.view, core.proj, core.viewport);
+ Eigen::Vector3f pos0 = igl::unproject(Eigen::Vector3f(down_mouse_x, core.viewport[3] - down_mouse_y, down_mouse_z), core.view, core.proj, core.viewport);
+
+ Eigen::Vector3f diff = pos1 - pos0;
+ core.camera_translation = down_translation + Eigen::Vector3f(diff[0],diff[1],diff[2]);
+
+ break;
+ }
+ case MouseMode::Zoom:
+ {
+ float delta = 0.001f * (mouse_x - down_mouse_x + mouse_y - down_mouse_y);
+ core.camera_zoom *= 1 + delta;
+ down_mouse_x = mouse_x;
+ down_mouse_y = mouse_y;
+ break;
+ }
+
+ default:
+ break;
+ }
+ }
+ return true;
+ }
+
+ IGL_INLINE bool Viewer::mouse_scroll(float delta_y)
+ {
+ scroll_position += delta_y;
+
+ if (callback_mouse_scroll)
+ if (callback_mouse_scroll(*this,delta_y))
+ return true;
+
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ if (plugins[i]->mouse_scroll(delta_y))
+ return true;
+
+ // Only zoom if there's actually a change
+ if(delta_y != 0)
+ {
+ float mult = (1.0+((delta_y>0)?1.:-1.)*0.05);
+ const float min_zoom = 0.1f;
+ core.camera_zoom = (core.camera_zoom * mult > min_zoom ? core.camera_zoom * mult : min_zoom);
+ }
+ return true;
+ }
+
+ IGL_INLINE bool Viewer::load_scene()
+ {
+ std::string fname = igl::file_dialog_open();
+ if(fname.length() == 0)
+ return false;
+ return load_scene(fname);
+ }
+
+ IGL_INLINE bool Viewer::load_scene(std::string fname)
+ {
+ igl::deserialize(core,"Core",fname.c_str());
+ igl::deserialize(data(),"Data",fname.c_str());
+ return true;
+ }
+
+ IGL_INLINE bool Viewer::save_scene()
+ {
+ std::string fname = igl::file_dialog_save();
+ if (fname.length() == 0)
+ return false;
+ return save_scene(fname);
+ }
+
+ IGL_INLINE bool Viewer::save_scene(std::string fname)
+ {
+ igl::serialize(core,"Core",fname.c_str(),true);
+ igl::serialize(data(),"Data",fname.c_str());
+
+ return true;
+ }
+
+ IGL_INLINE void Viewer::draw()
+ {
+ using namespace std;
+ using namespace Eigen;
+
+ int width, height;
+ glfwGetFramebufferSize(window, &width, &height);
+
+ int width_window, height_window;
+ glfwGetWindowSize(window, &width_window, &height_window);
+
+ auto highdpi_tmp = width/width_window;
+
+ if(fabs(highdpi_tmp-highdpi)>1e-8)
+ {
+ post_resize(width, height);
+ highdpi=highdpi_tmp;
+ }
+
+ core.clear_framebuffers();
+ if (callback_pre_draw)
+ {
+ if (callback_pre_draw(*this))
+ {
+ return;
+ }
+ }
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ {
+ if (plugins[i]->pre_draw())
+ {
+ return;
+ }
+ }
+ for(int i = 0;i<data_list.size();i++)
+ {
+ core.draw(data_list[i]);
+ }
+ if (callback_post_draw)
+ {
+ if (callback_post_draw(*this))
+ {
+ return;
+ }
+ }
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ {
+ if (plugins[i]->post_draw())
+ {
+ break;
+ }
+ }
+ }
+
+ IGL_INLINE void Viewer::resize(int w,int h)
+ {
+ if (window) {
+ glfwSetWindowSize(window, w/highdpi, h/highdpi);
+ }
+ post_resize(w, h);
+ }
+
+ IGL_INLINE void Viewer::post_resize(int w,int h)
+ {
+ core.viewport = Eigen::Vector4f(0,0,w,h);
+ for (unsigned int i = 0; i<plugins.size(); ++i)
+ {
+ plugins[i]->post_resize(w, h);
+ }
+ }
+
+ IGL_INLINE void Viewer::snap_to_canonical_quaternion()
+ {
+ Eigen::Quaternionf snapq = this->core.trackball_angle;
+ igl::snap_to_canonical_view_quat(snapq,1.0f,this->core.trackball_angle);
+ }
+
+ IGL_INLINE void Viewer::open_dialog_load_mesh()
+ {
+ std::string fname = igl::file_dialog_open();
+
+ if (fname.length() == 0)
+ return;
+
+ this->load_mesh_from_file(fname.c_str());
+ }
+
+ IGL_INLINE void Viewer::open_dialog_save_mesh()
+ {
+ std::string fname = igl::file_dialog_save();
+
+ if(fname.length() == 0)
+ return;
+
+ this->save_mesh_to_file(fname.c_str());
+ }
+
+ IGL_INLINE ViewerData& Viewer::data()
+ {
+ assert(!data_list.empty() && "data_list should never be empty");
+ assert(
+ (selected_data_index >= 0 && selected_data_index < data_list.size()) &&
+ "selected_data_index should be in bounds");
+ return data_list[selected_data_index];
+ }
+
+ IGL_INLINE int Viewer::append_mesh()
+ {
+ assert(data_list.size() >= 1);
+
+ data_list.emplace_back();
+ selected_data_index = data_list.size()-1;
+ data_list.back().id = next_data_id++;
+ return data_list.back().id;
+ }
+
+ IGL_INLINE bool Viewer::erase_mesh(const size_t index)
+ {
+ assert((index >= 0 && index < data_list.size()) && "index should be in bounds");
+ assert(data_list.size() >= 1);
+ if(data_list.size() == 1)
+ {
+ // Cannot remove last mesh
+ return false;
+ }
+ data_list[index].meshgl.free();
+ data_list.erase(data_list.begin() + index);
+ if(selected_data_index >= index && selected_data_index>0)
+ {
+ selected_data_index--;
+ }
+ return true;
+ }
+
+ IGL_INLINE size_t Viewer::mesh_index(const int id) const {
+ for (size_t i = 0; i < data_list.size(); ++i)
+ {
+ if (data_list[i].id == id)
+ return i;
+ }
+ return 0;
+ }
+
+
+} // end namespace
+} // end namespace
+}
diff --git a/xs/src/igl/opengl/glfw/Viewer.h b/xs/src/igl/opengl/glfw/Viewer.h
new file mode 100644
index 000000000..35aa7dfa2
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/Viewer.h
@@ -0,0 +1,178 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GLFW_VIEWER_H
+#define IGL_OPENGL_GLFW_VIEWER_H
+
+#ifndef IGL_OPENGL_4
+#define IGL_OPENGL_4
+#endif
+
+#include "../../igl_inline.h"
+#include "../MeshGL.h"
+#include "../ViewerCore.h"
+#include "../ViewerData.h"
+#include "ViewerPlugin.h"
+
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+#include <vector>
+#include <string>
+#include <cstdint>
+
+#define IGL_MOD_SHIFT 0x0001
+#define IGL_MOD_CONTROL 0x0002
+#define IGL_MOD_ALT 0x0004
+#define IGL_MOD_SUPER 0x0008
+
+struct GLFWwindow;
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+ // GLFW-based mesh viewer
+ class Viewer
+ {
+ public:
+ // UI Enumerations
+ enum class MouseButton {Left, Middle, Right};
+ enum class MouseMode { None, Rotation, Zoom, Pan, Translation} mouse_mode;
+ IGL_INLINE int launch(bool resizable = true,bool fullscreen = false);
+ IGL_INLINE int launch_init(bool resizable = true,bool fullscreen = false);
+ IGL_INLINE bool launch_rendering(bool loop = true);
+ IGL_INLINE void launch_shut();
+ IGL_INLINE void init();
+ IGL_INLINE void init_plugins();
+ IGL_INLINE void shutdown_plugins();
+ Viewer();
+ ~Viewer();
+ // Mesh IO
+ IGL_INLINE bool load_mesh_from_file(const std::string & mesh_file_name);
+ IGL_INLINE bool save_mesh_to_file(const std::string & mesh_file_name);
+ // Callbacks
+ IGL_INLINE bool key_pressed(unsigned int unicode_key,int modifier);
+ IGL_INLINE bool key_down(int key,int modifier);
+ IGL_INLINE bool key_up(int key,int modifier);
+ IGL_INLINE bool mouse_down(MouseButton button,int modifier);
+ IGL_INLINE bool mouse_up(MouseButton button,int modifier);
+ IGL_INLINE bool mouse_move(int mouse_x,int mouse_y);
+ IGL_INLINE bool mouse_scroll(float delta_y);
+ // Scene IO
+ IGL_INLINE bool load_scene();
+ IGL_INLINE bool load_scene(std::string fname);
+ IGL_INLINE bool save_scene();
+ IGL_INLINE bool save_scene(std::string fname);
+ // Draw everything
+ IGL_INLINE void draw();
+ // OpenGL context resize
+ IGL_INLINE void resize(int w,int h); // explicitly set window size
+ IGL_INLINE void post_resize(int w,int h); // external resize due to user interaction
+ // Helper functions
+ IGL_INLINE void snap_to_canonical_quaternion();
+ IGL_INLINE void open_dialog_load_mesh();
+ IGL_INLINE void open_dialog_save_mesh();
+ IGL_INLINE ViewerData& data();
+
+ // Append a new "slot" for a mesh (i.e., create empty entires at the end of
+ // the data_list and opengl_state_list.
+ //
+ // Returns the id of the last appended mesh
+ //
+ // Side Effects:
+ // selected_data_index is set this newly created, last entry (i.e.,
+ // #meshes-1)
+ IGL_INLINE int append_mesh();
+
+ // Erase a mesh (i.e., its corresponding data and state entires in data_list
+ // and opengl_state_list)
+ //
+ // Inputs:
+ // index index of mesh to erase
+ // Returns whether erasure was successful <=> cannot erase last mesh
+ //
+ // Side Effects:
+ // If selected_data_index is greater than or equal to index then it is
+ // decremented
+ // Example:
+ // // Erase all mesh slots except first and clear remaining mesh
+ // viewer.selected_data_index = viewer.data_list.size()-1;
+ // while(viewer.erase_mesh(viewer.selected_data_index)){};
+ // viewer.data().clear();
+ //
+ IGL_INLINE bool erase_mesh(const size_t index);
+
+ // Retrieve mesh index from its unique identifier
+ // Returns 0 if not found
+ IGL_INLINE size_t mesh_index(const int id) const;
+
+ // Alec: I call this data_list instead of just data to avoid confusion with
+ // old "data" variable.
+ // Stores all the data that should be visualized
+ std::vector<ViewerData> data_list;
+
+ size_t selected_data_index;
+ int next_data_id;
+ GLFWwindow* window;
+ // Stores all the viewing options
+ ViewerCore core;
+ // List of registered plugins
+ std::vector<ViewerPlugin*> plugins;
+ // Temporary data stored when the mouse button is pressed
+ Eigen::Quaternionf down_rotation;
+ int current_mouse_x;
+ int current_mouse_y;
+ int down_mouse_x;
+ int down_mouse_y;
+ float down_mouse_z;
+ Eigen::Vector3f down_translation;
+ bool down;
+ bool hack_never_moved;
+ // Keep track of the global position of the scrollwheel
+ float scroll_position;
+ // C++-style functions
+ //
+ // Returns **true** if action should be cancelled.
+ std::function<bool(Viewer& viewer)> callback_init;
+ std::function<bool(Viewer& viewer)> callback_pre_draw;
+ std::function<bool(Viewer& viewer)> callback_post_draw;
+ std::function<bool(Viewer& viewer, int button, int modifier)> callback_mouse_down;
+ std::function<bool(Viewer& viewer, int button, int modifier)> callback_mouse_up;
+ std::function<bool(Viewer& viewer, int mouse_x, int mouse_y)> callback_mouse_move;
+ std::function<bool(Viewer& viewer, float delta_y)> callback_mouse_scroll;
+ std::function<bool(Viewer& viewer, unsigned int key, int modifiers)> callback_key_pressed;
+ // THESE SHOULD BE DEPRECATED:
+ std::function<bool(Viewer& viewer, unsigned int key, int modifiers)> callback_key_down;
+ std::function<bool(Viewer& viewer, unsigned int key, int modifiers)> callback_key_up;
+ // Pointers to per-callback data
+ void* callback_init_data;
+ void* callback_pre_draw_data;
+ void* callback_post_draw_data;
+ void* callback_mouse_down_data;
+ void* callback_mouse_up_data;
+ void* callback_mouse_move_data;
+ void* callback_mouse_scroll_data;
+ void* callback_key_pressed_data;
+ void* callback_key_down_data;
+ void* callback_key_up_data;
+
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ };
+
+} // end namespace
+} // end namespace
+} // end namespace
+
+#ifndef IGL_STATIC_LIBRARY
+# include "Viewer.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/glfw/ViewerPlugin.h b/xs/src/igl/opengl/glfw/ViewerPlugin.h
new file mode 100644
index 000000000..9ba7903a8
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/ViewerPlugin.h
@@ -0,0 +1,182 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GLFW_VIEWERPLUGIN_H
+#define IGL_OPENGL_GLFW_VIEWERPLUGIN_H
+
+// TODO:
+// * create plugins/skeleton.h
+// * pass time in draw function
+// * remove Preview3D from comments
+// * clean comments
+#include <string>
+#include <igl/igl_inline.h>
+#include <vector>
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+
+// Abstract class for plugins
+// All plugins MUST have this class as their parent and may implement any/all
+// the callbacks marked `virtual` here.
+//
+// /////For an example of a basic plugins see plugins/skeleton.h
+//
+// Return value of callbacks: returning true to any of the callbacks tells
+// Viewer that the event has been handled and that it should not be passed to
+// other plugins or to other internal functions of Viewer
+
+// Forward declaration of the viewer
+class Viewer;
+
+class ViewerPlugin
+{
+public:
+ IGL_INLINE ViewerPlugin()
+ {plugin_name = "dummy";}
+
+ virtual ~ViewerPlugin(){}
+
+ // This function is called when the viewer is initialized (no mesh will be loaded at this stage)
+ IGL_INLINE virtual void init(Viewer *_viewer)
+ {
+ viewer = _viewer;
+ }
+
+ // This function is called before shutdown
+ IGL_INLINE virtual void shutdown()
+ {
+ }
+
+ // This function is called before a mesh is loaded
+ IGL_INLINE virtual bool load(std::string filename)
+ {
+ return false;
+ }
+
+ // This function is called before a mesh is saved
+ IGL_INLINE virtual bool save(std::string filename)
+ {
+ return false;
+ }
+
+ // This function is called when the scene is serialized
+ IGL_INLINE virtual bool serialize(std::vector<char>& buffer) const
+ {
+ return false;
+ }
+
+ // This function is called when the scene is deserialized
+ IGL_INLINE virtual bool deserialize(const std::vector<char>& buffer)
+ {
+ return false;
+ }
+
+ // Runs immediately after a new mesh has been loaded.
+ IGL_INLINE virtual bool post_load()
+ {
+ return false;
+ }
+
+ // This function is called before the draw procedure of Preview3D
+ IGL_INLINE virtual bool pre_draw()
+ {
+ return false;
+ }
+
+ // This function is called after the draw procedure of Preview3D
+ IGL_INLINE virtual bool post_draw()
+ {
+ return false;
+ }
+
+ // This function is called after the window has been resized
+ IGL_INLINE virtual void post_resize(int w, int h)
+ {
+ }
+
+ // This function is called when the mouse button is pressed
+ // - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
+ // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
+ IGL_INLINE virtual bool mouse_down(int button, int modifier)
+ {
+ return false;
+ }
+
+ // This function is called when the mouse button is released
+ // - button can be GLUT_LEFT_BUTTON, GLUT_MIDDLE_BUTTON or GLUT_RIGHT_BUTTON
+ // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
+ IGL_INLINE virtual bool mouse_up(int button, int modifier)
+ {
+ return false;
+ }
+
+ // This function is called every time the mouse is moved
+ // - mouse_x and mouse_y are the new coordinates of the mouse pointer in screen coordinates
+ IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y)
+ {
+ return false;
+ }
+
+ // This function is called every time the scroll wheel is moved
+ // Note: this callback is not working with every glut implementation
+ IGL_INLINE virtual bool mouse_scroll(float delta_y)
+ {
+ return false;
+ }
+
+ // This function is called when a keyboard key is pressed. Unlike key_down
+ // this will reveal the actual character being sent (not just the physical
+ // key)
+ // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
+ IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers)
+ {
+ return false;
+ }
+
+ // This function is called when a keyboard key is down
+ // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
+ IGL_INLINE virtual bool key_down(int key, int modifiers)
+ {
+ return false;
+ }
+
+ // This function is called when a keyboard key is release
+ // - modifiers is a bitfield that might one or more of the following bits Preview3D::NO_KEY, Preview3D::SHIFT, Preview3D::CTRL, Preview3D::ALT;
+ IGL_INLINE virtual bool key_up(int key, int modifiers)
+ {
+ return false;
+ }
+
+ std::string plugin_name;
+protected:
+ // Pointer to the main Viewer class
+ Viewer *viewer;
+};
+
+namespace serialization
+{
+ inline void serialize(const ViewerPlugin& obj,std::vector<char>& buffer)
+ {
+ obj.serialize(buffer);
+ }
+
+ inline void deserialize(ViewerPlugin& obj,const std::vector<char>& buffer)
+ {
+ obj.deserialize(buffer);
+ }
+}
+
+}
+}
+}
+
+#endif
diff --git a/xs/src/igl/opengl/glfw/background_window.cpp b/xs/src/igl/opengl/glfw/background_window.cpp
new file mode 100644
index 000000000..964202cc2
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/background_window.cpp
@@ -0,0 +1,30 @@
+#include "background_window.h"
+
+#include <iostream>
+
+IGL_INLINE bool igl::opengl::glfw::background_window(GLFWwindow* & window)
+{
+ if(!glfwInit()) return false;
+ glfwSetErrorCallback([](int id,const char* m){std::cerr<<m<<std::endl;});
+ glfwWindowHint(GLFW_SAMPLES, 4);
+ // Use 3.2 core profile
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3);
+ glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 2);
+ glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
+ glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE);
+ // Use background window
+ glfwWindowHint(GLFW_VISIBLE, GL_FALSE);
+ window = glfwCreateWindow(1, 1,"", NULL, NULL);
+ if(!window) return false;
+ glfwMakeContextCurrent(window);
+ if (!gladLoadGLLoader((GLADloadproc) glfwGetProcAddress))
+ {
+ printf("Failed to load OpenGL and its extensions");
+ }
+ glGetError(); // pull and safely ignore unhandled errors like GL_INVALID_ENUM
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/opengl/glfw/background_window.h b/xs/src/igl/opengl/glfw/background_window.h
new file mode 100644
index 000000000..a37515b89
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/background_window.h
@@ -0,0 +1,34 @@
+#ifndef IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
+#define IGL_OPENGL_GLFW_BACKGROUND_WINDOW_H
+#include "../../igl_inline.h"
+
+#include "../gl.h"
+#include <GLFW/glfw3.h>
+
+namespace igl
+{
+ namespace opengl
+ {
+ namespace glfw
+ {
+ // Create a background window with a valid core profile opengl context
+ // set to current.
+ //
+ // After you're finished with this window you may call
+ // `glfwDestroyWindow(window)`
+ //
+ // After you're finished with glfw you should call `glfwTerminate()`
+ //
+ // Outputs:
+ // window pointer to glfw window
+ // Returns true iff success
+ IGL_INLINE bool background_window(GLFWwindow* & window);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "background_window.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/glfw/imgui/ImGuiHelpers.h b/xs/src/igl/opengl/glfw/imgui/ImGuiHelpers.h
new file mode 100644
index 000000000..892274b0f
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/imgui/ImGuiHelpers.h
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
+#define IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
+
+////////////////////////////////////////////////////////////////////////////////
+#include <imgui/imgui.h>
+#include <vector>
+#include <string>
+#include <algorithm>
+#include <functional>
+////////////////////////////////////////////////////////////////////////////////
+
+// Extend ImGui by populating its namespace directly
+//
+// Code snippets taken from there:
+// https://eliasdaler.github.io/using-imgui-with-sfml-pt2/
+namespace ImGui
+{
+
+static auto vector_getter = [](void* vec, int idx, const char** out_text)
+{
+ auto& vector = *static_cast<std::vector<std::string>*>(vec);
+ if (idx < 0 || idx >= static_cast<int>(vector.size())) { return false; }
+ *out_text = vector.at(idx).c_str();
+ return true;
+};
+
+inline bool Combo(const char* label, int* idx, std::vector<std::string>& values)
+{
+ if (values.empty()) { return false; }
+ return Combo(label, idx, vector_getter,
+ static_cast<void*>(&values), values.size());
+}
+
+inline bool Combo(const char* label, int* idx, std::function<const char *(int)> getter, int items_count)
+{
+ auto func = [](void* data, int i, const char** out_text) {
+ auto &getter = *reinterpret_cast<std::function<const char *(int)> *>(data);
+ const char *s = getter(i);
+ if (s) { *out_text = s; return true; }
+ else { return false; }
+ };
+ return Combo(label, idx, func, reinterpret_cast<void *>(&getter), items_count);
+}
+
+inline bool ListBox(const char* label, int* idx, std::vector<std::string>& values)
+{
+ if (values.empty()) { return false; }
+ return ListBox(label, idx, vector_getter,
+ static_cast<void*>(&values), values.size());
+}
+
+inline bool InputText(const char* label, std::string &str, ImGuiInputTextFlags flags = 0, ImGuiTextEditCallback callback = NULL, void* user_data = NULL)
+{
+ char buf[1024];
+ std::fill_n(buf, 1024, 0);
+ std::copy_n(str.begin(), std::min(1024, (int) str.size()), buf);
+ if (ImGui::InputText(label, buf, 1024, flags, callback, user_data))
+ {
+ str = std::string(buf);
+ return true;
+ }
+ return false;
+}
+
+} // namespace ImGui
+
+#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIHELPERS_H
diff --git a/xs/src/igl/opengl/glfw/imgui/ImGuiMenu.cpp b/xs/src/igl/opengl/glfw/imgui/ImGuiMenu.cpp
new file mode 100644
index 000000000..627e055cb
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/imgui/ImGuiMenu.cpp
@@ -0,0 +1,385 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+////////////////////////////////////////////////////////////////////////////////
+#include "ImGuiMenu.h"
+#include <igl/project.h>
+#include <imgui/imgui.h>
+#include <imgui_impl_glfw_gl3.h>
+#include <imgui_fonts_droid_sans.h>
+#include <GLFW/glfw3.h>
+#include <iostream>
+////////////////////////////////////////////////////////////////////////////////
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+namespace imgui
+{
+
+IGL_INLINE void ImGuiMenu::init(igl::opengl::glfw::Viewer *_viewer)
+{
+ ViewerPlugin::init(_viewer);
+ // Setup ImGui binding
+ if (_viewer)
+ {
+ if (context_ == nullptr)
+ {
+ context_ = ImGui::CreateContext();
+ }
+ ImGui_ImplGlfwGL3_Init(viewer->window, false);
+ ImGui::GetIO().IniFilename = nullptr;
+ ImGui::StyleColorsDark();
+ ImGuiStyle& style = ImGui::GetStyle();
+ style.FrameRounding = 5.0f;
+ reload_font();
+ }
+}
+
+IGL_INLINE void ImGuiMenu::reload_font(int font_size)
+{
+ hidpi_scaling_ = hidpi_scaling();
+ pixel_ratio_ = pixel_ratio();
+ ImGuiIO& io = ImGui::GetIO();
+ io.Fonts->Clear();
+ io.Fonts->AddFontFromMemoryCompressedTTF(droid_sans_compressed_data,
+ droid_sans_compressed_size, font_size * hidpi_scaling_);
+ io.FontGlobalScale = 1.0 / pixel_ratio_;
+}
+
+IGL_INLINE void ImGuiMenu::shutdown()
+{
+ // Cleanup
+ ImGui_ImplGlfwGL3_Shutdown();
+ ImGui::DestroyContext(context_);
+ context_ = nullptr;
+}
+
+IGL_INLINE bool ImGuiMenu::pre_draw()
+{
+ glfwPollEvents();
+
+ // Check whether window dpi has changed
+ float scaling = hidpi_scaling();
+ if (std::abs(scaling - hidpi_scaling_) > 1e-5)
+ {
+ reload_font();
+ ImGui_ImplGlfwGL3_InvalidateDeviceObjects();
+ }
+
+ ImGui_ImplGlfwGL3_NewFrame();
+ return false;
+}
+
+IGL_INLINE bool ImGuiMenu::post_draw()
+{
+ draw_menu();
+ ImGui::Render();
+ return false;
+}
+
+IGL_INLINE void ImGuiMenu::post_resize(int width, int height)
+{
+ if (context_)
+ {
+ ImGui::GetIO().DisplaySize.x = float(width);
+ ImGui::GetIO().DisplaySize.y = float(height);
+ }
+}
+
+// Mouse IO
+IGL_INLINE bool ImGuiMenu::mouse_down(int button, int modifier)
+{
+ ImGui_ImplGlfwGL3_MouseButtonCallback(viewer->window, button, GLFW_PRESS, modifier);
+ return ImGui::GetIO().WantCaptureMouse;
+}
+
+IGL_INLINE bool ImGuiMenu::mouse_up(int button, int modifier)
+{
+ return ImGui::GetIO().WantCaptureMouse;
+}
+
+IGL_INLINE bool ImGuiMenu::mouse_move(int mouse_x, int mouse_y)
+{
+ return ImGui::GetIO().WantCaptureMouse;
+}
+
+IGL_INLINE bool ImGuiMenu::mouse_scroll(float delta_y)
+{
+ ImGui_ImplGlfwGL3_ScrollCallback(viewer->window, 0.f, delta_y);
+ return ImGui::GetIO().WantCaptureMouse;
+}
+
+// Keyboard IO
+IGL_INLINE bool ImGuiMenu::key_pressed(unsigned int key, int modifiers)
+{
+ ImGui_ImplGlfwGL3_CharCallback(nullptr, key);
+ return ImGui::GetIO().WantCaptureKeyboard;
+}
+
+IGL_INLINE bool ImGuiMenu::key_down(int key, int modifiers)
+{
+ ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_PRESS, modifiers);
+ return ImGui::GetIO().WantCaptureKeyboard;
+}
+
+IGL_INLINE bool ImGuiMenu::key_up(int key, int modifiers)
+{
+ ImGui_ImplGlfwGL3_KeyCallback(viewer->window, key, 0, GLFW_RELEASE, modifiers);
+ return ImGui::GetIO().WantCaptureKeyboard;
+}
+
+// Draw menu
+IGL_INLINE void ImGuiMenu::draw_menu()
+{
+ // Text labels
+ draw_labels_window();
+
+ // Viewer settings
+ if (callback_draw_viewer_window) { callback_draw_viewer_window(); }
+ else { draw_viewer_window(); }
+
+ // Other windows
+ if (callback_draw_custom_window) { callback_draw_custom_window(); }
+ else { draw_custom_window(); }
+}
+
+IGL_INLINE void ImGuiMenu::draw_viewer_window()
+{
+ float menu_width = 180.f * menu_scaling();
+ ImGui::SetNextWindowPos(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
+ ImGui::SetNextWindowSize(ImVec2(0.0f, 0.0f), ImGuiSetCond_FirstUseEver);
+ ImGui::SetNextWindowSizeConstraints(ImVec2(menu_width, -1.0f), ImVec2(menu_width, -1.0f));
+ bool _viewer_menu_visible = true;
+ ImGui::Begin(
+ "Viewer", &_viewer_menu_visible,
+ ImGuiWindowFlags_NoSavedSettings
+ | ImGuiWindowFlags_AlwaysAutoResize
+ );
+ ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.4f);
+ if (callback_draw_viewer_menu) { callback_draw_viewer_menu(); }
+ else { draw_viewer_menu(); }
+ ImGui::PopItemWidth();
+ ImGui::End();
+}
+
+IGL_INLINE void ImGuiMenu::draw_viewer_menu()
+{
+ // Workspace
+ if (ImGui::CollapsingHeader("Workspace", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ float w = ImGui::GetContentRegionAvailWidth();
+ float p = ImGui::GetStyle().FramePadding.x;
+ if (ImGui::Button("Load##Workspace", ImVec2((w-p)/2.f, 0)))
+ {
+ viewer->load_scene();
+ }
+ ImGui::SameLine(0, p);
+ if (ImGui::Button("Save##Workspace", ImVec2((w-p)/2.f, 0)))
+ {
+ viewer->save_scene();
+ }
+ }
+
+ // Mesh
+ if (ImGui::CollapsingHeader("Mesh", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ float w = ImGui::GetContentRegionAvailWidth();
+ float p = ImGui::GetStyle().FramePadding.x;
+ if (ImGui::Button("Load##Mesh", ImVec2((w-p)/2.f, 0)))
+ {
+ viewer->open_dialog_load_mesh();
+ }
+ ImGui::SameLine(0, p);
+ if (ImGui::Button("Save##Mesh", ImVec2((w-p)/2.f, 0)))
+ {
+ viewer->open_dialog_save_mesh();
+ }
+ }
+
+ // Viewing options
+ if (ImGui::CollapsingHeader("Viewing Options", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ if (ImGui::Button("Center object", ImVec2(-1, 0)))
+ {
+ viewer->core.align_camera_center(viewer->data().V, viewer->data().F);
+ }
+ if (ImGui::Button("Snap canonical view", ImVec2(-1, 0)))
+ {
+ viewer->snap_to_canonical_quaternion();
+ }
+
+ // Zoom
+ ImGui::PushItemWidth(80 * menu_scaling());
+ ImGui::DragFloat("Zoom", &(viewer->core.camera_zoom), 0.05f, 0.1f, 20.0f);
+
+ // Select rotation type
+ int rotation_type = static_cast<int>(viewer->core.rotation_type);
+ static Eigen::Quaternionf trackball_angle = Eigen::Quaternionf::Identity();
+ static bool orthographic = true;
+ if (ImGui::Combo("Camera Type", &rotation_type, "Trackball\0Two Axes\0002D Mode\0\0"))
+ {
+ using RT = igl::opengl::ViewerCore::RotationType;
+ auto new_type = static_cast<RT>(rotation_type);
+ if (new_type != viewer->core.rotation_type)
+ {
+ if (new_type == RT::ROTATION_TYPE_NO_ROTATION)
+ {
+ trackball_angle = viewer->core.trackball_angle;
+ orthographic = viewer->core.orthographic;
+ viewer->core.trackball_angle = Eigen::Quaternionf::Identity();
+ viewer->core.orthographic = true;
+ }
+ else if (viewer->core.rotation_type == RT::ROTATION_TYPE_NO_ROTATION)
+ {
+ viewer->core.trackball_angle = trackball_angle;
+ viewer->core.orthographic = orthographic;
+ }
+ viewer->core.set_rotation_type(new_type);
+ }
+ }
+
+ // Orthographic view
+ ImGui::Checkbox("Orthographic view", &(viewer->core.orthographic));
+ ImGui::PopItemWidth();
+ }
+
+ // Draw options
+ if (ImGui::CollapsingHeader("Draw Options", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ if (ImGui::Checkbox("Face-based", &(viewer->data().face_based)))
+ {
+ viewer->data().set_face_based(viewer->data().face_based);
+ }
+ ImGui::Checkbox("Show texture", &(viewer->data().show_texture));
+ if (ImGui::Checkbox("Invert normals", &(viewer->data().invert_normals)))
+ {
+ viewer->data().dirty |= igl::opengl::MeshGL::DIRTY_NORMAL;
+ }
+ ImGui::Checkbox("Show overlay", &(viewer->data().show_overlay));
+ ImGui::Checkbox("Show overlay depth", &(viewer->data().show_overlay_depth));
+ ImGui::ColorEdit4("Background", viewer->core.background_color.data(),
+ ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
+ ImGui::ColorEdit4("Line color", viewer->data().line_color.data(),
+ ImGuiColorEditFlags_NoInputs | ImGuiColorEditFlags_PickerHueWheel);
+ ImGui::PushItemWidth(ImGui::GetWindowWidth() * 0.3f);
+ ImGui::DragFloat("Shininess", &(viewer->data().shininess), 0.05f, 0.0f, 100.0f);
+ ImGui::PopItemWidth();
+ }
+
+ // Overlays
+ if (ImGui::CollapsingHeader("Overlays", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ ImGui::Checkbox("Wireframe", &(viewer->data().show_lines));
+ ImGui::Checkbox("Fill", &(viewer->data().show_faces));
+ ImGui::Checkbox("Show vertex labels", &(viewer->data().show_vertid));
+ ImGui::Checkbox("Show faces labels", &(viewer->data().show_faceid));
+ }
+}
+
+IGL_INLINE void ImGuiMenu::draw_labels_window()
+{
+ // Text labels
+ ImGui::SetNextWindowPos(ImVec2(0,0), ImGuiSetCond_Always);
+ ImGui::SetNextWindowSize(ImGui::GetIO().DisplaySize, ImGuiSetCond_Always);
+ bool visible = true;
+ ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0,0,0,0));
+ ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0);
+ ImGui::Begin("ViewerLabels", &visible,
+ ImGuiWindowFlags_NoTitleBar
+ | ImGuiWindowFlags_NoResize
+ | ImGuiWindowFlags_NoMove
+ | ImGuiWindowFlags_NoScrollbar
+ | ImGuiWindowFlags_NoScrollWithMouse
+ | ImGuiWindowFlags_NoCollapse
+ | ImGuiWindowFlags_NoSavedSettings
+ | ImGuiWindowFlags_NoInputs);
+ for (const auto & data : viewer->data_list)
+ {
+ draw_labels(data);
+ }
+ ImGui::End();
+ ImGui::PopStyleColor();
+ ImGui::PopStyleVar();
+}
+
+IGL_INLINE void ImGuiMenu::draw_labels(const igl::opengl::ViewerData &data)
+{
+ if (data.show_vertid)
+ {
+ for (int i = 0; i < data.V.rows(); ++i)
+ {
+ draw_text(data.V.row(i), data.V_normals.row(i), std::to_string(i));
+ }
+ }
+
+ if (data.show_faceid)
+ {
+ for (int i = 0; i < data.F.rows(); ++i)
+ {
+ Eigen::RowVector3d p = Eigen::RowVector3d::Zero();
+ for (int j = 0; j < data.F.cols(); ++j)
+ {
+ p += data.V.row(data.F(i,j));
+ }
+ p /= (double) data.F.cols();
+
+ draw_text(p, data.F_normals.row(i), std::to_string(i));
+ }
+ }
+
+ if (data.labels_positions.rows() > 0)
+ {
+ for (int i = 0; i < data.labels_positions.rows(); ++i)
+ {
+ draw_text(data.labels_positions.row(i), Eigen::Vector3d(0.0,0.0,0.0),
+ data.labels_strings[i]);
+ }
+ }
+}
+
+IGL_INLINE void ImGuiMenu::draw_text(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text)
+{
+ pos += normal * 0.005f * viewer->core.object_scale;
+ Eigen::Vector3f coord = igl::project(Eigen::Vector3f(pos.cast<float>()),
+ viewer->core.view, viewer->core.proj, viewer->core.viewport);
+
+ // Draw text labels slightly bigger than normal text
+ ImDrawList* drawList = ImGui::GetWindowDrawList();
+ drawList->AddText(ImGui::GetFont(), ImGui::GetFontSize() * 1.2,
+ ImVec2(coord[0]/pixel_ratio_, (viewer->core.viewport[3] - coord[1])/pixel_ratio_),
+ ImGui::GetColorU32(ImVec4(0, 0, 10, 255)),
+ &text[0], &text[0] + text.size());
+}
+
+IGL_INLINE float ImGuiMenu::pixel_ratio()
+{
+ // Computes pixel ratio for hidpi devices
+ int buf_size[2];
+ int win_size[2];
+ GLFWwindow* window = glfwGetCurrentContext();
+ glfwGetFramebufferSize(window, &buf_size[0], &buf_size[1]);
+ glfwGetWindowSize(window, &win_size[0], &win_size[1]);
+ return (float) buf_size[0] / (float) win_size[0];
+}
+
+IGL_INLINE float ImGuiMenu::hidpi_scaling()
+{
+ // Computes scaling factor for hidpi devices
+ float xscale, yscale;
+ GLFWwindow* window = glfwGetCurrentContext();
+ glfwGetWindowContentScale(window, &xscale, &yscale);
+ return 0.5 * (xscale + yscale);
+}
+
+} // end namespace
+} // end namespace
+} // end namespace
+} // end namespace
diff --git a/xs/src/igl/opengl/glfw/imgui/ImGuiMenu.h b/xs/src/igl/opengl/glfw/imgui/ImGuiMenu.h
new file mode 100644
index 000000000..e7144a675
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/imgui/ImGuiMenu.h
@@ -0,0 +1,110 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Jérémie Dumas <jeremie.dumas@ens-lyon.org>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
+#define IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
+
+////////////////////////////////////////////////////////////////////////////////
+#include <igl/opengl/glfw/Viewer.h>
+#include <igl/opengl/glfw/ViewerPlugin.h>
+#include <igl/igl_inline.h>
+////////////////////////////////////////////////////////////////////////////////
+
+// Forward declarations
+struct ImGuiContext;
+
+namespace igl
+{
+namespace opengl
+{
+namespace glfw
+{
+namespace imgui
+{
+
+class ImGuiMenu : public igl::opengl::glfw::ViewerPlugin
+{
+protected:
+ // Hidpi scaling to be used for text rendering.
+ float hidpi_scaling_;
+
+ // Ratio between the framebuffer size and the window size.
+ // May be different from the hipdi scaling!
+ float pixel_ratio_;
+
+ // ImGui Context
+ ImGuiContext * context_ = nullptr;
+
+public:
+ IGL_INLINE virtual void init(igl::opengl::glfw::Viewer *_viewer) override;
+
+ IGL_INLINE virtual void reload_font(int font_size = 13);
+
+ IGL_INLINE virtual void shutdown() override;
+
+ IGL_INLINE virtual bool pre_draw() override;
+
+ IGL_INLINE virtual bool post_draw() override;
+
+ IGL_INLINE virtual void post_resize(int width, int height) override;
+
+ // Mouse IO
+ IGL_INLINE virtual bool mouse_down(int button, int modifier) override;
+
+ IGL_INLINE virtual bool mouse_up(int button, int modifier) override;
+
+ IGL_INLINE virtual bool mouse_move(int mouse_x, int mouse_y) override;
+
+ IGL_INLINE virtual bool mouse_scroll(float delta_y) override;
+
+ // Keyboard IO
+ IGL_INLINE virtual bool key_pressed(unsigned int key, int modifiers) override;
+
+ IGL_INLINE virtual bool key_down(int key, int modifiers) override;
+
+ IGL_INLINE virtual bool key_up(int key, int modifiers) override;
+
+ // Draw menu
+ IGL_INLINE virtual void draw_menu();
+
+ // Can be overwritten by `callback_draw_viewer_window`
+ IGL_INLINE virtual void draw_viewer_window();
+
+ // Can be overwritten by `callback_draw_viewer_menu`
+ IGL_INLINE virtual void draw_viewer_menu();
+
+ // Can be overwritten by `callback_draw_custom_window`
+ IGL_INLINE virtual void draw_custom_window() { }
+
+ // Easy-to-customize callbacks
+ std::function<void(void)> callback_draw_viewer_window;
+ std::function<void(void)> callback_draw_viewer_menu;
+ std::function<void(void)> callback_draw_custom_window;
+
+ IGL_INLINE void draw_labels_window();
+
+ IGL_INLINE void draw_labels(const igl::opengl::ViewerData &data);
+
+ IGL_INLINE void draw_text(Eigen::Vector3d pos, Eigen::Vector3d normal, const std::string &text);
+
+ IGL_INLINE float pixel_ratio();
+
+ IGL_INLINE float hidpi_scaling();
+
+ float menu_scaling() { return hidpi_scaling_ / pixel_ratio_; }
+};
+
+} // end namespace
+} // end namespace
+} // end namespace
+} // end namespace
+
+#ifndef IGL_STATIC_LIBRARY
+# include "ImGuiMenu.cpp"
+#endif
+
+#endif // IGL_OPENGL_GLFW_IMGUI_IMGUIMENU_H
diff --git a/xs/src/igl/opengl/glfw/map_texture.cpp b/xs/src/igl/opengl/glfw/map_texture.cpp
new file mode 100644
index 000000000..7975d87d4
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/map_texture.cpp
@@ -0,0 +1,211 @@
+#ifdef IGL_OPENGL_4
+
+#include "map_texture.h"
+#include "background_window.h"
+#include "../create_shader_program.h"
+
+#include "../gl.h"
+#include <GLFW/glfw3.h>
+
+#include <iostream>
+#include <string>
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE bool igl::opengl::glfw::map_texture(
+ const Eigen::MatrixBase<DerivedV> & _V,
+ const Eigen::MatrixBase<DerivedF> & _F,
+ const Eigen::MatrixBase<DerivedU> & _U,
+ const unsigned char * in_data,
+ const int w,
+ const int h,
+ const int nc,
+ std::vector<unsigned char> & out_data)
+{
+ int out_w = w;
+ int out_h = h;
+ int out_nc = nc;
+ return map_texture(_V,_F,_U,in_data,w,h,nc,out_data,out_w,out_h,out_nc);
+}
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedU>
+IGL_INLINE bool igl::opengl::glfw::map_texture(
+ const Eigen::MatrixBase<DerivedV> & _V,
+ const Eigen::MatrixBase<DerivedF> & _F,
+ const Eigen::MatrixBase<DerivedU> & _U,
+ const unsigned char * in_data,
+ const int w,
+ const int h,
+ const int nc,
+ std::vector<unsigned char> & out_data,
+ int & out_w,
+ int & out_h,
+ int & out_nc)
+{
+ const auto fail = [](const std::string msg)
+ {
+ std::cerr<<msg<<std::endl;
+ glfwTerminate();
+ return false;
+ };
+ // Force inputs to be RowMajor at the cost of a copy
+ Eigen::Matrix<
+ double,
+ DerivedV::RowsAtCompileTime,
+ DerivedV::ColsAtCompileTime,
+ Eigen::RowMajor> V = _V.template cast<double>();
+ Eigen::Matrix<
+ double,
+ DerivedU::RowsAtCompileTime,
+ DerivedU::ColsAtCompileTime,
+ Eigen::RowMajor> U = _U.template cast<double>();
+ Eigen::Matrix<
+ int,
+ DerivedF::RowsAtCompileTime,
+ DerivedF::ColsAtCompileTime,
+ Eigen::RowMajor> F = _F.template cast<int>();
+ const int dim = U.cols();
+ GLFWwindow * window;
+ if(!background_window(window))
+ {
+ fail("Could not initialize glfw window");
+ }
+
+ // Compile each shader
+ std::string vertex_shader = dim == 2 ?
+ R"(
+#version 330 core
+layout(location = 0) in vec2 position;
+layout(location = 1) in vec2 tex_coord_v;
+out vec2 tex_coord_f;
+void main()
+{
+ tex_coord_f = vec2(tex_coord_v.x,1.-tex_coord_v.y);
+ gl_Position = vec4( 2.*position.x-1., 2.*(1.-position.y)-1., 0.,1.);
+}
+)"
+ :
+ R"(
+#version 330 core
+layout(location = 0) in vec3 position;
+layout(location = 1) in vec2 tex_coord_v;
+out vec2 tex_coord_f;
+void main()
+{
+ tex_coord_f = vec2(tex_coord_v.x,1.-tex_coord_v.y);
+ gl_Position = vec4( 2.*position.x-1., 2.*(1.-position.y)-1., position.z,1.);
+}
+)"
+ ;
+ std::string fragment_shader = R"(
+#version 330 core
+layout(location = 0) out vec3 color;
+uniform sampler2D tex;
+in vec2 tex_coord_f;
+void main()
+{
+ color = texture(tex,tex_coord_f).rgb;
+}
+)";
+ GLuint prog_id =
+ igl::opengl::create_shader_program(vertex_shader,fragment_shader,{});
+ glUniform1i(glGetUniformLocation(prog_id, "tex"),0);
+ // Generate and attach buffers to vertex array
+ glDisable(GL_CULL_FACE);
+ GLuint VAO = 0;
+ glGenVertexArrays(1,&VAO);
+ glBindVertexArray(VAO);
+ GLuint ibo,vbo,tbo;
+ glGenBuffers(1,&ibo);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW);
+ glGenBuffers(1,&vbo);
+ glEnableVertexAttribArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER,vbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(double)*U.size(), U.data(), GL_STATIC_DRAW);
+ glVertexAttribLPointer(0, U.cols(), GL_DOUBLE, U.cols() * sizeof(GLdouble), (GLvoid*)0);
+ glGenBuffers(1,&tbo);
+ glEnableVertexAttribArray(1);
+ glBindBuffer(GL_ARRAY_BUFFER,tbo);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(double)*V.size(), V.data(), GL_STATIC_DRAW);
+ glVertexAttribLPointer(1, V.cols(), GL_DOUBLE, V.cols() * sizeof(GLdouble), (GLvoid*)0);
+ glBindVertexArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+ // Prepare texture
+ GLuint in_tex;
+ GLenum format;
+ {
+ format = nc==1 ? GL_RED : (nc==3 ? GL_RGB : (nc == 4 ? GL_RGBA : GL_FALSE));
+ glGenTextures(1, &in_tex);
+ glBindTexture(GL_TEXTURE_2D, in_tex);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, w, h, 0,format, GL_UNSIGNED_BYTE, in_data);
+ }
+ // Prepare framebuffer
+ GLuint fb = 0;
+ glGenFramebuffers(1, &fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
+ GLuint out_tex;
+ glGenTextures(1, &out_tex);
+ glBindTexture(GL_TEXTURE_2D, out_tex);
+ // always use float for internal storage
+ assert(out_nc == 3);
+ glTexImage2D(GL_TEXTURE_2D, 0,GL_RGB, out_w, out_h, 0,GL_RGB, GL_FLOAT, 0);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, out_tex, 0);
+ {
+ GLenum bufs[1] = {GL_COLOR_ATTACHMENT0};
+ glDrawBuffers(1, bufs);
+ }
+ if(glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
+ {
+ fail("framebuffer setup failed.");
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, fb);
+ // clear screen and set viewport
+ glClearColor(0.0,1.0,0.0,0.);
+ glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0,0,out_w,out_h);
+ // Attach shader program
+ glUseProgram(prog_id);
+ glActiveTexture(GL_TEXTURE0 + 0);
+ glBindTexture(GL_TEXTURE_2D, in_tex);
+ // Draw mesh as wireframe
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glBindVertexArray(VAO);
+ glDrawElements(GL_TRIANGLES, F.size(), GL_UNSIGNED_INT, 0);
+ glBindVertexArray(0);
+ // Write into memory
+ assert(out_nc == 3);
+ out_data.resize(out_nc*out_w*out_h);
+ glBindTexture(GL_TEXTURE_2D, out_tex);
+ glGetTexImage(GL_TEXTURE_2D, 0, format, GL_UNSIGNED_BYTE, &out_data[0]);
+ // OpenGL cleanup
+ glDeleteBuffers(1,&fb);
+ glDeleteBuffers(1,&ibo);
+ glDeleteBuffers(1,&vbo);
+ glDeleteBuffers(1,&tbo);
+ glDeleteTextures(1,&in_tex);
+ glDeleteTextures(1,&out_tex);
+ glDeleteVertexArrays(1,&VAO);
+ glUseProgram(0);
+ glDeleteProgram(prog_id);
+ // GLFW cleanup
+ glfwDestroyWindow(window);
+ glfwTerminate();
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::opengl::glfw::map_texture<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, unsigned char const*, int, int, int, std::vector<unsigned char, std::allocator<unsigned char> >&);
+#endif
+
+#endif // IGL_OPENGL_4
diff --git a/xs/src/igl/opengl/glfw/map_texture.h b/xs/src/igl/opengl/glfw/map_texture.h
new file mode 100644
index 000000000..ee3b30a45
--- /dev/null
+++ b/xs/src/igl/opengl/glfw/map_texture.h
@@ -0,0 +1,63 @@
+#ifndef IGL_OPENGL_GLFW_MAP_TEXTURE_H
+#define IGL_OPENGL_GLFW_MAP_TEXTURE_H
+
+#ifdef IGL_OPENGL_4
+
+#include "../../igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace opengl
+ {
+ namespace glfw
+ {
+ // Given a mesh (V,F) in [0,1]² and new positions (U) and a texture image
+ // (in_data), _render_ a new image (out_data) of the same size.
+ // Inputs:
+ // V #V by 2 list of undeformed mesh vertex positions (matching texture)
+ // F #F by 3 list of mesh triangle indices into V
+ // U #U by 2 list of deformed vertex positions
+ // in_data w*h*nc array of color values, channels, then columns, then
+ // rows (e.g., what stbi_image returns and expects)
+ // w width
+ // h height
+ // nc number of channels
+ // Outputs:
+ // out_data h*w*nc list of output colors in same order as input
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedU>
+ IGL_INLINE bool map_texture(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedU> & U,
+ const unsigned char * in_data,
+ const int w,
+ const int h,
+ const int nc,
+ std::vector<unsigned char> & out_data);
+ template <typename DerivedV, typename DerivedF, typename DerivedU>
+ IGL_INLINE bool map_texture(
+ const Eigen::MatrixBase<DerivedV> & _V,
+ const Eigen::MatrixBase<DerivedF> & _F,
+ const Eigen::MatrixBase<DerivedU> & _U,
+ const unsigned char * in_data,
+ const int w,
+ const int h,
+ const int nc,
+ std::vector<unsigned char> & out_data,
+ int & out_w,
+ int & out_h,
+ int & out_nc);
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "map_texture.cpp"
+#endif
+
+#endif // IGL_OPENGL_4
+
+#endif
diff --git a/xs/src/igl/opengl/init_render_to_texture.cpp b/xs/src/igl/opengl/init_render_to_texture.cpp
new file mode 100644
index 000000000..7fbcfea10
--- /dev/null
+++ b/xs/src/igl/opengl/init_render_to_texture.cpp
@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "init_render_to_texture.h"
+#include "gl.h"
+#include <cassert>
+
+IGL_INLINE void igl::opengl::init_render_to_texture(
+ const size_t width,
+ const size_t height,
+ const bool depth_texture,
+ GLuint & tex_id,
+ GLuint & fbo_id,
+ GLuint & d_id)
+{
+ using namespace std;
+ // http://www.opengl.org/wiki/Framebuffer_Object_Examples#Quick_example.2C_render_to_texture_.282D.29
+ const auto & gen_tex = [](GLuint & tex_id)
+ {
+ glGenTextures(1, &tex_id);
+ glBindTexture(GL_TEXTURE_2D, tex_id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ };
+ gen_tex(tex_id);
+ //NULL means reserve texture memory, but texels are undefined
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, width, height, 0, GL_BGRA, GL_FLOAT, NULL);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ glGenFramebuffers(1, &fbo_id);
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
+ //Attach 2D texture to this FBO
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex_id, 0);
+ if(depth_texture)
+ {
+ // Generate a depth texture
+ gen_tex(d_id);
+ glTexImage2D(
+ GL_TEXTURE_2D,
+ 0,
+ GL_DEPTH_COMPONENT32,
+ width,
+ height,
+ 0,
+ GL_DEPTH_COMPONENT,
+ GL_FLOAT,
+ NULL);
+ glFramebufferTexture2D(
+ GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_TEXTURE_2D,d_id,0);
+ }else
+ {
+ // Attach a depth buffer
+ glGenRenderbuffers(1, &d_id);
+ glBindRenderbuffer(GL_RENDERBUFFER, d_id);
+ glRenderbufferStorage(GL_RENDERBUFFER,GL_DEPTH_COMPONENT24,width,height);
+ glFramebufferRenderbuffer(
+ GL_FRAMEBUFFER,GL_DEPTH_ATTACHMENT,GL_RENDERBUFFER,d_id);
+ }
+
+ //Does the GPU support current FBO configuration?
+ GLenum status;
+ status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ assert(status == GL_FRAMEBUFFER_COMPLETE);
+ // Unbind to clean up
+ if(!depth_texture)
+ {
+ glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ }
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+}
+
+IGL_INLINE void igl::opengl::init_render_to_texture(
+ const size_t width,
+ const size_t height,
+ GLuint & tex_id,
+ GLuint & fbo_id,
+ GLuint & dfbo_id)
+{
+ return init_render_to_texture(width,height,false,tex_id,fbo_id,dfbo_id);
+}
diff --git a/xs/src/igl/opengl/init_render_to_texture.h b/xs/src/igl/opengl/init_render_to_texture.h
new file mode 100644
index 000000000..ae854e770
--- /dev/null
+++ b/xs/src/igl/opengl/init_render_to_texture.h
@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_INIT_RENDER_TO_TEXTURE_H
+#define IGL_OPENGL_INIT_RENDER_TO_TEXTURE_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <cstdlib>
+namespace igl
+{
+ namespace opengl
+ {
+ // Create a frame buffer that renders color to a RGBA texture a depth to a
+ // "render buffer".
+ //
+ // After calling this, you can use with something like:
+ //
+ // glBindFramebuffer(GL_FRAMEBUFFER, fbo_id);
+ // if(!depth_texture)
+ // {
+ // glBindRenderbuffer(GL_RENDERBUFFER, d_id);
+ // }
+ // //
+ // // draw scene ...
+ // //
+ // // clean up
+ // glBindFramebuffer(GL_FRAMEBUFFER,0);
+ // if(!depth_texture)
+ // {
+ // glBindRenderbuffer(GL_RENDERBUFFER, 0);
+ // }
+ // // Later ...
+ // glActiveTexture(GL_TEXTURE0+0);
+ // glBindTexture(GL_TEXTURE_2D,tex_id);
+ // if(depth_texture)
+ // {
+ // glActiveTexture(GL_TEXTURE0+1);
+ // glBindTexture(GL_TEXTURE_2D,d_id);
+ // }
+ // // draw textures
+ //
+ //
+ //
+ // Inputs:
+ // width image width
+ // height image height
+ // depth_texture whether to create a texture for depth or to create a
+ // render buffer for depth
+ // Outputs:
+ // tex_id id of the texture
+ // fbo_id id of the frame buffer object
+ // d_id id of the depth texture or frame buffer object
+ //
+ IGL_INLINE void init_render_to_texture(
+ const size_t width,
+ const size_t height,
+ const bool depth_texture,
+ GLuint & tex_id,
+ GLuint & fbo_id,
+ GLuint & d_id);
+ // Wrapper with depth_texture = false for legacy reasons
+ IGL_INLINE void init_render_to_texture(
+ const size_t width,
+ const size_t height,
+ GLuint & tex_id,
+ GLuint & fbo_id,
+ GLuint & dfbo_id);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "init_render_to_texture.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl/load_shader.cpp b/xs/src/igl/opengl/load_shader.cpp
new file mode 100644
index 000000000..0ee0a978f
--- /dev/null
+++ b/xs/src/igl/opengl/load_shader.cpp
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "load_shader.h"
+
+// Copyright Denis Kovacs 4/10/08
+#include "print_shader_info_log.h"
+#include <cstdio>
+IGL_INLINE GLuint igl::opengl::load_shader(
+ const std::string & src,const GLenum type)
+{
+ if(src.empty())
+ {
+ return (GLuint) 0;
+ }
+
+ GLuint s = glCreateShader(type);
+ if(s == 0)
+ {
+ fprintf(stderr,"Error: load_shader() failed to create shader.\n");
+ return 0;
+ }
+ // Pass shader source string
+ const char *c = src.c_str();
+ glShaderSource(s, 1, &c, NULL);
+ glCompileShader(s);
+ // Print info log (if any)
+ igl::opengl::print_shader_info_log(s);
+ return s;
+}
diff --git a/xs/src/igl/opengl/load_shader.h b/xs/src/igl/opengl/load_shader.h
new file mode 100644
index 000000000..6c234d8fc
--- /dev/null
+++ b/xs/src/igl/opengl/load_shader.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_LOAD_SHADER_H
+#define IGL_OPENGL_LOAD_SHADER_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <string>
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Creates and compiles a shader from a given string
+ //
+ // Inputs:
+ // src string containing GLSL shader code
+ // type GLSL type of shader, one of:
+ // GL_VERTEX_SHADER
+ // GL_FRAGMENT_SHADER
+ // GL_GEOMETRY_SHADER
+ // Returns index id of the newly created shader, 0 on error
+ //
+ // Will immediately return 0 if src is empty.
+ IGL_INLINE GLuint load_shader(
+ const std::string & src,const GLenum type);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "load_shader.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/print_program_info_log.cpp b/xs/src/igl/opengl/print_program_info_log.cpp
new file mode 100644
index 000000000..41b37b7fb
--- /dev/null
+++ b/xs/src/igl/opengl/print_program_info_log.cpp
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "print_program_info_log.h"
+
+#include <cstdio>
+#include <stdlib.h>
+// Copyright Denis Kovacs 4/10/08
+IGL_INLINE void igl::opengl::print_program_info_log(const GLuint obj)
+{
+ GLint infologLength = 0;
+ GLint charsWritten = 0;
+ char *infoLog;
+
+ glGetProgramiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
+
+ if (infologLength > 0)
+ {
+ infoLog = (char *)malloc(infologLength);
+ glGetProgramInfoLog(obj, infologLength, &charsWritten, infoLog);
+ printf("%s\n",infoLog);
+ free(infoLog);
+ }
+}
diff --git a/xs/src/igl/opengl/print_program_info_log.h b/xs/src/igl/opengl/print_program_info_log.h
new file mode 100644
index 000000000..43bcc0974
--- /dev/null
+++ b/xs/src/igl/opengl/print_program_info_log.h
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_PRINT_PROGRAM_INFO_LOG_H
+#define IGL_OPENGL_PRINT_PROGRAM_INFO_LOG_H
+#include "../igl_inline.h"
+#include "gl.h"
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Inputs:
+ // obj OpenGL index of program to print info log about
+ IGL_INLINE void print_program_info_log(const GLuint obj);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "print_program_info_log.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/print_shader_info_log.cpp b/xs/src/igl/opengl/print_shader_info_log.cpp
new file mode 100644
index 000000000..2d3554387
--- /dev/null
+++ b/xs/src/igl/opengl/print_shader_info_log.cpp
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "print_shader_info_log.h"
+
+#include <cstdio>
+#include <stdlib.h>
+// Copyright Denis Kovacs 4/10/08
+IGL_INLINE void igl::opengl::print_shader_info_log(const GLuint obj)
+{
+ GLint infologLength = 0;
+ GLint charsWritten = 0;
+ char *infoLog;
+
+ // Get shader info log from opengl
+ glGetShaderiv(obj, GL_INFO_LOG_LENGTH,&infologLength);
+ // Only print if there is something in the log
+ if (infologLength > 0)
+ {
+ infoLog = (char *)malloc(infologLength);
+ glGetShaderInfoLog(obj, infologLength, &charsWritten, infoLog);
+ printf("%s\n",infoLog);
+ free(infoLog);
+ }
+}
diff --git a/xs/src/igl/opengl/print_shader_info_log.h b/xs/src/igl/opengl/print_shader_info_log.h
new file mode 100644
index 000000000..5a571fb11
--- /dev/null
+++ b/xs/src/igl/opengl/print_shader_info_log.h
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_PRINT_SHADER_INFO_LOG_H
+#define IGL_OPENGL_PRINT_SHADER_INFO_LOG_H
+#include "../igl_inline.h"
+#include "gl.h"
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Inputs:
+ // obj OpenGL index of shader to print info log about
+ IGL_INLINE void print_shader_info_log(const GLuint obj);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "print_shader_info_log.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/report_gl_error.cpp b/xs/src/igl/opengl/report_gl_error.cpp
new file mode 100644
index 000000000..2dcc0b632
--- /dev/null
+++ b/xs/src/igl/opengl/report_gl_error.cpp
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "report_gl_error.h"
+#include "../verbose.h"
+#include <cstdio>
+
+IGL_INLINE GLenum igl::opengl::report_gl_error(const std::string id)
+{
+ // http://stackoverflow.com/q/28485180/148668
+
+ // gluErrorString was deprecated
+ const auto gluErrorString = [](GLenum errorCode)->const char *
+ {
+ switch(errorCode)
+ {
+ default:
+ return "unknown error code";
+ case GL_NO_ERROR:
+ return "no error";
+ case GL_INVALID_ENUM:
+ return "invalid enumerant";
+ case GL_INVALID_VALUE:
+ return "invalid value";
+ case GL_INVALID_OPERATION:
+ return "invalid operation";
+#ifndef GL_VERSION_3_0
+ case GL_STACK_OVERFLOW:
+ return "stack overflow";
+ case GL_STACK_UNDERFLOW:
+ return "stack underflow";
+ case GL_TABLE_TOO_LARGE:
+ return "table too large";
+#endif
+ case GL_OUT_OF_MEMORY:
+ return "out of memory";
+#ifdef GL_EXT_framebuffer_object
+ case GL_INVALID_FRAMEBUFFER_OPERATION_EXT:
+ return "invalid framebuffer operation";
+#endif
+ }
+ };
+
+ GLenum err = glGetError();
+ if(GL_NO_ERROR != err)
+ {
+ verbose("GL_ERROR: ");
+ fprintf(stderr,"%s%s\n",id.c_str(),gluErrorString(err));
+ }
+ return err;
+}
+
+IGL_INLINE GLenum igl::opengl::report_gl_error()
+{
+ return igl::opengl::report_gl_error(std::string(""));
+}
+
diff --git a/xs/src/igl/opengl/report_gl_error.h b/xs/src/igl/opengl/report_gl_error.h
new file mode 100644
index 000000000..70e5c7d74
--- /dev/null
+++ b/xs/src/igl/opengl/report_gl_error.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_REPORT_GL_ERROR_H
+#define IGL_OPENGL_REPORT_GL_ERROR_H
+#include "../igl_inline.h"
+
+// Hack to allow both opengl/ and opengl2 to use this (we shouldn't allow this)
+#ifndef __gl_h_
+# include "gl.h"
+#endif
+#include <string>
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Print last OpenGL error to stderr prefixed by specified id string
+ // Inputs:
+ // id string to appear before any error msgs
+ // Returns result of glGetError()
+ IGL_INLINE GLenum report_gl_error(const std::string id);
+ // No prefix
+ IGL_INLINE GLenum report_gl_error();
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "report_gl_error.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/uniform_type_to_string.cpp b/xs/src/igl/opengl/uniform_type_to_string.cpp
new file mode 100644
index 000000000..b2f9a2fdb
--- /dev/null
+++ b/xs/src/igl/opengl/uniform_type_to_string.cpp
@@ -0,0 +1,71 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "uniform_type_to_string.h"
+
+IGL_INLINE std::string igl::opengl::uniform_type_to_string(const GLenum type)
+{
+ switch(type)
+ {
+ case GL_FLOAT:
+ return "GL_FLOAT";
+ case GL_FLOAT_VEC2:
+ return "GL_FLOAT_VEC2";
+ case GL_FLOAT_VEC3:
+ return "GL_FLOAT_VEC3";
+ case GL_FLOAT_VEC4:
+ return "GL_FLOAT_VEC4";
+ case GL_INT:
+ return "GL_INT";
+ case GL_INT_VEC2:
+ return "GL_INT_VEC2";
+ case GL_INT_VEC3:
+ return "GL_INT_VEC3";
+ case GL_INT_VEC4:
+ return "GL_INT_VEC4";
+ case GL_BOOL:
+ return "GL_BOOL";
+ case GL_BOOL_VEC2:
+ return "GL_BOOL_VEC2";
+ case GL_BOOL_VEC3:
+ return "GL_BOOL_VEC3";
+ case GL_BOOL_VEC4:
+ return "GL_BOOL_VEC4";
+ case GL_FLOAT_MAT2:
+ return "GL_FLOAT_MAT2";
+ case GL_FLOAT_MAT3:
+ return "GL_FLOAT_MAT3";
+ case GL_FLOAT_MAT4:
+ return "GL_FLOAT_MAT4";
+ case GL_FLOAT_MAT2x3:
+ return "GL_FLOAT_MAT2x3";
+ case GL_FLOAT_MAT2x4:
+ return "GL_FLOAT_MAT2x4";
+ case GL_FLOAT_MAT3x2:
+ return "GL_FLOAT_MAT3x2";
+ case GL_FLOAT_MAT3x4:
+ return "GL_FLOAT_MAT3x4";
+ case GL_FLOAT_MAT4x2:
+ return "GL_FLOAT_MAT4x2";
+ case GL_FLOAT_MAT4x3:
+ return "GL_FLOAT_MAT4x3";
+ case GL_SAMPLER_1D:
+ return "GL_SAMPLER_1D";
+ case GL_SAMPLER_2D:
+ return "GL_SAMPLER_2D";
+ case GL_SAMPLER_3D:
+ return "GL_SAMPLER_3D";
+ case GL_SAMPLER_CUBE:
+ return "GL_SAMPLER_CUBE";
+ case GL_SAMPLER_1D_SHADOW:
+ return "GL_SAMPLER_1D_SHADOW";
+ case GL_SAMPLER_2D_SHADOW:
+ return "GL_SAMPLER_2D_SHADOW";
+ default:
+ return "UNKNOWN_TYPE";
+ }
+}
diff --git a/xs/src/igl/opengl/uniform_type_to_string.h b/xs/src/igl/opengl/uniform_type_to_string.h
new file mode 100644
index 000000000..ed0a93e90
--- /dev/null
+++ b/xs/src/igl/opengl/uniform_type_to_string.h
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_UNIFORM_TYPE_TO_STRING_H
+#define IGL_OPENGL_UNIFORM_TYPE_TO_STRING_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <string>
+
+namespace igl
+{
+ namespace opengl
+ {
+ // Convert a GL uniform variable type (say, returned from
+ // glGetActiveUniform) and output a string naming that type
+ // Inputs:
+ // type enum for given type
+ // Returns string name of that type
+ IGL_INLINE std::string uniform_type_to_string(const GLenum type);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "uniform_type_to_string.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl/vertex_array.cpp b/xs/src/igl/opengl/vertex_array.cpp
new file mode 100644
index 000000000..c07113ad3
--- /dev/null
+++ b/xs/src/igl/opengl/vertex_array.cpp
@@ -0,0 +1,61 @@
+#include "vertex_array.h"
+#include <igl/opengl/report_gl_error.h>
+
+template <
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE void igl::opengl::vertex_array(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ GLuint & va_id,
+ GLuint & ab_id,
+ GLuint & eab_id)
+{
+ // Inputs should be in RowMajor storage. If not, we have no choice but to
+ // create a copy.
+ if(!(V.Options & Eigen::RowMajor))
+ {
+ Eigen::Matrix<
+ typename DerivedV::Scalar,
+ DerivedV::RowsAtCompileTime,
+ DerivedV::ColsAtCompileTime,
+ Eigen::RowMajor> VR = V;
+ return vertex_array(VR,F,va_id,ab_id,eab_id);
+ }
+ if(!(F.Options & Eigen::RowMajor))
+ {
+ Eigen::Matrix<
+ typename DerivedF::Scalar,
+ DerivedF::RowsAtCompileTime,
+ DerivedF::ColsAtCompileTime,
+ Eigen::RowMajor> FR = F;
+ return vertex_array(V,FR,va_id,ab_id,eab_id);
+ }
+ // Generate and attach buffers to vertex array
+ glGenVertexArrays(1, &va_id);
+ glGenBuffers(1, &ab_id);
+ glGenBuffers(1, &eab_id);
+ glBindVertexArray(va_id);
+ glBindBuffer(GL_ARRAY_BUFFER, ab_id);
+ const auto size_VScalar = sizeof(typename DerivedV::Scalar);
+ const auto size_FScalar = sizeof(typename DerivedF::Scalar);
+ glBufferData(GL_ARRAY_BUFFER,size_VScalar*V.size(),V.data(),GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, eab_id);
+ assert(sizeof(GLuint) == size_FScalar && "F type does not match GLuint");
+ glBufferData(
+ GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint)*F.size(), F.data(), GL_STATIC_DRAW);
+ glVertexAttribPointer(
+ 0,
+ V.cols(),
+ size_VScalar==sizeof(float)?GL_FLOAT:GL_DOUBLE,
+ GL_FALSE,
+ V.cols()*size_VScalar,
+ (GLvoid*)0);
+ glEnableVertexAttribArray(0);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ glBindVertexArray(0);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::opengl::vertex_array<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, unsigned int&, unsigned int&, unsigned int&);
+#endif
diff --git a/xs/src/igl/opengl/vertex_array.h b/xs/src/igl/opengl/vertex_array.h
new file mode 100644
index 000000000..1342a9c90
--- /dev/null
+++ b/xs/src/igl/opengl/vertex_array.h
@@ -0,0 +1,38 @@
+#ifndef IGL_OPENGL_VERTEX_ARRAY_H
+#define IGL_OPENGL_VERTEX_ARRAY_H
+#include <igl/opengl/../igl_inline.h>
+#include <igl/opengl/gl.h>
+#include <Eigen/Core>
+namespace igl
+{
+ namespace opengl
+ {
+ // Create a GL_VERTEX_ARRAY for a given mesh (V,F)
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by 3 list of mesh triangle indices into V
+ // Outputs:
+ // va_id id of vertex array
+ // ab_id id of array buffer (vertex buffer object)
+ // eab_id id of element array buffer (element/face buffer object)
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE void vertex_array(
+ // Note: Unlike most libigl functions, the **input** Eigen matrices must
+ // be `Eigen::PlainObjectBase` because we want to directly access it's
+ // underlying storage. It cannot be `Eigen::MatrixBase` (see
+ // http://stackoverflow.com/questions/25094948/)
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ GLuint & va_id,
+ GLuint & ab_id,
+ GLuint & eab_id);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "vertex_array.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl2/MouseController.h b/xs/src/igl/opengl2/MouseController.h
new file mode 100644
index 000000000..eb38802ad
--- /dev/null
+++ b/xs/src/igl/opengl2/MouseController.h
@@ -0,0 +1,691 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_MOUSECONTROLLER_H
+#define IGL_OPENGL2_MOUSECONTROLLER_H
+// Needs to be included before others
+#include <Eigen/StdVector>
+#include "RotateWidget.h"
+#include "TranslateWidget.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <vector>
+
+// Class for control a skeletal FK rig with the mouse.
+namespace igl
+{
+ namespace opengl2
+ {
+ class MouseController
+ {
+ public:
+ typedef Eigen::VectorXi VectorXb;
+ // Propagate selection to descendants so that selected bones and their
+ // subtrees are all selected.
+ //
+ // Input:
+ // S #S list of whether selected
+ // P #S list of bone parents
+ // Output:
+ // T #S list of whether selected
+ static inline void propogate_to_descendants_if(
+ const VectorXb & S,
+ const Eigen::VectorXi & P,
+ VectorXb & T);
+ // Create a matrix of colors for the selection and their descendants.
+ //
+ // Inputs:
+ // selection #S list of whether a bone is selected
+ // selected_color color for selected bones
+ // unselected_color color for unselected bones
+ // Outputs:
+ // C #P by 4 list of colors
+ static inline void color_if(
+ const VectorXb & S,
+ const Eigen::Vector4f & selected_color,
+ const Eigen::Vector4f & unselected_color,
+ Eigen::MatrixXf & C);
+ enum WidgetMode
+ {
+ WIDGET_MODE_ROTATE = 0,
+ WIDGET_MODE_TRANSLATE = 1,
+ NUM_WIDGET_MODES = 2,
+ };
+ private:
+ // m_is_selecting whether currently selecting
+ // m_selection #m_rotations list of whether a bone is selected
+ // m_down_x x-coordinate of mouse location at down
+ // m_down_y y-coordinate 〃
+ // m_drag_x x-coordinate of mouse location at drag
+ // m_drag_y y-coordinate 〃
+ // m_widget rotation widget for selected bone
+ // m_width width of containing window
+ // m_height height 〃
+ // m_rotations list of rotations for each bone
+ // m_rotations_at_selection list of rotations for each bone at time of
+ // selection
+ // m_translations list of translations for each bone
+ // m_fk_rotations_at_selection list of rotations for each bone at time of
+ // selection
+ // m_root_enabled Whether root is enabled
+ bool m_is_selecting;
+ VectorXb m_selection;
+ int m_down_x,m_down_y,m_drag_x,m_drag_y;
+ int m_width,m_height;
+ igl::opengl2::RotateWidget m_widget;
+ igl::opengl2::TranslateWidget m_trans_widget;
+ Eigen::Quaterniond m_widget_rot_at_selection;
+ //Eigen::Vector3d m_trans_widget_trans_at_selection;
+ typedef std::vector<
+ Eigen::Quaterniond,
+ Eigen::aligned_allocator<Eigen::Quaterniond> > RotationList;
+ typedef std::vector< Eigen::Vector3d > TranslationList;
+ RotationList
+ m_rotations,
+ m_rotations_at_selection,
+ m_fk_rotations_at_selection,
+ m_parent_rotations_at_selection;
+ TranslationList
+ m_translations,
+ m_translations_at_selection,
+ m_fk_translations_at_selection;
+ bool m_root_enabled;
+ WidgetMode m_widget_mode;
+ public:
+ MouseController();
+ // Returns const reference to m_selection
+ inline const VectorXb & selection() const{return m_selection;};
+ // 〃 m_is_selecting
+ inline const bool & is_selecting() const{return m_is_selecting;}
+ inline bool is_widget_down() const{return m_widget.is_down();}
+ inline bool is_trans_widget_down() const{return m_trans_widget.is_down();}
+ // 〃 m_rotations
+ inline const RotationList & rotations() const{return m_rotations;}
+ inline const TranslationList & translations() const{return m_translations;}
+ // Returns non-const reference to m_root_enabled
+ inline bool & root_enabled(){ return m_root_enabled;}
+ inline void reshape(const int w, const int h);
+ // Process down, drag, up mouse events
+ //
+ // Inputs:
+ // x x-coordinate of mouse click with respect to container
+ // y y-coordinate 〃
+ // Returns true if accepted (action taken).
+ inline bool down(const int x, const int y);
+ inline bool drag(const int x, const int y);
+ inline bool up(const int x, const int y);
+ // Draw selection box and widget
+ inline void draw() const;
+ // Set `m_selection` based on the last drag selection and initialize
+ // widget.
+ //
+ // Inputs:
+ // C #C by dim list of joint positions at rest
+ // BE #BE by 2 list of bone indices at rest
+ // P #P list of bone parents
+ inline void set_selection_from_last_drag(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const Eigen::VectorXi & RP);
+ // Set from explicit selection
+ inline void set_selection(
+ const Eigen::VectorXi & S,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const Eigen::VectorXi & RP);
+ // Set size of skeleton
+ //
+ // Inputs:
+ // n number of bones
+ inline void set_size(const int n);
+ // Resets m_rotation elements to identity
+ inline void reset();
+ inline void reset_selected();
+ inline void reset_rotations();
+ inline void reset_selected_rotations();
+ inline void reset_translations();
+ inline void reset_selected_translations();
+ inline bool set_rotations(const RotationList & vQ);
+ inline bool set_translations(const TranslationList & vT);
+ // Sets all entries in m_selection to false
+ inline void clear_selection();
+ // Returns true iff some element in m_selection is true
+ inline bool any_selection() const;
+ inline void set_widget_mode(const WidgetMode & mode);
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ };
+ }
+}
+
+// Implementation
+#include "../line_segment_in_rectangle.h"
+#include "draw_rectangular_marquee.h"
+#include "project.h"
+#include "../forward_kinematics.h"
+#include <iostream>
+#include <algorithm>
+#include <functional>
+
+inline void igl::opengl2::MouseController::propogate_to_descendants_if(
+ const VectorXb & S,
+ const Eigen::VectorXi & P,
+ VectorXb & T)
+{
+ using namespace std;
+ const int n = S.rows();
+ assert(P.rows() == n);
+ // dynamic programming
+ T = S;
+ vector<bool> seen(n,false);
+ // Recursively look up chain and see if ancestor is selected
+ const function<bool(int)> look_up = [&](int e) -> bool
+ {
+ if(e==-1)
+ {
+ return false;
+ }
+ if(!seen[e])
+ {
+ seen[e] = true;
+ T(e) |= look_up(P(e));
+ }
+ return T(e);
+ };
+ for(int e = 0;e<n;e++)
+ {
+ if(!seen[e])
+ {
+ T(e) = look_up(e);
+ }
+ }
+}
+
+inline void igl::opengl2::MouseController::color_if(
+ const VectorXb & S,
+ const Eigen::Vector4f & selected_color,
+ const Eigen::Vector4f & unselected_color,
+ Eigen::MatrixXf & C)
+{
+ C.resize(S.rows(),4);
+ for(int e=0;e<S.rows();e++)
+ {
+ C.row(e) = S(e)?selected_color:unselected_color;
+ }
+}
+
+inline igl::opengl2::MouseController::MouseController():
+ m_is_selecting(false),
+ m_selection(),
+ m_down_x(-1),m_down_y(-1),m_drag_x(-1),m_drag_y(-1),
+ m_width(-1),m_height(-1),
+ m_widget(),
+ m_widget_rot_at_selection(),
+ //m_trans_widget_trans_at_selection(),
+ m_trans_widget(),
+ m_rotations(),
+ m_translations(),
+ m_rotations_at_selection(),
+ m_root_enabled(true),
+ m_widget_mode(WIDGET_MODE_ROTATE)
+{
+}
+
+inline void igl::opengl2::MouseController::reshape(const int w, const int h)
+{
+ m_width = w;
+ m_height = h;
+}
+
+inline bool igl::opengl2::MouseController::down(const int x, const int y)
+{
+ using namespace std;
+ m_down_x = m_drag_x =x;
+ m_down_y = m_drag_y =y;
+ const bool widget_down = any_selection() &&
+ (
+ (m_widget_mode == WIDGET_MODE_ROTATE && m_widget.down(x,m_height-y)) ||
+ (m_widget_mode == WIDGET_MODE_TRANSLATE &&
+ m_trans_widget.down(x,m_height-y))
+ );
+ if(!widget_down)
+ {
+ m_is_selecting = true;
+ }
+ return m_is_selecting || widget_down;
+}
+
+inline bool igl::opengl2::MouseController::drag(const int x, const int y)
+{
+ using namespace std;
+ using namespace Eigen;
+ m_drag_x = x;
+ m_drag_y = y;
+ if(m_is_selecting)
+ {
+ return m_is_selecting;
+ }else
+ {
+ switch(m_widget_mode)
+ {
+ default: // fall through
+ case WIDGET_MODE_ROTATE:
+ {
+ if(!m_widget.drag(x,m_height-y))
+ {
+ return false;
+ }
+ assert(any_selection());
+ assert(m_selection.size() == (int)m_rotations.size());
+ assert(m_selection.size() == (int)m_translations.size());
+ for(int e = 0;e<m_selection.size();e++)
+ {
+ if(m_selection(e))
+ {
+ // Let:
+ // w.θr = w.θ ⋅ w.θ₀*
+ // w.θr takes (absolute) frame of w.θ₀ to w.θ:
+ // w.θ = w.θr ⋅ w.θ₀
+ // Define:
+ // w.θ₀ = θfk ⋅ θx,
+ // the absolute rotation of the x axis to the deformed bone at
+ // selection. Likewise,
+ // w.θ = θfk' ⋅ θx,
+ // the current absolute rotation of the x axis to the deformed bone.
+ // Define recursively:
+ // θfk = θfk(p) ⋅ Θr,
+ // then because we're only changeing this relative rotation
+ // θfk' = θfk(p) ⋅ Θr ⋅ θr* ⋅ θr'
+ // θfk' = θfk ⋅ θr* ⋅ θr'
+ // w.θ ⋅ θx* = θfk ⋅ θr* ⋅ θr'
+ // θr ⋅ θfk* ⋅ w.θ ⋅ θx* = θr'
+ // θr ⋅ θfk* ⋅ w.θr ⋅ w.θ₀ ⋅ θx* = θr'
+ // θr ⋅ θfk* ⋅ w.θr ⋅ θfk ⋅θx ⋅ θx* = θr'
+ // θr ⋅ θfk* ⋅ w.θr ⋅ θfk = θr'
+ // which I guess is the right multiply change after being changed to
+ // the bases of θfk, the rotation of the bone relative to its rest
+ // frame.
+ //
+ const Quaterniond & frame = m_fk_rotations_at_selection[e];
+ m_rotations[e] =
+ m_rotations_at_selection[e] *
+ frame.conjugate() *
+ (m_widget.rot*m_widget_rot_at_selection.conjugate()) *
+ frame;
+ }
+ }
+ }
+ case WIDGET_MODE_TRANSLATE:
+ {
+ if(!m_trans_widget.drag(x,m_height-y))
+ {
+ return false;
+ }
+ assert(any_selection());
+ assert(m_selection.size() == (int)m_rotations.size());
+ assert(m_selection.size() == (int)m_translations.size());
+ for(int e = 0;e<m_selection.size();e++)
+ {
+ if(m_selection(e))
+ {
+ m_translations[e] =
+ m_translations_at_selection[e] +
+ m_parent_rotations_at_selection[e].conjugate()*
+ m_trans_widget.m_trans;
+ }
+ }
+ }
+ }
+ return true;
+ }
+}
+
+inline bool igl::opengl2::MouseController::up(const int x, const int y)
+{
+ m_is_selecting = false;
+ m_widget.up(x,m_height-y);
+ m_trans_widget.up(x,m_height-y);
+ return false;
+}
+
+inline void igl::opengl2::MouseController::draw() const
+{
+ if(any_selection())
+ {
+ switch(m_widget_mode)
+ {
+ default:
+ case WIDGET_MODE_ROTATE:
+ m_widget.draw();
+ break;
+ case WIDGET_MODE_TRANSLATE:
+ m_trans_widget.draw();
+ break;
+ }
+ }
+ if(m_is_selecting)
+ {
+ // Remember settings
+ GLboolean dt;
+ glGetBooleanv(GL_DEPTH_TEST,&dt);
+ int old_vp[4];
+ glGetIntegerv(GL_VIEWPORT,old_vp);
+
+ // True screen space
+ glViewport(0,0,m_width,m_height);
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ gluOrtho2D(0,m_width,0,m_height);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDisable(GL_DEPTH_TEST);
+ draw_rectangular_marquee(
+ m_down_x,
+ m_height-m_down_y,
+ m_drag_x,
+ m_height-m_drag_y);
+
+ // Restore settings
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glPopMatrix();
+ glViewport(old_vp[0],old_vp[1],old_vp[2],old_vp[3]);
+ dt?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST);
+
+ }
+}
+
+inline void igl::opengl2::MouseController::set_selection_from_last_drag(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const Eigen::VectorXi & RP)
+{
+ using namespace Eigen;
+ using namespace std;
+ m_rotations_at_selection = m_rotations;
+ m_translations_at_selection = m_translations;
+ assert(BE.rows() == P.rows());
+ m_selection = VectorXb::Zero(BE.rows());
+ // m_rotation[e] is the relative rotation stored at bone e (as seen by the
+ // joint traveling with its parent)
+ // vQ[e] is the absolute rotation of a bone at rest to its current position:
+ // vQ[e] = vQ[p(e)] * m_rotation[e]
+ vector<Quaterniond,aligned_allocator<Quaterniond> > vQ;
+ vector<Vector3d> vT;
+ forward_kinematics(C,BE,P,m_rotations,m_translations,vQ,vT);
+ // Loop over deformed bones
+ for(int e = 0;e<BE.rows();e++)
+ {
+ Affine3d a = Affine3d::Identity();
+ a.translate(vT[e]);
+ a.rotate(vQ[e]);
+ Vector3d s = a * (Vector3d)C.row(BE(e,0));
+ Vector3d d = a * (Vector3d)C.row(BE(e,1));
+ Vector3d projs = project(s);
+ Vector3d projd = project(d);
+ m_selection(e) = line_segment_in_rectangle(
+ projs.head(2),projd.head(2),
+ Vector2d(m_down_x,m_height-m_down_y),
+ Vector2d(m_drag_x,m_height-m_drag_y));
+ }
+ return set_selection(m_selection,C,BE,P,RP);
+}
+
+inline void igl::opengl2::MouseController::set_selection(
+ const Eigen::VectorXi & S,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const Eigen::VectorXi & P,
+ const Eigen::VectorXi & RP)
+{
+ using namespace Eigen;
+ using namespace std;
+ vector<Quaterniond,aligned_allocator<Quaterniond> > & vQ =
+ m_fk_rotations_at_selection;
+ vector<Vector3d> & vT = m_fk_translations_at_selection;
+ forward_kinematics(C,BE,P,m_rotations,m_translations,vQ,vT);
+ m_parent_rotations_at_selection.resize(
+ m_rotations.size(),Quaterniond::Identity());
+ for(size_t r = 0;r<vQ.size();r++)
+ {
+ if(P(r)>=0)
+ {
+ m_parent_rotations_at_selection[r] = vQ[P(r)];
+ }
+ }
+
+
+ if(&m_selection != &S)
+ {
+ m_selection = S;
+ }
+ assert(m_selection.rows() == BE.rows());
+ assert(BE.rows() == P.rows());
+ assert(BE.rows() == RP.rows());
+ // Zero-out S up a path of ones from e
+ auto propagate = [&](const int e, const VectorXb & S, VectorXb & N)
+ {
+ if(S(e))
+ {
+ int f = e;
+ while(true)
+ {
+ int p = P(f);
+ if(p==-1||!S(p))
+ {
+ break;
+ }
+ N(f) = false;
+ f = p;
+ }
+ }
+ };
+ VectorXb prev_selection = m_selection;
+ // Combine upward, group rigid parts, repeat
+ while(true)
+ {
+ // Spread selection across rigid pieces
+ VectorXb SRP(VectorXb::Zero(RP.maxCoeff()+1));
+ for(int e = 0;e<BE.rows();e++)
+ {
+ SRP(RP(e)) |= m_selection(e);
+ }
+ for(int e = 0;e<BE.rows();e++)
+ {
+ m_selection(e) = SRP(RP(e));
+ }
+ // Clear selections below m_selection ancestors
+ VectorXb new_selection = m_selection;
+ for(int e = 0;e<P.rows();e++)
+ {
+ propagate(e,m_selection,new_selection);
+ }
+ m_selection = new_selection;
+ if(m_selection==prev_selection)
+ {
+ break;
+ }
+ prev_selection = m_selection;
+ }
+
+ // Now selection should contain just bone roots of m_selection subtrees
+ if(m_selection.array().any())
+ {
+ // Taking average
+ Vector3d avg_pos(0,0,0);
+ //m_trans_widget_trans_at_selection.setConstant(0);
+ m_widget_rot_at_selection.coeffs().setConstant(0);
+ m_widget.rot.coeffs().array().setConstant(0);
+ Quaterniond cur_rot(0,0,0,0);
+ int num_selection = 0;
+ // Compute average widget for selection
+ for(int e = 0;e<BE.rows();e++)
+ {
+ if(m_selection(e))
+ {
+ Vector3d s = C.row(BE(e,0));
+ Vector3d d = C.row(BE(e,1));
+ auto b = (d-s).transpose().eval();
+ {
+ Affine3d a = Affine3d::Identity();
+ a.translate(vT[e]);
+ a.rotate(vQ[e]);
+ avg_pos += a*s;
+ }
+ // Rotation of x axis to this bone
+ Quaterniond rot_at_bind;
+ rot_at_bind.setFromTwoVectors(Vector3d(1,0,0),b);
+ const Quaterniond abs_rot = vQ[e] * rot_at_bind;
+ m_widget_rot_at_selection.coeffs() += abs_rot.coeffs();
+ //m_trans_widget_trans_at_selection += vT[e];
+ num_selection++;
+ }
+ }
+ // Take average
+ avg_pos.array() /= (double)num_selection;
+ //m_trans_widget_trans_at_selection.array() /= (double)num_selection;
+ m_widget_rot_at_selection.coeffs().array() /= (double)num_selection;
+ m_widget_rot_at_selection.normalize();
+ m_widget.rot = m_widget_rot_at_selection;
+ m_widget.pos = avg_pos;
+ m_trans_widget.m_pos = avg_pos;
+ //m_trans_widget.m_trans = m_trans_widget_trans_at_selection;
+ m_trans_widget.m_trans.setConstant(0);
+ }
+ m_widget.m_is_enabled = true;
+ m_trans_widget.m_is_enabled = true;
+ for(int s = 0;s<m_selection.rows();s++)
+ {
+ // a root is selected then disable.
+ if(!m_root_enabled && m_selection(s) && P(s) == -1)
+ {
+ m_widget.m_is_enabled = false;
+ m_trans_widget.m_is_enabled = false;
+ break;
+ }
+ }
+}
+
+inline void igl::opengl2::MouseController::set_size(const int n)
+{
+ using namespace Eigen;
+ clear_selection();
+ m_rotations.clear();
+ m_rotations.resize(n,Quaterniond::Identity());
+ m_translations.clear();
+ m_translations.resize(n,Vector3d(0,0,0));
+ m_selection = VectorXb::Zero(n);
+}
+
+inline void igl::opengl2::MouseController::reset()
+{
+ reset_rotations();
+ reset_translations();
+}
+
+inline void igl::opengl2::MouseController::reset_selected()
+{
+ reset_selected_rotations();
+ reset_selected_translations();
+}
+
+inline void igl::opengl2::MouseController::reset_rotations()
+{
+ using namespace Eigen;
+ using namespace std;
+ fill(m_rotations.begin(),m_rotations.end(),Quaterniond::Identity());
+ // cop out. just clear selection
+ clear_selection();
+}
+
+inline void igl::opengl2::MouseController::reset_selected_rotations()
+{
+ using namespace Eigen;
+ for(int e = 0;e<m_selection.size();e++)
+ {
+ if(m_selection(e))
+ {
+ m_rotations[e] = Quaterniond::Identity();
+ }
+ }
+}
+
+inline void igl::opengl2::MouseController::reset_translations()
+{
+ using namespace Eigen;
+ using namespace std;
+ fill(m_translations.begin(),m_translations.end(),Vector3d(0,0,0));
+ // cop out. just clear selection
+ clear_selection();
+}
+
+inline void igl::opengl2::MouseController::reset_selected_translations()
+{
+ using namespace Eigen;
+ for(int e = 0;e<m_selection.size();e++)
+ {
+ if(m_selection(e))
+ {
+ m_translations[e] = Vector3d(0,0,0);
+ }
+ }
+}
+
+inline bool igl::opengl2::MouseController::set_rotations(const RotationList & vQ)
+{
+ if(vQ.size() != m_rotations.size())
+ {
+ return false;
+ }
+ assert(!any_selection());
+ m_rotations = vQ;
+ return true;
+}
+
+inline bool igl::opengl2::MouseController::set_translations(const TranslationList & vT)
+{
+ if(vT.size() != m_translations.size())
+ {
+ return false;
+ }
+ assert(!any_selection());
+ m_translations = vT;
+ return true;
+}
+
+inline void igl::opengl2::MouseController::clear_selection()
+{
+ m_selection.setConstant(false);
+}
+
+inline bool igl::opengl2::MouseController::any_selection() const
+{
+ return m_selection.array().any();
+}
+
+inline void igl::opengl2::MouseController::set_widget_mode(const WidgetMode & mode)
+{
+ switch(m_widget_mode)
+ {
+ default:
+ case WIDGET_MODE_TRANSLATE:
+ m_widget.pos = m_trans_widget.m_pos+m_trans_widget.m_trans;
+ break;
+ case WIDGET_MODE_ROTATE:
+ break;
+ }
+ m_widget_mode = mode;
+}
+
+#endif
diff --git a/xs/src/igl/opengl2/RotateWidget.h b/xs/src/igl/opengl2/RotateWidget.h
new file mode 100644
index 000000000..f2900979a
--- /dev/null
+++ b/xs/src/igl/opengl2/RotateWidget.h
@@ -0,0 +1,547 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_ROTATE_WIDGET_H
+#define IGL_OPENGL2_ROTATE_WIDGET_H
+#include "../material_colors.h"
+#include <Eigen/Geometry>
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace opengl2
+ {
+ // 3D Rotate tool widget similar to Maya's. Works best if field of view angle
+ // is less than ~25.
+ class RotateWidget
+ {
+ // If a is true then use A else use desaturated A
+ static inline void glColor4fv(const bool a, const Eigen::Vector4f & A);
+ public:
+ inline static Eigen::Quaterniond axis_q(const int a);
+ inline static Eigen::Vector3d view_direction(const int x, const int y);
+ inline static Eigen::Vector3d view_direction(const Eigen::Vector3d & pos);
+ Eigen::Vector3d pos;
+ Eigen::Quaterniond rot,down_rot;
+ Eigen::Vector2d down_xy,drag_xy,down_dir;
+ Eigen::Vector3d udown,udrag;
+ double outer_radius_on_screen;
+ double outer_over_inner;
+ bool m_is_enabled;
+ enum DownType
+ {
+ DOWN_TYPE_X = 0,
+ DOWN_TYPE_Y = 1,
+ DOWN_TYPE_Z = 2,
+ DOWN_TYPE_OUTLINE = 3,
+ DOWN_TYPE_TRACKBALL = 4,
+ DOWN_TYPE_NONE = 5,
+ NUM_DOWN_TYPES = 6
+ } down_type, selected_type;
+ inline RotateWidget();
+ // Vector from origin to mouse click "Unprojected" onto plane with depth of
+ // origin and scale to so that outer radius is 1
+ //
+ // Inputs:
+ // x mouse x position
+ // y mouse y position
+ // Returns vector
+ inline Eigen::Vector3d unproject_onto(const int x, const int y) const;
+ // Shoot ray from mouse click to sphere
+ //
+ // Inputs:
+ // x mouse x position
+ // y mouse y position
+ // Outputs:
+ // hit position of hit
+ // Returns true only if there was a hit
+ inline bool intersect(
+ const int x,
+ const int y,
+ Eigen::Vector3d & hit) const;
+ inline double unprojected_inner_radius() const;
+ inline bool down(const int x, const int y);
+ inline bool drag(const int x, const int y);
+ inline bool up(const int x, const int y);
+ inline bool is_down() const;
+ inline void draw() const;
+ inline void draw_guide() const;
+ public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW
+ };
+ }
+}
+
+// Implementation
+#include "../PI.h"
+#include "../EPS.h"
+#include "../ray_sphere_intersect.h"
+#include "../mat_to_quat.h"
+#include "../trackball.h"
+#include "gl.h"
+#include "project.h"
+#include "unproject.h"
+#include <iostream>
+#include <cassert>
+
+inline void igl::opengl2::RotateWidget::glColor4fv(
+ const bool a,
+ const Eigen::Vector4f & A)
+{
+ if(a)
+ {
+ ::glColor4fv(A.data());
+ }else
+ {
+ Eigen::Vector4f B;
+ const double f = 0.95; // desaturate by 95%
+ const double L = 0.3*A(0) + 0.6*A(1) + 0.1*A(2);
+ B.head(3) = A.head(3).array() + f*(L-A.head(3).array());
+ B(3) = A(3);
+ ::glColor4fv(B.data());
+ }
+}
+
+inline Eigen::Quaterniond igl::opengl2::RotateWidget::axis_q(const int a)
+{
+ assert(a<3 && a>=0);
+ const Eigen::Quaterniond axes[3] = {
+ Eigen::Quaterniond(Eigen::AngleAxisd(igl::PI*0.5,Eigen::Vector3d(0,1,0))),
+ Eigen::Quaterniond(Eigen::AngleAxisd(igl::PI*0.5,Eigen::Vector3d(1,0,0))),
+ Eigen::Quaterniond::Identity()};
+ return axes[a];
+}
+
+inline Eigen::Vector3d igl::opengl2::RotateWidget::view_direction(const int x, const int y)
+{
+ using namespace Eigen;
+ const Vector3d win_s(x,y,0), win_d(x,y,1);
+ const Vector3d s = unproject(win_s);
+ const Vector3d d = unproject(win_d);
+ return d-s;
+}
+
+inline Eigen::Vector3d igl::opengl2::RotateWidget::view_direction(const Eigen::Vector3d & pos)
+{
+ using namespace Eigen;
+ const Vector3d ppos = project(pos);
+ return view_direction(ppos(0),ppos(1));
+}
+
+inline igl::opengl2::RotateWidget::RotateWidget():
+ pos(0,0,0),
+ rot(Eigen::Quaterniond::Identity()),
+ down_rot(rot),
+ down_xy(-1,-1),drag_xy(-1,-1),
+ outer_radius_on_screen(91.),
+ outer_over_inner(1.13684210526),
+ m_is_enabled(true),
+ down_type(DOWN_TYPE_NONE),
+ selected_type(DOWN_TYPE_NONE)
+{
+}
+
+inline Eigen::Vector3d igl::opengl2::RotateWidget::unproject_onto(
+ const int x,
+ const int y) const
+{
+ using namespace Eigen;
+ // KNOWN BUG: This projects to same depths as pos. I think what we actually
+ // want is The intersection with the plane perpendicular to the view
+ // direction at pos. If the field of view angle is small then this difference
+ // is negligible.
+ //const Vector3d ppos = project(pos);
+ //const Vector3d uxy = unproject( Vector3d(x,y,ppos(2)));
+ // http://en.wikipedia.org/wiki/Line-plane_intersection
+ //
+ // Hrrmmm. There's still something wrong here if the ball's in the corner of
+ // the screen. Am I somehow not accounting for perspective correctly?
+ //
+ // Q: What about just projecting the circle's equation and solving for the
+ // distance?
+ const Vector3d l0 = unproject(Vector3d(x,y,0));
+ const Vector3d l = unproject(Vector3d(x,y,1))-l0;
+ const Vector3d n = view_direction(pos);
+ const double t = (pos-l0).dot(n)/l.dot(n);
+ const Vector3d uxy = l0+t*l;
+ return (uxy-pos)/unprojected_inner_radius()*outer_over_inner*outer_over_inner;
+}
+
+inline bool igl::opengl2::RotateWidget::intersect(
+ const int x,
+ const int y,
+ Eigen::Vector3d & hit) const
+{
+ using namespace Eigen;
+ Vector3d view = view_direction(x,y);
+ const Vector3d ppos = project(pos);
+ Vector3d uxy = unproject(Vector3d(x,y,ppos(2)));
+ double t0,t1;
+ if(!ray_sphere_intersect(uxy,view,pos,unprojected_inner_radius(),t0,t1))
+ {
+ return false;
+ }
+ hit = uxy+t0*view;
+ return true;
+}
+
+
+inline double igl::opengl2::RotateWidget::unprojected_inner_radius() const
+{
+ using namespace Eigen;
+ Vector3d off,ppos,ppos_off,pos_off;
+ project(pos,ppos);
+ ppos_off = ppos;
+ ppos_off(0) += outer_radius_on_screen/outer_over_inner;
+ unproject(ppos_off,pos_off);
+ return (pos-pos_off).norm();
+}
+inline bool igl::opengl2::RotateWidget::down(const int x, const int y)
+{
+ using namespace Eigen;
+ using namespace std;
+ if(!m_is_enabled)
+ {
+ return false;
+ }
+ down_type = DOWN_TYPE_NONE;
+ selected_type = DOWN_TYPE_NONE;
+ down_xy = Vector2d(x,y);
+ drag_xy = down_xy;
+ down_rot = rot;
+ Vector3d ppos = project(pos);
+ const double r = (ppos.head(2) - down_xy).norm();
+ const double thresh = 3;
+ if(fabs(r - outer_radius_on_screen)<thresh)
+ {
+ udown = unproject_onto(x,y);
+ udrag = udown;
+ down_type = DOWN_TYPE_OUTLINE;
+ selected_type = DOWN_TYPE_OUTLINE;
+ // project mouse to same depth as pos
+ return true;
+ }else if(r < outer_radius_on_screen/outer_over_inner+thresh*0.5)
+ {
+ Vector3d hit;
+ const bool is_hit = intersect(down_xy(0),down_xy(1),hit);
+ if(!is_hit)
+ {
+ //cout<<"~~~!is_hit"<<endl;
+ }
+ auto on_meridian = [&](
+ const Vector3d & hit,
+ const Quaterniond & rot,
+ const Quaterniond & m,
+ Vector3d & pl_hit) -> bool
+ {
+ // project onto rotate plane
+ pl_hit = hit-pos;
+ pl_hit = (m.conjugate()*rot.conjugate()*pl_hit).eval();
+ pl_hit(2) = 0;
+ pl_hit = (rot*m*pl_hit).eval();
+ pl_hit.normalize();
+ pl_hit *= unprojected_inner_radius();
+ pl_hit += pos;
+ return (project(pl_hit).head(2)-project(hit).head(2)).norm()<2*thresh;
+ };
+ udown = (hit-pos).normalized()/outer_radius_on_screen;
+ udrag = udown;
+ for(int a = 0;a<3;a++)
+ {
+ Vector3d pl_hit;
+ if(on_meridian(hit,rot,Quaterniond(axis_q(a)),pl_hit))
+ {
+ udown = (pl_hit-pos).normalized()/outer_radius_on_screen;
+ udrag = udown;
+ down_type = DownType(DOWN_TYPE_X+a);
+ selected_type = down_type;
+ {
+ Vector3d dir3 = axis_q(a).conjugate()*down_rot.conjugate()*(hit-pos);
+ dir3 = AngleAxisd(-PI*0.5,Vector3d(0,0,1))*dir3;
+ dir3 = (rot*axis_q(a)*dir3).eval();
+ down_dir = (project((hit+dir3).eval())-project(hit)).head(2);
+ down_dir.normalize();
+ //// flip y because y coordinate is going to be given backwards in
+ //// drag()
+ //down_dir(1) *= -1;
+ }
+ return true;
+ }
+ }
+ //assert(is_hit);
+ down_type = DOWN_TYPE_TRACKBALL;
+ selected_type = DOWN_TYPE_TRACKBALL;
+ return true;
+ }else
+ {
+ return false;
+ }
+}
+
+inline bool igl::opengl2::RotateWidget::drag(const int x, const int y)
+{
+ using namespace std;
+ using namespace Eigen;
+ if(!m_is_enabled)
+ {
+ return false;
+ }
+ drag_xy = Vector2d(x,y);
+ switch(down_type)
+ {
+ case DOWN_TYPE_NONE:
+ return false;
+ default:
+ {
+ const Quaterniond & q = axis_q(down_type-DOWN_TYPE_X);
+ const double dtheta = -(drag_xy - down_xy).dot(down_dir)/
+ outer_radius_on_screen/outer_over_inner*PI/2.;
+ Quaterniond dq(AngleAxisd(dtheta,down_rot*q*Vector3d(0,0,1)));
+ rot = dq * down_rot;
+ udrag = dq * udown;
+ return true;
+ }
+ case DOWN_TYPE_OUTLINE:
+ {
+ Vector3d ppos = project(pos);
+ // project mouse to same depth as pos
+ udrag = unproject_onto(x,y);
+ const Vector2d A = down_xy - ppos.head(2);
+ const Vector2d B = drag_xy - ppos.head(2);
+ const double dtheta = atan2(A(0)*B(1)-A(1)*B(0),A(0)*B(0)+A(1)*B(1));
+ Vector3d n = view_direction(pos).normalized();
+ Quaterniond dq(AngleAxisd(dtheta,-n));
+ //Vector3d n = udrag.cross(udown).normalized();
+ //Quaterniond dq(AngleAxisd(fabs(dtheta),-n));
+ rot = dq * down_rot;
+ }
+ return true;
+ case DOWN_TYPE_TRACKBALL:
+ {
+ Vector3d ppos = project(pos);
+ const double r = (double)outer_radius_on_screen/outer_over_inner*2.0;
+ //const int h = w;
+ Vector4i vp;
+ glGetIntegerv(GL_VIEWPORT,vp.data());
+ const int h = vp(3);
+ Quaterniond dq;
+ trackball(
+ r,r,
+ 1,
+ Quaterniond::Identity(),
+ double( down_xy(0)-ppos(0) )+r/2.,
+ double((h-down_xy(1))-(h-ppos(1)))+r/2.,
+ double( x-ppos(0) )+r/2.,
+ double( (h-y)-(h-ppos(1)))+r/2.,
+ dq);
+ // We've computed change in rotation according to this view:
+ // R = mv * r, R' = rot * (mv * r)
+ // But we only want new value for r:
+ // R' = mv * r'
+ // mv * r' = rot * (mv * r)
+ // r' = mv* * rot * mv * r
+ Matrix4d mv;
+ glGetDoublev(GL_MODELVIEW_MATRIX,mv.data());
+ Quaterniond scene_rot;
+ // Convert modelview matrix to quaternion
+ mat4_to_quat(mv.data(),scene_rot.coeffs().data());
+ scene_rot.normalize();
+ rot = scene_rot.conjugate() * dq * scene_rot * down_rot;
+ }
+ return true;
+ }
+}
+
+inline bool igl::opengl2::RotateWidget::up(const int /*x*/, const int /*y*/)
+{
+ // even if disabled process up
+ down_type = DOWN_TYPE_NONE;
+ return false;
+}
+
+inline bool igl::opengl2::RotateWidget::is_down() const
+{
+ return down_type != DOWN_TYPE_NONE;
+}
+
+inline void igl::opengl2::RotateWidget::draw() const
+{
+ using namespace Eigen;
+ using namespace std;
+ glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT | GL_LINE_BIT);
+ glDisable(GL_CLIP_PLANE0);
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_DEPTH_TEST);
+ glLineWidth(2.0);
+
+ double r = unprojected_inner_radius();
+ Vector3d view = view_direction(pos).normalized();
+
+ auto draw_circle = [&](const bool cull)
+ {
+ Vector3d view = view_direction(pos).normalized();
+ glBegin(GL_LINES);
+ const double th_step = (2.0*igl::PI/100.0);
+ for(double th = 0;th<2.0*igl::PI+th_step;th+=th_step)
+ {
+ Vector3d a(cos(th),sin(th),0.0);
+ Vector3d b(cos(th+th_step),sin(th+th_step),0.0);
+ if(!cull || (0.5*(a+b)).dot(view)<FLOAT_EPS)
+ {
+ glVertex3dv(a.data());
+ glVertex3dv(b.data());
+ }
+ }
+ glEnd();
+ };
+
+
+ glPushMatrix();
+ glTranslated(pos(0),pos(1),pos(2));
+
+ glScaled(r,r,r);
+ // Draw outlines
+ {
+ glPushMatrix();
+ glColor4fv(m_is_enabled,MAYA_GREY);
+ Quaterniond q;
+ q.setFromTwoVectors(Vector3d(0,0,1),view);
+ glMultMatrixd(Affine3d(q).matrix().data());
+ draw_circle(false);
+ glScaled(outer_over_inner,outer_over_inner,outer_over_inner);
+ if(selected_type == DOWN_TYPE_OUTLINE)
+ {
+ glColor4fv(m_is_enabled,MAYA_YELLOW);
+ }else
+ {
+ glColor4fv(m_is_enabled,MAYA_CYAN);
+ }
+ draw_circle(false);
+ glPopMatrix();
+ }
+ // Draw quartiles
+ {
+ glPushMatrix();
+ glMultMatrixd(Affine3d(rot).matrix().data());
+ if(selected_type == DOWN_TYPE_Z)
+ {
+ glColor4fv(m_is_enabled,MAYA_YELLOW);
+ }else
+ {
+ glColor4fv(m_is_enabled,MAYA_BLUE);
+ }
+ draw_circle(true);
+ if(selected_type == DOWN_TYPE_Y)
+ {
+ glColor4fv(m_is_enabled,MAYA_YELLOW);
+ }else
+ {
+ glColor4fv(m_is_enabled,MAYA_GREEN);
+ }
+ glRotated(90.0,1.0,0.0,0.0);
+ draw_circle(true);
+ if(selected_type == DOWN_TYPE_X)
+ {
+ glColor4fv(m_is_enabled,MAYA_YELLOW);
+ }else
+ {
+ glColor4fv(m_is_enabled,MAYA_RED);
+ }
+ glRotated(90.0,0.0,1.0,0.0);
+ draw_circle(true);
+ glPopMatrix();
+ }
+ glColor4fv(m_is_enabled,MAYA_GREY);
+ draw_guide();
+ glPopMatrix();
+
+ glPopAttrib();
+};
+
+inline void igl::opengl2::RotateWidget::draw_guide() const
+{
+ using namespace Eigen;
+ using namespace std;
+ glPushAttrib(
+ GL_DEPTH_BUFFER_BIT |
+ GL_ENABLE_BIT |
+ GL_POLYGON_BIT |
+ GL_POINT_BIT |
+ GL_TRANSFORM_BIT |
+ GL_STENCIL_BUFFER_BIT |
+ GL_LIGHTING_BIT);
+
+ // http://www.codeproject.com/Articles/23444/A-Simple-OpenGL-Stipple-Polygon-Example-EP_OpenGL_
+ const GLubyte halftone[] = {
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55,
+ 0xAA, 0xAA, 0xAA, 0xAA, 0x55, 0x55, 0x55, 0x55};
+
+
+ switch(down_type)
+ {
+ case DOWN_TYPE_NONE:
+ case DOWN_TYPE_TRACKBALL:
+ goto finish;
+ case DOWN_TYPE_OUTLINE:
+ glScaled(outer_over_inner,outer_over_inner,outer_over_inner);
+ break;
+ default:
+ break;
+ }
+ {
+ const Vector3d nudown(udown.normalized()),
+ nudrag(udrag.normalized());
+ glPushMatrix();
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_POINT_SMOOTH);
+ glPointSize(5.);
+ glBegin(GL_POINTS);
+ glVertex3dv(nudown.data());
+ glVertex3d(0,0,0);
+ glVertex3dv(nudrag.data());
+ glEnd();
+ glBegin(GL_LINE_STRIP);
+ glVertex3dv(nudown.data());
+ glVertex3d(0,0,0);
+ glVertex3dv(nudrag.data());
+ glEnd();
+ glEnable(GL_POLYGON_STIPPLE);
+ glPolygonStipple(halftone);
+ glBegin(GL_TRIANGLE_FAN);
+ glVertex3d(0,0,0);
+ Quaterniond dq = rot * down_rot.conjugate();
+ //dq.setFromTwoVectors(nudown,nudrag);
+ for(double t = 0;t<1;t+=0.1)
+ {
+ const Vector3d p = Quaterniond::Identity().slerp(t,dq) * nudown;
+ glVertex3dv(p.data());
+ }
+ glVertex3dv(nudrag.data());
+ glEnd();
+ glPopMatrix();
+ }
+finish:
+ glPopAttrib();
+}
+
+#endif
diff --git a/xs/src/igl/opengl2/TranslateWidget.h b/xs/src/igl/opengl2/TranslateWidget.h
new file mode 100644
index 000000000..7ab06e228
--- /dev/null
+++ b/xs/src/igl/opengl2/TranslateWidget.h
@@ -0,0 +1,211 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_TRANSLATE_WIDGET_H
+#define IGL_OPENGL2_TRANSLATE_WIDGET_H
+#include "../material_colors.h"
+#include <Eigen/Geometry>
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace opengl2
+ {
+ class TranslateWidget
+ {
+public:
+ // m_pos position of center
+ // m_trans translation vector
+ // m_down_xy mouse position on down
+ // m_drag_xy mouse position on drag
+ // m_is_enabled whether enabled
+ Eigen::Vector3d m_pos,m_trans,m_down_trans;
+ Eigen::Vector2d m_down_xy, m_drag_xy;
+ bool m_is_enabled;
+ double m_len;
+ enum DownType
+ {
+ DOWN_TYPE_X = 0,
+ DOWN_TYPE_Y = 1,
+ DOWN_TYPE_Z = 2,
+ DOWN_TYPE_CENTER = 3,
+ DOWN_TYPE_NONE = 4,
+ NUM_DOWN_TYPES = 5
+ } m_down_type, m_selected_type;
+ inline TranslateWidget(const Eigen::Vector3d & pos = Eigen::Vector3d(0,0,0));
+ inline bool down(const int x, const int y);
+ inline bool drag(const int x, const int y);
+ inline bool up(const int x, const int y);
+ inline bool is_down() const;
+ inline void draw() const;
+public:
+ EIGEN_MAKE_ALIGNED_OPERATOR_NEW;
+ };
+ }
+}
+
+// Implementation
+#include "project.h"
+#include "unproject.h"
+
+inline igl::opengl2::TranslateWidget::TranslateWidget(
+ const Eigen::Vector3d & pos):
+ m_pos(pos),
+ m_trans(0,0,0),
+ m_down_xy(-1,-1),
+ m_drag_xy(-1,-1),
+ m_is_enabled(true),
+ m_len(50),
+ m_down_type(DOWN_TYPE_NONE),
+ m_selected_type(DOWN_TYPE_NONE)
+{
+}
+
+inline bool igl::opengl2::TranslateWidget::down(const int x, const int y)
+{
+ using namespace Eigen;
+ using namespace std;
+ if(!m_is_enabled)
+ {
+ return false;
+ }
+ m_down_trans = m_trans;
+ m_down_xy = Vector2d(x,y);
+ m_drag_xy = m_down_xy;
+ m_down_type = DOWN_TYPE_NONE;
+ m_selected_type = DOWN_TYPE_NONE;
+ Vector3d ppos = project((m_pos+m_trans).eval());
+ const double r = (ppos.head(2) - m_down_xy).norm();
+ const double center_thresh = 10;
+ if(r < center_thresh)
+ {
+ m_down_type = DOWN_TYPE_CENTER;
+ m_selected_type = m_down_type;
+ return true;
+ }else if(r < m_len)
+ {
+ // Might be hit on lines
+ }
+ return false;
+}
+
+inline bool igl::opengl2::TranslateWidget::drag(const int x, const int y)
+{
+ using namespace std;
+ using namespace Eigen;
+ if(!m_is_enabled)
+ {
+ return false;
+ }
+ m_drag_xy = Vector2d(x,y);
+ switch(m_down_type)
+ {
+ case DOWN_TYPE_NONE:
+ return false;
+ default:
+ {
+ Vector3d ppos = project((m_pos+m_trans).eval());
+ Vector3d drag3(m_drag_xy(0),m_drag_xy(1),ppos(2));
+ Vector3d down3(m_down_xy(0),m_down_xy(1),ppos(2));
+ m_trans = m_down_trans + unproject(drag3)-unproject(down3);
+ return true;
+ }
+ }
+}
+
+inline bool igl::opengl2::TranslateWidget::up(const int /*x*/, const int /*y*/)
+{
+ // even if disabled process up
+ m_down_type = DOWN_TYPE_NONE;
+ return false;
+}
+
+inline bool igl::opengl2::TranslateWidget::is_down() const
+{
+ return m_down_type != DOWN_TYPE_NONE;
+}
+
+inline void igl::opengl2::TranslateWidget::draw() const
+{
+ using namespace Eigen;
+ using namespace std;
+ glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT | GL_DEPTH_BUFFER_BIT | GL_LINE_BIT);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_DEPTH_TEST);
+ glLineWidth(2.0);
+ auto draw_axes = [&]()
+ {
+ glBegin(GL_LINES);
+ glColor3f(1,0,0);
+ glVertex3f(0,0,0);
+ glVertex3f(1,0,0);
+ glColor3f(0,1,0);
+ glVertex3f(0,0,0);
+ glVertex3f(0,1,0);
+ glColor3f(0,0,1);
+ glVertex3f(0,0,0);
+ glVertex3f(0,0,1);
+ glEnd();
+ };
+ auto draw_cube = []
+ {
+ glBegin(GL_LINES);
+ glVertex3f(-1.0f, 1.0f, 1.0f);
+ glVertex3f(1.0f, 1.0f, 1.0f);
+ glVertex3f(1.0f, 1.0f, 1.0f);
+ glVertex3f(1.0f, -1.0f, 1.0f);
+ glVertex3f(1.0f, -1.0f, 1.0f);
+ glVertex3f(-1.0f, -1.0f, 1.0f);
+ glVertex3f(-1.0f, -1.0f, 1.0f);
+ glVertex3f(-1.0f, 1.0f, 1.0f);
+ glVertex3f(1.0f, 1.0f, 1.0f);
+ glVertex3f(1.0f, 1.0f, -1.0f);
+ glVertex3f(1.0f, 1.0f, -1.0f);
+ glVertex3f(1.0f, -1.0f, -1.0f);
+ glVertex3f(1.0f, -1.0f, -1.0f);
+ glVertex3f(1.0f, -1.0f, 1.0f);
+ glVertex3f(1.0f, 1.0f, -1.0f);
+ glVertex3f(-1.0f, 1.0f, -1.0f);
+ glVertex3f(-1.0f, -1.0f, -1.0f);
+ glVertex3f(1.0f, -1.0f, -1.0f);
+ glVertex3f(-1.0f, -1.0f, -1.0f);
+ glVertex3f(-1.0f, 1.0f, -1.0f);
+ glVertex3f(-1.0f, 1.0f, -1.0f);
+ glVertex3f(-1.0f, 1.0f, 1.0f);
+ glVertex3f(-1.0f, -1.0f, 1.0f);
+ glVertex3f(-1.0f, -1.0f, -1.0f);
+ glEnd();
+ };
+ glPushMatrix();
+ glTranslated( m_pos(0)+m_trans(0), m_pos(1)+m_trans(1), m_pos(2)+m_trans(2));
+
+ {
+ Vector3d off,ppos,ppos_off,pos_off;
+ project((m_pos+m_trans).eval(),ppos);
+ ppos_off = ppos;
+ ppos_off(0) += m_len;
+ unproject(ppos_off,pos_off);
+ const double r = (m_pos+m_trans-pos_off).norm();
+ glScaled(r,r,r);
+ }
+
+ draw_axes();
+ glScaled(0.05,0.05,0.05);
+ if(m_selected_type == DOWN_TYPE_CENTER)
+ {
+ glColor3fv(MAYA_YELLOW.data());
+ }else
+ {
+ glColor3fv(MAYA_GREY.data());
+ }
+ draw_cube();
+ glPopMatrix();
+ glPopAttrib();
+}
+
+#endif
diff --git a/xs/src/igl/opengl2/draw_beach_ball.cpp b/xs/src/igl/opengl2/draw_beach_ball.cpp
new file mode 100644
index 000000000..a661ce4ae
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_beach_ball.cpp
@@ -0,0 +1,283 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "draw_beach_ball.h"
+#include "gl.h"
+
+// I'm not sure why windows would need it this way:
+// http://lists.cairographics.org/archives/cairo/2008-January/012722.html
+#ifdef _MSC_VER
+#define SAFE_INLINE __inline
+#else
+#define SAFE_INLINE inline
+#endif
+
+#include <vector>
+#include <cmath>
+#include <iostream>
+
+// Most of this implementation comes from the AntTweakBar source code:
+// TwMgr.cpp, TwMgr.h, TwColor.h, TwColor.cpp, TwOpenGL.h and TwOpenGL.cpp
+
+////////////////////////////////////////////////////////////////////////////
+// Begin Copied Straight from AntTweakBar
+////////////////////////////////////////////////////////////////////////////
+enum EArrowParts { ARROW_CONE, ARROW_CONE_CAP, ARROW_CYL, ARROW_CYL_CAP };
+
+template <typename T> SAFE_INLINE const T& TClamp(const T& X, const T& Limit1, const T& Limit2)
+{
+ if( Limit1<Limit2 )
+ return (X<=Limit1) ? Limit1 : ( (X>=Limit2) ? Limit2 : X );
+ else
+ return (X<=Limit2) ? Limit2 : ( (X>=Limit1) ? Limit1 : X );
+}
+
+typedef unsigned int color32;
+static SAFE_INLINE color32 Color32FromARGBi(int A, int R, int G, int B)
+{
+ return (((color32)TClamp(A, 0, 255))<<24) | (((color32)TClamp(R, 0, 255))<<16) | (((color32)TClamp(G, 0, 255))<<8) | ((color32)TClamp(B, 0, 255));
+}
+
+static SAFE_INLINE color32 Color32FromARGBf(float A, float R, float G, float B)
+{
+ return (((color32)TClamp(A*256.0f, 0.0f, 255.0f))<<24) | (((color32)TClamp(R*256.0f, 0.0f, 255.0f))<<16) | (((color32)TClamp(G*256.0f, 0.0f, 255.0f))<<8) | ((color32)TClamp(B*256.0f, 0.0f, 255.0f));
+}
+
+static SAFE_INLINE void Color32ToARGBi(color32 Color, int *A, int *R, int *G, int *B)
+{
+ if(A) *A = (Color>>24)&0xff;
+ if(R) *R = (Color>>16)&0xff;
+ if(G) *G = (Color>>8)&0xff;
+ if(B) *B = Color&0xff;
+}
+
+static SAFE_INLINE void Color32ToARGBf(color32 Color, float *A, float *R, float *G, float *B)
+{
+ if(A) *A = (1.0f/255.0f)*float((Color>>24)&0xff);
+ if(R) *R = (1.0f/255.0f)*float((Color>>16)&0xff);
+ if(G) *G = (1.0f/255.0f)*float((Color>>8)&0xff);
+ if(B) *B = (1.0f/255.0f)*float(Color&0xff);
+}
+
+static color32 ColorBlend(color32 Color1, color32 Color2, float S)
+{
+ float a1, r1, g1, b1, a2, r2, g2, b2;
+ Color32ToARGBf(Color1, &a1, &r1, &g1, &b1);
+ Color32ToARGBf(Color2, &a2, &r2, &g2, &b2);
+ float t = 1.0f-S;
+ return Color32FromARGBf(t*a1+S*a2, t*r1+S*r2, t*g1+S*g2, t*b1+S*b2);
+}
+
+static std::vector<float> s_SphTri;
+static std::vector<color32> s_SphCol;
+static void CreateSphere()
+{
+ const int SUBDIV = 7;
+ s_SphTri.clear();
+ s_SphCol.clear();
+
+ const float A[8*3] = { 1,0,0, 0,0,-1, -1,0,0, 0,0,1, 0,0,1, 1,0,0, 0,0,-1, -1,0,0 };
+ const float B[8*3] = { 0,1,0, 0,1,0, 0,1,0, 0,1,0, 0,-1,0, 0,-1,0, 0,-1,0, 0,-1,0 };
+ const float C[8*3] = { 0,0,1, 1,0,0, 0,0,-1, -1,0,0, 1,0,0, 0,0,-1, -1,0,0, 0,0,1 };
+ //const color32 COL_A[8] = { 0xffff8080, 0xff000080, 0xff800000, 0xff8080ff, 0xff8080ff, 0xffff8080, 0xff000080, 0xff800000 };
+ //const color32 COL_B[8] = { 0xff80ff80, 0xff80ff80, 0xff80ff80, 0xff80ff80, 0xff008000, 0xff008000, 0xff008000, 0xff008000 };
+ //const color32 COL_C[8] = { 0xff8080ff, 0xffff8080, 0xff000080, 0xff800000, 0xffff8080, 0xff000080, 0xff800000, 0xff8080ff };
+ const color32 COL_A[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
+ const color32 COL_B[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
+ const color32 COL_C[8] = { 0xffffffff, 0xffffff40, 0xff40ff40, 0xff40ffff, 0xffff40ff, 0xffff4040, 0xff404040, 0xff4040ff };
+
+ int i, j, k, l;
+ float xa, ya, za, xb, yb, zb, xc, yc, zc, x, y, z, norm, u[3], v[3];
+ color32 col;
+ for( i=0; i<8; ++i )
+ {
+ xa = A[3*i+0]; ya = A[3*i+1]; za = A[3*i+2];
+ xb = B[3*i+0]; yb = B[3*i+1]; zb = B[3*i+2];
+ xc = C[3*i+0]; yc = C[3*i+1]; zc = C[3*i+2];
+ for( j=0; j<=SUBDIV; ++j )
+ for( k=0; k<=2*(SUBDIV-j); ++k )
+ {
+ if( k%2==0 )
+ {
+ u[0] = ((float)j)/(SUBDIV+1);
+ v[0] = ((float)(k/2))/(SUBDIV+1);
+ u[1] = ((float)(j+1))/(SUBDIV+1);
+ v[1] = ((float)(k/2))/(SUBDIV+1);
+ u[2] = ((float)j)/(SUBDIV+1);
+ v[2] = ((float)(k/2+1))/(SUBDIV+1);
+ }
+ else
+ {
+ u[0] = ((float)j)/(SUBDIV+1);
+ v[0] = ((float)(k/2+1))/(SUBDIV+1);
+ u[1] = ((float)(j+1))/(SUBDIV+1);
+ v[1] = ((float)(k/2))/(SUBDIV+1);
+ u[2] = ((float)(j+1))/(SUBDIV+1);
+ v[2] = ((float)(k/2+1))/(SUBDIV+1);
+ }
+
+ for( l=0; l<3; ++l )
+ {
+ x = (1.0f-u[l]-v[l])*xa + u[l]*xb + v[l]*xc;
+ y = (1.0f-u[l]-v[l])*ya + u[l]*yb + v[l]*yc;
+ z = (1.0f-u[l]-v[l])*za + u[l]*zb + v[l]*zc;
+ norm = sqrtf(x*x+y*y+z*z);
+ x /= norm; y /= norm; z /= norm;
+ s_SphTri.push_back(x); s_SphTri.push_back(y); s_SphTri.push_back(z);
+static const float FLOAT_EPS = 1.0e-7f;
+ if( u[l]+v[l]>FLOAT_EPS )
+ col = ColorBlend(COL_A[i], ColorBlend(COL_B[i], COL_C[i], v[l]/(u[l]+v[l])), u[l]+v[l]);
+ else
+ col = COL_A[i];
+ //if( (j==0 && k==0) || (j==0 && k==2*SUBDIV) || (j==SUBDIV && k==0) )
+ // col = 0xffff0000;
+ s_SphCol.push_back(col);
+ }
+ }
+ }
+ //s_SphTriProj.clear();
+ //s_SphTriProj.resize(2*s_SphCol.size(), 0);
+ //s_SphColLight.clear();
+ //s_SphColLight.resize(s_SphCol.size(), 0);
+}
+
+static std::vector<float> s_ArrowTri[4];
+static std::vector<float> s_ArrowNorm[4];
+static void CreateArrow()
+{
+ const int SUBDIV = 15;
+ const float CYL_RADIUS = 0.08f;
+ const float CONE_RADIUS = 0.16f;
+ const float CONE_LENGTH = 0.25f;
+ const float ARROW_BGN = -1.1f;
+ const float ARROW_END = 1.15f;
+ int i;
+ for(i=0; i<4; ++i)
+ {
+ s_ArrowTri[i].clear();
+ s_ArrowNorm[i].clear();
+ }
+
+ float x0, x1, y0, y1, z0, z1, a0, a1, nx, nn;
+ for(i=0; i<SUBDIV; ++i)
+ {
+static const float FLOAT_PI = 3.14159265358979323846f;
+ a0 = 2.0f*FLOAT_PI*(float(i))/SUBDIV;
+ a1 = 2.0f*FLOAT_PI*(float(i+1))/SUBDIV;
+ x0 = ARROW_BGN;
+ x1 = ARROW_END-CONE_LENGTH;
+ y0 = cosf(a0);
+ z0 = sinf(a0);
+ y1 = cosf(a1);
+ z1 = sinf(a1);
+ s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
+ s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
+ s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
+ s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z0);
+ s_ArrowTri[ARROW_CYL].push_back(x0); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
+ s_ArrowTri[ARROW_CYL].push_back(x1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL].push_back(CYL_RADIUS*z1);
+ s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
+ s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
+ s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
+ s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y0); s_ArrowNorm[ARROW_CYL].push_back(z0);
+ s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
+ s_ArrowNorm[ARROW_CYL].push_back(0); s_ArrowNorm[ARROW_CYL].push_back(y1); s_ArrowNorm[ARROW_CYL].push_back(z1);
+ s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(0); s_ArrowTri[ARROW_CYL_CAP].push_back(0);
+ s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*y1); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*z1);
+ s_ArrowTri[ARROW_CYL_CAP].push_back(x0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*y0); s_ArrowTri[ARROW_CYL_CAP].push_back(CYL_RADIUS*z0);
+ s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
+ s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
+ s_ArrowNorm[ARROW_CYL_CAP].push_back(-1); s_ArrowNorm[ARROW_CYL_CAP].push_back(0); s_ArrowNorm[ARROW_CYL_CAP].push_back(0);
+ x0 = ARROW_END-CONE_LENGTH;
+ x1 = ARROW_END;
+ nx = CONE_RADIUS/(x1-x0);
+ nn = 1.0f/sqrtf(nx*nx+1);
+ s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
+ s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z0);
+ s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z1);
+ s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
+ s_ArrowTri[ARROW_CONE].push_back(x0); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE].push_back(CONE_RADIUS*z1);
+ s_ArrowTri[ARROW_CONE].push_back(x1); s_ArrowTri[ARROW_CONE].push_back(0); s_ArrowTri[ARROW_CONE].push_back(0);
+ s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
+ s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
+ s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
+ s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y0); s_ArrowNorm[ARROW_CONE].push_back(nn*z0);
+ s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
+ s_ArrowNorm[ARROW_CONE].push_back(nn*nx); s_ArrowNorm[ARROW_CONE].push_back(nn*y1); s_ArrowNorm[ARROW_CONE].push_back(nn*z1);
+ s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(0); s_ArrowTri[ARROW_CONE_CAP].push_back(0);
+ s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*y1); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*z1);
+ s_ArrowTri[ARROW_CONE_CAP].push_back(x0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*y0); s_ArrowTri[ARROW_CONE_CAP].push_back(CONE_RADIUS*z0);
+ s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
+ s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
+ s_ArrowNorm[ARROW_CONE_CAP].push_back(-1); s_ArrowNorm[ARROW_CONE_CAP].push_back(0); s_ArrowNorm[ARROW_CONE_CAP].push_back(0);
+ }
+
+ //for(i=0; i<4; ++i)
+ //{
+ // s_ArrowTriProj[i].clear();
+ // s_ArrowTriProj[i].resize(2*(s_ArrowTri[i].size()/3), 0);
+ // s_ArrowColLight[i].clear();
+ // s_ArrowColLight[i].resize(s_ArrowTri[i].size()/3, 0);
+ //}
+}
+
+////////////////////////////////////////////////////////////////////////////
+// End Copied Straight from AntTweakBar
+////////////////////////////////////////////////////////////////////////////
+
+IGL_INLINE void igl::opengl2::draw_beach_ball()
+{
+ using namespace std;
+
+ CreateSphere();
+ // Keep track of opengl settings
+ int cm;
+ glGetIntegerv(GL_COLOR_MATERIAL,&cm);
+ // Draw triangles
+ glEnable(GL_COLOR_MATERIAL);
+ glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE);
+ float mat_ambient[4] = {0.1,0.1,0.1,1.0};
+ float mat_specular[4] = {0.0,0.0,0.0,1.0};
+ float mat_shininess = 1;
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+ glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+
+ glPushMatrix();
+ glScalef(0.7,0.7,0.7);
+ glEnable(GL_NORMALIZE);
+ glBegin(GL_TRIANGLES);
+ for(int i = 0;i<(int)s_SphCol.size();i++)
+ {
+ glNormal3fv(&s_SphTri[i*3]);
+ glColor4ub(GLubyte(s_SphCol[i]>>16), GLubyte(s_SphCol[i]>>8), GLubyte(s_SphCol[i]), GLubyte(s_SphCol[i]>>24));
+ glVertex3fv(&s_SphTri[i*3]);
+ }
+ glEnd();
+ glPopMatrix();
+
+ CreateArrow();
+ for(int k = 0;k<3;k++)
+ {
+ glPushMatrix();
+ glColor3f(k==0,k==1,k==2);
+ glRotatef((k==2?-1.0:1.0)*90,k==0,k==2,k==1);
+ glBegin(GL_TRIANGLES);
+ for(int j = 0;j<4;j++)
+ {
+ for(int i = 0;i<(int)s_ArrowTri[j].size();i+=3)
+ {
+ glNormal3fv(&s_ArrowNorm[j][i]);
+ glVertex3fv(&s_ArrowTri[j][i]);
+ }
+ }
+ glEnd();
+ glPopMatrix();
+ }
+
+ (cm ? glEnable(GL_COLOR_MATERIAL):glDisable(GL_COLOR_MATERIAL));
+}
diff --git a/xs/src/igl/opengl2/draw_beach_ball.h b/xs/src/igl/opengl2/draw_beach_ball.h
new file mode 100644
index 000000000..d430dc5ed
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_beach_ball.h
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_DRAW_BEACH_BALL_H
+#define IGL_OPENGL2_DRAW_BEACH_BALL_H
+#include "../igl_inline.h"
+
+namespace igl
+{
+ namespace opengl2
+ {
+ // Draw a beach ball icon/glyph (from AntTweakBar) at the current origin
+ // according to the current orientation: ball has radius 0.75 and axis have
+ // length 1.15
+ IGL_INLINE void draw_beach_ball();
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "draw_beach_ball.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl2/draw_floor.cpp b/xs/src/igl/opengl2/draw_floor.cpp
new file mode 100644
index 000000000..61fa47491
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_floor.cpp
@@ -0,0 +1,161 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "draw_floor.h"
+#include "gl.h"
+
+IGL_INLINE void igl::opengl2::draw_floor(const float * colorA, const float * colorB,
+ const int GridSizeX,
+ const int GridSizeY)
+{
+ const float SizeX = 0.5f*100./(double)GridSizeX;
+ const float SizeY = 0.5f*100./(double)GridSizeY;
+ // old settings
+ int old_lighting=0,old_color_material=0;
+ glGetIntegerv(GL_LIGHTING,&old_lighting);
+ glGetIntegerv(GL_COLOR_MATERIAL,&old_color_material);
+ glDisable(GL_LIGHTING);
+ glColorMaterial( GL_FRONT, GL_EMISSION);
+ glEnable(GL_COLOR_MATERIAL);
+ glColorMaterial( GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+ // Set material
+ const float black[] = {0.,0.,0.,1.};
+ glMaterialfv(GL_FRONT, GL_AMBIENT, black);
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, black);
+ glMaterialfv(GL_FRONT, GL_SPECULAR, black);
+ glMaterialfv(GL_FRONT, GL_EMISSION, black);
+ glMaterialf(GL_FRONT, GL_SHININESS,0);
+ const bool use_lighting = false;
+ if(use_lighting)
+ {
+ glEnable(GL_LIGHTING);
+ }else
+ {
+ glDisable(GL_LIGHTING);
+ }
+
+
+ glBegin(GL_QUADS);
+ glNormal3f(0,1,0);
+ for (int x =-GridSizeX/2;x<GridSizeX/2;++x)
+ {
+ for (int y =-GridSizeY/2;y<GridSizeY/2;++y)
+ {
+ if ((x+y)&0x00000001) //modulo 2
+ {
+ glColor4fv(colorA);
+ }else
+ {
+ glColor4fv(colorB);
+ }
+ glVertex3f( x*SizeX,0,(y+1)*SizeY);
+ glVertex3f((x+1)*SizeX,0,(y+1)*SizeY);
+ glVertex3f((x+1)*SizeX,0, y*SizeY);
+ glVertex3f( x*SizeX,0, y*SizeY);
+ }
+ }
+ glEnd();
+
+ (old_lighting ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING));
+ (old_color_material? glEnable(GL_COLOR_MATERIAL) : glDisable(GL_COLOR_MATERIAL));
+}
+
+IGL_INLINE void igl::opengl2::draw_floor()
+{
+ const float grey[] = {0.80,0.80,0.80,1.};
+ const float white[] = {0.95,0.95,0.95,1.};
+ igl::opengl2::draw_floor(grey,white);
+}
+
+IGL_INLINE void igl::opengl2::draw_floor_outline(const float * colorA, const float * colorB,
+ const int GridSizeX,
+ const int GridSizeY)
+{
+ const float SizeX = 0.5f*100./(double)GridSizeX;
+ const float SizeY = 0.5f*100./(double)GridSizeY;
+ float old_line_width =0;
+ // old settings
+ int old_lighting=0,old_color_material=0;
+ glGetIntegerv(GL_LIGHTING,&old_lighting);
+ glGetIntegerv(GL_COLOR_MATERIAL,&old_color_material);
+ glDisable(GL_LIGHTING);
+
+ // Set material
+ const float black[] = {0.,0.,0.,1.};
+ glMaterialfv(GL_FRONT, GL_AMBIENT, black);
+ glMaterialfv(GL_FRONT, GL_DIFFUSE, black);
+ glMaterialfv(GL_FRONT, GL_SPECULAR, black);
+ glMaterialfv(GL_FRONT, GL_EMISSION, black);
+ glMaterialf(GL_FRONT, GL_SHININESS,0);
+ const bool use_lighting = false;
+ if(use_lighting)
+ {
+ glEnable(GL_LIGHTING);
+ }else
+ {
+ glDisable(GL_LIGHTING);
+ }
+
+ glLineWidth(2.0f);
+ glBegin(GL_LINES);
+ for (int x =-GridSizeX/2;x<=GridSizeX/2;++x)
+ {
+ if(x!=(GridSizeX/2))
+ {
+ for(int s = -1;s<2;s+=2)
+ {
+ int y = s*(GridSizeY/2);
+ int cy = y==(GridSizeY/2) ? y-1 : y;
+ if ((x+cy)&0x00000001) //modulo 2
+ {
+ glColor4fv(colorA);
+ //glColor3f(1,0,0);
+ }else
+ {
+ glColor4fv(colorB);
+ //glColor3f(0,0,1);
+ }
+ glVertex3f((x+1)*SizeX,0,y*SizeY);
+ glVertex3f( x*SizeX,0,y*SizeY);
+ }
+ }
+ if(x==-(GridSizeX/2) || x==(GridSizeX/2))
+ {
+ int cx = x==(GridSizeX/2) ? x-1 : x;
+ for (int y =-GridSizeY/2;y<GridSizeY/2;++y)
+ {
+ if ((cx+y)&0x00000001) //modulo 2
+ {
+ glColor4fv(colorA);
+ //glColor3f(1,0,0);
+ }else
+ {
+ glColor4fv(colorB);
+ //glColor3f(0,0,1);
+ }
+ glVertex3f(x*SizeX,0,(y+1)*SizeY);
+ glVertex3f(x*SizeX,0, y*SizeY);
+ }
+ }
+ }
+ glEnd();
+
+ glGetFloatv(GL_LINE_WIDTH,&old_line_width);
+ glLineWidth(old_line_width);
+ (old_lighting ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING));
+ (old_color_material? glEnable(GL_COLOR_MATERIAL) : glDisable(GL_COLOR_MATERIAL));
+}
+
+IGL_INLINE void igl::opengl2::draw_floor_outline()
+{
+ const float grey[] = {0.80,0.80,0.80,1.};
+ const float white[] = {0.95,0.95,0.95,1.};
+ igl::opengl2::draw_floor_outline(grey,white);
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/opengl2/draw_floor.h b/xs/src/igl/opengl2/draw_floor.h
new file mode 100644
index 000000000..3f06fa9b0
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_floor.h
@@ -0,0 +1,60 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_DRAW_FLOOR_H
+#define IGL_OPENGL2_DRAW_FLOOR_H
+#include "../igl_inline.h"
+namespace igl
+{
+ namespace opengl2
+ {
+
+ // Draw a checkerboard floor aligned with current (X,Z) plane using ../opengl/OpenGL_
+ // calls. side=50 centered at (0,0):
+ // (-25,-25)-->(-25,25)-->(25,25)-->(25,-25)
+ //
+ // Use glPushMatrix(), glScaled(), glTranslated() to arrange the floor.
+ //
+ // Inputs:
+ // colorA float4 color
+ // colorB float4 color
+ //
+ // Example:
+ // // Draw a nice floor
+ // glPushMatrix();
+ // glCullFace(GL_BACK);
+ // glEnable(GL_CULL_FACE);
+ // glEnable(GL_LIGHTING);
+ // glTranslated(0,-1,0);
+ // if(project(Vector3d(0,0,0))(2) - project(Vector3d(0,1,0))(2) > -FLOAT_EPS)
+ // {
+ // draw_floor_outline();
+ // }
+ // draw_floor();
+ // glPopMatrix();
+ // glDisable(GL_CULL_FACE);
+ //
+ IGL_INLINE void draw_floor(
+ const float * colorA,
+ const float * colorB,
+ const int GridSizeX=100,
+ const int GridSizeY=100);
+ // Wrapper with default colors
+ IGL_INLINE void draw_floor();
+ IGL_INLINE void draw_floor_outline(
+ const float * colorA,
+ const float * colorB,
+ const int GridSizeX=100,
+ const int GridSizeY=100);
+ // Wrapper with default colors
+ IGL_INLINE void draw_floor_outline();
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "draw_floor.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl2/draw_mesh.cpp b/xs/src/igl/opengl2/draw_mesh.cpp
new file mode 100644
index 000000000..aeaed12f0
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_mesh.cpp
@@ -0,0 +1,278 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "draw_mesh.h"
+
+IGL_INLINE void igl::opengl2::draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N)
+{
+ using namespace Eigen;
+ MatrixXd _d;
+ MatrixXi _i;
+ return draw_mesh(V,F,N,_i,_d,_d,_i,_d,0,_i,0);
+}
+
+IGL_INLINE void igl::opengl2::draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXd & C)
+{
+ using namespace Eigen;
+ MatrixXd _d;
+ MatrixXi _i;
+ return draw_mesh(V,F,N,_i,C,_d,_i,_d,0,_i,0);
+}
+
+IGL_INLINE void igl::opengl2::draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXd & TC)
+{
+ using namespace Eigen;
+ MatrixXd _d;
+ MatrixXi _i;
+ return draw_mesh(V,F,N,_i,C,TC,_i,_d,0,_i,0);
+}
+
+IGL_INLINE void igl::opengl2::draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXd & TC,
+ const Eigen::MatrixXd & W,
+ const GLuint W_index,
+ const Eigen::MatrixXi & WI,
+ const GLuint WI_index)
+{
+ using namespace Eigen;
+ return draw_mesh(V,F,N,MatrixXi(),C,TC,MatrixXi(),W,W_index,WI,WI_index);
+}
+
+IGL_INLINE void igl::opengl2::draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXi & NF,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXd & TC,
+ const Eigen::MatrixXi & TF,
+ const Eigen::MatrixXd & W,
+ const GLuint W_index,
+ const Eigen::MatrixXi & WI,
+ const GLuint WI_index)
+{
+ using namespace std;
+ using namespace Eigen;
+ const int rF = F.rows();
+ const int cF = F.cols();
+ const int cC = C.cols();
+ const int rC = C.rows();
+ const int cW = W.cols();
+ const int rW = W.rows();
+ const int rV = V.rows();
+ const int rTC = TC.rows();
+ const int rTF = TF.rows();
+ const int rNF = NF.rows();
+ const int rN = N.rows();
+
+ if(F.size() > 0)
+ {
+ assert(F.maxCoeff() < V.rows());
+ assert(V.cols() == 3);
+ assert(rC == rV || rC == rF || rC == rF*3 || rC==1 || C.size() == 0);
+ assert(C.cols() >= 3 || C.size() == 0);
+ assert(N.cols() == 3 || N.size() == 0);
+ assert(TC.cols() == 2 || TC.size() == 0);
+ assert(cF == 3 || cF == 4);
+ assert(TF.size() == 0 || TF.cols() == F.cols());
+ assert(NF.size() == 0 || NF.cols() == NF.cols());
+ }
+ if(W.size()>0)
+ {
+ assert(W.rows() == V.rows());
+ assert(WI.rows() == V.rows());
+ assert(W.cols() == WI.cols());
+ }
+
+ switch(F.cols())
+ {
+ default:
+ case 3:
+ glBegin(GL_TRIANGLES);
+ break;
+ case 4:
+ glBegin(GL_QUADS);
+ break;
+ }
+ // loop over faces
+ for(int i = 0; i<rF;i++)
+ {
+ // loop over corners of triangle
+ for(int j = 0;j<cF;j++)
+ {
+
+ int tc = -1;
+ if(rTF != 0)
+ {
+ tc = TF(i,j);
+ } else if(rTC == 1)
+ {
+ tc = 0;
+ }else if(rTC == rV)
+ {
+ tc = F(i,j);
+ }else if(rTC == rF*cF)
+ {
+ tc = i*cF + j;
+ }else if(rTC == rF)
+ {
+ tc = i;
+ }else
+ {
+ assert(TC.size() == 0);
+ }
+
+ // RGB(A)
+ Matrix<MatrixXd::Scalar,1,Dynamic> color;
+ if(rC == 1)
+ {
+ color = C.row(0);
+ }else if(rC == rV)
+ {
+ color = C.row(F(i,j));
+ }else if(rC == rF*cF)
+ {
+ color = C.row(i*cF+j);
+ }else if(rC == rF)
+ {
+ color = C.row(i);
+ }else
+ {
+ assert(C.size() == 0);
+ }
+
+ int n = -1;
+ if(rNF != 0)
+ {
+ n = NF(i,j); // indexed normals
+ } else if(rN == 1)
+ {
+ n = 0; // uniform normals
+ }else if(rN == rF)
+ {
+ n = i; // face normals
+ }else if(rN == rV)
+ {
+ n = F(i,j); // vertex normals
+ }else if(rN == rF*cF)
+ {
+ n = i*cF + j; // corner normals
+ }else
+ {
+ assert(N.size() == 0);
+ }
+
+ {
+ if(rW>0 && W_index !=0 && WI_index != 0)
+ {
+ int weights_left = cW;
+ while(weights_left != 0)
+ {
+ int pass_size = std::min(4,weights_left);
+ int weights_already_passed = cW-weights_left;
+ // Get attribute location of next 4 weights
+ int pass_W_index = W_index + weights_already_passed/4;
+ int pass_WI_index = WI_index + weights_already_passed/4;
+ switch(pass_size)
+ {
+ case 1:
+ glVertexAttrib1d(
+ pass_W_index,
+ W(F(i,j),0+weights_already_passed));
+ glVertexAttrib1d(
+ pass_WI_index,
+ WI(F(i,j),0+weights_already_passed));
+ break;
+ case 2:
+ glVertexAttrib2d(
+ pass_W_index,
+ W(F(i,j),0+weights_already_passed),
+ W(F(i,j),1+weights_already_passed));
+ glVertexAttrib2d(
+ pass_WI_index,
+ WI(F(i,j),0+weights_already_passed),
+ WI(F(i,j),1+weights_already_passed));
+ break;
+ case 3:
+ glVertexAttrib3d(
+ pass_W_index,
+ W(F(i,j),0+weights_already_passed),
+ W(F(i,j),1+weights_already_passed),
+ W(F(i,j),2+weights_already_passed));
+ glVertexAttrib3d(
+ pass_WI_index,
+ WI(F(i,j),0+weights_already_passed),
+ WI(F(i,j),1+weights_already_passed),
+ WI(F(i,j),2+weights_already_passed));
+ break;
+ default:
+ glVertexAttrib4d(
+ pass_W_index,
+ W(F(i,j),0+weights_already_passed),
+ W(F(i,j),1+weights_already_passed),
+ W(F(i,j),2+weights_already_passed),
+ W(F(i,j),3+weights_already_passed));
+ glVertexAttrib4d(
+ pass_WI_index,
+ WI(F(i,j),0+weights_already_passed),
+ WI(F(i,j),1+weights_already_passed),
+ WI(F(i,j),2+weights_already_passed),
+ WI(F(i,j),3+weights_already_passed));
+ break;
+ }
+ weights_left -= pass_size;
+ }
+ }
+ if(tc != -1)
+ {
+ glTexCoord2d(TC(tc,0),TC(tc,1));
+ }
+ if(rC>0)
+ {
+ switch(cC)
+ {
+ case 3:
+ glColor3dv(color.data());
+ break;
+ case 4:
+ glColor4dv(color.data());
+ break;
+ default:
+ break;
+ }
+ }
+ if(n != -1)
+ {
+ glNormal3d(N(n,0),N(n,1),N(n,2));
+ }
+ glVertex3d(V(F(i,j),0),V(F(i,j),1),V(F(i,j),2));
+ }
+ }
+ }
+ glEnd();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
+
diff --git a/xs/src/igl/opengl2/draw_mesh.h b/xs/src/igl/opengl2/draw_mesh.h
new file mode 100644
index 000000000..ea1559c20
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_mesh.h
@@ -0,0 +1,122 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_DRAW_MESH_H
+#define IGL_OPENGL2_DRAW_MESH_H
+#include "../igl_inline.h"
+#include "gl.h"
+#include <Eigen/Dense>
+
+
+namespace igl
+{
+ namespace opengl2
+ {
+
+ // Draw ../opengl/OpenGL_ commands needed to display a mesh with normals
+ //
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3|4 eigen Matrix of face (triangle/quad) indices
+ // N #V|#F by 3 eigen Matrix of 3D normals
+ IGL_INLINE void draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N);
+
+ // Draw ../opengl/OpenGL_ commands needed to display a mesh with normals and per-vertex
+ // colors
+ //
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3|4 eigen Matrix of face (triangle/quad) indices
+ // N #V|#F by 3 eigen Matrix of 3D normals
+ // C #V|#F|1 by 3 eigen Matrix of RGB colors
+ IGL_INLINE void draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXd & C);
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3|4 eigen Matrix of face (triangle/quad) indices
+ // N #V|#F by 3 eigen Matrix of 3D normals
+ // C #V|#F|1 by 3 eigen Matrix of RGB colors
+ // TC #V|#F|1 by 3 eigen Matrix of Texture Coordinates
+ IGL_INLINE void draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXd & TC);
+
+ // Draw ../opengl/OpenGL_ commands needed to display a mesh with normals, per-vertex
+ // colors and LBS weights
+ //
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3|4 eigen Matrix of face (triangle/quad) indices
+ // N #V by 3 eigen Matrix of mesh vertex 3D normals
+ // C #V by 3 eigen Matrix of mesh vertex RGB colors
+ // TC #V by 3 eigen Matrix of mesh vertex UC coorindates between 0 and 1
+ // W #V by #H eigen Matrix of per mesh vertex, per handle weights
+ // W_index Specifies the index of the "weight" vertex attribute: see
+ // glBindAttribLocation, if W_index is 0 then weights are ignored
+ // WI #V by #H eigen Matrix of per mesh vertex, per handle weight ids
+ // WI_index Specifies the index of the "weight" vertex attribute: see
+ // glBindAttribLocation, if WI_index is 0 then weight indices are ignored
+ IGL_INLINE void draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXd & TC,
+ const Eigen::MatrixXd & W,
+ const GLuint W_index,
+ const Eigen::MatrixXi & WI,
+ const GLuint WI_index);
+
+ // Draw ../opengl/OpenGL_ commands needed to display a mesh with normals, per-vertex
+ // colors and LBS weights
+ //
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3|4 eigen Matrix of face (triangle/quad) indices
+ // N #V by 3 eigen Matrix of mesh vertex 3D normals
+ // NF #F by 3 eigen Matrix of face (triangle/quad) normal indices, <0
+ // means no normal
+ // C #V by 3 eigen Matrix of mesh vertex RGB colors
+ // TC #V by 3 eigen Matrix of mesh vertex UC coorindates between 0 and 1
+ // TF #F by 3 eigen Matrix of face (triangle/quad) texture indices, <0
+ // means no texture
+ // W #V by #H eigen Matrix of per mesh vertex, per handle weights
+ // W_index Specifies the index of the "weight" vertex attribute: see
+ // glBindAttribLocation, if W_index is 0 then weights are ignored
+ // WI #V by #H eigen Matrix of per mesh vertex, per handle weight ids
+ // WI_index Specifies the index of the "weight" vertex attribute: see
+ // glBindAttribLocation, if WI_index is 0 then weight indices are ignored
+ IGL_INLINE void draw_mesh(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXd & N,
+ const Eigen::MatrixXi & NF,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXd & TC,
+ const Eigen::MatrixXi & TF,
+ const Eigen::MatrixXd & W,
+ const GLuint W_index,
+ const Eigen::MatrixXi & WI,
+ const GLuint WI_index);
+
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "draw_mesh.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl2/draw_point.cpp b/xs/src/igl/opengl2/draw_point.cpp
new file mode 100644
index 000000000..910fcc716
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_point.cpp
@@ -0,0 +1,100 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "draw_point.h"
+
+// Implementation
+#include "gl.h"
+
+#include <cassert>
+#include <cmath>
+
+IGL_INLINE void igl::opengl2::draw_point(
+ const double x,
+ const double y,
+ const double z,
+ const double requested_r,
+ const bool selected)
+{
+ // Push GL settings
+ glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT);
+
+ float f;
+ glGetFloatv(GL_POINT_SIZE_MAX,&f);
+ // THIS IS OVERZEALOUS on Mac OS X: OpenGL reports a smaller point size than
+ // possible.
+ //assert(requested_r<=0.5*f);
+ double r = (requested_r<0.5*f?requested_r:0.5*f);
+
+ //glDisable(GL_DEPTH_TEST);
+ glDisable(GL_LIGHTING);
+
+ // get current color
+ float color[4];
+ glGetFloatv(GL_CURRENT_COLOR,color);
+
+ double outline_size = (r>7 ? sqrt(r/7.0) : 1.0);
+
+ // White outline
+ glColor4f(1,1,1,color[3]);
+ glPointSize(2*r);
+ glBegin(GL_POINTS);
+ glVertex3d(x,y,z);
+ glEnd();
+ // Black outline
+ glColor4f(0,0,0,color[3]);
+ glPointSize(2*r-2*outline_size);
+ glBegin(GL_POINTS);
+ glVertex3d(x,y,z);
+ glEnd();
+
+ // Foreground
+ glColor4fv(color);
+ glPointSize(2*r-4*outline_size);
+ glBegin(GL_POINTS);
+ glVertex3d(x,y,z);
+ glEnd();
+ // Selection inner circle
+ if(selected)
+ {
+ glColor4f(0,0,0,color[3]);
+ double selected_size = 2*r-7*outline_size;
+ selected_size = (selected_size>3?selected_size:3);
+ glPointSize(selected_size);
+ glBegin(GL_POINTS);
+ glVertex3d(x,y,z);
+ glEnd();
+ }
+
+ // reset color
+ glColor4fv(color);
+
+ // Pop GL settings
+ glPopAttrib();
+}
+
+template <typename DerivedP>
+IGL_INLINE void igl::opengl2::draw_point(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const double requested_r,
+ const bool selected)
+{
+ switch(P.size())
+ {
+ case 2:
+ return draw_point(P(0),P(1),0,requested_r,selected);
+ default:
+ return draw_point(P(0),P(1),P(2),requested_r,selected);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::opengl2::draw_point<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, double, bool);
+template void igl::opengl2::draw_point<Eigen::Matrix<double, 2, 1, 0, 2, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, double, bool);
+#endif
+
diff --git a/xs/src/igl/opengl2/draw_point.h b/xs/src/igl/opengl2/draw_point.h
new file mode 100644
index 000000000..2c7cc1c7d
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_point.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_DRAW_POINT_H
+#define IGL_OPENGL2_DRAW_POINT_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace opengl2
+ {
+
+ //double POINT_COLOR[3] = {239./255.,213./255.,46./255.};
+ // Draw a nice looking, colored dot at a given point in 3d.
+ //
+ // Note: expects that GL_CURRENT_COLOR is set with the desired foreground color
+ //
+ // Inputs:
+ // x x-coordinate of point, modelview coordinates
+ // y y-coordinate of point, modelview coordinates
+ // z z-coordinate of point, modelview coordinates
+ // requested_r outer-most radius of dot {7}, measured in screen space pixels
+ // selected fills inner circle with black {false}
+ // Asserts that requested_r does not exceed 0.5*GL_POINT_SIZE_MAX
+ IGL_INLINE void draw_point(
+ const double x,
+ const double y,
+ const double z,
+ const double requested_r = 7,
+ const bool selected = false);
+ template <typename DerivedP>
+ IGL_INLINE void draw_point(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const double requested_r = 7,
+ const bool selected = false);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "draw_point.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl2/draw_rectangular_marquee.cpp b/xs/src/igl/opengl2/draw_rectangular_marquee.cpp
new file mode 100644
index 000000000..73f97c844
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_rectangular_marquee.cpp
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+
+#include "draw_rectangular_marquee.h"
+#include "gl.h"
+#include "glu.h"
+#include "../material_colors.h"
+
+IGL_INLINE void igl::opengl2::draw_rectangular_marquee(
+ const int from_x,
+ const int from_y,
+ const int to_x,
+ const int to_y)
+{
+ using namespace std;
+ int l;
+ glGetIntegerv(GL_LIGHTING,&l);
+ int s;
+ glGetIntegerv(GL_LINE_STIPPLE,&s);
+ double lw;
+ glGetDoublev(GL_LINE_WIDTH,&lw);
+ glDisable(GL_LIGHTING);
+ // Screen space for this viewport
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT,viewport);
+ const int width = viewport[2];
+ const int height = viewport[3];
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+ gluOrtho2D(0,width,0,height);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glEnable(GL_LINE_STIPPLE);
+ glLineStipple(3,0xAAAA);
+ glLineWidth(1);
+ glColor4f(0.2,0.2,0.2,1);
+ glBegin(GL_LINE_STRIP);
+ glVertex2d(from_x,from_y);
+ glVertex2d(to_x,from_y);
+ glVertex2d(to_x,to_y);
+ glVertex2d(from_x,to_y);
+ glVertex2d(from_x,from_y);
+ glEnd();
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ glMatrixMode(GL_MODELVIEW);
+ glLineWidth(lw);
+ (s ? glEnable(GL_LINE_STIPPLE):glDisable(GL_LINE_STIPPLE));
+ (l ? glEnable(GL_LIGHTING):glDisable(GL_LIGHTING));
+}
+
diff --git a/xs/src/igl/opengl2/draw_rectangular_marquee.h b/xs/src/igl/opengl2/draw_rectangular_marquee.h
new file mode 100644
index 000000000..bbb2e3f18
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_rectangular_marquee.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_DRAW_RECTANGULAR_MARQUEE_H
+#define IGL_OPENGL2_DRAW_RECTANGULAR_MARQUEE_H
+#include "../igl_inline.h"
+namespace igl
+{
+ namespace opengl2
+ {
+ // Draw a rectangular marquee (selection box) in screen space. This sets up
+ // screen space using current viewport.
+ //
+ // Inputs:
+ // from_x x coordinate of from point
+ // from_y y coordinate of from point
+ // to_x x coordinate of to point
+ // to_y y coordinate of to point
+ IGL_INLINE void draw_rectangular_marquee(
+ const int from_x,
+ const int from_y,
+ const int to_x,
+ const int to_y);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "draw_rectangular_marquee.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl2/draw_skeleton_3d.cpp b/xs/src/igl/opengl2/draw_skeleton_3d.cpp
new file mode 100644
index 000000000..a0ca6139a
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_skeleton_3d.cpp
@@ -0,0 +1,166 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "draw_skeleton_3d.h"
+#include "../PI.h"
+#include "../material_colors.h"
+#include "gl.h"
+#include <Eigen/Geometry>
+#include <iostream>
+
+
+template <
+ typename DerivedC,
+ typename DerivedBE,
+ typename DerivedT,
+ typename Derivedcolor>
+IGL_INLINE void igl::opengl2::draw_skeleton_3d(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const Eigen::PlainObjectBase<Derivedcolor> & color,
+ const double half_bbd)
+{
+ // Note: Maya's skeleton *does* scale with the mesh suggesting a scale
+ // parameter. Further, its joint balls are not rotated with the bones.
+ using namespace Eigen;
+ using namespace std;
+ if(color.size() == 0)
+ {
+ return draw_skeleton_3d(C,BE,T,MAYA_SEA_GREEN,half_bbd);
+ }
+ assert(color.cols() == 4 || color.size() == 4);
+ if(T.size() == 0)
+ {
+ typedef Eigen::Matrix<typename DerivedT::Scalar,Dynamic,Dynamic> Mat;
+ Mat I = Mat::Identity(C.cols()+1,C.cols());
+ Mat T = I.replicate(BE.rows(),1);
+ // insane base case
+ if(T.size() == 0)
+ {
+ return;
+ }
+ return draw_skeleton_3d(C,BE,T,color,half_bbd);
+ }
+ assert(T.rows() == BE.rows()*(C.cols()+1));
+ assert(T.cols() == C.cols());
+ // push old settings
+ glPushAttrib(GL_LIGHTING_BIT);
+ glPushAttrib(GL_LINE_BIT);
+ glDisable(GL_LIGHTING);
+ glLineWidth(1.0);
+
+ auto draw_sphere = [](const double r)
+ {
+ auto draw_circle = []()
+ {
+ glBegin(GL_LINE_STRIP);
+ for(double th = 0;th<2.0*igl::PI;th+=(2.0*igl::PI/30.0))
+ {
+ glVertex3d(cos(th),sin(th),0.0);
+ }
+ glVertex3d(cos(0),sin(0),0.0);
+ glEnd();
+ };
+ glPushMatrix();
+ glScaled(r,r,r);
+ draw_circle();
+ glRotated(90.0,1.0,0.0,0.0);
+ draw_circle();
+ glRotated(90.0,0.0,1.0,0.0);
+ draw_circle();
+ glPopMatrix();
+ };
+ auto draw_pyramid = []()
+ {
+ glBegin(GL_LINE_STRIP);
+ glVertex3d(0, 1,-1);
+ glVertex3d(0,-1,-1);
+ glVertex3d(0,-1, 1);
+ glVertex3d(0, 1, 1);
+ glVertex3d(0, 1,-1);
+ glEnd();
+ glBegin(GL_LINES);
+ glVertex3d(0, 1,-1);
+ glVertex3d(1,0,0);
+ glVertex3d(0,-1,-1);
+ glVertex3d(1,0,0);
+ glVertex3d(0,-1, 1);
+ glVertex3d(1,0,0);
+ glVertex3d(0, 1, 1);
+ glVertex3d(1,0,0);
+ glEnd();
+ };
+
+ // Loop over bones
+ for(int e = 0;e < BE.rows();e++)
+ {
+ // Draw a sphere
+ auto s = C.row(BE(e,0));
+ auto d = C.row(BE(e,1));
+ auto b = (d-s).transpose().eval();
+ double r = 0.02*half_bbd;
+ Matrix4d Te = Matrix4d::Identity();
+ Te.block(0,0,3,4) = T.block(e*4,0,4,3).transpose();
+ Quaterniond q;
+ q.setFromTwoVectors(Vector3d(1,0,0),b);
+ glPushMatrix();
+ glMultMatrixd(Te.data());
+ glTranslated(s(0),s(1),s(2));
+ if(color.size() == 4)
+ {
+ glColor4d( color(0), color(1), color(2), color(3));
+ }else
+ {
+ glColor4d( color(e,0), color(e,1), color(e,2), color(e,3));
+ }
+ draw_sphere(r);
+ const double len = b.norm()-2.*r;
+ if(len>=0)
+ {
+ auto u = b.normalized()*r;
+ glPushMatrix();
+ glTranslated(u(0),u(1),u(2));
+ glMultMatrixd(Affine3d(q).matrix().data());
+ glScaled(b.norm()-2.*r,r,r);
+ draw_pyramid();
+ glPopMatrix();
+ }
+ glTranslated(b(0),b(1),b(2));
+ draw_sphere(r);
+ glPopMatrix();
+ }
+ // Reset settings
+ glPopAttrib();
+ glPopAttrib();
+}
+
+template <typename DerivedC, typename DerivedBE, typename DerivedT>
+IGL_INLINE void igl::opengl2::draw_skeleton_3d(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T)
+{
+ return draw_skeleton_3d(C,BE,T,MAYA_SEA_GREEN);
+}
+
+template <typename DerivedC, typename DerivedBE>
+IGL_INLINE void igl::opengl2::draw_skeleton_3d(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE)
+{
+ return draw_skeleton_3d(C,BE,Eigen::MatrixXd(),MAYA_SEA_GREEN);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::opengl2::draw_skeleton_3d<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template void igl::opengl2::draw_skeleton_3d<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+template void igl::opengl2::draw_skeleton_3d<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 4, 1, 0, 4, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, double);
+template void igl::opengl2::draw_skeleton_3d<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, double);
+#endif
diff --git a/xs/src/igl/opengl2/draw_skeleton_3d.h b/xs/src/igl/opengl2/draw_skeleton_3d.h
new file mode 100644
index 000000000..7bbb59717
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_skeleton_3d.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_DRAW_SKELETON_3D_H
+#define IGL_OPENGL2_DRAW_SKELETON_3D_H
+#include "../igl_inline.h"
+#include "../material_colors.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace opengl2
+ {
+
+ // Draw a skeleton
+ //
+ // Inputs:
+ // C #C by dim List of joint rest positions
+ // BE #BE by 2 list of bone edge indices into C
+ // T #BE*(dim+1) by dim matrix of stacked transposed bone transformations
+ // color #BE|1 by 4 list of color
+ // half_bbd half bounding box diagonal to determine scaling {1.0}
+ template <
+ typename DerivedC,
+ typename DerivedBE,
+ typename DerivedT,
+ typename Derivedcolor>
+ IGL_INLINE void draw_skeleton_3d(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const Eigen::PlainObjectBase<Derivedcolor> & color,
+ const double half_bbd=0.5);
+ // Default color
+ template <typename DerivedC, typename DerivedBE, typename DerivedT>
+ IGL_INLINE void draw_skeleton_3d(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T);
+ template <typename DerivedC, typename DerivedBE>
+ IGL_INLINE void draw_skeleton_3d(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "draw_skeleton_3d.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl2/draw_skeleton_vector_graphics.cpp b/xs/src/igl/opengl2/draw_skeleton_vector_graphics.cpp
new file mode 100644
index 000000000..e45706120
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_skeleton_vector_graphics.cpp
@@ -0,0 +1,122 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "draw_skeleton_vector_graphics.h"
+#include "draw_point.h"
+#include "gl.h"
+#include "../material_colors.h"
+
+IGL_INLINE void igl::opengl2::draw_skeleton_vector_graphics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE)
+{
+ return draw_skeleton_vector_graphics(C,BE,BBW_POINT_COLOR,BBW_LINE_COLOR);
+}
+
+IGL_INLINE void igl::opengl2::draw_skeleton_vector_graphics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const float * point_color,
+ const float * line_color)
+{
+ using namespace Eigen;
+
+ int old_lighting=0;
+ double old_line_width=1;
+ glGetIntegerv(GL_LIGHTING,&old_lighting);
+ glGetDoublev(GL_LINE_WIDTH,&old_line_width);
+ int cm;
+ glGetIntegerv(GL_COLOR_MATERIAL,&cm);
+ glDisable(GL_LIGHTING);
+ glDisable(GL_LINE_STIPPLE);
+ //glEnable(GL_POLYGON_OFFSET_FILL);
+ glEnable(GL_COLOR_MATERIAL);
+ glLineWidth(10.0);
+ glColorMaterial(GL_FRONT_AND_BACK,GL_DIFFUSE);
+ float mat_ambient[4] = {0.1,0.1,0.1,1.0};
+ float mat_specular[4] = {0.0,0.0,0.0,1.0};
+ float mat_shininess = 1;
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, mat_ambient);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, mat_specular);
+ glMaterialf( GL_FRONT_AND_BACK, GL_SHININESS, mat_shininess);
+
+ for(int i = 0;i<3;i++)
+ {
+ switch(i)
+ {
+ case 0: glColor3fv(WHITE); glLineWidth(10); break;
+ case 1: glColor3fv(BLACK); glLineWidth( 6); break;
+ case 2: glColor3fv(line_color); glLineWidth( 4); break;
+ }
+ // Loop over bone edges
+ glBegin(GL_LINES);
+ for(int e = 0;e<BE.rows();e++)
+ {
+ RowVector3d tip = C.row(BE(e,0));
+ RowVector3d tail = C.row(BE(e,1));
+ glVertex3dv(tip.data());
+ glVertex3dv(tail.data());
+ }
+ glEnd();
+ }
+
+ glColor3fv(point_color);
+ for(int i = 0;i<C.rows();i++)
+ {
+ RowVector3d p = C.row(i);
+ draw_point(p(0),p(1),p(2));
+ }
+
+ (cm ? glEnable(GL_COLOR_MATERIAL):glDisable(GL_COLOR_MATERIAL));
+ //glDisable(GL_POLYGON_OFFSET_FILL);
+ glEnable(GL_LIGHTING);
+ (old_lighting ? glEnable(GL_LIGHTING) : glDisable(GL_LIGHTING));
+ glLineWidth(old_line_width);
+}
+
+template <typename DerivedC, typename DerivedBE, typename DerivedT>
+IGL_INLINE void igl::opengl2::draw_skeleton_vector_graphics(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T)
+{
+ return draw_skeleton_vector_graphics(C,BE,T,BBW_POINT_COLOR,BBW_LINE_COLOR);
+}
+
+template <typename DerivedC, typename DerivedBE, typename DerivedT>
+IGL_INLINE void igl::opengl2::draw_skeleton_vector_graphics(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const float * point_color,
+ const float * line_color)
+{
+ DerivedC CT;
+ DerivedBE BET;
+ const int dim = T.cols();
+ assert(dim == C.cols());
+ CT.resize(2*BE.rows(),C.cols());
+ BET.resize(BE.rows(),2);
+ for(int e = 0;e<BE.rows();e++)
+ {
+ BET(e,0) = 2*e;
+ BET(e,1) = 2*e+1;
+ const auto & c0 = C.row(BE(e,0));
+ const auto & c1 = C.row(BE(e,1));
+ const auto & L = T.block(e*(dim+1),0,dim,dim);
+ const auto & t = T.block(e*(dim+1)+dim,0,1,dim);
+ CT.row(2*e) = c0 * L + t;
+ CT.row(2*e+1) = c1 * L + t;
+ }
+ draw_skeleton_vector_graphics(CT,BET,point_color,line_color);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::opengl2::draw_skeleton_vector_graphics<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/opengl2/draw_skeleton_vector_graphics.h b/xs/src/igl/opengl2/draw_skeleton_vector_graphics.h
new file mode 100644
index 000000000..8091cbb78
--- /dev/null
+++ b/xs/src/igl/opengl2/draw_skeleton_vector_graphics.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_DRAW_SKELETON_VECTOR_GRAPHICS_H
+#define IGL_OPENGL2_DRAW_SKELETON_VECTOR_GRAPHICS_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace opengl2
+ {
+ // Draw a skeleton with a 2D vector graphcis style à la BBW, STBS, Monotonic,
+ // FAST papers.
+ //
+ // Inputs:
+ // C #C by dim list of joint positions
+ // BE #BE by 2 list of bone edge indices into C
+ // point_color color of points
+ // line_color color of lines
+ IGL_INLINE void draw_skeleton_vector_graphics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE,
+ const float * point_color,
+ const float * line_color);
+ // Use default colors (originally from BBW paper)
+ IGL_INLINE void draw_skeleton_vector_graphics(
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & BE);
+ // T #BE*(dim+1) by dim matrix of stacked transposed bone transformations
+ template <typename DerivedC, typename DerivedBE, typename DerivedT>
+ IGL_INLINE void draw_skeleton_vector_graphics(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const float * point_color,
+ const float * line_color);
+ template <typename DerivedC, typename DerivedBE, typename DerivedT>
+ IGL_INLINE void draw_skeleton_vector_graphics(
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ const Eigen::PlainObjectBase<DerivedBE> & BE,
+ const Eigen::PlainObjectBase<DerivedT> & T);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "draw_skeleton_vector_graphics.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl2/flare_textures.h b/xs/src/igl/opengl2/flare_textures.h
new file mode 100644
index 000000000..0455195eb
--- /dev/null
+++ b/xs/src/igl/opengl2/flare_textures.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_FLARE_TEXTURES_H
+#define IGL_OPENGL2_FLARE_TEXTURES_H
+#include <cstdint>
+namespace igl
+{
+ namespace opengl2
+ {
+
+ const uint8_t FLARE_TEXTURE_0[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,20,20,20,20,23,23,23,23,23,23,23,23,23,23,23,23,23,23,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,20,20,20,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,20,20,23,23,28,28,28,28,28,28,28,31,31,31,31,31,31,31,31,31,31,31,31,31,31,28,28,28,28,28,28,28,28,23,23,20,20,20,20,15,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,20,23,28,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,31,28,28,28,28,28,23,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,15,20,20,20,23,23,28,28,28,28,31,31,36,36,36,36,36,36,36,36,39,39,39,39,39,39,39,39,39,39,39,39,39,36,36,36,36,36,36,36,36,31,28,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,31,36,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,44,44,47,47,47,47,47,47,47,47,47,47,47,47,47,44,44,44,44,44,44,44,39,39,36,36,36,36,31,31,28,28,28,23,23,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,28,31,31,36,36,36,36,39,44,44,44,44,44,47,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,44,44,39,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,28,28,31,36,36,36,39,44,44,44,44,44,47,47,52,52,52,52,52,52,52,55,55,55,55,55,55,55,55,55,55,55,55,55,52,52,52,52,52,52,52,47,47,44,44,44,44,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,52,47,47,44,44,44,39,39,36,36,36,31,28,28,28,23,20,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,55,55,60,60,60,60,60,60,60,63,63,63,63,63,63,63,63,63,63,63,63,60,60,60,60,60,60,60,60,55,52,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,15,20,20,23,28,28,28,36,36,36,39,44,44,44,47,47,52,52,52,55,55,60,60,60,60,60,63,63,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,63,63,63,60,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,20,23,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,63,68,68,68,68,68,68,68,71,71,71,71,71,71,71,71,71,71,71,71,68,68,68,68,68,68,68,63,63,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,28,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,20,28,28,28,31,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,68,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,71,71,68,68,68,68,68,63,63,60,60,60,55,55,52,52,52,47,44,44,39,36,36,36,31,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,36,39,44,44,47,52,52,52,55,60,60,60,63,63,68,68,68,68,71,76,76,76,76,76,76,76,79,79,79,79,79,79,79,79,79,79,79,79,76,76,76,76,76,76,76,71,71,68,68,68,68,63,60,60,60,55,52,52,52,47,44,44,44,39,36,36,31,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,39,44,44,44,47,52,52,55,60,60,60,63,63,68,68,68,71,71,76,76,76,76,79,79,79,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,79,79,76,76,76,76,76,71,68,68,68,68,63,60,60,60,55,52,52,52,47,44,44,39,36,36,31,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,79,79,84,84,84,84,84,84,84,87,87,87,87,87,87,87,87,87,87,87,84,84,84,84,84,84,84,79,76,76,76,76,71,71,68,68,68,63,60,60,60,55,52,52,47,44,44,44,36,36,36,28,28,28,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,31,36,36,39,44,44,47,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,79,84,84,84,84,84,87,87,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,87,87,84,84,84,84,84,79,76,76,76,71,71,68,68,68,60,60,60,55,52,52,52,44,44,44,36,36,36,28,28,28,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,31,36,36,39,44,44,47,52,52,55,60,60,63,68,68,68,71,76,76,76,79,79,84,84,84,84,87,92,92,92,92,92,92,92,95,95,95,95,95,95,95,95,95,95,95,92,92,92,92,92,92,87,87,84,84,84,84,79,76,76,76,71,68,68,68,63,60,60,60,52,52,52,47,44,44,39,36,36,28,28,28,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,31,36,36,39,44,44,47,52,52,55,60,60,63,68,68,68,71,76,76,79,79,84,84,84,87,92,92,92,92,92,95,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,92,87,84,84,84,84,79,76,76,76,71,68,68,68,60,60,60,55,52,52,47,44,44,39,36,36,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,31,36,36,39,44,44,52,52,52,60,60,60,63,68,68,71,76,76,76,79,84,84,84,87,92,92,92,92,95,100,100,100,100,100,100,100,103,103,103,103,103,103,103,103,103,103,100,100,100,100,100,100,100,95,95,92,92,92,87,87,84,84,84,79,76,76,71,68,68,68,63,60,60,55,52,52,47,44,44,39,36,36,28,28,23,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,28,28,31,36,36,39,44,44,52,52,52,60,60,60,68,68,68,71,76,76,79,84,84,84,87,92,92,92,95,95,100,100,100,100,103,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,100,100,100,100,100,95,92,92,92,87,84,84,84,79,76,76,76,71,68,68,63,60,60,55,52,52,47,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,23,28,31,36,36,39,44,44,52,52,52,60,60,63,68,68,68,76,76,76,79,84,84,87,92,92,92,95,95,100,100,100,103,103,108,108,108,108,108,108,111,111,111,111,111,111,111,111,111,111,108,108,108,108,108,108,108,103,100,100,100,100,95,92,92,92,87,84,84,84,79,76,76,71,68,68,63,60,60,55,52,52,47,44,44,36,36,31,28,28,23,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,44,47,52,52,60,60,63,68,68,71,76,76,79,84,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,111,108,108,108,108,103,103,100,100,100,95,92,92,92,87,84,84,79,76,76,71,68,68,63,60,60,55,52,52,47,44,44,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,31,36,39,44,44,47,52,52,60,60,63,68,68,71,76,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,111,116,116,116,116,116,116,119,119,119,119,119,119,119,119,119,119,116,116,116,116,116,116,111,111,108,108,108,103,103,100,100,100,95,92,92,87,84,84,79,76,76,71,68,68,63,60,60,55,52,52,44,44,39,36,36,31,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,36,44,44,47,52,52,60,60,63,68,68,71,76,76,79,84,84,87,92,92,92,100,100,100,103,108,108,108,111,111,116,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,87,84,84,84,76,76,76,68,68,63,60,60,55,52,52,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,47,52,52,55,60,60,68,68,71,76,76,79,84,84,87,92,92,95,100,100,100,108,108,108,111,116,116,116,116,119,119,124,124,124,124,124,124,127,127,127,127,127,127,127,127,127,124,124,124,124,124,124,119,116,116,116,116,111,108,108,108,103,100,100,100,92,92,92,84,84,84,76,76,76,68,68,63,60,60,55,52,47,44,44,39,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,39,44,44,52,52,55,60,60,68,68,71,76,76,79,84,84,87,92,92,95,100,100,103,108,108,108,111,116,116,116,119,124,124,124,124,127,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,119,119,116,116,116,111,108,108,103,100,100,100,95,92,92,87,84,84,76,76,71,68,68,63,60,60,52,52,47,44,44,36,36,31,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,28,28,31,36,36,44,44,47,52,55,60,60,63,68,68,76,76,79,84,84,87,92,92,95,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,132,135,135,135,135,135,135,135,135,135,132,132,132,132,132,132,127,124,124,124,119,119,116,116,111,108,108,108,103,100,100,95,92,92,87,84,84,76,76,71,68,68,63,60,55,52,52,44,44,39,36,36,28,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,39,44,47,52,52,60,60,63,68,68,76,76,79,84,84,87,92,92,100,100,100,108,108,108,111,116,116,119,124,124,124,127,127,132,132,132,132,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,87,84,84,76,76,71,68,68,60,60,55,52,52,44,44,39,36,31,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,39,44,44,52,52,55,60,63,68,68,71,76,79,84,84,87,92,92,100,100,100,108,108,108,116,116,116,119,124,124,124,127,132,132,132,135,140,140,140,140,140,140,143,143,143,143,143,143,143,143,140,140,140,140,140,140,135,135,132,132,132,127,124,124,124,119,116,116,111,108,108,103,100,100,95,92,92,84,84,79,76,76,71,68,63,60,60,52,52,47,44,44,36,36,28,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,44,44,47,52,55,60,60,68,68,71,76,76,84,84,87,92,92,95,100,100,108,108,111,116,116,116,124,124,124,127,132,132,132,135,140,140,140,140,143,143,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,103,100,100,95,92,92,84,84,79,76,76,68,68,63,60,55,52,52,44,44,39,36,31,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,28,28,31,36,39,44,44,52,52,60,60,63,68,68,76,76,79,84,87,92,92,95,100,100,108,108,111,116,116,119,124,124,124,132,132,132,135,140,140,140,143,143,148,148,148,148,148,151,151,151,151,151,151,151,151,148,148,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,103,100,100,92,92,87,84,84,79,76,71,68,68,60,60,55,52,47,44,44,36,36,31,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,31,36,36,44,44,47,52,55,60,60,68,68,71,76,79,84,84,92,92,95,100,100,108,108,111,116,116,119,124,124,127,132,132,132,140,140,140,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,111,108,108,103,100,100,92,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,31,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,28,28,31,36,39,44,47,52,52,60,60,63,68,71,76,76,84,84,87,92,92,100,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,140,143,148,148,148,151,156,156,156,156,156,156,159,159,159,159,159,159,159,156,156,156,156,156,151,151,148,148,148,143,140,140,135,132,132,132,124,124,119,116,116,111,108,108,100,100,95,92,92,84,84,79,76,76,68,68,60,60,55,52,47,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,44,44,47,52,55,60,63,68,68,76,76,79,84,87,92,92,100,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,156,159,164,164,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,151,148,148,143,140,140,140,132,132,132,124,124,119,116,116,111,108,108,100,100,95,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,31,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,44,52,52,60,60,63,68,71,76,79,84,84,92,92,95,100,100,108,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,151,156,156,156,159,159,164,164,164,164,164,167,167,167,167,167,167,167,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,103,100,100,92,92,87,84,79,76,76,68,68,63,60,55,52,47,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,47,52,55,60,63,68,68,76,76,79,84,87,92,92,100,100,108,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,151,156,156,159,164,164,164,164,167,167,172,172,172,172,172,172,172,172,172,172,172,167,164,164,164,164,159,156,156,156,151,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,103,100,95,92,92,84,84,79,76,71,68,63,60,60,52,52,44,44,39,36,31,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,36,44,44,52,52,60,60,63,68,71,76,79,84,84,92,92,95,100,103,108,108,116,116,119,124,124,132,132,135,140,140,143,148,148,156,156,156,159,164,164,164,167,172,172,172,172,172,175,175,175,175,175,175,175,172,172,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,111,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,31,36,39,44,47,52,55,60,60,68,68,76,76,79,84,87,92,95,100,100,108,108,111,116,119,124,124,132,132,135,140,140,143,148,148,156,156,156,164,164,164,167,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,108,108,103,100,95,92,92,84,84,79,76,71,68,63,60,60,52,52,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,52,52,55,60,63,68,71,76,76,84,84,92,92,95,100,103,108,111,116,116,124,124,127,132,132,140,140,143,148,148,156,156,156,164,164,164,172,172,172,175,180,180,180,180,180,183,183,183,183,183,183,180,180,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,132,124,124,119,116,111,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,52,52,47,44,39,36,31,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,44,52,52,60,60,68,68,71,76,79,84,87,92,95,100,100,108,108,116,116,119,124,124,132,132,140,140,143,148,148,156,156,156,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,188,188,188,188,188,188,183,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,124,116,116,111,108,103,100,95,92,92,84,84,76,76,71,68,63,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,47,52,55,60,63,68,68,76,76,84,84,92,92,95,100,103,108,111,116,116,124,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,180,183,188,188,188,188,191,191,191,191,191,191,188,188,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,127,124,119,116,111,108,108,100,100,92,92,87,84,79,76,71,68,63,60,60,52,52,44,44,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,47,52,55,60,63,68,71,76,79,84,84,92,92,100,100,108,108,111,116,119,124,127,132,132,140,140,143,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,188,191,191,196,196,196,196,196,196,196,196,196,191,188,188,188,183,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,111,108,103,100,95,92,87,84,84,76,76,68,68,60,60,52,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,79,84,87,92,95,100,103,108,108,116,116,124,124,127,132,135,140,143,148,148,156,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,196,196,199,199,199,199,199,196,196,196,196,191,188,188,188,180,180,180,172,172,167,164,164,156,156,151,148,143,140,140,132,132,127,124,119,116,111,108,108,100,100,92,92,84,84,76,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,52,60,60,68,68,76,76,84,84,92,92,100,100,103,108,111,116,119,124,124,132,132,140,140,148,148,151,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,204,204,204,204,204,204,199,199,196,196,196,191,188,188,180,180,180,172,172,167,164,159,156,156,148,148,143,140,135,132,127,124,124,116,116,108,108,100,100,95,92,87,84,79,76,71,68,63,60,55,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,84,92,92,100,100,108,108,116,116,119,124,127,132,135,140,143,148,148,156,156,164,164,167,172,172,180,180,183,188,188,191,196,196,199,204,204,204,204,207,207,207,207,207,204,204,204,204,196,196,196,191,188,188,180,180,175,172,172,164,164,159,156,151,148,143,140,140,132,132,124,124,119,116,111,108,103,100,95,92,87,84,79,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,108,116,116,124,124,132,132,140,140,143,148,151,156,159,164,164,172,172,175,180,183,188,188,191,196,196,199,204,204,207,212,212,212,212,212,212,212,212,207,204,204,204,199,196,196,191,188,188,180,180,175,172,167,164,164,156,156,148,148,140,140,135,132,127,124,119,116,111,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,132,140,140,148,148,156,156,159,164,167,172,175,180,180,188,188,191,196,196,204,204,204,207,212,212,212,215,215,215,215,212,212,212,212,207,204,204,199,196,196,188,188,183,180,180,172,172,164,164,159,156,151,148,143,140,135,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,100,100,108,108,111,116,119,124,127,132,135,140,143,148,151,156,156,164,164,172,172,180,180,183,188,191,196,196,199,204,204,212,212,212,215,220,220,220,220,220,220,220,215,212,212,207,204,204,199,196,191,188,188,180,180,175,172,167,164,159,156,156,148,148,140,140,132,132,124,124,116,116,108,108,103,100,95,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,7,12,15,20,23,28,31,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,100,100,108,108,116,116,124,124,132,132,140,140,143,148,151,156,159,164,167,172,175,180,180,188,188,196,196,199,204,204,212,212,215,220,220,220,220,223,223,223,220,220,220,215,212,212,207,204,204,196,196,191,188,183,180,175,172,172,164,164,156,156,148,148,140,140,135,132,127,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,84,92,92,100,100,108,108,116,116,124,124,132,132,140,140,148,148,156,156,164,164,167,172,175,180,183,188,191,196,196,204,204,207,212,215,220,220,223,228,228,228,228,228,228,223,220,220,215,212,212,207,204,199,196,196,188,188,180,180,172,172,164,164,159,156,151,148,143,140,135,132,127,124,119,116,111,108,103,100,95,92,87,84,79,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,124,132,132,140,140,148,148,156,156,164,164,172,172,180,180,188,188,191,196,199,204,207,212,212,220,220,223,228,228,228,231,231,231,228,228,228,220,220,215,212,212,204,204,196,196,188,188,183,180,175,172,167,164,159,156,151,148,143,140,135,132,127,124,119,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,156,164,164,172,172,180,180,188,188,196,196,204,204,212,212,215,220,223,228,228,231,236,236,236,236,236,228,228,223,220,220,212,212,207,204,199,196,191,188,183,180,175,172,167,164,159,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,196,204,204,212,212,220,220,228,228,231,236,236,239,239,236,236,236,228,228,223,220,215,212,207,204,199,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,220,228,228,236,236,239,244,244,244,239,236,231,228,223,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,244,247,244,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,247,252,244,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,236,244,244,244,244,239,236,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,212,220,220,228,228,236,236,239,244,244,239,236,236,231,228,223,220,215,212,207,204,204,196,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,151,156,159,164,167,172,175,180,180,188,188,196,196,204,204,212,212,220,220,223,228,228,236,236,236,236,236,236,231,228,228,220,220,215,212,207,204,199,196,191,188,183,180,175,172,172,164,164,156,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,140,148,148,156,156,164,164,172,172,180,180,188,188,196,196,199,204,207,212,215,220,220,228,228,228,231,236,236,236,231,228,228,223,220,220,212,212,204,204,199,196,191,188,183,180,175,172,167,164,159,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,95,100,100,108,108,116,116,124,124,132,132,140,140,148,148,156,156,164,164,172,172,180,180,183,188,191,196,199,204,204,212,212,215,220,220,223,228,228,228,228,228,228,228,223,220,220,212,212,207,204,204,196,196,188,188,180,180,175,172,167,164,159,156,151,148,143,140,135,132,127,124,119,116,111,108,103,100,100,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,60,68,68,76,76,84,84,92,92,100,100,108,108,116,116,124,124,132,132,140,140,148,148,151,156,159,164,167,172,175,180,183,188,188,196,196,204,204,207,212,212,215,220,220,223,223,228,228,228,223,220,220,220,215,212,212,204,204,199,196,191,188,188,180,180,172,172,164,164,156,156,151,148,143,140,135,132,127,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,63,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,100,100,108,108,116,116,124,124,127,132,135,140,143,148,151,156,159,164,164,172,172,180,180,188,188,191,196,196,204,204,207,212,212,215,220,220,220,220,220,220,220,220,220,212,212,212,204,204,199,196,196,188,188,183,180,175,172,167,164,164,156,156,148,148,140,140,132,132,124,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,68,68,76,76,84,84,92,92,95,100,103,108,111,116,119,124,127,132,135,140,143,148,148,156,156,164,164,172,172,175,180,183,188,188,196,196,199,204,204,207,212,212,212,215,220,220,220,220,215,215,212,212,212,204,204,204,196,196,191,188,188,180,180,172,172,167,164,159,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,100,92,92,87,84,79,76,71,68,63,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,63,68,71,76,79,84,87,92,95,100,103,108,111,116,119,124,124,132,132,140,140,148,148,151,156,159,164,167,172,172,180,180,183,188,191,196,196,199,204,204,207,212,212,212,212,212,212,212,212,212,212,207,204,204,204,196,196,191,188,188,180,180,175,172,172,164,164,156,156,151,148,143,140,135,132,127,124,119,116,116,108,108,100,100,92,92,84,84,76,76,68,68,60,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,47,52,55,60,63,68,71,76,79,84,87,92,92,100,100,108,108,116,116,124,124,132,132,135,140,143,148,151,156,156,164,164,167,172,175,180,180,188,188,191,196,196,199,204,204,204,207,207,212,212,212,212,207,207,204,204,204,199,196,196,191,188,188,183,180,180,172,172,167,164,159,156,156,148,148,140,140,132,132,127,124,119,116,111,108,103,100,95,92,92,84,84,76,76,68,68,60,60,52,52,44,44,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,55,60,63,68,68,76,76,84,84,92,92,100,100,108,108,111,116,119,124,127,132,135,140,140,148,148,156,156,159,164,164,172,172,175,180,180,188,188,191,196,196,196,199,204,204,204,204,204,204,204,204,204,204,204,199,196,196,191,188,188,183,180,180,175,172,167,164,164,156,156,151,148,143,140,135,132,132,124,124,116,116,108,108,103,100,95,92,87,84,79,76,71,68,68,60,60,52,52,44,44,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,36,44,44,52,52,60,60,68,68,76,76,84,84,87,92,95,100,103,108,111,116,116,124,124,132,132,140,140,143,148,151,156,156,164,164,167,172,172,180,180,180,188,188,188,191,196,196,196,199,199,204,204,204,204,204,199,199,196,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,151,148,148,140,140,135,132,127,124,119,116,116,108,108,100,100,92,92,84,84,79,76,71,68,63,60,55,52,47,44,39,36,36,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,44,44,52,52,60,60,63,68,71,76,79,84,87,92,95,100,100,108,108,116,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,180,180,180,188,188,188,191,196,196,196,196,196,196,196,196,196,196,196,196,191,188,188,188,183,180,180,175,172,172,167,164,159,156,156,148,148,143,140,140,132,132,124,124,119,116,111,108,103,100,95,92,92,84,84,76,76,68,68,60,60,55,52,47,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,39,44,47,52,55,60,63,68,71,76,76,84,84,92,92,100,100,103,108,111,116,119,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,183,188,188,188,188,191,196,196,196,196,196,196,191,191,188,188,188,188,180,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,124,116,116,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,52,52,44,44,36,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,31,36,39,44,47,52,52,60,60,68,68,76,76,84,84,87,92,95,100,103,108,108,116,116,119,124,127,132,132,140,140,143,148,151,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,188,188,188,188,188,188,188,188,188,188,183,180,180,180,175,172,172,167,164,164,156,156,151,148,148,143,140,135,132,132,124,124,119,116,111,108,103,100,100,92,92,84,84,79,76,71,68,63,60,55,52,52,44,44,36,36,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,44,44,52,52,60,60,63,68,71,76,79,84,84,92,92,100,100,103,108,111,116,119,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,180,183,183,188,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,127,124,119,116,116,108,108,103,100,95,92,87,84,84,76,76,68,68,60,60,55,52,47,44,39,36,31,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,36,36,39,44,47,52,55,60,63,68,68,76,76,84,84,87,92,95,100,103,108,108,116,116,119,124,127,132,132,135,140,143,148,148,151,156,156,159,164,164,167,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,175,172,172,172,167,164,164,164,156,156,156,148,148,143,140,140,135,132,127,124,124,116,116,111,108,103,100,100,92,92,87,84,79,76,71,68,68,60,60,52,52,44,44,39,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,47,52,52,60,60,68,68,71,76,79,84,87,92,92,100,100,103,108,111,116,116,124,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,180,175,175,175,172,172,172,172,167,164,164,159,156,156,156,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,100,100,95,92,87,84,84,76,76,68,68,63,60,55,52,47,44,44,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,44,44,52,52,55,60,63,68,71,76,76,84,84,87,92,95,100,100,108,108,111,116,119,124,124,127,132,132,140,140,143,148,148,151,156,156,156,159,164,164,164,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,159,156,156,151,148,148,143,140,140,135,132,132,127,124,119,116,116,111,108,103,100,100,92,92,87,84,79,76,71,68,68,60,60,52,52,47,44,39,36,31,28,28,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,28,28,31,36,39,44,47,52,52,60,60,68,68,71,76,79,84,84,92,92,100,100,103,108,108,116,116,119,124,124,132,132,135,140,140,143,148,148,148,156,156,156,159,164,164,164,164,164,167,167,172,172,172,172,172,172,172,167,167,164,164,164,164,159,156,156,156,151,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,108,100,100,95,92,87,84,84,76,76,71,68,63,60,55,52,52,44,44,36,36,31,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,31,36,36,44,44,52,52,55,60,63,68,71,76,76,84,84,87,92,95,100,100,103,108,111,116,116,119,124,124,132,132,135,140,140,140,148,148,148,151,156,156,156,159,159,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,111,108,108,103,100,95,92,92,84,84,79,76,71,68,68,60,60,55,52,47,44,39,36,36,28,28,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,39,44,47,52,55,60,60,68,68,71,76,79,84,84,92,92,95,100,100,108,108,111,116,116,119,124,124,132,132,132,140,140,140,143,148,148,148,151,156,156,156,156,159,159,159,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,100,92,92,87,84,84,76,76,68,68,63,60,55,52,52,44,44,36,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,39,44,44,52,52,55,60,63,68,68,76,76,79,84,87,92,92,100,100,103,108,108,111,116,116,119,124,124,132,132,132,135,140,140,143,143,148,148,148,151,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,100,95,92,87,84,84,79,76,71,68,68,60,60,55,52,47,44,39,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,36,36,39,44,47,52,52,60,60,68,68,71,76,76,84,84,87,92,92,100,100,103,108,108,111,116,116,119,124,124,127,132,132,135,140,140,140,143,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,151,151,151,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,92,84,84,79,76,76,68,68,63,60,55,52,52,44,44,39,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,36,44,44,52,52,55,60,60,68,68,71,76,79,84,84,87,92,95,100,100,103,108,108,111,116,116,119,124,124,127,132,132,132,135,140,140,140,140,143,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,127,124,124,124,119,116,116,111,108,108,100,100,95,92,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,36,28,28,23,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,23,28,28,36,36,39,44,47,52,52,60,60,63,68,68,76,76,79,84,84,92,92,95,100,100,103,108,108,111,116,116,119,124,124,124,127,132,132,132,135,140,140,140,140,140,143,143,148,148,148,148,148,148,148,148,143,143,143,140,140,140,140,135,135,132,132,132,127,124,124,119,116,116,116,108,108,108,100,100,95,92,92,87,84,84,76,76,71,68,68,60,60,55,52,52,44,44,36,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,31,36,36,44,44,47,52,55,60,60,68,68,71,76,76,79,84,84,92,92,95,100,100,103,108,108,111,116,116,116,124,124,124,127,132,132,132,132,135,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,132,132,132,132,127,124,124,124,119,116,116,111,108,108,108,100,100,100,92,92,87,84,84,79,76,76,68,68,63,60,55,52,52,44,44,39,36,36,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,39,44,44,52,52,55,60,60,68,68,71,76,76,84,84,87,92,92,95,100,100,103,108,108,108,116,116,116,119,124,124,124,127,127,132,132,132,132,135,135,135,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,87,84,84,79,76,76,68,68,63,60,60,52,52,47,44,44,36,36,31,28,23,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,23,28,28,36,36,39,44,47,52,52,60,60,63,68,68,71,76,76,84,84,87,92,92,95,100,100,100,108,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,44,44,39,36,31,28,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,36,44,44,47,52,52,60,60,63,68,68,71,76,76,84,84,87,92,92,92,100,100,100,103,108,108,108,111,116,116,116,119,124,124,124,124,124,127,127,127,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,124,119,119,116,116,116,111,108,108,108,103,100,100,95,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,44,44,39,36,36,28,28,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,36,36,39,44,44,52,52,55,60,60,63,68,68,76,76,76,84,84,84,92,92,92,95,100,100,103,108,108,108,111,111,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,47,44,44,36,36,31,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,44,52,52,55,60,60,63,68,68,76,76,76,84,84,84,87,92,92,95,100,100,100,103,108,108,108,111,111,116,116,116,116,116,119,119,119,124,124,124,124,124,124,124,124,124,119,119,119,116,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,92,87,84,84,79,76,76,71,68,68,63,60,60,52,52,47,44,44,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,20,28,28,31,36,36,44,44,47,52,52,55,60,60,63,68,68,71,76,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,108,108,108,108,103,103,100,100,100,95,92,92,87,84,84,84,79,76,76,71,68,68,63,60,60,52,52,47,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,28,28,31,36,36,44,44,47,52,52,55,60,60,63,68,68,71,76,76,79,84,84,84,87,92,92,95,95,100,100,100,103,108,108,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,111,111,111,108,108,108,108,108,103,100,100,100,100,95,92,92,92,87,84,84,84,76,76,76,71,68,68,63,60,60,52,52,47,44,44,39,36,36,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,31,36,36,44,44,47,52,52,55,60,60,63,68,68,71,76,76,79,84,84,84,87,92,92,92,95,95,100,100,100,100,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,100,100,100,100,95,92,92,92,87,84,84,84,79,76,76,76,68,68,68,60,60,60,52,52,52,44,44,39,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,20,20,23,28,28,36,36,39,44,44,47,52,52,55,60,60,63,68,68,71,76,76,76,79,84,84,84,87,92,92,92,92,95,100,100,100,100,100,103,103,103,108,108,108,108,108,108,108,108,108,108,103,103,103,100,100,100,100,100,95,95,92,92,92,87,87,84,84,84,79,76,76,71,68,68,68,60,60,60,52,52,52,44,44,39,36,36,31,28,28,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,36,36,39,44,44,47,52,52,55,60,60,63,68,68,68,71,76,76,76,79,84,84,84,87,92,92,92,92,95,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,87,87,84,84,84,79,76,76,76,71,68,68,63,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,23,28,28,36,36,39,44,44,47,52,52,55,60,60,60,63,68,68,71,76,76,76,79,79,84,84,84,87,87,92,92,92,92,92,95,95,95,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,92,92,87,84,84,84,84,79,76,76,76,71,68,68,68,63,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,28,36,36,39,44,44,44,52,52,52,55,60,60,63,68,68,68,71,76,76,76,79,79,84,84,84,84,87,87,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,87,84,84,84,84,84,79,76,76,76,71,68,68,68,63,60,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,28,36,36,36,44,44,44,47,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,79,84,84,84,84,84,84,87,87,87,92,92,92,92,92,92,92,92,92,92,92,87,87,87,84,84,84,84,84,79,79,76,76,76,71,71,68,68,68,63,60,60,55,52,52,52,47,44,44,39,36,36,31,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,28,28,28,36,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,76,79,79,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,79,79,76,76,76,76,71,68,68,68,68,63,60,60,60,55,52,52,52,44,44,44,39,36,36,31,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,31,36,36,39,44,44,44,52,52,52,55,60,60,60,63,63,68,68,68,71,71,76,76,76,76,76,76,79,79,79,84,84,84,84,84,84,84,84,84,84,84,79,79,79,76,76,76,76,76,76,71,68,68,68,68,63,60,60,60,55,52,52,52,47,44,44,44,36,36,36,31,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,31,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,71,71,68,68,68,68,68,63,60,60,60,55,55,52,52,52,44,44,44,39,36,36,36,28,28,28,23,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,63,68,68,68,68,68,71,71,71,76,76,76,76,76,76,76,76,76,76,76,76,71,71,71,68,68,68,68,68,68,63,60,60,60,60,55,55,52,52,52,47,44,44,44,39,36,36,31,28,28,28,20,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,28,31,36,36,39,44,44,44,47,47,52,52,52,55,60,60,60,60,60,63,63,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,63,60,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,23,20,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,31,36,36,36,39,44,44,44,47,47,52,52,52,52,55,60,60,60,60,60,60,63,63,63,68,68,68,68,68,68,68,68,68,68,68,68,63,63,63,60,60,60,60,60,60,55,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,47,47,44,44,44,39,39,36,36,36,31,28,28,23,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,47,52,52,52,52,52,52,55,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,55,52,52,52,52,52,52,47,44,44,44,44,39,36,36,36,36,31,28,28,28,23,20,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,20,23,28,28,28,31,31,36,36,36,39,39,44,44,44,44,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,44,44,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,47,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,47,44,44,44,44,44,44,39,39,36,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,28,28,31,36,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,31,31,28,28,28,23,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,28,28,28,31,36,36,36,36,36,36,39,39,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,39,36,36,36,36,36,36,31,31,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,23,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,28,28,23,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,20,23,23,28,28,28,28,28,28,31,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,31,28,28,28,28,28,28,28,23,20,20,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,20,20,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,20,20,23,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,23,20,20,20,20,20,20,15,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,12,12,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t FLARE_TEXTURE_1[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,15,15,15,15,15,15,15,15,15,15,15,15,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,15,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,15,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,20,20,20,23,23,23,23,23,20,20,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,23,23,23,23,28,28,28,28,28,28,28,28,28,23,23,23,23,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,15,15,20,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,20,20,20,20,20,20,15,15,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,20,23,23,28,28,28,28,28,28,28,28,31,31,31,31,31,31,31,31,28,28,28,28,28,28,28,28,23,23,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,23,23,28,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,31,31,31,28,28,28,28,28,28,23,20,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,20,20,23,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,28,23,23,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,23,28,28,28,28,28,31,36,36,36,36,36,39,39,39,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,20,23,28,28,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,39,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,23,23,28,28,28,31,36,36,36,36,39,44,44,44,44,44,47,47,52,52,52,52,52,52,52,52,47,47,47,44,44,44,44,39,39,36,36,36,31,28,28,28,28,23,20,20,20,20,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,15,20,20,20,23,28,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,39,39,36,36,36,31,28,28,28,23,20,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,55,55,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,60,63,63,63,63,63,63,60,60,60,60,60,55,55,52,52,52,47,44,44,44,39,36,36,31,28,28,28,23,20,20,20,15,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,68,68,68,68,68,68,68,68,68,63,60,60,60,60,55,52,52,47,44,44,44,39,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,23,28,28,31,36,36,36,44,44,44,47,52,52,55,60,60,60,63,68,68,68,71,71,76,76,76,76,76,76,71,71,68,68,68,68,63,60,60,60,52,52,52,47,44,44,39,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,36,44,44,44,52,52,52,60,60,60,63,68,68,71,76,76,76,76,76,79,79,79,79,76,76,76,76,76,71,68,68,68,63,60,60,55,52,52,47,44,44,39,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,28,36,36,36,44,44,44,52,52,55,60,60,63,68,68,71,76,76,76,79,84,84,84,84,84,84,84,84,84,84,84,79,76,76,76,68,68,68,60,60,55,52,52,47,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,28,28,28,31,36,36,39,44,44,52,52,55,60,60,68,68,68,76,76,79,84,84,84,87,87,92,92,92,92,92,92,92,87,84,84,84,79,76,76,71,68,68,63,60,60,52,52,47,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,44,52,52,55,60,60,68,68,71,76,76,84,84,84,92,92,92,95,95,100,100,100,100,95,95,92,92,92,87,84,84,79,76,76,68,68,63,60,60,52,52,47,44,44,36,36,36,28,28,28,23,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,23,28,28,28,36,36,39,44,44,47,52,55,60,60,68,68,71,76,79,84,84,92,92,95,100,100,100,100,103,103,103,103,103,100,100,100,95,92,92,87,84,84,76,76,71,68,63,60,60,52,52,47,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,52,60,60,68,68,76,76,79,84,87,92,92,100,100,103,108,108,108,108,111,111,108,108,108,108,103,100,100,95,92,92,84,84,76,76,71,68,63,60,55,52,52,44,44,39,36,36,28,28,28,23,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,28,36,36,39,44,44,52,52,60,60,68,68,71,76,84,84,87,92,95,100,103,108,108,111,116,116,116,116,116,116,116,116,116,111,108,108,100,100,92,92,87,84,76,76,68,68,63,60,55,52,47,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,55,60,63,68,71,76,79,84,92,92,100,100,108,108,116,116,119,124,124,124,124,124,124,124,124,119,116,116,111,108,103,100,95,92,87,84,76,76,68,68,60,60,52,52,44,44,39,36,36,28,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,28,28,28,36,36,39,44,44,52,52,60,60,68,68,76,79,84,87,92,100,100,108,111,116,119,124,124,127,132,132,132,132,132,132,132,127,124,124,116,116,108,103,100,95,92,84,84,76,76,68,63,60,55,52,47,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,47,52,55,60,63,68,76,76,84,87,92,100,100,108,111,116,124,124,132,132,135,140,140,140,140,140,140,140,132,132,127,124,119,116,108,108,100,95,92,84,79,76,71,68,60,60,52,52,44,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,39,44,44,52,52,60,60,68,71,76,84,84,92,95,100,108,111,116,124,127,132,135,140,143,148,148,148,148,148,148,148,140,140,132,132,124,119,116,108,103,100,92,87,84,76,76,68,63,60,55,52,47,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,28,36,36,39,44,47,52,55,60,63,68,76,79,84,92,92,100,108,111,116,124,127,132,140,143,148,151,156,156,156,156,156,156,156,148,148,140,135,132,124,119,116,108,103,100,92,84,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,84,92,100,103,108,116,124,127,132,140,143,148,156,159,164,164,167,167,164,164,164,156,151,148,140,135,132,124,116,111,108,100,95,92,84,76,76,68,63,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,39,44,44,52,52,60,63,68,76,76,84,92,95,100,108,116,119,124,132,140,143,151,156,164,167,172,172,175,175,175,172,172,164,159,156,148,140,135,127,124,116,108,103,100,92,84,84,76,68,68,60,55,52,47,44,39,36,36,31,28,28,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,68,68,76,79,84,92,100,103,108,116,124,132,135,143,148,156,164,172,175,180,183,188,188,183,180,180,172,164,159,156,148,140,132,124,119,116,108,100,92,87,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,68,71,76,84,87,92,100,108,111,119,124,132,140,148,156,164,172,175,180,188,191,196,196,196,188,188,180,172,164,156,151,143,135,132,124,116,108,100,95,92,84,79,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,87,95,100,108,116,124,127,135,143,151,159,167,175,180,188,196,204,204,204,204,199,196,188,180,172,164,156,148,140,132,124,116,111,103,100,92,84,79,76,68,63,60,55,52,47,44,39,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,52,60,63,68,76,76,84,92,95,100,108,116,124,132,140,148,156,164,172,180,188,196,204,212,215,220,212,207,199,191,183,175,167,156,148,140,132,127,119,111,108,100,92,87,84,76,68,68,60,55,52,47,44,39,36,36,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,108,116,124,132,140,148,156,164,172,183,191,204,212,220,228,228,223,215,204,196,188,180,172,164,151,143,135,127,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,111,116,124,132,140,148,156,167,175,188,196,204,215,228,236,236,231,220,212,199,188,180,172,164,156,148,140,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,111,116,124,132,140,148,156,167,175,188,196,204,220,228,236,244,236,220,212,204,191,180,172,164,156,148,140,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,79,84,92,100,103,108,116,124,132,140,148,156,164,175,183,196,204,212,223,231,236,228,220,212,199,188,180,172,164,156,148,135,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,76,84,92,95,103,108,116,124,132,140,148,156,164,172,180,188,199,207,215,220,220,220,212,204,196,188,180,167,159,151,143,135,127,119,116,108,100,92,87,84,76,68,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,92,95,100,108,116,124,132,140,148,156,164,172,180,188,196,199,204,212,212,212,204,196,188,180,172,164,156,148,140,132,124,116,111,108,100,92,84,79,76,68,68,60,55,52,47,44,39,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,28,36,36,44,44,47,52,60,60,68,71,76,84,87,92,100,108,116,119,127,132,140,148,156,164,172,180,188,191,196,199,204,199,196,188,183,175,167,164,156,148,140,132,124,116,108,103,100,92,84,79,76,68,63,60,55,52,44,44,39,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,68,68,76,84,84,92,100,103,111,116,124,132,140,148,151,159,164,172,180,183,188,188,191,188,188,180,175,172,164,156,148,140,132,127,124,116,108,100,95,92,84,76,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,20,20,20,23,28,28,31,36,39,44,47,52,55,60,63,68,76,79,84,92,95,100,108,116,124,127,132,140,148,156,159,164,172,175,180,180,180,180,180,172,167,164,156,148,143,140,132,124,116,111,108,100,92,87,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,52,52,60,60,68,71,76,84,87,92,100,108,111,116,124,132,135,140,148,156,156,164,167,172,172,172,172,167,164,164,156,148,148,140,132,124,119,116,108,100,95,92,84,79,76,68,68,60,55,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,44,44,47,52,55,60,68,68,76,79,84,92,95,100,108,116,119,124,132,135,140,148,151,156,156,164,164,164,164,159,156,156,148,143,140,132,127,124,116,108,103,100,92,87,84,76,71,68,63,60,52,52,44,44,39,36,31,28,28,23,20,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,55,60,63,68,76,76,84,87,92,100,103,108,116,119,124,132,135,140,143,148,148,151,156,156,156,151,148,148,140,140,132,127,124,116,111,108,100,95,92,84,79,76,68,68,60,60,52,52,44,44,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,52,52,60,60,68,68,76,79,84,92,92,100,103,108,116,119,124,127,132,135,140,140,143,148,148,148,143,140,140,132,132,124,124,116,111,108,100,100,92,87,84,76,71,68,63,60,55,52,47,44,39,36,36,28,28,28,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,31,36,36,39,44,47,52,55,60,63,68,71,76,84,84,92,95,100,108,108,116,116,124,124,132,132,132,135,140,140,135,135,132,132,127,124,119,116,111,108,100,100,92,87,84,79,76,68,68,60,60,52,52,44,44,39,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,36,36,39,44,44,52,52,60,60,68,68,76,76,84,87,92,95,100,103,108,111,116,119,124,124,127,127,132,132,132,127,124,124,124,116,116,108,108,100,100,92,92,84,79,76,71,68,63,60,55,52,47,44,39,36,36,31,28,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,47,52,52,60,60,68,68,76,76,84,87,92,95,100,103,108,108,116,116,116,119,124,124,124,124,119,116,116,116,111,108,103,100,100,92,92,84,79,76,71,68,63,60,55,52,52,44,44,39,36,36,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,28,28,28,36,36,39,44,44,47,52,55,60,63,68,71,76,76,84,84,92,92,100,100,103,108,108,111,111,116,116,116,116,116,111,108,108,108,100,100,95,92,87,84,79,76,76,68,68,60,60,52,52,47,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,44,52,52,55,60,63,68,71,76,76,84,84,87,92,95,100,100,100,103,108,108,108,108,108,108,108,103,100,100,95,92,92,87,84,79,76,76,68,68,60,60,55,52,47,44,44,36,36,31,28,28,28,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,52,60,60,63,68,68,76,76,79,84,84,92,92,92,95,100,100,100,100,100,100,100,100,100,95,92,92,87,84,84,79,76,71,68,68,60,60,55,52,52,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,23,28,28,28,36,36,39,44,44,47,52,52,60,60,63,68,68,76,76,76,84,84,84,87,92,92,92,92,92,92,92,92,92,92,92,87,84,84,79,76,76,71,68,68,60,60,55,52,52,44,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,31,36,36,39,44,44,47,52,52,60,60,63,68,68,71,76,76,76,84,84,84,84,87,87,87,87,87,87,84,84,84,84,79,76,76,71,68,68,63,60,60,55,52,52,44,44,44,36,36,31,28,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,15,20,20,20,28,28,28,31,36,36,39,44,44,47,52,52,55,60,60,63,68,68,71,76,76,76,79,79,84,84,84,84,84,84,79,79,76,76,76,71,68,68,68,63,60,60,55,52,52,44,44,44,36,36,36,28,28,28,23,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,39,44,44,47,52,52,55,60,60,60,63,68,68,68,71,76,76,76,76,76,76,76,76,76,76,76,71,68,68,68,63,60,60,55,52,52,52,44,44,44,36,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,28,31,36,36,39,44,44,47,52,52,52,55,60,60,60,63,68,68,68,68,68,71,71,71,71,68,68,68,68,68,68,63,60,60,60,55,52,52,47,44,44,44,36,36,36,31,28,28,23,20,20,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,15,20,20,20,23,28,28,28,31,36,36,39,44,44,44,47,52,52,52,55,60,60,60,60,63,63,68,68,68,68,68,68,68,63,63,60,60,60,60,55,52,52,52,47,44,44,39,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,47,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,55,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,20,23,28,28,28,31,36,36,36,39,44,44,44,44,47,52,52,52,52,52,55,55,55,55,55,55,55,55,55,52,52,52,52,52,47,44,44,44,39,36,36,36,31,28,28,28,28,23,20,20,20,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,20,23,28,28,28,31,36,36,36,36,39,44,44,44,44,47,47,52,52,52,52,52,52,52,52,52,52,52,52,52,47,44,44,44,44,39,39,36,36,36,31,28,28,28,23,23,20,20,20,15,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,15,20,20,20,20,23,28,28,28,28,31,36,36,36,36,39,44,44,44,44,44,44,47,47,47,47,47,47,47,47,44,44,44,44,44,44,39,39,36,36,36,31,31,28,28,28,23,20,20,20,20,15,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,20,23,23,28,28,28,28,31,36,36,36,36,36,39,39,44,44,44,44,44,44,44,44,44,44,44,44,44,39,39,36,36,36,36,36,31,28,28,28,28,23,20,20,20,20,15,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,23,28,28,28,28,28,31,36,36,36,36,36,36,36,39,39,39,39,39,39,39,39,39,36,36,36,36,36,36,31,31,28,28,28,28,23,23,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,15,20,20,20,20,23,23,28,28,28,28,28,31,31,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,28,28,28,23,20,20,20,20,20,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,15,20,20,20,20,20,23,23,28,28,28,28,28,28,31,31,31,31,36,36,36,36,36,36,31,31,31,31,28,28,28,28,28,28,23,23,20,20,20,20,20,15,15,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,15,15,20,20,20,20,20,23,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,20,20,20,20,20,20,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,15,15,20,20,20,20,20,20,23,23,23,28,28,28,28,28,28,28,28,28,28,28,28,28,28,23,23,23,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,23,23,23,23,23,23,23,23,23,23,23,23,20,20,20,20,20,20,20,20,20,15,15,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,12,12,12,15,15,15,15,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,15,15,15,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,15,15,15,15,15,15,20,20,20,20,20,15,15,15,15,15,15,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,12,12,12,12,12,12,12,12,12,12,12,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t FLARE_TEXTURE_2[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,20,23,28,28,28,28,28,28,28,28,28,28,23,23,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,28,28,31,36,36,36,36,39,39,44,44,44,44,44,44,39,39,39,36,36,36,36,28,28,23,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,28,31,36,36,39,44,44,44,47,47,52,52,52,52,52,52,52,52,52,52,52,52,47,47,44,44,44,44,36,36,36,28,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,28,36,36,39,44,44,47,52,52,52,55,55,60,60,60,60,60,60,60,60,60,60,60,60,60,60,55,55,52,52,52,52,47,44,44,39,36,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,36,36,44,44,47,52,52,55,60,60,60,60,63,63,68,68,68,68,68,68,68,68,68,68,68,68,68,68,63,63,60,60,60,60,55,52,52,52,44,44,39,36,31,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,31,36,44,44,47,52,52,60,60,60,63,68,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,71,71,68,68,68,68,68,63,60,60,60,55,52,52,47,44,39,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,47,52,52,60,60,60,63,68,68,68,71,76,76,76,76,76,76,79,79,79,79,84,84,84,84,84,79,79,79,79,76,76,76,76,76,71,71,68,68,68,63,60,60,55,52,52,44,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,52,52,55,60,60,63,68,68,71,76,76,76,76,79,79,84,84,84,84,84,84,84,84,84,87,87,87,84,84,84,84,84,84,84,84,84,79,79,76,76,76,71,68,68,68,63,60,60,52,52,47,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,39,44,52,52,60,60,63,68,68,71,76,76,76,79,84,84,84,84,84,87,87,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,92,87,87,84,84,84,84,79,76,76,76,71,68,68,68,60,60,55,52,47,44,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,31,36,44,52,52,60,60,63,68,68,76,76,76,79,84,84,84,84,87,92,92,92,92,92,92,95,95,95,100,100,100,100,100,100,100,100,95,95,95,95,92,92,92,92,92,92,87,84,84,84,79,76,76,76,71,68,68,60,60,55,52,47,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,44,47,52,60,60,63,68,71,76,76,76,84,84,84,87,92,92,92,92,92,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,92,92,92,92,87,84,84,84,79,76,76,71,68,68,63,60,55,52,44,39,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,39,44,52,55,60,63,68,71,76,76,79,84,84,84,87,92,92,92,95,100,100,100,100,100,100,103,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,103,100,100,100,100,100,95,92,92,92,92,87,84,84,79,76,76,71,68,68,60,60,52,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,44,52,52,60,63,68,68,76,76,79,84,84,87,92,92,92,95,100,100,100,100,103,103,108,108,108,108,108,108,108,108,111,111,111,111,111,111,111,111,111,108,108,108,108,108,108,108,108,103,100,100,100,100,95,92,92,92,87,84,84,84,76,76,71,68,68,60,55,52,44,39,36,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,39,44,52,55,60,68,68,76,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,108,111,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,111,108,108,108,108,108,103,100,100,100,100,95,92,92,87,84,84,79,76,76,71,68,63,60,52,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,36,44,47,52,60,63,68,71,76,76,84,84,87,92,92,92,100,100,100,103,103,108,108,108,108,111,116,116,116,116,116,116,116,116,119,119,119,119,119,119,119,119,119,119,119,116,116,116,116,116,116,116,111,111,108,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,76,68,68,60,55,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,52,55,60,68,68,76,76,79,84,84,92,92,92,100,100,100,103,108,108,108,108,111,116,116,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,116,111,111,108,108,108,103,100,100,100,95,92,92,87,84,84,76,76,71,68,63,60,52,47,39,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,52,60,60,68,71,76,76,84,84,87,92,92,95,100,100,103,108,108,108,111,116,116,116,116,119,119,124,124,124,124,124,124,124,124,127,127,127,127,127,127,127,127,127,127,127,124,124,124,124,124,124,124,119,119,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,84,84,79,76,76,68,63,60,52,47,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,52,60,63,68,71,76,79,84,84,92,92,95,100,100,103,108,108,108,111,116,116,116,116,119,124,124,124,124,124,127,127,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,124,119,119,116,116,116,111,111,108,108,103,100,100,100,92,92,87,84,84,76,76,68,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,39,44,52,60,63,68,76,76,84,84,87,92,92,100,100,100,108,108,108,111,116,116,116,119,124,124,124,124,124,127,132,132,132,132,132,132,132,132,132,135,135,135,135,135,135,135,135,135,132,132,132,132,132,132,132,132,127,127,124,124,124,124,119,116,116,116,111,108,108,108,103,100,100,95,92,92,84,84,79,76,71,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,39,47,52,60,63,68,76,76,84,84,92,92,95,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,132,135,135,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,135,135,132,132,132,132,132,127,127,124,124,124,119,116,116,116,111,108,108,108,100,100,100,92,92,87,84,79,76,71,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,47,52,60,68,68,76,76,84,84,92,92,95,100,100,108,108,108,111,116,116,119,124,124,124,124,127,132,132,132,132,135,135,140,140,140,140,140,140,140,140,140,140,140,143,143,140,140,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,87,84,84,76,71,68,60,55,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,52,60,68,68,76,79,84,87,92,92,100,100,103,108,108,111,116,116,116,119,124,124,124,127,132,132,132,132,135,140,140,140,140,140,140,143,143,143,148,148,148,148,148,148,148,148,148,148,148,148,143,143,143,140,140,140,140,140,140,135,135,132,132,132,132,127,124,124,124,119,116,116,111,108,108,108,100,100,95,92,92,84,84,76,71,68,60,55,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,36,44,52,60,68,68,76,79,84,87,92,92,100,100,103,108,108,111,116,116,119,124,124,124,127,132,132,132,135,135,140,140,140,140,143,143,143,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,140,135,132,132,132,132,127,124,124,124,116,116,116,111,108,108,100,100,95,92,92,84,84,76,71,68,60,55,52,44,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,63,68,76,79,84,87,92,95,100,100,108,108,108,116,116,116,124,124,124,127,132,132,132,135,135,140,140,140,140,143,148,148,148,148,148,148,148,151,151,151,151,151,151,156,156,156,151,151,151,151,151,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,132,127,124,124,124,119,116,116,111,108,108,103,100,100,92,92,84,84,76,71,68,60,55,52,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,63,68,76,79,84,87,92,95,100,100,108,108,111,116,116,119,124,124,124,127,132,132,132,135,140,140,140,143,143,148,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,148,148,148,143,140,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,103,100,100,92,92,84,84,76,71,68,60,52,47,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,44,52,60,63,68,76,76,84,87,92,95,100,100,108,108,111,116,116,119,124,124,127,132,132,132,135,140,140,140,143,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,159,159,159,159,159,159,159,156,156,156,156,156,156,156,156,156,151,148,148,148,148,148,143,140,140,140,140,135,132,132,127,124,124,124,116,116,116,108,108,103,100,100,92,92,84,84,76,71,68,60,52,44,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,47,55,60,68,76,76,84,87,92,95,100,100,108,108,111,116,116,119,124,124,127,132,132,135,140,140,140,140,143,148,148,148,148,151,156,156,156,156,156,156,159,159,159,164,164,164,164,164,164,164,164,164,164,164,164,159,159,159,156,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,108,108,103,100,100,92,92,84,79,76,68,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,71,76,84,84,92,92,100,100,108,108,111,116,116,124,124,124,127,132,132,135,140,140,140,143,148,148,148,148,151,156,156,156,156,156,159,159,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,148,148,148,143,143,140,140,140,132,132,132,127,124,124,119,116,116,108,108,103,100,95,92,87,84,79,76,68,63,60,52,44,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,71,76,84,84,92,92,100,100,108,108,111,116,116,124,124,124,132,132,132,135,140,140,143,148,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,164,164,167,167,167,167,167,167,167,167,167,167,167,167,164,164,164,164,164,164,164,164,159,156,156,156,156,151,151,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,95,92,87,84,76,76,68,60,55,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,52,55,63,68,76,79,84,92,92,100,100,108,108,111,116,116,124,124,124,132,132,132,140,140,140,143,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,167,167,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,164,164,164,159,156,156,156,156,151,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,108,108,103,100,95,92,87,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,76,76,84,87,92,95,100,103,108,111,116,116,124,124,124,132,132,132,140,140,140,143,148,148,148,151,156,156,156,159,159,164,164,164,164,167,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,164,164,159,156,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,116,108,108,100,100,92,92,84,84,76,68,63,60,52,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,44,52,60,68,71,76,84,84,92,95,100,103,108,108,116,116,119,124,124,132,132,135,140,140,140,143,148,148,151,156,156,156,156,159,164,164,164,164,167,167,172,172,172,172,172,172,175,175,175,175,175,180,180,180,180,180,175,175,175,175,172,172,172,172,172,172,172,167,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,119,116,111,108,108,100,100,92,92,84,79,76,68,60,55,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,47,55,63,68,76,79,84,92,92,100,100,108,108,116,116,119,124,124,132,132,132,140,140,140,143,148,148,151,156,156,156,159,164,164,164,164,167,167,172,172,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,175,175,175,172,172,172,172,172,167,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,103,100,95,92,87,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,76,84,87,92,100,100,108,108,111,116,119,124,124,127,132,132,140,140,140,148,148,148,151,156,156,156,159,164,164,164,167,167,172,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,175,175,172,172,172,172,172,167,164,164,164,164,159,156,156,156,148,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,103,100,95,92,84,84,76,68,63,55,52,39,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,39,52,60,63,68,76,84,84,92,95,100,103,108,111,116,116,124,124,127,132,132,140,140,140,143,148,148,151,156,156,156,159,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,180,183,183,183,183,188,188,188,188,188,188,188,183,183,183,180,180,180,180,180,180,180,175,172,172,172,172,167,167,164,164,164,159,156,156,156,148,148,148,143,140,140,135,132,132,124,124,119,116,116,108,108,100,100,92,92,84,79,76,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,79,84,92,92,100,100,108,108,116,116,124,124,127,132,132,135,140,140,143,148,148,151,156,156,156,159,164,164,164,167,172,172,172,175,175,180,180,180,180,180,183,183,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,183,183,183,180,180,180,180,180,175,172,172,172,172,167,164,164,164,159,156,156,156,148,148,148,143,140,140,135,132,132,124,124,119,116,111,108,103,100,95,92,87,84,76,68,63,60,52,39,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,39,52,60,63,71,76,84,87,92,95,100,108,108,111,116,119,124,124,132,132,135,140,140,143,148,148,151,156,156,156,164,164,164,167,172,172,172,172,175,180,180,180,180,180,183,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,183,183,180,180,180,180,175,175,172,172,172,167,164,164,164,159,156,156,156,148,148,148,140,140,140,132,132,127,124,124,116,116,111,108,103,100,92,92,84,79,76,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,79,84,92,92,100,103,108,111,116,116,124,124,127,132,135,140,140,143,148,148,151,156,156,156,164,164,164,167,172,172,172,175,175,180,180,180,180,183,188,188,188,188,188,188,191,191,191,191,196,196,196,196,196,196,191,191,191,191,188,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,148,140,140,135,132,132,127,124,119,116,116,108,108,100,100,92,87,84,76,71,63,60,52,39,28,0,0,0,0,0,0,0,0,0,0,0,0,28,39,52,60,63,71,76,84,87,92,100,100,108,108,116,116,119,124,127,132,132,140,140,143,148,148,151,156,156,156,159,164,164,167,172,172,172,175,180,180,180,180,183,188,188,188,188,188,191,191,191,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,191,191,188,188,188,188,188,183,180,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,135,132,132,124,124,119,116,111,108,103,100,92,92,84,79,76,68,60,52,44,36,15,0,0,0,0,0,0,0,0,0,0,12,31,44,52,60,68,76,79,84,92,92,100,103,108,111,116,119,124,124,132,132,135,140,140,148,148,148,156,156,156,159,164,164,167,172,172,172,175,180,180,180,180,183,188,188,188,188,191,191,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,191,191,188,188,188,188,188,183,180,180,180,175,172,172,172,167,164,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,108,108,100,100,92,87,84,76,68,63,55,47,36,23,0,0,0,0,0,0,0,0,0,0,23,36,47,55,63,68,76,84,87,92,100,100,108,108,116,116,124,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,191,191,196,196,196,196,196,196,199,199,199,199,199,204,204,199,199,199,199,199,196,196,196,196,196,196,196,191,188,188,188,188,183,180,180,180,175,172,172,172,167,164,164,164,156,156,156,151,148,148,140,140,135,132,132,124,124,119,116,111,108,103,100,92,92,84,79,76,68,60,52,44,31,12,0,0,0,0,0,0,0,0,0,28,44,52,60,68,76,76,84,92,92,100,103,108,111,116,119,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,164,172,172,172,175,180,180,180,183,188,188,188,188,191,196,196,196,196,196,199,199,199,204,204,204,204,204,204,204,204,204,204,204,204,204,199,199,196,196,196,196,196,191,191,188,188,188,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,140,135,132,127,124,124,116,116,108,108,100,95,92,87,84,76,68,63,55,44,36,20,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,84,84,92,95,100,108,108,116,116,124,124,127,132,135,140,140,143,148,148,156,156,156,164,164,164,167,172,172,175,180,180,180,183,188,188,188,188,191,196,196,196,196,199,199,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,199,199,196,196,196,196,196,191,188,188,188,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,135,132,132,124,124,119,116,111,108,103,100,92,92,84,76,71,68,60,52,39,28,0,0,0,0,0,0,0,0,23,36,47,60,63,71,76,84,87,92,100,103,108,111,116,119,124,124,132,132,135,140,143,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,191,191,196,196,196,196,199,204,204,204,204,204,204,204,207,207,207,207,207,207,207,207,207,204,204,204,204,204,204,199,199,196,196,196,196,191,188,188,188,183,180,180,180,175,172,172,172,164,164,164,159,156,156,148,148,143,140,140,135,132,127,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,31,12,0,0,0,0,0,0,7,28,44,52,60,68,76,79,84,92,95,100,103,108,116,116,124,124,127,132,135,140,140,143,148,148,156,156,159,164,164,167,172,172,172,175,180,180,183,188,188,188,191,196,196,196,196,199,204,204,204,204,204,204,207,207,212,212,212,212,212,212,212,212,212,212,207,207,207,204,204,204,204,204,199,196,196,196,196,191,188,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,143,140,135,132,132,124,124,119,116,111,108,100,100,92,87,84,76,68,63,55,47,36,20,0,0,0,0,0,0,20,36,44,52,60,68,76,84,87,92,100,100,108,108,116,116,124,124,132,132,135,140,143,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,196,199,204,204,204,204,207,207,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,207,207,204,204,204,204,199,199,196,196,196,191,188,188,188,183,180,180,180,172,172,172,167,164,164,159,156,156,148,148,143,140,140,135,132,127,124,119,116,111,108,103,100,92,92,84,76,71,68,60,52,39,28,0,0,0,0,0,0,23,36,47,60,63,71,76,84,92,92,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,191,196,196,196,199,204,204,204,204,207,212,212,212,212,212,212,212,212,215,215,215,215,215,212,212,212,212,212,212,212,207,207,204,204,204,204,199,196,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,148,143,140,135,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,31,12,0,0,0,0,0,28,39,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,183,188,188,188,191,196,196,196,199,204,204,204,204,207,212,212,212,212,212,215,215,215,220,220,220,220,220,220,215,215,215,212,212,212,212,212,212,207,204,204,204,204,199,196,196,196,191,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,127,124,119,116,111,108,100,100,92,87,84,76,68,63,55,44,36,20,0,0,0,0,12,31,44,52,60,68,76,84,84,92,100,100,108,108,116,119,124,124,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,199,204,204,204,207,207,212,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,220,220,220,215,212,212,212,212,212,207,204,204,204,199,199,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,124,116,111,108,103,100,92,92,84,76,71,68,60,47,36,23,0,0,0,0,20,36,44,55,63,68,76,84,87,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,204,207,207,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,215,215,212,212,212,212,207,204,204,204,199,196,196,196,191,188,188,188,180,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,39,28,0,0,0,0,20,36,47,60,68,71,76,84,92,92,100,103,108,116,116,124,124,132,132,135,140,143,148,148,151,156,156,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,204,204,204,204,207,212,212,212,215,215,220,220,220,220,220,223,223,223,223,223,223,223,223,220,220,220,220,220,220,215,212,212,212,212,207,204,204,204,199,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,143,140,140,132,132,127,124,119,116,111,108,100,100,92,84,84,76,68,60,52,44,31,12,0,0,0,28,39,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,204,207,212,212,212,215,220,220,220,220,220,223,223,228,228,228,228,228,228,228,228,228,223,223,220,220,220,220,215,212,212,212,212,207,204,204,204,199,196,196,191,188,188,188,180,180,180,175,172,172,164,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,60,52,44,36,15,0,0,0,28,44,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,132,140,140,143,148,151,156,156,159,164,164,172,172,172,180,180,180,188,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,220,223,223,228,228,228,228,228,228,228,228,228,228,228,228,228,223,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,47,36,20,0,0,12,31,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,215,215,220,220,220,223,228,228,228,228,228,228,228,231,231,228,228,228,228,228,228,228,223,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,79,71,68,60,52,36,23,0,0,15,36,44,55,63,68,76,84,87,92,100,103,108,111,116,124,124,127,132,135,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,223,228,228,228,228,228,231,231,231,236,236,236,231,231,231,228,228,228,228,223,220,220,220,220,215,212,212,212,207,204,204,199,196,196,196,188,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,127,124,119,116,108,108,100,95,92,84,79,76,68,60,52,39,28,0,0,20,36,47,55,63,71,76,84,92,92,100,103,108,116,116,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,191,196,196,199,204,204,204,212,212,212,215,220,220,220,223,228,228,228,228,231,231,236,236,236,236,236,236,236,236,236,231,228,228,228,228,223,220,220,220,215,212,212,212,207,204,204,204,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,100,100,92,84,79,76,68,60,52,44,28,0,0,20,36,47,60,68,71,76,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,151,156,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,215,220,220,220,223,228,228,228,231,231,236,236,236,236,236,236,236,236,236,236,236,231,228,228,228,228,223,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,151,148,148,140,140,135,132,127,124,119,116,111,108,100,100,92,87,84,76,68,60,52,44,28,7,0,23,36,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,215,220,220,220,223,228,228,228,231,231,236,236,236,236,239,239,239,239,236,236,236,236,236,231,228,228,228,223,220,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,188,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,60,52,44,31,12,0,28,39,52,60,68,76,79,84,92,95,100,108,108,116,119,124,127,132,132,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,212,212,212,215,220,220,220,223,228,228,228,231,236,236,236,236,239,244,244,244,244,239,239,236,236,236,236,231,228,228,228,223,220,220,220,212,212,212,207,204,204,199,196,196,196,188,188,188,183,180,180,172,172,172,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,92,87,84,76,68,63,52,44,36,12,0,28,39,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,207,212,212,212,215,220,220,223,228,228,228,231,236,236,236,236,239,244,244,244,244,244,244,244,239,236,236,236,231,228,228,228,223,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,148,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,68,63,55,44,36,15,0,28,44,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,175,180,180,188,188,188,196,196,196,199,204,204,207,212,212,212,220,220,220,223,228,228,228,231,236,236,236,239,244,244,244,244,244,244,244,244,239,239,236,236,236,231,228,228,223,220,220,220,215,212,212,212,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,44,36,20,0,28,44,52,60,68,76,84,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,215,220,220,220,223,228,228,228,231,236,236,239,244,244,244,244,247,247,244,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,204,204,204,207,212,212,215,220,220,220,223,228,228,231,236,236,236,239,244,244,244,247,252,252,247,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,143,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,204,204,204,207,212,212,215,220,220,220,223,228,228,231,236,236,236,239,244,244,244,247,252,252,247,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,156,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,215,220,220,220,223,228,228,228,236,236,236,239,244,244,244,244,247,247,247,244,244,244,239,236,236,236,231,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,95,92,84,76,71,63,55,47,36,20,0,28,44,52,60,68,76,84,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,215,220,220,220,223,228,228,228,231,236,236,236,239,244,244,244,244,244,244,244,244,244,239,236,236,236,231,228,228,228,220,220,220,215,212,212,212,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,44,36,20,0,28,39,52,60,68,76,79,84,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,159,164,164,167,172,172,175,180,180,188,188,188,191,196,196,199,204,204,207,212,212,212,215,220,220,223,228,228,228,231,236,236,236,239,244,244,244,244,244,244,244,244,239,236,236,236,231,228,228,228,223,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,103,100,92,92,84,76,71,63,55,44,36,20,0,28,39,52,60,68,76,79,84,92,95,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,207,212,212,212,215,220,220,220,228,228,228,231,236,236,236,236,239,239,244,244,244,244,244,239,236,236,236,236,231,228,228,228,223,220,220,220,215,212,212,207,204,204,204,196,196,196,191,188,188,183,180,180,175,172,172,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,92,87,84,76,68,63,55,44,36,15,0,23,39,52,60,68,76,79,84,92,95,100,108,108,116,119,124,127,132,132,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,215,220,220,220,223,228,228,228,231,236,236,236,236,239,239,239,239,239,239,236,236,236,236,231,228,228,228,228,223,220,220,215,212,212,212,207,204,204,199,196,196,196,188,188,188,180,180,180,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,111,108,103,100,92,87,84,76,68,60,52,44,31,12,0,23,36,47,60,68,71,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,151,156,156,159,164,164,172,172,175,180,180,183,188,188,191,196,196,196,204,204,204,207,212,212,212,220,220,220,223,228,228,228,228,231,236,236,236,236,236,236,236,236,236,236,236,236,231,231,228,228,228,223,220,220,220,215,212,212,212,207,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,60,52,44,31,12,0,20,36,47,55,63,71,76,84,92,95,100,103,108,116,116,124,124,132,132,140,140,143,148,148,156,156,159,164,164,172,172,172,180,180,180,188,188,188,196,196,196,199,204,204,207,212,212,212,215,220,220,220,223,228,228,228,228,231,236,236,236,236,236,236,236,236,236,236,231,231,228,228,228,223,220,220,220,220,215,212,212,207,204,204,204,199,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,100,100,92,87,84,76,68,60,52,44,28,0,0,20,36,44,55,63,68,76,84,92,92,100,103,108,116,116,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,223,228,228,228,228,231,231,236,236,236,236,236,236,231,231,228,228,228,228,228,223,220,220,220,215,212,212,212,207,204,204,199,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,132,132,127,124,119,116,108,108,100,95,92,84,79,76,68,60,52,44,28,0,0,12,36,44,52,60,68,76,84,87,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,215,220,220,220,220,223,228,228,228,228,228,231,231,231,231,231,231,228,228,228,228,228,228,223,220,220,220,215,212,212,212,207,204,204,204,199,196,196,191,188,188,188,180,180,180,172,172,172,164,164,159,156,156,151,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,39,28,0,0,7,28,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,164,172,172,175,180,180,183,188,188,188,191,196,196,199,204,204,204,207,212,212,212,215,220,220,220,220,223,228,228,228,228,228,228,228,228,228,228,228,228,228,228,223,223,220,220,220,220,215,212,212,212,207,204,204,204,196,196,196,191,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,135,132,132,124,124,116,116,108,103,100,95,92,84,76,71,68,60,47,36,20,0,0,0,28,44,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,191,196,196,196,199,204,204,207,212,212,212,212,215,220,220,220,220,223,223,228,228,228,228,228,228,228,228,228,228,228,223,220,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,196,188,188,188,183,180,180,175,172,172,167,164,164,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,68,63,55,44,36,20,0,0,0,23,36,52,60,68,71,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,188,196,196,196,199,204,204,204,207,212,212,212,212,215,220,220,220,220,220,223,223,223,228,228,228,228,228,223,223,223,220,220,220,220,220,215,212,212,212,207,204,204,204,199,196,196,196,191,188,188,183,180,180,180,172,172,172,164,164,159,156,156,151,148,148,140,140,132,132,127,124,119,116,111,108,100,100,92,87,84,76,68,60,52,44,31,12,0,0,0,20,36,47,55,63,71,76,84,92,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,164,164,164,172,172,172,180,180,180,183,188,188,191,196,196,196,199,204,204,204,207,212,212,212,212,215,220,220,220,220,220,220,220,223,223,223,223,220,220,220,220,220,220,220,215,215,212,212,212,207,207,204,204,204,199,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,148,148,143,140,140,132,132,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,28,0,0,0,0,15,36,44,52,60,68,76,84,87,92,100,100,108,111,116,119,124,127,132,132,140,140,143,148,148,156,156,159,164,164,167,172,172,175,180,180,183,188,188,188,191,196,196,196,199,204,204,204,207,212,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,215,212,212,212,212,207,207,204,204,204,199,196,196,196,191,188,188,183,180,180,180,172,172,172,164,164,164,156,156,151,148,148,143,140,135,132,132,124,124,116,116,108,103,100,95,92,84,79,71,68,60,52,39,28,0,0,0,0,0,28,44,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,143,148,148,151,156,156,164,164,164,172,172,172,180,180,180,183,188,188,191,196,196,196,199,204,204,204,204,207,212,212,212,212,212,215,215,220,220,220,220,220,220,220,220,220,220,215,215,215,212,212,212,212,207,207,204,204,204,199,196,196,196,191,188,188,188,183,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,119,116,111,108,103,100,92,87,84,76,71,63,55,47,36,20,0,0,0,0,0,28,39,52,60,68,71,76,84,92,92,100,103,108,111,116,119,124,127,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,188,188,188,191,196,196,196,199,204,204,204,204,207,207,212,212,212,212,212,212,215,215,215,215,215,215,215,215,215,212,212,212,212,212,212,207,204,204,204,204,199,196,196,196,191,188,188,188,183,180,180,180,172,172,172,164,164,164,156,156,151,148,148,143,140,140,132,132,124,124,119,116,108,108,100,100,92,87,84,76,68,60,52,44,36,15,0,0,0,0,0,20,36,44,55,63,68,76,84,87,92,100,100,108,111,116,119,124,127,132,132,140,140,143,148,148,156,156,156,164,164,164,172,172,172,175,180,180,183,188,188,188,191,196,196,196,199,199,204,204,204,204,207,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,207,207,204,204,204,204,199,196,196,196,191,191,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,127,124,124,116,116,108,108,100,95,92,84,79,76,68,60,52,44,28,0,0,0,0,0,0,12,31,44,52,60,68,76,79,84,92,95,100,108,108,116,116,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,175,180,180,180,183,188,188,188,191,196,196,196,199,199,204,204,204,204,207,207,207,212,212,212,212,212,212,212,212,212,212,212,212,212,207,207,204,204,204,204,204,199,196,196,196,196,191,188,188,188,183,180,180,175,172,172,172,164,164,164,156,156,156,148,148,143,140,140,132,132,127,124,119,116,111,108,103,100,92,92,84,76,71,63,60,47,36,23,0,0,0,0,0,0,0,28,39,52,60,68,71,76,84,92,92,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,151,156,156,164,164,164,167,172,172,175,180,180,180,183,188,188,188,191,196,196,196,196,199,204,204,204,204,204,204,207,207,207,212,212,212,212,212,212,207,207,207,207,204,204,204,204,204,199,199,196,196,196,191,191,188,188,188,183,180,180,180,172,172,172,167,164,164,159,156,156,151,148,148,140,140,135,132,132,124,124,116,116,108,108,100,100,92,87,84,76,68,60,52,44,36,20,0,0,0,0,0,0,0,20,36,47,55,63,68,76,84,87,92,100,100,108,108,116,116,124,124,132,132,135,140,140,148,148,151,156,156,159,164,164,167,172,172,172,175,180,180,180,183,188,188,188,191,196,196,196,196,199,199,204,204,204,204,204,204,204,204,204,207,207,207,204,204,204,204,204,204,204,204,204,199,196,196,196,196,191,191,188,188,188,183,180,180,180,175,172,172,167,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,119,116,111,108,103,100,95,92,84,79,76,68,60,52,44,28,7,0,0,0,0,0,0,0,12,31,44,52,60,68,76,79,84,92,95,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,167,172,172,172,175,180,180,180,183,188,188,188,191,191,196,196,196,196,199,199,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,199,199,196,196,196,196,196,191,188,188,188,188,183,180,180,180,175,172,172,167,164,164,164,159,156,156,151,148,148,140,140,135,132,132,124,124,116,116,108,108,100,100,92,87,84,76,71,63,60,47,36,23,0,0,0,0,0,0,0,0,0,28,39,52,60,68,71,76,84,87,92,100,100,108,111,116,116,124,124,132,132,135,140,140,143,148,148,156,156,156,164,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,191,196,196,196,196,196,196,199,199,199,204,204,204,204,204,204,204,204,204,199,199,199,196,196,196,196,196,191,191,188,188,188,188,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,140,132,132,127,124,119,116,111,108,103,100,95,92,84,79,76,68,60,52,44,36,15,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,79,84,92,95,100,103,108,111,116,119,124,127,132,132,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,175,180,180,180,183,188,188,188,188,191,191,196,196,196,196,196,196,196,199,199,199,199,199,199,199,199,196,196,196,196,196,196,196,196,191,188,188,188,188,183,183,180,180,180,175,172,172,172,167,164,164,159,156,156,151,148,148,143,140,140,135,132,132,124,124,116,116,108,108,100,100,92,87,84,76,71,68,60,52,39,28,0,0,0,0,0,0,0,0,0,0,7,28,44,52,60,68,71,76,84,87,92,100,100,108,108,116,116,124,124,127,132,135,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,175,180,180,180,183,183,188,188,188,188,191,191,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,191,191,188,188,188,188,188,183,180,180,180,180,175,172,172,172,167,164,164,159,156,156,156,148,148,148,140,140,135,132,132,127,124,119,116,111,108,103,100,95,92,84,84,76,68,60,55,44,36,20,0,0,0,0,0,0,0,0,0,0,0,20,36,47,55,60,68,76,84,84,92,95,100,103,108,111,116,119,124,124,132,132,135,140,140,143,148,148,151,156,156,159,164,164,164,167,172,172,172,175,180,180,180,180,183,188,188,188,188,188,188,191,191,191,196,196,196,196,196,196,196,196,196,196,196,191,191,191,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,167,164,164,164,156,156,156,151,148,148,143,140,140,132,132,127,124,124,116,116,108,108,100,100,92,87,84,76,71,68,60,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,12,31,44,52,60,68,71,76,84,87,92,100,100,108,108,116,116,124,124,127,132,132,140,140,140,148,148,148,156,156,156,159,164,164,164,167,172,172,172,175,180,180,180,180,180,183,188,188,188,188,188,188,188,188,191,191,191,191,191,191,191,191,191,188,188,188,188,188,188,188,183,183,180,180,180,180,175,172,172,172,172,167,164,164,164,156,156,156,151,148,148,143,140,140,135,132,132,124,124,119,116,111,108,103,100,95,92,84,84,76,68,63,55,47,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,47,55,63,68,76,79,84,92,95,100,103,108,111,116,116,124,124,127,132,132,140,140,143,148,148,148,156,156,156,159,164,164,164,167,172,172,172,172,175,180,180,180,180,180,183,183,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,183,183,180,180,180,180,180,175,172,172,172,167,167,164,164,164,156,156,156,151,148,148,143,140,140,135,132,132,127,124,119,116,116,108,108,100,100,92,87,84,76,71,68,60,52,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,52,60,68,71,76,84,87,92,100,100,108,108,111,116,119,124,124,132,132,135,140,140,143,148,148,148,156,156,156,159,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,183,183,183,188,188,188,188,188,188,188,188,188,188,188,188,183,183,183,180,180,180,180,180,180,175,172,172,172,172,167,164,164,164,159,156,156,156,151,148,148,143,140,140,135,132,132,127,124,124,116,116,111,108,103,100,95,92,84,79,76,68,60,55,47,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,47,55,60,68,76,79,84,92,92,100,100,108,108,116,116,119,124,127,132,132,135,140,140,143,148,148,148,156,156,156,159,164,164,164,164,167,172,172,172,172,175,175,180,180,180,180,180,180,180,183,183,183,183,183,183,183,183,183,183,180,180,180,180,180,180,180,180,175,172,172,172,172,172,167,164,164,164,159,156,156,156,151,148,148,148,140,140,140,132,132,127,124,124,119,116,111,108,103,100,95,92,87,84,76,71,68,60,52,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,60,68,71,76,84,84,92,95,100,103,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,159,164,164,164,167,167,172,172,172,172,175,175,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,175,175,172,172,172,172,172,167,164,164,164,164,159,156,156,156,151,148,148,148,140,140,140,132,132,132,124,124,119,116,116,108,108,100,100,92,92,84,79,76,68,60,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,76,76,84,87,92,100,100,108,108,111,116,116,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,159,164,164,164,164,167,167,172,172,172,172,172,175,175,175,180,180,180,180,180,180,180,180,180,180,180,180,175,175,175,172,172,172,172,172,172,167,164,164,164,164,159,159,156,156,156,151,148,148,143,140,140,140,132,132,132,124,124,119,116,116,108,108,103,100,95,92,84,84,76,68,63,60,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,39,52,55,63,68,76,79,84,92,92,100,100,108,108,111,116,119,124,124,127,132,132,135,140,140,143,148,148,148,151,156,156,156,159,159,164,164,164,164,167,167,172,172,172,172,172,172,172,172,175,175,175,175,175,175,175,175,175,172,172,172,172,172,172,172,172,167,164,164,164,164,164,159,156,156,156,151,148,148,148,143,140,140,140,132,132,132,124,124,119,116,116,111,108,103,100,95,92,87,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,68,71,76,84,84,92,95,100,100,108,108,116,116,119,124,124,127,132,132,135,140,140,140,148,148,148,151,151,156,156,156,159,159,164,164,164,164,164,167,167,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,172,167,167,164,164,164,164,164,159,156,156,156,156,151,148,148,148,143,140,140,140,132,132,132,124,124,124,116,116,111,108,103,100,100,92,87,84,79,76,68,60,55,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,76,76,84,87,92,95,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,140,143,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,164,167,167,167,172,172,172,172,172,172,172,172,172,172,167,167,167,167,164,164,164,164,164,164,159,156,156,156,156,151,151,148,148,148,143,140,140,135,132,132,132,124,124,124,116,116,111,108,108,100,100,92,92,84,79,76,68,63,60,52,44,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,52,55,63,68,76,79,84,87,92,95,100,103,108,108,116,116,119,124,124,127,132,132,135,140,140,140,143,148,148,148,148,151,156,156,156,156,159,159,164,164,164,164,164,164,164,164,164,164,164,167,167,167,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,148,148,148,143,140,140,140,135,132,132,132,124,124,124,116,116,111,108,108,100,100,92,92,84,84,76,71,68,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,63,68,76,79,84,92,92,100,100,103,108,108,116,116,119,124,124,127,132,132,132,135,140,140,140,143,148,148,148,148,151,156,156,156,156,156,159,159,159,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,159,159,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,87,84,76,71,68,60,52,47,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,60,68,71,76,84,84,92,92,100,100,103,108,108,116,116,119,124,124,124,132,132,132,135,140,140,140,143,143,148,148,148,148,151,156,156,156,156,156,156,156,159,159,159,159,159,159,164,164,159,159,159,159,159,159,156,156,156,156,156,156,156,151,151,148,148,148,148,143,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,87,84,76,76,68,60,55,52,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,36,47,52,60,68,71,76,84,84,92,92,100,100,103,108,108,116,116,116,124,124,124,127,132,132,132,135,140,140,140,143,143,148,148,148,148,151,151,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,148,148,148,148,148,143,140,140,140,140,135,132,132,132,127,124,124,119,116,116,111,108,108,100,100,95,92,87,84,79,76,68,63,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,47,55,60,68,71,76,84,84,92,92,100,100,103,108,108,111,116,116,119,124,124,127,132,132,132,135,135,140,140,140,143,143,148,148,148,148,148,148,151,151,151,156,156,156,156,156,156,156,156,156,156,156,156,156,151,151,151,148,148,148,148,148,148,143,140,140,140,140,135,132,132,132,127,124,124,124,119,116,116,111,108,108,100,100,95,92,87,84,79,76,68,63,60,52,44,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,44,52,55,60,68,71,76,84,84,92,92,95,100,103,108,108,111,116,116,119,124,124,124,127,132,132,132,135,135,140,140,140,140,143,143,148,148,148,148,148,148,148,148,148,151,151,151,151,151,151,151,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,135,132,132,132,132,127,124,124,119,116,116,116,108,108,103,100,100,95,92,87,84,79,76,68,68,60,52,44,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,55,60,68,71,76,84,84,92,92,95,100,100,108,108,111,116,116,116,119,124,124,124,127,132,132,132,135,135,140,140,140,140,140,143,143,143,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,148,143,143,140,140,140,140,140,140,135,132,132,132,132,127,124,124,124,119,116,116,111,108,108,103,100,100,92,92,87,84,79,76,68,68,60,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,55,60,68,71,76,84,84,87,92,95,100,100,103,108,108,111,116,116,119,124,124,124,124,127,132,132,132,132,135,135,140,140,140,140,140,140,140,143,143,143,143,143,143,143,143,143,143,143,143,143,140,140,140,140,140,140,140,135,135,132,132,132,132,127,124,124,124,119,116,116,116,111,108,108,103,100,100,92,92,87,84,79,76,68,68,60,52,47,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,55,60,68,71,76,79,84,87,92,92,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,132,132,132,132,132,135,135,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,140,135,135,132,132,132,132,132,127,127,124,124,124,119,116,116,116,111,108,108,103,100,100,95,92,92,84,84,76,76,68,68,60,52,47,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,55,60,68,71,76,79,84,87,92,92,95,100,100,103,108,108,111,116,116,116,119,124,124,124,124,127,127,132,132,132,132,132,132,135,135,135,135,140,140,140,140,140,140,140,140,135,135,135,135,132,132,132,132,132,132,132,127,124,124,124,124,119,116,116,116,111,108,108,108,103,100,100,95,92,87,84,84,76,76,68,63,60,52,47,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,55,60,68,68,76,76,84,84,92,92,95,100,100,103,108,108,108,111,116,116,116,119,119,124,124,124,124,127,127,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,127,127,124,124,124,124,124,119,116,116,116,111,108,108,108,103,100,100,95,92,92,87,84,79,76,71,68,63,60,52,44,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,44,52,52,60,68,68,76,76,84,84,87,92,92,95,100,100,103,108,108,108,111,116,116,116,116,119,124,124,124,124,124,124,127,127,127,127,132,132,132,132,132,132,132,132,132,132,132,127,127,127,124,124,124,124,124,124,119,119,116,116,116,111,108,108,108,103,100,100,100,95,92,92,84,84,79,76,71,68,60,60,52,44,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,39,47,52,60,63,68,71,76,79,84,84,92,92,92,100,100,100,103,108,108,108,111,111,116,116,116,116,119,119,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,119,119,116,116,116,116,116,111,108,108,108,103,100,100,100,95,92,92,87,84,84,76,76,68,68,60,55,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,39,44,52,60,60,68,68,76,76,84,84,87,92,92,92,100,100,100,103,108,108,108,108,111,111,116,116,116,116,116,119,119,119,119,124,124,124,124,124,124,124,124,124,124,124,119,119,119,116,116,116,116,116,116,111,108,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,71,68,63,60,52,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,52,55,60,63,68,71,76,79,84,84,87,92,92,92,95,100,100,100,103,108,108,108,108,111,111,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,116,111,111,108,108,108,108,108,103,100,100,100,95,92,92,87,84,84,79,76,76,68,68,60,60,52,47,39,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,44,47,52,60,60,68,68,76,76,79,84,84,87,92,92,92,95,100,100,100,100,103,108,108,108,108,108,108,111,111,111,116,116,116,116,116,116,116,116,116,116,111,111,111,108,108,108,108,108,108,103,103,100,100,100,100,95,92,92,87,84,84,84,76,76,71,68,63,60,55,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,44,52,55,60,63,68,68,76,76,79,84,84,87,92,92,92,92,95,100,100,100,100,103,103,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,108,103,103,100,100,100,100,100,95,92,92,92,87,84,84,84,76,76,71,68,68,60,60,52,47,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,47,52,55,60,63,68,71,76,76,79,84,84,84,87,92,92,92,92,95,100,100,100,100,100,100,100,103,103,103,103,103,108,108,103,103,103,103,103,103,100,100,100,100,100,100,95,95,92,92,92,92,87,84,84,79,76,76,71,68,68,60,60,52,52,44,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,44,52,52,60,60,63,68,68,76,76,76,79,84,84,84,87,92,92,92,92,92,95,95,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,100,95,95,95,92,92,92,92,87,87,84,84,84,79,76,76,71,68,68,63,60,55,52,44,44,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,44,52,52,60,60,63,68,68,71,76,76,76,79,84,84,84,84,87,92,92,92,92,92,92,92,92,92,95,95,95,95,92,92,92,92,92,92,92,92,92,87,87,84,84,84,84,79,76,76,76,71,68,68,60,60,55,52,47,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,52,52,55,60,63,68,68,68,71,76,76,76,79,84,84,84,84,84,84,87,87,87,92,92,92,92,92,92,92,92,87,87,87,87,84,84,84,84,84,79,79,76,76,76,71,68,68,63,60,60,55,52,47,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,39,44,47,52,55,60,60,63,68,68,68,71,76,76,76,76,79,79,79,84,84,84,84,84,84,84,84,84,84,84,84,84,84,84,79,79,76,76,76,76,71,71,68,68,63,60,60,60,52,52,44,44,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,36,44,44,52,52,55,60,60,63,68,68,68,68,71,71,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,71,68,68,68,68,63,60,60,60,52,52,47,44,39,36,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,31,36,39,44,47,52,52,55,60,60,60,60,63,68,68,68,68,68,68,68,71,71,71,71,71,71,71,68,68,68,68,68,68,68,63,60,60,60,55,52,52,47,44,44,36,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,31,36,39,44,44,47,52,52,52,55,60,60,60,60,60,63,63,63,63,63,63,63,63,63,63,60,60,60,60,60,60,55,52,52,52,47,44,44,36,36,28,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,31,36,36,39,44,44,47,52,52,52,52,52,52,55,55,55,55,55,55,55,55,55,52,52,52,52,52,47,44,44,44,39,36,36,28,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,28,31,36,36,36,39,44,44,44,44,44,44,47,47,47,47,44,44,44,44,44,44,44,39,36,36,31,28,28,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,23,28,28,28,31,36,36,36,36,36,36,36,36,36,36,31,31,28,28,28,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,20,20,20,20,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t FLARE_TEXTURE_3[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,52,55,60,60,60,60,60,60,60,52,52,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,60,68,76,84,92,95,100,108,108,108,111,111,111,108,108,103,100,92,84,79,71,60,52,44,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,71,84,95,108,116,124,132,140,148,148,156,156,159,164,164,164,159,156,151,148,140,135,127,119,111,100,92,76,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,60,76,92,108,119,132,143,156,164,172,180,188,196,199,204,207,212,212,212,212,212,204,204,196,191,188,180,172,159,148,140,124,116,100,84,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,55,76,92,108,124,140,156,167,180,191,204,212,220,228,236,244,252,252,244,244,244,244,244,244,247,252,247,244,236,228,220,207,196,188,172,164,148,132,116,100,84,63,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,100,119,140,156,172,188,204,215,228,244,252,244,231,223,215,212,204,199,196,196,191,191,196,196,196,204,207,212,220,228,236,244,244,236,220,212,196,180,164,148,132,108,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,60,84,108,124,148,164,183,204,220,236,252,239,228,212,204,191,183,172,167,159,156,148,148,143,140,140,143,148,148,151,156,164,172,180,188,196,207,220,236,247,244,228,212,196,175,156,135,116,95,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,60,84,108,132,151,172,191,212,228,247,236,220,204,191,180,164,156,143,132,124,116,111,108,100,100,92,92,92,92,95,100,103,108,116,124,132,140,148,159,172,188,199,212,228,244,239,220,204,180,164,140,116,92,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,76,100,124,148,172,196,220,236,244,228,207,191,172,159,143,132,116,108,95,84,76,68,60,55,52,47,44,44,44,44,44,52,52,60,68,71,79,92,100,111,124,140,151,164,180,199,220,236,247,228,204,183,164,140,116,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,68,92,119,148,172,196,220,239,244,220,199,180,164,143,127,111,95,84,68,60,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,12,15,23,31,44,52,63,76,92,103,119,135,156,172,188,212,228,252,228,204,180,156,132,108,79,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,79,108,135,164,188,212,236,244,220,196,175,156,132,116,100,79,63,52,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,44,55,71,92,108,124,143,164,188,207,228,252,228,204,175,148,124,92,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,92,124,148,180,204,228,247,220,196,172,151,132,108,87,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,79,100,119,140,164,188,212,236,244,220,191,164,135,108,76,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,71,100,132,164,188,220,244,228,204,180,156,132,108,84,63,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,76,95,119,140,164,191,220,244,231,204,175,148,116,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,108,140,172,204,231,244,215,188,164,135,111,84,63,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,76,100,124,148,175,204,228,244,215,188,156,124,92,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,148,180,212,244,231,204,172,148,119,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,55,79,108,132,159,188,220,247,228,196,164,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,124,156,188,220,252,220,191,164,132,108,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,63,92,119,148,180,207,236,236,204,172,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,124,156,191,228,244,212,183,151,124,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,76,108,140,167,196,228,244,207,175,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,124,159,196,228,244,207,175,143,116,84,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,68,100,127,159,191,228,244,212,180,143,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,159,196,228,236,204,172,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,156,188,220,247,212,180,140,108,68,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,84,124,156,196,228,236,204,167,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,151,188,220,247,212,175,140,103,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,116,156,191,228,236,204,167,132,100,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,47,79,116,148,183,220,247,212,172,135,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,108,148,188,228,244,204,167,132,95,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,116,148,188,223,244,204,167,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,220,244,207,172,132,100,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,79,116,151,188,228,236,199,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,132,172,212,252,212,175,140,100,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,84,119,156,196,236,231,191,151,111,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,124,164,204,244,220,183,143,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,164,204,244,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,108,148,188,231,231,191,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,55,92,132,172,212,252,212,172,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,92,135,180,220,244,204,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,60,100,140,180,223,239,196,156,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,204,244,215,172,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,116,156,196,236,228,183,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,228,228,188,148,108,63,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,124,167,212,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,124,172,212,247,204,164,119,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,140,183,228,236,191,148,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,148,196,236,220,180,135,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,199,244,215,172,127,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,132,172,220,244,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,239,196,151,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,151,196,239,220,172,132,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,108,151,196,244,220,172,127,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,124,172,220,244,196,151,108,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,132,172,220,239,196,148,103,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,100,148,191,236,220,175,132,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,151,196,244,215,172,124,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,119,164,212,244,199,156,108,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,132,180,223,236,188,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,183,228,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,111,156,204,252,207,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,247,207,164,116,68,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,231,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,236,191,143,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,167,212,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,220,172,127,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,103,151,196,244,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,204,159,111,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,87,135,180,228,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,71,119,167,215,239,191,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,119,167,215,239,191,143,95,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,143,191,244,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,215,167,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,228,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,244,191,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,119,167,220,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,231,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,207,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,223,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,247,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,148,196,244,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,220,172,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,252,204,156,108,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,79,132,180,228,223,175,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,108,156,204,252,199,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,175,228,228,180,132,79,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,207,244,196,148,100,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,124,172,220,231,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,244,196,143,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,119,172,220,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,244,191,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,167,220,236,188,135,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,244,191,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,167,220,236,188,140,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,244,196,143,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,167,220,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,244,196,148,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,119,172,220,236,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,76,124,172,223,231,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,103,151,204,252,204,151,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,127,180,228,228,180,127,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,247,207,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,231,220,172,124,76,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,220,172,124,71,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,100,148,196,244,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,79,127,180,228,228,180,132,79,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,108,156,204,252,204,156,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,119,172,220,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,68,116,164,212,244,196,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,159,207,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,236,183,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,207,159,111,63,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,87,135,183,231,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,247,199,151,103,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,79,127,175,223,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,212,164,119,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,47,95,143,188,236,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,228,180,135,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,111,159,204,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,244,199,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,223,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,239,220,172,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,55,100,148,196,239,215,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,220,236,188,143,100,52,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,167,212,244,196,151,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,156,204,247,212,164,119,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,100,140,188,231,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,135,180,228,228,188,140,95,52,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,207,252,204,159,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,164,204,252,207,164,119,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,100,140,188,228,228,183,140,92,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,95,140,183,228,228,188,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,207,252,207,164,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,204,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,231,228,183,140,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,92,140,180,228,236,191,148,108,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,84,127,172,212,247,204,159,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,204,244,220,175,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,111,156,196,236,220,180,135,92,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,244,204,159,119,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,223,236,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,191,231,228,188,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,127,167,212,252,212,172,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,79,124,164,204,244,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,76,116,156,196,236,228,183,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,135,175,215,247,207,167,127,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,108,148,188,228,236,196,156,116,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,148,188,228,236,196,159,124,84,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,103,140,180,220,244,207,167,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,116,156,196,236,228,191,156,116,79,44,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,100,135,172,212,252,215,175,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,124,164,204,244,228,188,151,116,79,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,100,132,172,204,244,220,183,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,132,172,207,244,220,188,148,116,79,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,100,132,167,204,239,228,188,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,63,100,140,175,212,247,220,183,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,167,204,236,228,196,156,119,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,140,180,212,247,220,188,151,119,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,68,103,135,172,204,236,231,196,159,124,84,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,143,180,212,247,223,188,156,124,92,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,47,76,108,140,172,204,239,228,196,159,124,92,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,175,212,244,228,196,164,132,100,71,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,87,116,148,180,212,244,228,196,159,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,172,204,236,236,204,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,68,100,127,156,188,220,252,220,188,156,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,68,103,135,167,199,231,244,212,180,156,124,100,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,111,140,167,196,228,244,215,183,151,119,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,164,191,220,252,223,196,167,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,76,100,127,156,180,212,236,236,207,175,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,151,180,212,239,236,212,183,156,132,108,84,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,76,100,119,148,172,196,223,252,228,196,167,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,111,140,172,196,228,252,228,199,175,151,132,108,84,68,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,55,76,100,116,140,164,188,212,236,236,212,183,156,127,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,71,100,132,156,183,212,236,244,220,196,172,151,132,111,92,76,60,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,47,68,84,100,124,140,164,188,207,231,247,220,196,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,87,116,140,164,191,215,239,244,220,196,180,156,140,124,103,87,71,60,44,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,28,39,52,68,79,95,111,132,148,167,188,207,228,252,228,204,180,156,127,100,76,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,71,100,124,148,172,196,220,239,244,223,204,188,167,151,135,119,108,92,84,68,60,52,44,36,31,28,20,20,20,20,20,20,23,28,36,39,47,55,68,76,87,100,116,127,143,159,175,196,212,231,252,228,207,183,159,135,111,84,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,79,108,127,151,172,196,215,236,252,231,212,196,180,167,156,140,132,119,108,100,92,84,79,76,71,68,68,68,68,68,76,76,84,92,100,108,116,124,135,148,164,175,188,204,223,239,244,228,204,183,164,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,108,127,148,172,188,207,228,244,244,228,215,204,188,180,167,156,148,140,135,132,124,124,119,116,116,116,119,124,127,132,140,148,156,164,172,183,196,212,223,236,252,236,215,196,180,159,140,116,95,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,103,124,143,164,180,196,212,228,239,252,236,228,220,207,199,191,188,180,175,172,172,167,167,167,172,172,180,180,188,196,204,212,220,231,244,244,236,220,204,188,172,151,132,116,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,60,76,95,116,132,148,164,180,191,204,215,228,236,247,247,244,236,228,228,220,220,220,220,220,220,223,228,231,236,244,252,244,236,220,212,196,188,172,156,140,124,108,87,68,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,68,84,100,116,132,143,156,167,180,188,196,204,212,220,223,228,231,236,236,236,236,236,231,228,220,215,212,204,196,183,172,164,148,140,124,108,92,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,68,84,95,108,119,132,140,148,156,164,172,175,180,180,188,188,188,188,183,180,180,172,167,159,156,143,135,124,116,100,92,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,60,71,84,92,100,108,116,119,124,132,132,135,135,140,135,132,132,127,124,116,111,103,95,84,76,68,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,60,68,71,76,79,84,84,87,87,84,84,84,76,76,68,60,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,28,36,36,36,36,36,36,31,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t FLARE_TEXTURE_4[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,52,55,60,60,60,60,60,60,60,52,52,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,60,68,76,84,92,95,100,108,108,108,111,111,111,108,108,103,100,92,84,79,71,60,52,44,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,71,84,95,108,116,124,132,140,148,148,156,156,159,164,164,164,159,156,151,148,140,135,127,119,111,100,92,76,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,60,76,92,108,119,132,143,156,164,172,180,188,196,199,204,207,212,212,212,212,212,204,204,196,191,188,180,172,159,148,140,124,116,100,84,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,55,76,92,108,124,140,156,167,180,191,204,212,220,228,236,244,252,252,252,252,252,252,252,252,252,252,247,244,236,228,220,207,196,188,172,164,148,132,116,100,84,63,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,100,119,140,156,172,188,204,215,228,244,252,252,252,252,247,247,247,244,244,244,244,244,244,244,244,247,247,247,247,252,252,252,244,236,220,212,196,180,164,148,132,108,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,60,84,108,124,148,164,183,204,220,236,252,252,252,247,247,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,247,247,252,252,244,228,212,196,175,156,135,116,95,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,60,84,108,132,151,172,191,212,228,247,252,247,247,244,244,244,244,244,239,239,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,239,239,244,244,244,244,244,247,252,252,239,220,204,180,164,140,116,92,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,76,100,124,148,172,196,220,236,252,252,247,244,244,244,244,239,236,236,236,236,236,236,231,231,231,231,231,231,231,231,231,231,231,231,236,236,236,236,236,236,239,239,244,244,244,244,247,252,247,228,204,183,164,140,116,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,68,92,119,148,172,196,220,239,252,247,244,244,244,244,239,236,236,236,236,231,231,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,228,231,236,236,236,236,236,239,244,244,244,247,252,252,228,204,180,156,132,108,79,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,79,108,135,164,188,212,236,252,247,244,244,244,239,236,236,236,236,231,228,228,228,228,228,223,223,223,220,220,220,220,220,220,220,220,220,220,220,223,223,228,228,228,228,228,228,231,236,236,236,239,244,244,244,247,252,252,228,204,175,148,124,92,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,92,124,148,180,204,228,252,252,244,244,244,239,236,236,236,231,228,228,228,228,223,220,220,220,220,220,220,220,220,215,215,215,215,215,215,215,220,220,220,220,220,220,220,223,223,228,228,228,231,231,236,236,236,239,244,244,247,252,244,220,191,164,135,108,76,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,71,100,132,164,188,220,244,252,247,244,244,239,236,236,236,231,228,228,228,223,220,220,220,220,215,215,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,212,215,215,220,220,220,220,223,223,228,228,228,231,236,236,236,244,244,244,247,252,231,204,175,148,116,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,108,140,172,204,231,252,247,244,244,239,236,236,236,228,228,228,223,220,220,220,220,215,212,212,212,212,212,212,207,207,207,204,204,204,204,204,204,204,207,207,207,212,212,212,212,212,215,215,220,220,220,223,228,228,228,231,236,236,239,244,244,247,252,244,215,188,156,124,92,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,148,180,212,244,252,247,244,244,236,236,236,231,228,228,223,220,220,220,215,212,212,212,212,207,207,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,204,207,212,212,212,212,215,220,220,220,223,228,228,228,231,236,236,239,244,244,247,252,228,196,164,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,124,156,188,220,252,252,244,244,239,236,236,231,228,228,223,220,220,220,215,212,212,212,207,204,204,204,204,204,199,199,196,196,196,196,196,196,196,196,196,196,196,196,196,199,199,204,204,204,204,207,207,212,212,212,215,220,220,223,228,228,228,236,236,236,244,244,247,252,236,204,172,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,124,156,191,228,252,247,244,244,239,236,236,228,228,228,220,220,220,215,212,212,207,204,204,204,204,199,196,196,196,196,196,196,191,191,191,191,191,191,191,191,191,191,196,196,196,196,196,196,199,199,204,204,204,207,212,212,212,215,220,220,223,228,228,231,236,236,239,244,244,252,244,207,175,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,124,159,196,228,252,247,244,244,236,236,231,228,228,223,220,220,215,212,212,207,204,204,204,199,196,196,196,196,191,191,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,188,191,196,196,196,196,199,204,204,204,207,212,212,212,215,220,220,223,228,228,236,236,239,244,244,252,244,212,180,143,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,159,196,228,252,247,244,239,236,236,231,228,228,220,220,215,212,212,207,204,204,204,199,196,196,196,191,188,188,188,188,188,183,183,180,180,180,180,180,180,180,180,180,180,183,183,188,188,188,188,188,191,196,196,196,196,199,204,204,207,212,212,215,220,220,223,228,228,231,236,239,244,244,247,247,212,180,140,108,68,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,84,124,156,196,228,252,247,244,239,236,236,228,228,223,220,220,215,212,212,207,204,204,199,196,196,196,191,188,188,188,183,183,180,180,180,180,180,180,175,175,175,175,175,175,180,180,180,180,180,180,180,183,188,188,188,188,191,196,196,196,199,204,204,207,212,212,215,220,220,228,228,231,236,236,244,244,247,247,212,175,140,103,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,116,156,191,228,252,247,244,239,236,236,228,228,223,220,220,212,212,207,204,204,199,196,196,196,188,188,188,183,180,180,180,180,175,175,172,172,172,172,172,172,172,172,172,172,172,172,172,172,175,175,180,180,180,180,183,188,188,188,191,196,196,199,204,204,204,212,212,215,220,220,223,228,231,236,236,244,244,247,247,212,172,135,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,108,148,188,228,252,247,244,239,236,231,228,228,220,220,215,212,212,207,204,204,196,196,196,188,188,188,183,180,180,180,175,172,172,172,172,172,167,167,167,164,164,164,164,164,164,167,167,167,172,172,172,172,172,175,180,180,180,183,188,188,188,191,196,196,199,204,204,207,212,212,220,220,223,228,231,236,236,244,244,252,244,204,167,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,220,252,247,244,239,236,231,228,228,220,220,215,212,212,204,204,199,196,196,191,188,188,183,180,180,180,175,172,172,172,167,167,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,164,167,172,172,172,172,175,180,180,183,188,188,188,196,196,196,204,204,207,212,212,220,220,223,228,231,236,236,244,244,252,236,199,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,132,172,212,252,247,244,239,236,236,228,228,220,220,215,212,207,204,204,199,196,196,188,188,183,180,180,180,175,172,172,172,167,164,164,164,164,159,159,156,156,156,156,156,156,156,156,156,156,156,159,159,164,164,164,164,167,172,172,172,175,180,180,183,188,188,191,196,196,199,204,207,212,212,220,220,223,228,231,236,236,244,244,252,231,191,151,111,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,124,164,204,244,252,244,244,236,236,228,228,220,220,215,212,207,204,204,196,196,191,188,188,183,180,180,175,172,172,167,164,164,164,159,159,156,156,156,156,156,151,151,151,151,151,151,151,151,156,156,156,156,156,156,159,164,164,164,167,172,172,172,175,180,180,183,188,188,196,196,199,204,204,212,212,220,220,223,228,231,236,239,244,247,252,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,108,148,188,231,252,244,244,236,236,228,228,220,220,215,212,207,204,204,196,196,191,188,188,180,180,175,172,172,167,164,164,164,159,156,156,156,151,151,148,148,148,148,148,148,148,148,148,148,148,148,148,148,151,151,156,156,156,156,159,164,164,167,172,172,175,180,180,183,188,188,196,196,199,204,204,212,212,220,220,223,228,231,236,239,244,247,252,212,172,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,92,135,180,220,252,247,244,239,236,231,228,223,220,215,212,207,204,204,196,196,188,188,183,180,180,175,172,172,164,164,164,159,156,156,156,151,148,148,148,148,143,143,140,140,140,140,140,140,140,140,143,143,148,148,148,148,148,151,156,156,156,159,164,164,167,172,172,175,180,180,188,188,191,196,199,204,204,212,212,220,220,228,228,236,236,244,244,252,239,196,156,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,204,244,247,244,239,236,231,228,223,220,215,212,207,204,204,196,196,188,188,183,180,180,172,172,167,164,164,159,156,156,151,148,148,148,148,143,140,140,140,140,140,140,135,135,135,135,140,140,140,140,140,140,140,143,148,148,148,151,156,156,156,164,164,164,172,172,175,180,180,188,188,191,196,199,204,204,212,212,220,220,228,228,236,236,244,244,252,228,183,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,228,252,244,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,183,180,175,172,172,167,164,164,156,156,156,148,148,148,143,140,140,140,140,135,132,132,132,132,132,132,132,132,132,132,132,132,135,135,140,140,140,143,148,148,148,151,156,156,159,164,164,167,172,175,180,180,188,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,247,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,124,172,212,252,247,244,236,236,228,228,220,220,212,212,204,204,196,196,188,188,183,180,175,172,172,164,164,159,156,156,151,148,148,143,140,140,140,135,132,132,132,132,127,127,127,124,124,124,124,127,127,127,132,132,132,132,132,135,140,140,140,148,148,148,156,156,156,164,164,167,172,172,180,180,188,188,191,196,199,204,207,212,215,220,223,228,231,236,239,244,252,236,191,148,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,148,196,236,252,244,239,236,231,228,223,220,215,212,207,204,199,196,191,188,183,180,175,172,172,164,164,159,156,156,148,148,143,140,140,140,135,132,132,132,127,124,124,124,124,124,124,124,124,124,124,124,124,124,124,124,127,132,132,132,135,140,140,143,148,148,151,156,156,164,164,167,172,172,180,180,188,188,196,196,204,204,212,212,220,220,228,228,236,236,244,244,252,215,172,127,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,132,172,220,252,244,244,236,236,228,228,220,215,212,207,204,199,196,191,188,183,180,175,172,172,164,164,159,156,151,148,148,143,140,140,135,132,132,127,124,124,124,124,119,119,116,116,116,116,116,116,116,116,116,119,119,124,124,124,127,132,132,132,135,140,140,143,148,151,156,156,159,164,167,172,175,180,180,188,188,196,196,204,204,212,212,220,220,228,231,236,239,244,247,239,196,151,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,151,196,239,247,244,239,236,231,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,164,164,156,156,151,148,148,140,140,135,132,132,127,124,124,124,119,116,116,116,116,116,111,111,111,111,111,111,111,116,116,116,116,119,119,124,124,127,132,132,135,140,140,143,148,148,156,156,159,164,167,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,236,236,244,244,252,220,172,127,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,124,172,220,252,244,244,236,236,228,223,220,215,212,207,204,196,196,188,188,180,180,172,172,164,164,159,156,151,148,148,140,140,135,132,132,124,124,124,119,116,116,116,111,108,108,108,108,108,108,108,108,108,108,108,108,111,111,116,116,116,119,124,124,127,132,132,140,140,143,148,148,156,156,159,164,167,172,175,180,183,188,191,196,199,204,212,212,220,220,228,228,236,239,244,247,239,196,148,103,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,100,148,191,236,247,244,239,236,228,228,220,220,212,207,204,199,196,191,188,183,180,175,172,167,164,159,156,151,148,143,140,140,132,132,127,124,124,119,116,116,111,108,108,108,108,103,103,100,100,100,100,100,100,103,103,108,108,108,108,111,116,116,116,124,124,124,132,132,135,140,143,148,148,156,156,164,164,172,172,180,180,188,188,196,196,204,204,212,215,220,223,228,236,236,244,244,252,215,172,124,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,119,164,212,252,244,244,236,236,228,223,220,215,212,204,204,196,196,188,183,180,175,172,167,164,159,156,151,148,148,140,140,132,132,127,124,124,116,116,116,108,108,108,103,100,100,100,100,100,100,95,95,95,100,100,100,100,100,103,108,108,108,111,116,116,119,124,124,132,132,135,140,143,148,148,156,156,164,164,172,172,180,180,188,191,196,199,204,207,212,220,220,228,228,236,239,244,252,236,188,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,183,228,252,244,239,236,231,228,220,220,212,207,204,199,196,188,188,180,180,172,172,164,164,156,156,148,148,140,140,132,132,127,124,119,116,116,111,108,108,103,100,100,100,95,92,92,92,92,92,92,92,92,92,92,95,100,100,100,100,108,108,108,116,116,119,124,124,132,132,135,140,143,148,151,156,159,164,167,172,175,180,183,188,196,196,204,204,212,215,220,223,228,236,236,244,247,252,207,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,247,247,244,236,236,228,223,220,215,212,204,204,196,196,188,183,180,175,172,164,164,156,156,148,148,140,140,132,132,127,124,119,116,116,108,108,103,100,100,100,95,92,92,92,87,87,87,84,84,84,87,87,92,92,92,92,95,100,100,103,108,108,111,116,116,124,124,132,132,135,140,143,148,151,156,159,164,172,172,180,180,188,188,196,199,204,207,212,220,220,228,231,236,239,244,252,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,252,244,244,236,231,228,220,220,212,207,204,199,196,188,188,180,180,172,167,164,159,156,151,148,143,140,135,132,127,124,119,116,116,108,108,103,100,100,95,92,92,87,84,84,84,84,84,84,84,84,84,84,84,84,87,92,92,92,95,100,100,108,108,111,116,116,124,124,132,132,140,140,148,148,156,156,164,164,172,175,180,183,188,196,196,204,204,212,215,220,223,228,236,236,244,247,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,247,244,239,236,228,228,220,215,212,204,204,196,196,188,183,180,175,172,164,164,156,156,148,143,140,135,132,127,124,119,116,116,108,108,100,100,95,92,92,87,84,84,84,79,79,76,76,76,76,76,76,76,79,84,84,84,87,92,92,95,100,100,103,108,111,116,116,124,124,132,132,140,140,148,151,156,159,164,167,172,180,180,188,188,196,199,204,212,212,220,223,228,231,236,244,244,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,247,244,236,236,228,223,220,212,212,204,199,196,191,188,180,180,172,167,164,159,156,148,148,140,140,132,132,124,124,116,116,108,108,100,100,95,92,92,84,84,84,79,76,76,76,76,71,71,71,71,71,76,76,76,76,79,84,84,87,92,92,100,100,103,108,111,116,119,124,127,132,135,140,143,148,156,156,164,164,172,175,180,183,188,196,196,204,207,212,215,220,228,228,236,239,244,252,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,71,119,167,215,252,244,244,236,231,228,220,220,212,207,204,196,196,188,183,180,175,172,164,164,156,151,148,143,140,135,132,124,124,116,116,108,108,100,100,95,92,87,84,84,79,76,76,71,71,68,68,68,68,68,68,68,68,68,71,76,76,76,84,84,87,92,92,100,100,103,108,111,116,119,124,127,132,140,140,148,148,156,159,164,167,172,180,180,188,191,196,204,204,212,215,220,223,228,236,236,244,247,239,191,143,95,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,252,244,239,236,228,228,220,215,212,204,204,196,191,188,180,180,172,172,164,159,156,148,148,140,140,132,127,124,119,116,111,108,103,100,95,92,87,84,84,76,76,76,68,68,68,63,63,60,60,60,60,60,63,68,68,68,71,76,76,79,84,84,92,92,100,100,108,108,116,116,124,124,132,135,140,143,148,156,156,164,164,172,175,180,188,188,196,199,204,207,212,220,223,228,231,236,244,247,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,143,191,244,247,244,236,236,228,223,220,212,212,204,199,196,188,188,180,175,172,167,164,156,156,148,143,140,135,132,124,124,116,116,108,103,100,95,92,87,84,84,76,76,71,68,68,63,60,60,60,60,55,55,60,60,60,60,60,63,68,68,76,76,79,84,84,92,92,100,100,108,111,116,119,124,127,132,140,140,148,151,156,159,164,172,172,180,183,188,196,196,204,207,212,215,220,228,231,236,244,244,252,215,167,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,247,244,236,231,228,220,220,212,207,204,196,196,188,183,180,172,172,164,159,156,151,148,140,140,132,127,124,119,116,108,108,100,100,92,92,84,84,76,76,71,68,63,60,60,60,55,52,52,52,52,52,52,52,55,60,60,63,68,68,71,76,79,84,87,92,95,100,103,108,111,116,124,124,132,135,140,143,148,156,156,164,167,172,180,180,188,191,196,204,204,212,215,220,228,228,236,239,244,252,228,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,244,244,236,231,228,220,215,212,207,204,196,191,188,183,180,172,167,164,159,156,148,148,140,135,132,124,124,116,111,108,103,100,95,92,84,84,76,76,71,68,63,60,60,55,52,52,47,47,47,44,47,47,52,52,52,55,60,60,68,68,71,76,79,84,87,92,100,100,108,108,116,119,124,127,132,140,140,148,151,156,164,164,172,175,180,188,188,196,199,204,212,212,220,223,228,236,236,244,247,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,252,244,239,236,228,228,220,215,212,204,204,196,191,188,180,175,172,167,164,156,151,148,143,140,132,132,124,119,116,108,108,100,100,92,87,84,79,76,71,68,63,60,55,52,52,47,44,44,44,44,44,44,44,44,47,52,52,55,60,60,68,68,76,76,84,84,92,95,100,103,108,116,116,124,124,132,135,140,148,148,156,159,164,172,172,180,183,188,196,196,204,207,212,220,223,228,231,236,244,247,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,252,244,239,236,228,223,220,212,212,204,199,196,188,188,180,175,172,164,164,156,151,148,140,140,132,127,124,116,116,108,103,100,95,92,84,84,76,76,68,63,60,55,52,52,44,44,44,39,36,36,36,36,36,39,44,44,47,52,55,60,60,68,68,76,79,84,87,92,100,100,108,111,116,119,124,132,132,140,143,148,156,156,164,167,172,180,183,188,191,196,204,207,212,220,220,228,231,236,244,244,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,247,244,236,236,228,223,220,212,212,204,199,196,188,183,180,172,172,164,159,156,148,148,140,135,132,124,124,116,111,108,100,100,92,87,84,79,76,68,68,60,60,52,52,44,44,39,36,36,36,31,31,31,36,36,36,44,44,47,52,55,60,63,68,71,76,84,84,92,95,100,103,108,116,119,124,127,132,140,143,148,151,156,164,167,172,180,180,188,191,196,204,204,212,215,220,228,231,236,244,244,252,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,148,196,244,247,244,236,231,228,223,220,212,207,204,196,196,188,183,180,172,167,164,159,156,148,143,140,132,132,124,119,116,108,108,100,95,92,84,84,76,71,68,63,60,55,52,44,44,39,36,31,28,28,28,28,28,28,31,36,36,44,44,47,52,60,60,68,68,76,79,84,92,92,100,103,108,111,116,124,127,132,140,140,148,151,156,164,164,172,175,180,188,191,196,199,204,212,215,220,228,228,236,239,244,252,220,172,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,252,247,244,236,231,228,220,220,212,207,204,196,191,188,180,180,172,167,164,156,156,148,143,140,132,127,124,119,116,108,103,100,92,92,84,79,76,71,68,60,60,52,47,44,39,36,31,28,28,23,20,20,20,23,28,28,36,36,44,44,52,52,60,63,68,76,76,84,87,92,100,100,108,111,116,124,124,132,135,140,148,148,156,159,164,172,175,180,188,188,196,199,204,212,215,220,223,228,236,239,244,252,223,175,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,108,156,204,252,244,244,236,231,228,220,220,212,207,204,196,191,188,180,180,172,167,164,156,151,148,140,140,132,127,124,116,116,108,103,100,92,87,84,79,76,68,63,60,55,52,44,44,36,31,28,28,20,20,20,20,20,20,23,28,28,36,39,44,47,52,60,60,68,71,76,84,84,92,95,100,108,108,116,119,124,132,135,140,148,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,239,244,252,228,180,132,79,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,207,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,140,132,127,124,116,111,108,100,100,92,87,84,76,76,68,63,60,52,47,44,39,36,28,28,20,20,12,12,12,12,15,20,23,28,31,36,44,44,52,55,60,68,68,76,79,84,92,95,100,108,108,116,119,124,132,132,140,143,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,239,244,247,231,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,100,92,87,84,76,71,68,60,60,52,47,44,36,36,28,23,20,12,12,7,7,12,12,20,20,28,28,36,39,44,52,55,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,159,164,172,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,95,92,84,84,76,71,68,60,55,52,47,44,36,31,28,20,20,12,7,0,0,0,12,15,20,23,28,36,39,44,52,52,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,156,164,167,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,135,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,95,92,84,84,76,71,68,60,55,52,44,44,36,31,28,20,20,12,7,0,0,0,12,12,20,23,28,36,39,44,52,52,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,156,164,167,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,140,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,135,132,124,124,116,111,108,100,95,92,84,84,76,71,68,60,60,52,47,44,36,31,28,20,20,12,12,0,0,7,12,15,20,28,28,36,39,44,52,52,60,63,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,159,164,167,172,180,183,188,196,196,204,207,212,220,223,228,236,236,244,247,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,175,172,164,164,156,151,148,140,140,132,127,124,116,111,108,100,100,92,87,84,76,71,68,60,60,52,47,44,36,36,28,23,20,15,12,12,12,12,12,20,20,28,31,36,44,44,52,55,60,68,68,76,79,84,92,92,100,103,108,116,119,124,132,132,140,143,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,236,244,247,236,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,244,244,236,231,228,220,215,212,204,204,196,191,188,180,180,172,167,164,156,151,148,140,140,132,127,124,116,111,108,103,100,92,87,84,76,76,68,63,60,52,52,44,39,36,31,28,23,20,20,15,12,15,20,20,28,28,36,36,44,47,52,55,60,68,71,76,84,84,92,95,100,108,108,116,119,124,132,135,140,143,148,156,159,164,172,172,180,183,188,196,199,204,212,212,220,223,228,236,239,244,252,231,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,103,151,204,252,247,244,236,231,228,220,220,212,207,204,196,191,188,180,180,172,167,164,156,156,148,143,140,132,127,124,116,116,108,103,100,92,92,84,79,76,68,68,60,55,52,47,44,36,36,28,28,23,20,20,20,20,20,28,28,31,36,39,44,52,52,60,63,68,71,76,84,84,92,95,100,108,111,116,124,124,132,135,140,148,148,156,159,164,172,175,180,188,188,196,199,204,212,212,220,223,228,236,239,244,252,228,180,127,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,247,247,244,236,231,228,220,220,212,207,204,196,196,188,183,180,172,167,164,156,156,148,143,140,132,132,124,119,116,108,108,100,95,92,84,84,76,71,68,60,60,52,52,44,44,36,36,28,28,28,23,23,28,28,28,31,36,39,44,47,52,55,60,68,68,76,76,84,87,92,100,100,108,111,116,124,124,132,135,140,148,151,156,164,164,172,175,180,188,188,196,199,204,212,215,220,228,228,236,239,244,252,220,172,124,76,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,247,244,236,236,228,223,220,212,207,204,196,196,188,183,180,172,172,164,159,156,148,148,140,135,132,124,119,116,111,108,100,100,92,87,84,76,76,68,63,60,55,52,47,44,44,36,36,31,28,28,28,28,31,36,36,39,44,44,52,52,60,60,68,71,76,79,84,92,92,100,103,108,116,116,124,127,132,140,140,148,151,156,164,164,172,175,180,188,191,196,204,204,212,215,220,228,228,236,239,244,252,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,247,244,236,236,228,223,220,212,212,204,199,196,188,188,180,175,172,164,159,156,151,148,140,135,132,124,124,116,111,108,103,100,92,92,84,79,76,71,68,63,60,55,52,47,44,44,39,36,36,36,36,36,36,36,39,44,44,52,52,60,60,68,68,76,76,84,87,92,95,100,108,108,116,119,124,132,132,140,143,148,156,156,164,167,172,180,180,188,191,196,204,207,212,215,220,228,231,236,244,244,252,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,79,127,180,228,252,244,239,236,228,228,220,215,212,204,199,196,188,188,180,175,172,164,164,156,151,148,140,140,132,127,124,119,116,108,108,100,95,92,87,84,76,76,68,68,60,60,55,52,47,44,44,44,39,39,39,39,44,44,44,47,52,52,55,60,63,68,71,76,79,84,92,92,100,100,108,111,116,124,124,132,135,140,148,148,156,159,164,172,172,180,183,188,196,196,204,207,212,220,220,228,231,236,244,247,252,204,156,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,119,172,220,252,244,239,236,228,228,220,215,212,204,204,196,191,188,180,180,172,167,164,156,156,148,143,140,132,132,124,119,116,111,108,100,100,92,92,84,84,76,76,68,68,60,60,55,52,52,47,44,44,44,44,44,44,47,52,52,52,60,60,63,68,71,76,79,84,87,92,95,100,108,108,116,116,124,127,132,140,140,148,151,156,159,164,172,175,180,183,188,196,199,204,212,212,220,223,228,236,236,244,247,244,196,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,159,207,252,244,244,236,231,228,220,220,212,207,204,196,196,188,183,180,172,172,164,159,156,148,148,140,135,132,127,124,116,116,108,108,100,95,92,87,84,79,76,71,68,68,60,60,60,52,52,52,52,52,52,52,52,52,52,55,60,60,63,68,68,76,76,84,84,92,92,100,100,108,111,116,119,124,132,132,140,143,148,151,156,164,167,172,175,180,188,188,196,199,204,212,215,220,223,228,236,239,244,252,236,183,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,247,244,236,236,228,223,220,212,212,204,199,196,188,188,180,175,172,164,164,156,151,148,143,140,132,132,124,119,116,111,108,103,100,95,92,87,84,79,76,71,68,68,63,60,60,60,55,55,52,52,52,55,55,60,60,60,68,68,71,76,76,84,84,92,92,100,100,108,108,116,116,124,127,132,135,140,148,148,156,159,164,167,172,180,180,188,191,196,204,204,212,215,220,228,228,236,239,244,252,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,247,244,239,236,228,223,220,215,212,204,199,196,191,188,180,180,172,167,164,156,156,148,148,140,135,132,127,124,116,116,108,108,100,100,92,92,84,84,79,76,76,68,68,68,63,60,60,60,60,60,60,60,60,63,68,68,68,71,76,76,84,84,87,92,95,100,103,108,111,116,119,124,132,132,140,140,148,151,156,164,164,172,175,180,183,188,196,196,204,207,212,220,220,228,231,236,244,244,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,252,244,239,236,228,228,220,215,212,207,204,196,196,188,183,180,172,172,164,159,156,151,148,140,140,132,132,124,124,116,116,108,108,100,100,92,92,84,84,79,76,76,71,68,68,68,68,63,63,63,63,68,68,68,68,71,76,76,79,84,84,87,92,95,100,103,108,111,116,119,124,127,132,135,140,148,148,156,156,164,167,172,175,180,188,188,196,199,204,212,212,220,223,228,236,236,244,247,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,244,244,236,231,228,223,220,212,207,204,199,196,188,188,180,175,172,167,164,156,156,148,148,140,135,132,127,124,119,116,111,108,103,100,100,92,92,87,84,84,79,76,76,76,71,68,68,68,68,68,68,71,71,76,76,76,79,84,84,92,92,95,100,100,108,108,116,116,124,124,132,132,140,143,148,151,156,159,164,172,172,180,183,188,191,196,204,204,212,215,220,228,228,236,239,244,252,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,247,244,236,236,228,223,220,215,212,204,204,196,191,188,183,180,172,172,164,159,156,151,148,143,140,135,132,124,124,119,116,111,108,103,100,100,92,92,87,84,84,84,79,76,76,76,76,76,76,76,76,76,76,76,79,84,84,87,92,92,95,100,100,108,108,116,116,124,124,132,132,140,140,148,148,156,156,164,167,172,175,180,188,188,196,199,204,207,212,220,220,228,231,236,244,244,252,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,252,244,239,236,231,228,220,220,212,207,204,196,196,188,188,180,175,172,167,164,156,156,148,148,140,140,132,132,124,124,116,116,111,108,103,100,100,95,92,92,87,84,84,84,84,79,79,79,79,79,79,84,84,84,84,87,92,92,92,100,100,103,108,108,116,116,119,124,127,132,135,140,143,148,151,156,164,164,172,172,180,180,188,191,196,204,204,212,212,220,223,228,236,236,244,247,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,244,244,236,231,228,223,220,212,212,204,199,196,191,188,183,180,172,172,164,164,156,156,148,143,140,140,132,132,124,124,116,116,111,108,108,100,100,100,95,92,92,92,87,84,84,84,84,84,84,84,84,84,87,92,92,92,95,100,100,103,108,108,116,116,119,124,127,132,135,140,140,148,151,156,159,164,167,172,175,180,188,188,196,196,204,207,212,215,220,228,228,236,239,244,252,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,239,247,244,239,236,228,228,220,215,212,207,204,196,196,188,188,180,175,172,167,164,159,156,151,148,143,140,135,132,132,124,124,116,116,111,108,108,103,100,100,100,95,92,92,92,92,92,92,92,92,92,92,92,92,92,95,100,100,100,108,108,111,116,116,119,124,127,132,132,140,140,148,148,156,156,164,164,172,172,180,183,188,191,196,199,204,212,212,220,223,228,231,236,244,244,252,215,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,220,252,244,244,236,231,228,223,220,212,212,204,199,196,191,188,183,180,175,172,164,164,156,156,151,148,143,140,135,132,132,124,124,119,116,116,111,108,108,103,100,100,100,100,95,95,92,92,92,92,92,95,95,100,100,100,100,108,108,108,111,116,116,124,124,127,132,132,140,140,148,148,151,156,159,164,167,172,180,180,188,188,196,196,204,207,212,215,220,228,228,236,236,244,247,244,196,151,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,156,204,247,247,244,236,236,228,228,220,215,212,207,204,199,196,188,188,180,180,172,172,164,164,156,156,148,148,143,140,135,132,132,124,124,119,116,116,111,108,108,108,103,103,100,100,100,100,100,100,100,100,100,100,100,103,108,108,108,111,116,116,119,124,124,127,132,132,140,140,143,148,151,156,159,164,167,172,175,180,183,188,191,196,204,204,212,212,220,223,228,231,236,244,244,252,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,135,180,228,252,244,239,236,231,228,223,220,212,212,204,204,196,196,188,183,180,175,172,167,164,164,156,156,148,148,143,140,135,132,132,127,124,124,119,116,116,116,111,108,108,108,108,108,103,103,103,103,103,108,108,108,108,108,111,116,116,116,119,124,124,132,132,135,140,140,143,148,151,156,159,164,164,172,172,180,180,188,191,196,199,204,207,212,215,220,228,228,236,236,244,247,252,204,159,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,164,204,252,247,244,236,236,228,228,220,215,212,207,204,199,196,191,188,183,180,175,172,167,164,159,156,156,148,148,143,140,140,132,132,127,124,124,124,119,116,116,116,111,111,108,108,108,108,108,108,108,108,111,111,116,116,116,116,119,124,124,127,132,132,135,140,140,148,148,151,156,159,164,164,172,172,180,180,188,188,196,196,204,204,212,212,220,223,228,231,236,239,244,252,228,183,140,92,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,95,140,183,228,252,244,244,236,231,228,223,220,215,212,204,204,196,196,188,188,180,180,175,172,167,164,159,156,156,148,148,143,140,140,135,132,132,127,124,124,124,119,119,116,116,116,116,116,116,116,116,116,116,116,116,116,119,124,124,124,127,132,132,132,140,140,140,148,148,151,156,159,164,164,172,172,180,180,183,188,191,196,199,204,212,212,220,220,228,228,236,236,244,247,252,207,164,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,204,252,247,244,239,236,228,228,220,220,212,212,204,204,196,196,188,188,180,180,172,172,167,164,159,156,156,151,148,148,140,140,140,135,132,132,127,124,124,124,124,124,119,119,119,119,119,119,119,119,124,124,124,124,124,127,132,132,132,135,140,140,143,148,148,151,156,159,164,164,172,172,175,180,183,188,191,196,199,204,207,212,215,220,223,228,231,236,244,244,252,228,183,140,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,92,140,180,228,252,244,244,236,236,228,223,220,215,212,207,204,199,196,196,188,188,180,180,172,172,167,164,164,156,156,151,148,148,143,140,140,140,135,132,132,132,127,127,124,124,124,124,124,124,124,124,124,124,124,127,132,132,132,132,135,140,140,143,148,148,151,156,156,159,164,164,172,172,175,180,183,188,191,196,196,204,204,212,212,220,220,228,231,236,239,244,247,247,204,159,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,204,244,247,244,239,236,231,228,223,220,215,212,207,204,199,196,191,188,188,180,180,175,172,167,164,164,159,156,156,151,148,148,143,140,140,140,135,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,132,135,140,140,140,140,148,148,148,151,156,156,159,164,164,172,172,175,180,183,188,188,196,196,204,204,212,212,220,220,228,228,236,236,244,244,252,220,180,135,92,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,252,247,244,236,236,228,228,220,220,212,212,207,204,199,196,191,188,188,180,180,175,172,172,164,164,159,156,156,156,148,148,148,143,140,140,140,140,140,135,135,132,132,132,132,132,132,135,135,135,140,140,140,140,143,148,148,148,151,156,156,159,164,164,167,172,172,180,180,183,188,188,196,196,204,204,212,212,215,220,223,228,231,236,239,244,252,236,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,191,231,252,244,244,236,236,228,228,220,220,212,212,204,204,199,196,191,188,188,180,180,175,172,172,167,164,164,159,156,156,156,151,148,148,148,143,143,140,140,140,140,140,140,140,140,140,140,140,140,140,143,148,148,148,148,151,156,156,156,164,164,164,167,172,172,180,180,183,188,188,196,196,204,204,207,212,215,220,223,228,231,236,239,244,247,252,212,172,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,79,124,164,204,244,247,244,239,236,231,228,223,220,220,212,212,204,204,199,196,191,188,188,183,180,180,172,172,172,164,164,164,159,156,156,156,151,148,148,148,148,148,148,143,143,143,143,143,143,143,148,148,148,148,148,151,151,156,156,156,159,164,164,167,172,172,175,180,180,183,188,191,196,196,204,204,207,212,215,220,223,228,228,236,236,244,244,252,228,183,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,135,175,215,252,247,244,239,236,231,228,223,220,220,212,212,204,204,199,196,196,188,188,183,180,180,175,172,172,167,164,164,164,159,156,156,156,156,151,151,148,148,148,148,148,148,148,148,148,148,151,151,156,156,156,156,159,164,164,164,167,172,172,172,180,180,180,188,188,191,196,196,204,204,207,212,215,220,220,228,228,236,236,244,244,252,236,196,156,116,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,148,188,228,252,244,244,239,236,231,228,223,220,220,212,212,204,204,199,196,196,191,188,188,180,180,180,175,172,172,167,164,164,164,164,159,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,156,159,159,164,164,164,167,172,172,172,175,180,180,183,188,188,191,196,196,204,204,207,212,215,220,220,228,228,236,236,239,244,247,244,207,167,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,116,156,196,236,252,244,244,236,236,231,228,223,220,220,212,212,207,204,204,196,196,191,188,188,183,180,180,180,175,172,172,172,167,164,164,164,164,164,159,159,159,159,156,156,159,159,159,159,164,164,164,164,164,167,167,172,172,172,175,180,180,183,188,188,191,196,196,199,204,204,212,212,215,220,220,228,228,236,236,239,244,247,252,215,175,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,124,164,204,244,252,244,244,236,236,231,228,223,220,220,212,212,207,204,204,199,196,196,191,188,188,183,180,180,180,175,172,172,172,172,167,167,164,164,164,164,164,164,164,164,164,164,164,164,164,167,172,172,172,172,175,175,180,180,180,188,188,188,191,196,196,199,204,204,212,212,215,220,220,228,228,231,236,239,244,247,252,220,183,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,132,172,207,244,247,244,244,236,236,231,228,223,220,220,215,212,212,204,204,199,196,196,196,188,188,188,183,180,180,180,180,175,172,172,172,172,172,172,172,172,167,167,167,172,172,172,172,172,172,172,175,175,180,180,180,183,188,188,188,191,196,196,199,204,204,207,212,212,215,220,223,228,228,236,236,239,244,247,252,228,188,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,63,100,140,175,212,247,247,244,244,236,236,231,228,228,220,220,215,212,212,207,204,204,199,196,196,196,188,188,188,188,183,180,180,180,180,180,175,175,172,172,172,172,172,172,172,172,175,175,175,180,180,180,180,180,183,188,188,188,191,196,196,196,204,204,204,212,212,212,220,220,223,228,228,236,236,239,244,247,252,228,196,156,119,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,140,180,212,247,247,244,244,236,236,231,228,228,223,220,220,212,212,212,204,204,204,199,196,196,196,191,188,188,188,188,183,183,180,180,180,180,180,180,180,180,180,180,180,180,180,180,180,183,183,188,188,188,188,191,196,196,196,199,204,204,207,212,212,215,220,220,223,228,228,236,236,239,244,247,252,231,196,159,124,84,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,143,180,212,247,252,244,244,239,236,236,228,228,223,220,220,215,212,212,207,204,204,204,199,196,196,196,196,191,188,188,188,188,188,188,183,183,183,183,183,183,183,183,188,188,188,188,188,188,188,191,196,196,196,199,204,204,204,207,212,212,212,220,220,220,228,228,231,236,236,239,244,247,252,228,196,159,124,92,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,175,212,244,252,244,244,239,236,236,231,228,228,220,220,220,215,212,212,207,204,204,204,204,199,196,196,196,196,191,191,191,188,188,188,188,188,188,188,188,188,188,188,191,191,196,196,196,196,196,199,204,204,204,207,212,212,212,215,220,220,223,228,228,231,236,236,244,244,247,252,228,196,159,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,172,204,236,252,247,244,244,236,236,231,228,228,223,220,220,220,215,212,212,212,207,204,204,204,204,199,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,196,199,199,204,204,204,204,207,212,212,212,215,220,220,223,228,228,231,236,236,239,244,244,247,252,220,188,156,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,68,103,135,167,199,231,252,247,244,244,239,236,236,231,228,228,223,220,220,220,215,212,212,212,207,207,204,204,204,204,204,199,199,199,199,196,196,196,196,199,199,199,199,204,204,204,204,204,204,207,212,212,212,212,215,220,220,223,228,228,228,231,236,236,239,244,244,252,244,215,183,151,119,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,164,191,220,252,252,244,244,239,236,236,236,228,228,228,223,220,220,220,215,215,212,212,212,212,207,207,204,204,204,204,204,204,204,204,204,204,204,204,204,204,207,207,212,212,212,212,212,215,220,220,220,223,228,228,228,231,236,236,239,244,244,247,252,236,207,175,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,151,180,212,239,252,247,244,244,239,236,236,236,228,228,228,223,223,220,220,220,215,215,212,212,212,212,212,212,212,212,207,207,207,207,212,212,212,212,212,212,212,212,215,215,220,220,220,220,223,228,228,228,231,236,236,236,244,244,244,252,252,228,196,167,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,111,140,172,196,228,252,252,244,244,244,239,236,236,236,231,228,228,228,223,223,220,220,220,220,220,215,215,215,212,212,212,212,212,212,212,212,212,215,215,215,220,220,220,220,220,223,228,228,228,228,231,236,236,236,239,244,244,247,252,236,212,183,156,127,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,71,100,132,156,183,212,236,252,247,244,244,244,239,236,236,236,231,228,228,228,228,228,223,223,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,220,223,223,228,228,228,228,231,236,236,236,236,244,244,244,247,252,247,220,196,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,87,116,140,164,191,215,239,252,247,244,244,244,239,236,236,236,236,231,231,228,228,228,228,228,228,223,223,223,223,223,223,223,223,223,223,228,228,228,228,228,228,228,231,236,236,236,236,239,244,244,244,247,252,252,228,204,180,156,127,100,76,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,71,100,124,148,172,196,220,239,252,252,247,244,244,244,239,236,236,236,236,236,231,231,231,228,228,228,228,228,228,228,228,228,228,228,228,228,231,231,236,236,236,236,236,239,244,244,244,244,247,252,252,228,207,183,159,135,111,84,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,79,108,127,151,172,196,215,236,252,252,247,244,244,244,244,244,239,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,236,239,239,244,244,244,244,247,252,252,244,228,204,183,164,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,108,127,148,172,188,207,228,244,252,252,247,247,244,244,244,244,244,244,239,239,239,239,236,236,236,236,236,239,239,239,239,244,244,244,244,244,244,247,252,252,252,236,215,196,180,159,140,116,95,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,103,124,143,164,180,196,212,228,239,252,252,252,247,247,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,247,247,252,252,252,244,236,220,204,188,172,151,132,116,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,60,76,95,116,132,148,164,180,191,204,215,228,236,247,252,252,252,252,252,247,247,247,247,247,247,252,252,252,252,252,252,244,236,220,212,196,188,172,156,140,124,108,87,68,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,68,84,100,116,132,143,156,167,180,188,196,204,212,220,223,228,231,236,236,236,236,236,231,228,220,215,212,204,196,183,172,164,148,140,124,108,92,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,68,84,95,108,119,132,140,148,156,164,172,175,180,180,188,188,188,188,183,180,180,172,167,159,156,143,135,124,116,100,92,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,60,71,84,92,100,108,116,119,124,132,132,135,135,140,135,132,132,127,124,116,111,103,95,84,76,68,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,60,68,71,76,79,84,84,87,87,84,84,84,76,76,68,60,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,28,36,36,36,36,36,36,31,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t FLARE_TEXTURE_5[16384] ={0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,52,55,60,60,60,60,60,60,60,52,52,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,60,68,76,84,92,95,100,108,108,108,111,111,111,108,108,103,100,92,84,79,71,60,52,44,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,71,84,95,108,116,124,132,140,148,148,156,156,159,164,164,164,159,156,151,148,140,135,127,119,111,100,92,76,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,60,76,92,108,119,132,143,156,164,172,180,188,196,199,204,207,212,212,212,212,212,204,204,196,191,188,180,172,159,148,140,124,116,100,84,68,52,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,55,76,92,108,124,140,156,167,180,191,204,212,220,228,236,244,252,252,252,252,252,252,252,252,252,252,247,244,236,228,220,207,196,188,172,164,148,132,116,100,84,63,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,100,119,140,156,172,188,204,215,228,244,252,247,244,244,244,239,236,236,236,236,236,236,236,236,236,236,236,239,244,244,247,252,244,236,220,212,196,180,164,148,132,108,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,60,84,108,124,148,164,183,204,220,236,252,247,244,239,236,236,231,228,228,228,223,220,220,220,220,220,220,220,220,223,223,228,228,228,236,236,239,244,244,252,244,228,212,196,175,156,135,116,95,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,60,84,108,132,151,172,191,212,228,247,247,244,236,236,228,228,223,220,220,215,212,212,212,212,207,207,207,207,207,207,207,212,212,212,212,220,220,220,228,228,231,236,239,244,252,239,220,204,180,164,140,116,92,71,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,76,100,124,148,172,196,220,236,252,244,239,236,228,228,220,220,212,212,207,204,204,199,199,196,196,196,196,196,196,196,196,196,196,196,199,204,204,204,212,212,215,220,223,228,231,236,244,247,247,228,204,183,164,140,116,92,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,68,92,119,148,172,196,220,239,247,244,236,231,228,220,215,212,207,204,204,196,196,191,188,188,188,188,183,183,180,180,180,180,180,183,183,188,188,188,191,196,196,199,204,204,212,212,220,223,228,236,239,244,252,228,204,180,156,132,108,79,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,79,108,135,164,188,212,236,252,244,236,228,223,220,212,207,204,199,196,191,188,188,183,180,180,175,172,172,172,172,172,172,172,172,172,172,172,172,175,180,180,180,183,188,188,196,196,204,204,212,215,220,228,231,236,244,252,228,204,175,148,124,92,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,92,124,148,180,204,228,252,244,236,228,223,220,212,204,204,196,191,188,183,180,180,172,172,172,164,164,164,164,159,159,159,156,156,159,159,159,164,164,164,164,167,172,172,175,180,180,188,188,196,196,204,207,212,220,228,231,239,244,244,220,191,164,135,108,76,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,39,71,100,132,164,188,220,244,244,236,228,223,220,212,204,199,196,188,183,180,175,172,172,164,164,159,156,156,156,151,151,148,148,148,148,148,148,148,148,148,151,156,156,156,159,164,164,167,172,172,180,180,188,191,196,204,207,212,220,228,236,244,252,231,204,175,148,116,87,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,108,140,172,204,231,252,244,236,228,220,212,204,199,196,188,183,180,172,172,164,164,156,156,151,148,148,148,143,140,140,140,140,140,140,140,140,140,140,140,140,140,143,148,148,151,156,156,159,164,167,172,175,180,188,188,196,204,207,215,220,228,236,244,244,215,188,156,124,92,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,116,148,180,212,244,244,236,228,220,212,207,199,196,188,180,180,172,167,164,156,156,151,148,148,140,140,140,135,132,132,132,132,127,127,127,127,127,127,132,132,132,132,132,135,140,140,143,148,148,156,156,164,164,172,172,180,188,191,196,204,212,220,228,236,244,252,228,196,164,132,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,124,156,188,220,252,244,236,228,220,212,204,196,188,183,180,172,164,164,156,151,148,148,140,140,135,132,132,127,124,124,124,124,119,119,119,116,116,116,119,119,119,124,124,124,124,132,132,132,135,140,143,148,148,156,159,164,172,172,180,188,196,199,204,212,220,228,236,247,236,204,172,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,124,156,191,228,252,239,231,223,215,207,199,191,188,180,172,167,164,156,151,148,143,140,135,132,127,124,124,119,116,116,116,116,111,111,108,108,108,108,108,108,111,111,116,116,116,116,119,124,124,127,132,132,140,140,148,148,156,159,164,172,175,180,188,196,204,212,220,228,236,244,244,207,175,140,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,124,159,196,228,247,239,228,220,212,204,196,188,180,175,172,164,156,151,148,140,140,132,132,124,124,119,116,116,111,108,108,108,108,103,100,100,100,100,100,100,100,100,103,103,108,108,108,111,116,116,116,124,124,127,132,135,140,148,148,156,159,164,172,180,188,196,199,207,215,228,236,244,244,212,180,143,108,71,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,87,124,159,196,228,247,236,228,220,212,204,196,188,180,172,164,159,156,148,143,140,132,132,124,124,116,116,111,108,108,103,100,100,100,100,95,92,92,92,92,92,92,92,92,95,95,100,100,100,100,108,108,108,116,116,119,124,127,132,135,140,148,151,156,164,172,175,183,188,196,204,212,223,236,244,247,212,180,140,108,68,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,84,124,156,196,228,247,236,228,220,212,199,191,183,180,172,164,156,148,148,140,132,132,124,119,116,116,108,108,103,100,100,95,92,92,92,92,87,87,84,84,84,84,84,84,84,87,87,92,92,92,95,100,100,100,103,108,111,116,116,124,127,132,140,140,148,156,159,164,172,180,188,196,204,212,220,231,244,247,212,175,140,103,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,116,156,191,228,247,236,228,220,207,199,191,183,175,167,164,156,148,140,135,132,124,124,116,111,108,108,100,100,95,92,92,87,84,84,84,84,79,79,79,76,76,76,76,79,79,79,84,84,84,84,87,92,92,92,100,100,103,108,108,116,119,124,127,132,140,148,151,156,164,172,180,188,196,204,212,220,231,244,247,212,172,135,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,71,108,148,188,228,247,236,228,220,207,199,188,180,172,164,159,151,148,140,132,127,124,116,116,108,108,100,100,92,92,87,84,84,84,79,76,76,76,76,76,71,71,71,71,71,71,71,76,76,76,76,76,79,84,84,87,92,92,95,100,103,108,111,116,119,124,132,135,140,148,156,164,172,180,188,196,204,212,220,231,244,244,204,167,132,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,100,140,180,220,252,239,228,220,207,199,188,180,172,164,156,151,143,140,132,124,119,116,108,108,100,100,92,92,87,84,84,79,76,76,76,71,68,68,68,68,68,68,68,68,68,68,68,68,68,68,68,71,76,76,76,79,84,84,92,92,95,100,103,108,116,116,124,127,132,140,148,156,164,172,180,188,196,204,212,223,236,244,236,199,164,124,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,132,172,212,252,239,228,220,212,199,188,180,172,164,156,148,143,135,132,124,116,116,108,103,100,92,92,87,84,79,76,76,71,68,68,68,68,63,60,60,60,60,60,60,60,60,60,60,60,60,63,63,68,68,68,71,76,76,79,84,84,92,92,95,100,108,108,116,124,127,132,140,148,156,164,172,180,188,196,204,212,223,236,244,231,191,151,111,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,79,124,164,204,244,244,231,220,212,199,191,180,172,164,156,148,140,135,127,124,116,111,108,100,95,92,87,84,79,76,76,71,68,68,63,60,60,60,60,55,55,55,52,52,52,52,52,52,52,55,55,60,60,60,60,63,68,68,68,76,76,79,84,84,92,92,100,103,108,116,119,124,132,140,148,156,164,172,180,188,196,204,215,228,236,252,220,180,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,108,148,188,231,244,236,223,212,204,191,183,172,164,156,148,140,135,127,124,116,108,103,100,92,92,84,84,76,76,71,68,68,63,60,60,60,55,52,52,52,52,52,52,47,47,47,47,47,52,52,52,52,52,52,55,60,60,60,63,68,68,76,76,79,84,87,92,100,100,108,111,116,124,132,140,148,156,164,172,180,188,196,207,220,228,239,252,212,172,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,92,135,180,220,252,236,228,215,204,196,183,175,164,156,148,140,135,127,124,116,108,103,100,92,87,84,79,76,71,68,68,63,60,60,55,52,52,52,47,47,44,44,44,44,44,44,44,44,44,44,44,44,44,47,52,52,52,52,55,60,60,63,68,68,76,76,84,84,92,95,100,108,111,116,124,132,140,148,156,164,172,180,188,199,212,220,231,244,239,196,156,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,119,164,204,244,244,228,220,207,196,188,180,167,159,151,143,135,127,124,116,108,100,100,92,87,84,76,76,68,68,63,60,60,55,52,52,47,44,44,44,44,44,39,39,39,39,36,36,36,39,39,39,44,44,44,44,44,47,52,52,52,55,60,60,68,68,71,76,79,84,92,92,100,108,111,116,124,132,140,148,156,164,172,180,191,204,212,223,236,247,228,183,140,100,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,100,148,188,228,244,236,220,212,199,188,180,172,164,151,143,135,127,124,116,108,100,100,92,84,84,76,76,68,68,60,60,55,52,52,47,44,44,44,39,39,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,39,44,44,44,47,52,52,52,60,60,63,68,71,76,79,84,92,92,100,108,111,116,124,132,140,148,156,164,172,183,196,204,215,228,239,252,212,164,124,79,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,124,172,212,252,236,228,212,204,191,180,172,164,156,148,140,132,124,116,108,100,100,92,84,84,76,71,68,63,60,60,52,52,47,44,44,44,39,36,36,36,36,36,31,31,31,28,28,28,28,28,31,31,31,36,36,36,36,36,39,44,44,47,52,52,55,60,60,68,68,76,76,84,87,92,100,108,111,119,124,132,140,148,156,167,180,188,196,207,220,231,244,236,191,148,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,108,148,196,236,244,228,220,207,196,188,175,164,156,148,140,132,124,116,108,103,100,92,84,79,76,71,68,63,60,55,52,52,44,44,44,39,36,36,36,31,31,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,31,36,36,36,36,39,44,44,47,52,52,60,60,68,68,76,76,84,87,92,100,108,116,119,127,135,143,151,164,172,180,191,204,212,223,236,252,215,172,127,84,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,84,132,172,220,252,236,223,212,199,188,180,172,159,148,140,132,124,116,111,103,100,92,84,84,76,71,68,60,60,52,52,47,44,44,39,36,36,36,31,28,28,28,28,28,23,23,23,23,23,23,23,23,23,23,28,28,28,28,28,31,31,36,36,36,44,44,44,52,52,55,60,63,68,76,76,84,92,95,100,108,116,124,132,140,148,156,164,172,183,196,204,220,228,244,239,196,151,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,151,196,239,244,228,220,204,196,183,172,164,156,148,135,127,119,116,108,100,92,87,84,76,71,68,60,60,52,52,47,44,44,36,36,36,31,28,28,28,28,23,23,20,20,20,20,20,20,20,20,20,20,20,20,20,23,28,28,28,28,31,36,36,36,39,44,44,52,52,55,60,63,68,76,79,84,92,95,100,108,116,124,132,140,148,156,167,180,188,199,212,223,236,247,220,172,127,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,124,172,220,247,236,223,212,199,188,180,167,156,148,140,132,124,116,108,100,92,87,84,76,71,68,60,60,52,52,44,44,39,36,36,31,28,28,28,28,23,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,23,23,28,28,28,31,36,36,39,44,44,47,52,55,60,63,68,76,79,84,92,100,103,111,119,127,135,143,156,164,172,183,196,204,220,228,244,239,196,148,103,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,55,100,148,191,236,244,228,220,204,196,180,172,164,151,143,132,124,116,108,103,95,92,84,76,76,68,63,60,52,52,44,44,39,36,36,31,28,28,28,23,20,20,20,20,20,15,15,15,15,12,12,12,12,12,15,15,15,20,20,20,20,20,23,23,28,28,28,36,36,36,44,44,47,52,55,60,68,68,76,84,87,92,100,108,116,124,132,140,148,156,167,180,188,199,212,223,236,252,215,172,124,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,119,164,212,252,236,223,212,199,188,180,164,156,148,140,132,124,116,108,100,92,84,79,76,68,63,60,52,52,44,44,39,36,36,31,28,28,23,20,20,20,20,20,15,15,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,20,23,28,28,28,31,36,36,44,44,47,52,60,60,68,71,76,84,92,95,100,108,116,124,132,140,151,164,172,180,196,204,220,228,244,236,188,143,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,183,228,244,231,220,204,196,183,172,164,151,140,132,124,116,108,100,92,87,84,76,68,68,60,55,52,47,44,39,36,36,31,28,28,23,20,20,20,20,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,20,28,28,28,31,36,36,44,44,52,52,60,60,68,76,79,84,92,100,108,116,124,132,140,148,156,167,180,188,199,212,223,236,252,207,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,247,239,228,212,204,188,180,167,156,148,140,132,119,111,108,100,92,84,76,71,68,60,60,52,47,44,39,36,36,31,28,28,23,20,20,20,15,12,12,12,12,12,12,12,7,7,7,7,7,7,7,7,12,12,12,12,12,12,12,15,15,20,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,84,87,92,100,108,116,124,132,140,151,164,172,183,196,207,220,231,244,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,247,236,220,207,196,183,172,164,151,143,132,124,116,108,100,92,87,79,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,12,12,7,7,7,7,0,0,0,0,0,0,0,7,7,7,12,12,12,12,12,12,15,20,20,20,23,28,28,31,36,39,44,47,52,55,60,68,71,76,84,92,100,108,111,124,132,140,148,156,167,180,188,204,212,228,239,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,244,228,215,204,191,180,172,156,148,140,132,124,116,108,100,92,84,76,71,68,60,55,52,44,44,36,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,23,28,28,36,36,39,44,47,52,60,63,68,76,79,87,92,100,108,116,124,132,143,156,164,172,188,196,212,220,236,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,156,204,252,236,228,212,199,188,175,164,156,148,135,124,116,108,100,92,87,79,76,68,63,60,52,47,44,39,36,31,28,28,23,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,55,60,68,71,76,84,92,100,108,116,124,132,140,148,159,172,180,196,204,220,231,244,228,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,71,119,167,215,247,236,220,207,196,183,172,164,151,140,132,124,116,108,100,92,84,76,71,68,60,55,52,44,44,36,36,28,28,23,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,23,28,28,31,36,39,44,47,52,60,63,68,76,84,87,95,100,108,116,127,135,148,156,167,180,188,204,212,228,244,239,191,143,95,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,244,228,220,204,191,180,172,156,148,140,127,119,111,103,95,87,84,76,68,63,60,52,47,44,39,36,31,28,28,20,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,28,36,36,44,44,52,55,60,68,71,76,84,92,100,108,116,124,132,143,156,164,172,188,196,212,223,236,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,143,191,244,239,228,212,204,188,180,164,156,148,135,124,116,108,100,92,84,79,71,68,60,55,52,44,44,36,36,28,28,23,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,20,28,28,31,36,39,44,47,52,60,63,68,76,84,92,95,103,111,124,132,140,148,159,172,183,196,207,220,236,247,215,167,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,236,223,212,196,188,172,164,151,140,132,124,116,108,100,92,84,76,68,63,60,52,47,44,39,36,31,28,28,20,20,20,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,36,36,44,44,52,55,60,68,76,79,87,92,100,108,116,127,140,148,156,167,180,191,204,220,228,244,228,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,247,236,220,207,196,183,172,159,148,140,132,119,111,103,95,87,84,76,68,60,60,52,44,44,36,36,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,28,28,31,36,39,44,52,52,60,68,71,76,84,92,100,108,116,124,132,143,156,164,180,188,204,212,228,244,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,244,231,220,204,191,180,172,156,148,140,127,116,108,100,92,84,79,76,68,60,55,52,44,39,36,31,28,28,20,20,20,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,132,140,151,164,172,188,196,212,228,236,247,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,244,228,215,204,188,180,164,156,148,135,124,116,108,100,92,84,76,71,68,60,52,47,44,39,36,31,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,20,20,20,28,28,36,36,44,44,52,55,60,68,76,84,87,95,103,111,124,132,140,148,164,172,183,196,212,220,236,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,92,140,188,236,244,228,212,199,188,175,164,156,143,132,124,116,108,100,92,84,76,68,63,60,52,47,44,36,36,28,28,23,20,20,15,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,39,44,52,55,60,68,76,79,87,92,100,108,119,127,140,148,159,172,180,196,207,220,236,247,212,164,116,68,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,95,148,196,244,239,228,212,199,188,172,164,151,140,132,124,116,108,100,92,84,76,68,60,55,52,44,44,36,36,28,28,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,39,44,47,52,60,68,71,76,84,92,100,108,116,127,140,148,156,172,180,191,204,220,231,244,220,172,119,71,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,199,252,236,223,212,196,188,172,164,151,140,132,124,111,103,95,87,79,76,68,60,55,52,44,39,36,31,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,23,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,135,148,156,167,180,191,204,220,228,244,223,175,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,55,108,156,204,252,236,220,212,196,183,172,159,148,140,132,119,111,100,92,87,79,76,68,60,55,52,44,39,36,31,28,23,20,20,15,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,180,188,204,215,228,244,228,180,132,79,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,207,252,236,220,207,196,183,172,159,148,140,127,119,108,100,92,84,79,71,68,60,52,52,44,39,36,31,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,36,36,44,44,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,180,188,204,212,228,244,231,180,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,236,220,207,196,180,172,159,148,140,127,119,108,100,92,84,76,71,68,60,52,47,44,39,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,143,156,164,175,188,204,212,228,244,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,236,220,207,196,180,172,156,148,140,127,116,108,100,92,84,76,71,68,60,52,47,44,36,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,140,156,164,175,188,199,212,228,244,236,188,135,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,236,220,207,196,180,172,156,148,140,127,116,108,100,92,84,76,71,68,60,52,47,44,36,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,140,156,164,175,188,199,212,228,244,236,188,140,87,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,164,212,252,236,220,207,196,180,172,159,148,140,127,116,108,100,92,84,76,71,68,60,52,47,44,36,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,143,156,164,175,188,199,212,228,244,236,188,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,159,212,252,236,220,207,196,180,172,159,148,140,127,119,108,100,92,84,79,71,68,60,52,47,44,39,36,28,28,23,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,84,92,100,108,116,124,132,143,156,164,175,188,204,212,228,244,236,183,132,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,60,108,156,204,252,236,220,207,196,183,172,159,148,140,132,119,111,100,92,84,79,71,68,60,52,52,44,39,36,31,28,23,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,36,36,44,44,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,180,188,204,215,228,244,231,180,132,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,103,151,204,252,236,223,212,196,183,172,164,148,140,132,119,111,103,95,87,79,76,68,60,55,52,44,39,36,31,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,23,28,28,36,36,44,47,52,60,63,68,76,84,92,100,108,116,124,135,148,156,164,180,188,204,215,228,244,228,180,127,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,247,236,223,212,196,188,172,164,151,140,132,124,116,103,95,87,84,76,68,60,55,52,44,44,36,31,28,28,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,20,23,28,28,36,36,44,47,52,60,68,71,76,84,92,100,108,116,124,135,148,156,167,180,191,204,220,231,244,220,172,124,76,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,191,244,239,228,212,199,188,175,164,156,140,132,124,116,108,100,92,84,76,68,63,60,52,44,44,36,36,28,28,20,20,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,39,44,52,52,60,68,71,79,84,92,100,108,116,127,140,148,156,172,180,196,204,220,236,247,215,167,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,135,188,236,244,228,212,204,188,180,164,156,143,132,124,116,108,100,92,84,76,68,63,60,52,47,44,36,36,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,28,28,31,36,44,44,52,55,60,68,76,79,87,95,103,111,119,132,140,148,159,172,183,196,207,220,236,252,212,159,111,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,79,127,180,228,244,228,220,204,191,180,167,156,148,135,124,116,108,100,92,84,76,71,68,60,52,52,44,39,36,31,28,28,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,36,36,44,44,52,60,60,68,76,84,92,100,108,116,124,132,140,151,164,172,188,196,212,223,236,252,204,156,103,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,71,119,172,220,247,236,220,204,196,180,172,159,148,140,132,119,111,100,95,87,79,76,68,60,55,52,44,44,36,36,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,31,36,39,44,47,52,60,63,68,76,84,92,100,108,116,124,132,143,156,164,175,188,199,212,228,239,244,196,143,95,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,111,159,207,252,236,220,212,196,183,172,164,151,140,132,124,116,108,100,92,84,76,68,63,60,52,47,44,36,36,31,28,23,20,20,15,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,15,20,20,23,28,28,31,36,44,44,52,55,60,68,71,79,84,92,100,108,116,124,135,148,156,167,180,188,204,215,228,244,236,183,135,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,239,228,212,199,188,175,164,156,143,132,124,116,108,100,92,84,76,71,68,60,52,52,44,39,36,31,28,28,23,20,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,23,28,31,36,36,44,47,52,60,60,68,76,84,87,95,103,111,119,132,140,148,159,172,180,196,204,220,231,244,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,140,188,236,244,228,215,204,188,180,167,156,148,135,127,116,108,100,92,87,79,76,68,60,55,52,47,44,36,36,31,28,23,20,20,15,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,23,28,28,31,36,39,44,52,52,60,68,68,76,84,92,100,108,116,124,132,140,151,164,172,183,196,212,220,236,252,212,164,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,124,172,220,244,231,220,204,196,180,172,159,148,140,132,124,116,103,100,92,84,76,68,63,60,52,52,44,39,36,36,28,28,23,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,15,20,20,20,28,28,31,36,36,44,44,52,55,60,68,76,79,84,92,100,108,116,124,135,143,156,164,175,188,199,212,228,239,244,196,148,100,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,236,223,212,196,188,172,164,156,143,132,124,116,108,100,92,84,79,76,68,60,55,52,47,44,36,36,31,28,28,20,20,20,15,12,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,15,20,20,20,23,28,28,36,36,39,44,52,52,60,63,68,76,84,92,95,103,111,119,132,140,148,156,172,180,191,204,215,228,244,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,244,239,228,212,204,188,180,167,156,148,140,127,119,111,103,95,92,84,76,68,63,60,52,52,44,44,36,36,28,28,28,20,20,20,15,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,15,20,20,20,23,28,28,31,36,39,44,47,52,55,60,68,76,79,84,92,100,108,116,124,132,140,151,164,172,183,196,207,220,236,247,220,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,180,228,244,231,220,204,196,180,172,164,148,140,132,124,116,108,100,92,84,79,76,68,60,60,52,47,44,39,36,36,28,28,23,20,20,20,15,12,12,12,12,12,7,7,7,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,52,52,60,63,68,76,84,87,95,103,108,119,127,135,148,156,164,180,188,199,212,228,236,252,204,156,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,68,116,164,212,252,236,223,212,196,188,175,164,156,148,135,127,116,108,103,95,92,84,76,68,68,60,55,52,44,44,39,36,31,28,28,23,20,20,20,15,15,12,12,12,12,12,12,7,7,7,7,7,7,7,7,7,7,7,12,12,12,12,12,12,15,20,20,20,23,28,28,31,36,36,44,44,47,52,60,60,68,76,79,84,92,100,108,116,124,132,140,148,159,172,180,191,204,220,228,244,236,188,140,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,100,148,196,239,244,228,215,204,191,180,172,159,148,140,132,124,116,108,100,92,84,79,76,68,63,60,52,52,44,44,36,36,31,28,28,23,20,20,20,20,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,23,28,28,31,36,36,39,44,47,52,55,60,68,71,76,84,92,95,103,108,116,127,135,148,156,164,175,188,196,212,220,236,247,215,172,124,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,84,132,175,220,247,236,220,207,196,188,172,164,156,148,135,127,119,111,103,95,92,84,76,71,68,60,60,52,52,44,44,36,36,31,28,28,28,23,20,20,20,15,15,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,15,15,20,20,20,20,23,28,28,31,36,36,39,44,47,52,55,60,63,68,76,84,87,92,100,108,116,124,132,140,148,159,172,180,191,204,212,228,239,244,196,151,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,156,204,247,239,228,212,204,188,180,172,159,148,140,132,124,116,108,100,92,87,84,76,71,68,60,55,52,47,44,44,36,36,31,28,28,28,23,20,20,20,20,20,15,15,12,12,12,12,12,12,12,12,12,12,15,15,15,20,20,20,20,23,28,28,28,31,36,36,39,44,44,52,52,60,63,68,76,79,84,92,100,103,111,119,127,135,148,156,164,172,188,196,207,220,236,244,228,180,132,87,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,135,180,228,244,231,220,207,196,188,172,164,156,148,140,127,119,116,108,100,92,84,79,76,68,68,60,55,52,47,44,44,36,36,36,31,28,28,28,23,20,20,20,20,20,20,15,15,15,15,15,15,15,15,20,20,20,20,20,20,23,23,28,28,28,31,36,36,39,44,44,52,52,60,60,68,71,76,84,92,95,100,108,116,124,132,140,148,159,172,180,188,204,212,228,239,252,204,159,116,68,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,164,204,252,236,228,212,204,191,180,172,159,151,140,132,124,116,108,103,100,92,84,79,76,68,63,60,55,52,47,44,44,39,36,36,31,28,28,28,28,23,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,23,23,28,28,28,31,36,36,36,44,44,47,52,52,60,60,68,71,76,84,87,92,100,108,116,124,132,140,148,156,164,175,188,196,207,220,231,244,228,183,140,92,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,95,140,183,228,244,231,220,207,196,188,175,164,156,148,140,132,124,116,108,100,95,92,84,76,76,68,63,60,55,52,52,44,44,39,36,36,36,31,28,28,28,28,28,23,23,20,20,20,20,20,20,20,20,23,23,23,28,28,28,28,31,31,36,36,39,44,44,47,52,52,60,60,68,71,76,84,84,92,100,108,111,119,127,135,143,151,164,172,180,191,204,212,228,239,252,207,164,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,116,164,204,252,239,228,215,204,196,180,172,164,156,148,135,127,124,116,108,100,92,92,84,76,76,68,63,60,60,52,52,47,44,44,39,36,36,36,31,28,28,28,28,28,28,28,28,28,23,28,28,28,28,28,28,28,28,31,31,36,36,36,39,44,44,47,52,55,60,60,68,71,76,84,84,92,100,103,108,116,124,132,140,148,156,167,180,188,196,212,220,236,244,228,183,140,95,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,52,92,140,180,228,244,236,220,212,199,188,180,172,159,151,140,132,127,119,111,108,100,92,87,84,76,76,68,68,60,60,52,52,47,44,44,44,39,36,36,36,36,31,31,28,28,28,28,28,28,28,28,28,28,28,31,31,36,36,36,36,39,44,44,47,52,52,55,60,63,68,71,76,84,84,92,100,103,108,116,124,132,140,148,156,164,172,183,196,204,215,228,239,247,204,159,116,71,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,116,156,204,244,244,228,220,204,196,188,175,164,156,148,140,132,124,116,111,108,100,92,87,84,79,76,68,68,60,60,55,52,52,47,44,44,44,39,36,36,36,36,36,36,36,31,31,31,31,31,36,36,36,36,36,36,39,44,44,44,44,52,52,52,60,60,63,68,71,76,84,84,92,100,100,108,116,124,132,140,148,156,164,172,180,188,204,212,223,236,247,220,180,135,92,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,92,132,175,220,252,236,228,212,204,196,183,172,164,156,148,140,132,124,116,111,108,100,92,92,84,79,76,71,68,63,60,60,55,52,52,47,44,44,44,44,39,39,36,36,36,36,36,36,36,36,36,36,36,39,44,44,44,44,47,52,52,52,55,60,60,68,68,76,76,84,84,92,100,100,108,116,124,127,135,143,151,159,172,180,188,196,207,220,231,244,236,196,156,111,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,191,231,244,236,220,212,199,188,180,172,164,156,148,140,132,124,116,111,108,100,95,92,84,84,76,76,68,68,63,60,60,55,52,52,52,47,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,47,52,52,52,55,60,60,63,68,71,76,79,84,87,92,100,103,108,116,124,127,135,140,148,156,167,175,188,196,204,215,228,239,252,212,172,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,79,124,164,204,244,244,228,220,207,196,188,180,172,164,156,148,140,132,124,116,111,108,100,95,92,87,84,79,76,71,68,68,63,60,60,55,52,52,52,52,47,47,47,44,44,44,44,44,44,44,47,47,52,52,52,52,55,60,60,60,63,68,68,76,76,84,84,92,92,100,103,108,116,124,127,132,140,148,156,164,172,183,196,204,212,223,236,247,228,183,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,135,175,215,252,236,228,215,204,196,188,180,172,164,156,148,140,132,124,119,116,108,100,100,92,92,84,84,76,76,71,68,68,63,60,60,60,55,55,52,52,52,52,52,52,52,52,52,52,52,52,52,55,60,60,60,60,68,68,68,76,76,79,84,87,92,95,100,108,108,116,124,127,135,140,148,156,164,172,180,191,204,212,220,236,244,236,196,156,116,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,148,188,228,247,236,228,212,204,196,188,180,172,164,156,148,140,132,124,119,116,108,103,100,95,92,87,84,79,76,76,71,68,68,68,63,60,60,60,60,60,60,55,55,55,55,55,60,60,60,60,60,60,63,68,68,68,76,76,79,84,84,92,92,100,100,108,111,116,124,132,135,140,148,156,164,172,180,188,199,212,220,228,244,244,207,167,127,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,76,116,156,196,236,244,236,223,212,204,196,188,180,172,164,156,148,140,132,127,124,116,111,108,100,100,92,92,87,84,84,76,76,76,71,68,68,68,68,63,63,63,60,60,60,60,60,63,63,68,68,68,68,68,71,76,76,79,84,84,87,92,95,100,103,108,116,119,124,132,140,143,148,156,164,172,180,188,199,207,220,228,239,252,215,175,140,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,47,87,124,164,204,244,244,236,220,212,204,196,188,180,172,164,156,148,140,135,132,124,119,116,108,108,100,100,92,92,87,84,84,79,76,76,76,76,71,68,68,68,68,68,68,68,68,68,68,71,71,76,76,76,79,84,84,84,92,92,95,100,103,108,111,116,124,127,132,140,148,151,156,164,172,180,188,199,207,220,228,236,252,220,183,148,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,92,132,172,207,244,244,231,220,212,204,196,188,180,172,164,156,148,143,140,132,127,124,116,116,108,108,100,100,95,92,92,87,84,84,84,79,76,76,76,76,76,76,76,76,76,76,76,76,79,79,84,84,84,87,92,92,95,100,103,108,108,116,119,124,132,135,140,148,156,159,167,172,180,188,199,207,220,228,236,247,228,188,151,116,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,63,100,140,175,212,247,244,231,220,212,204,196,188,180,172,164,156,151,148,140,135,132,124,124,116,111,108,108,100,100,95,92,92,92,87,87,84,84,84,84,84,84,84,84,84,84,84,84,84,87,92,92,92,95,100,100,103,108,108,116,116,124,127,132,140,143,148,156,164,172,175,183,191,199,207,220,228,236,247,228,196,156,119,84,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,108,140,180,212,247,244,231,223,212,204,196,188,180,172,167,164,156,148,143,140,132,132,124,124,116,116,108,108,103,100,100,100,95,92,92,92,92,92,92,92,92,92,92,92,92,92,92,95,100,100,100,103,108,108,111,116,119,124,127,132,135,140,148,151,156,164,172,180,188,196,204,212,220,228,236,247,231,196,159,124,84,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,143,180,212,247,244,236,223,215,207,199,191,183,180,172,164,156,156,148,140,140,132,132,124,124,116,116,111,108,108,108,103,100,100,100,100,100,100,100,100,100,100,100,100,100,100,103,108,108,108,111,116,116,119,124,127,132,135,140,148,148,156,164,167,172,180,188,196,204,212,220,228,236,247,228,196,159,124,92,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,175,212,244,244,236,228,220,212,204,196,188,180,172,167,164,156,151,148,140,140,132,132,127,124,124,116,116,116,111,108,108,108,108,108,108,108,108,108,108,108,108,108,108,111,116,116,116,119,124,124,132,132,135,140,148,148,156,159,164,172,180,183,188,196,204,212,220,228,239,252,228,196,159,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,108,140,172,204,236,244,236,228,220,212,204,196,191,183,180,172,167,164,156,151,148,143,140,135,132,132,127,124,124,124,119,116,116,116,116,116,116,116,116,116,116,116,116,116,119,124,124,124,132,132,135,140,140,148,148,156,159,164,172,175,180,188,196,204,207,215,223,236,244,252,220,188,156,124,92,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,68,103,135,167,199,231,252,239,231,223,215,207,204,196,188,183,180,172,167,164,156,156,148,148,143,140,140,132,132,132,127,127,124,124,124,124,124,124,124,124,124,124,124,127,132,132,132,135,140,140,143,148,151,156,159,164,172,172,180,188,191,196,204,212,220,228,236,244,244,215,183,151,119,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,68,100,132,164,191,220,252,244,236,228,220,212,204,199,196,188,180,180,172,167,164,159,156,156,148,148,143,140,140,140,140,135,132,132,132,132,132,132,132,132,135,135,140,140,140,143,148,148,151,156,156,164,164,172,175,180,188,188,196,204,212,215,223,231,239,247,236,207,175,148,116,84,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,92,124,151,180,212,239,247,239,231,223,220,212,204,199,196,188,183,180,172,172,167,164,159,156,156,151,148,148,148,148,143,143,143,140,140,143,143,143,148,148,148,148,151,156,156,159,164,164,172,172,180,180,188,191,196,204,207,212,220,228,236,244,252,228,196,167,140,108,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,84,111,140,172,196,228,252,244,236,228,223,220,212,204,199,196,188,188,180,180,172,172,167,164,164,164,159,156,156,156,156,156,156,156,156,156,156,156,156,156,159,164,164,167,172,172,175,180,183,188,191,196,204,207,212,220,228,236,239,247,236,212,183,156,127,100,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,71,100,132,156,183,212,236,252,244,236,228,223,220,212,207,204,196,196,188,188,183,180,180,172,172,172,172,167,164,164,164,164,164,164,164,164,164,167,172,172,172,175,180,180,183,188,191,196,199,204,212,212,220,228,231,239,244,247,220,196,172,140,116,84,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,87,116,140,164,191,215,239,247,244,236,228,223,220,212,212,204,204,196,196,191,188,188,183,180,180,180,180,180,175,175,175,175,175,180,180,180,180,183,188,188,188,196,196,199,204,207,212,220,220,228,236,239,244,252,228,204,180,156,127,100,76,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,71,100,124,148,172,196,220,239,252,244,236,231,228,220,220,212,212,207,204,204,196,196,196,191,191,188,188,188,188,188,188,188,188,188,191,196,196,196,199,204,204,212,212,215,220,228,228,236,239,244,252,228,207,183,159,135,111,84,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,79,108,127,151,172,196,215,236,252,244,239,236,231,228,223,220,220,212,212,212,207,204,204,204,204,204,199,199,199,204,204,204,204,204,207,212,212,215,220,220,228,228,236,236,244,247,244,228,204,183,164,140,116,92,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,84,108,127,148,172,188,207,228,244,252,244,244,236,236,228,228,228,220,220,220,220,215,212,212,212,212,212,212,215,215,220,220,220,223,228,228,231,236,239,244,247,252,236,215,196,180,159,140,116,95,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,60,84,103,124,143,164,180,196,212,228,239,252,247,244,244,236,236,236,231,228,228,228,228,228,228,228,228,228,228,231,236,236,236,239,244,244,252,244,236,220,204,188,172,151,132,116,92,71,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,60,76,95,116,132,148,164,180,191,204,215,228,236,247,252,247,244,244,244,244,244,244,244,244,244,244,244,244,247,252,252,244,236,220,212,196,188,172,156,140,124,108,87,68,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,68,84,100,116,132,143,156,167,180,188,196,204,212,220,223,228,231,236,236,236,236,236,231,228,220,215,212,204,196,183,172,164,148,140,124,108,92,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,68,84,95,108,119,132,140,148,156,164,172,175,180,180,188,188,188,188,183,180,180,172,167,159,156,143,135,124,116,100,92,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,60,71,84,92,100,108,116,119,124,132,132,135,135,140,135,132,132,127,124,116,111,103,95,84,76,68,52,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,60,68,71,76,79,84,84,87,87,84,84,84,76,76,68,60,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,28,36,36,36,36,36,36,31,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t * FLARE_TEXTURES[6] ={
+ FLARE_TEXTURE_0,
+ FLARE_TEXTURE_1,
+ FLARE_TEXTURE_2,
+ FLARE_TEXTURE_3,
+ FLARE_TEXTURE_4,
+ FLARE_TEXTURE_5,
+ };
+ const int FLARE_TEXTURE_WIDTHS[10] = {
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ };
+ const int FLARE_TEXTURE_HEIGHTS[10] = {
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ };
+ }
+}
+#endif
diff --git a/xs/src/igl/opengl2/gl.h b/xs/src/igl/opengl2/gl.h
new file mode 100644
index 000000000..7147c9289
--- /dev/null
+++ b/xs/src/igl/opengl2/gl.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_GL_H
+#define IGL_OPENGL2_GL_H
+
+#ifdef IGL_OPENGL_GL_H
+# error "igl/opengl/gl.h already included"
+#endif
+
+// Always use this:
+// #include "gl.h"
+// Instead of:
+// #include <OpenGL/gl.h>
+// or
+// #include <GL/gl.h>
+//
+
+// For now this includes glu, glew and glext (perhaps these should be
+// separated)
+#ifdef _WIN32
+# define NOMINMAX
+# include <Windows.h>
+# undef DrawText
+# undef NOMINMAX
+#endif
+
+#ifndef __APPLE__
+# define GLEW_STATIC
+# include <GL/glew.h>
+#endif
+
+#ifdef __APPLE__
+# include <OpenGL/gl.h>
+# define __gl_h_ /* Prevent inclusion of the old gl.h */
+#else
+# include <GL/gl.h>
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl2/glext.h b/xs/src/igl/opengl2/glext.h
new file mode 100644
index 000000000..78ff45fea
--- /dev/null
+++ b/xs/src/igl/opengl2/glext.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL_GLEXT_H
+#define IGL_OPENGL_GLEXT_H
+
+#ifdef IGL_OPENGL2_GLEXT_H
+# error "igl/opengl2/glext.h already included"
+#endif
+
+// Always use this:
+// #include "gl.h"
+// Instead of:
+// #include <OpenGL/glext.h>
+// or
+// #include <GL/glext.h>
+//
+
+#ifdef __APPLE__
+# include <OpenGL/glext.h>
+#elif _WIN32
+// do nothing(?)
+#else
+# include <GL/glext.h>
+#endif
+
+#endif
+
diff --git a/xs/src/igl/opengl2/glu.h b/xs/src/igl/opengl2/glu.h
new file mode 100644
index 000000000..d4ab5e16c
--- /dev/null
+++ b/xs/src/igl/opengl2/glu.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_GLU_H
+#define IGL_OPENGL2_GLU_H
+
+#ifdef IGL_OPENGL_GLU_H
+# error "igl/opengl/glu.h already included"
+#endif
+
+// Always use this:
+// #include "glu.h"
+// Instead of:
+// #include <OpenGL/glu.h>
+// or
+// #include <GL/glu.h>
+//
+
+#ifdef __APPLE__
+# include <OpenGL/glu.h>
+#else
+# include <GL/glu.h>
+#endif
+
+#endif
+
diff --git a/xs/src/igl/opengl2/lens_flare.cpp b/xs/src/igl/opengl2/lens_flare.cpp
new file mode 100644
index 000000000..c99f634c8
--- /dev/null
+++ b/xs/src/igl/opengl2/lens_flare.cpp
@@ -0,0 +1,195 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "lens_flare.h"
+
+#include "../C_STR.h"
+#include "unproject.h"
+#include "project.h"
+#include "shine_textures.h"
+#include "flare_textures.h"
+
+#include <iostream>
+#include <stdint.h>
+
+// http://www.opengl.org/archives/resources/features/KilgardTechniques/LensFlare/glflare.c
+
+IGL_INLINE void igl::opengl2::lens_flare_load_textures(
+ std::vector<GLuint> & shine_id,
+ std::vector<GLuint> & flare_id)
+{
+
+ const auto setup_texture =[](
+ const uint8_t * texture,
+ const int width,
+ const int height,
+ GLuint texobj,
+ GLenum minFilter, GLenum maxFilter)
+ {
+ glBindTexture(GL_TEXTURE_2D, texobj);
+ glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, maxFilter);
+ glTexImage2D(GL_TEXTURE_2D, 0, 1, width, height, 0,
+ GL_LUMINANCE, GL_UNSIGNED_BYTE, texture);
+ };
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ shine_id.resize(10);
+ glGenTextures(10,&shine_id[0]);
+ for (int i = 0; i < (int)shine_id.size(); i++) {
+ setup_texture(
+ SHINE_TEXTURES[i],
+ SHINE_TEXTURE_WIDTHS[i],
+ SHINE_TEXTURE_HEIGHTS[i],
+ shine_id[i], GL_LINEAR, GL_LINEAR);
+ }
+ flare_id.resize(6);
+ glGenTextures(6,&flare_id[0]);
+ for (int i = 0; i < (int)flare_id.size(); i++) {
+ setup_texture(
+ FLARE_TEXTURES[i],
+ FLARE_TEXTURE_WIDTHS[i],
+ FLARE_TEXTURE_HEIGHTS[i],
+ flare_id[i], GL_LINEAR, GL_LINEAR);
+ }
+}
+
+IGL_INLINE void igl::opengl2::lens_flare_create(
+ const float * A,
+ const float * B,
+ const float * C,
+ std::vector<igl::opengl2::Flare> & flares)
+{
+ using namespace std;
+ flares.resize(12);
+ /* Shines */
+ flares[0] = Flare(-1, 1.0f, 0.1f, C, 1.0);
+ flares[1] = Flare(-1, 1.0f, 0.15f, B, 1.0);
+ flares[2] = Flare(-1, 1.0f, 0.35f, A, 1.0);
+
+ /* Flares */
+ flares[3] = Flare(2, 1.3f, 0.04f, A, 0.6);
+ flares[4] = Flare(3, 1.0f, 0.1f, A, 0.4);
+ flares[5] = Flare(1, 0.5f, 0.2f, A, 0.3);
+ flares[6] = Flare(3, 0.2f, 0.05f, A, 0.3);
+ flares[7] = Flare(0, 0.0f, 0.04f, A, 0.3);
+ flares[8] = Flare(5, -0.25f, 0.07f, A, 0.5);
+ flares[9] = Flare(5, -0.4f, 0.02f, A, 0.6);
+ flares[10] = Flare(5, -0.6f, 0.04f, A, 0.4);
+ flares[11] = Flare(5, -1.0f, 0.03f, A, 0.2);
+}
+
+IGL_INLINE void igl::opengl2::lens_flare_draw(
+ const std::vector<igl::opengl2::Flare> & flares,
+ const std::vector<GLuint> & shine_ids,
+ const std::vector<GLuint> & flare_ids,
+ const Eigen::Vector3f & light,
+ const float near_clip,
+ int & shine_tic)
+{
+ bool ot2 = glIsEnabled(GL_TEXTURE_2D);
+ bool ob = glIsEnabled(GL_BLEND);
+ bool odt = glIsEnabled(GL_DEPTH_TEST);
+ bool ocm = glIsEnabled(GL_COLOR_MATERIAL);
+ bool ol = glIsEnabled(GL_LIGHTING);
+ int obsa,obda,odf,odwm;
+ glGetIntegerv(GL_BLEND_SRC_ALPHA,&obsa);
+ glGetIntegerv(GL_BLEND_DST_ALPHA,&obda);
+ glGetIntegerv(GL_DEPTH_FUNC,&odf);
+ glGetIntegerv(GL_DEPTH_WRITEMASK,&odwm);
+
+ glDisable(GL_COLOR_MATERIAL);
+ glEnable(GL_DEPTH_TEST);
+ //glDepthFunc(GL_LEQUAL);
+ glDepthMask(GL_FALSE);
+ glEnable(GL_TEXTURE_2D);
+ glDisable(GL_LIGHTING);
+ glEnable(GL_BLEND);
+ glBlendFunc(GL_ONE, GL_ONE);
+
+ using namespace Eigen;
+ using namespace std;
+
+ //// view_dir direction from eye to position it is looking at
+ //const Vector3f view_dir = (at - from).normalized();
+
+ //// near_clip distance from eye to near clipping plane along view_dir
+ //// center position on near clipping plane along viewdir from eye
+ //const Vector3f center = from + near_clip*view_dir;
+
+ Vector3f plight = project(light);
+ // Orthogonal vectors to view direction at light
+ Vector3f psx = plight;
+ psx(0) += 1;
+ Vector3f psy = plight;
+ psy(1) += 1;
+
+ // axis toward center
+ int vp[4];
+ glGetIntegerv(GL_VIEWPORT,vp);
+ Vector3f center = unproject(Vector3f(0.5*vp[2],0.5*vp[3],plight[2]-1e-3));
+ //Vector3f center(0,0,1);
+ Vector3f axis = light-center;
+ //glLineWidth(4.);
+ //glColor3f(1,0,0);
+ //glBegin(GL_LINES);
+ //glVertex3fv(center.data());
+ //glVertex3fv(light.data());
+ //glEnd();
+
+ const Vector3f SX = unproject(psx).normalized();
+ const Vector3f SY = unproject(psy).normalized();
+
+ for(int i = 0; i < (int)flares.size(); i++)
+ {
+ const Vector3f sx = flares[i].scale * SX;
+ const Vector3f sy = flares[i].scale * SY;
+ glColor3fv(flares[i].color);
+ if (flares[i].type < 0) {
+ glBindTexture(GL_TEXTURE_2D, shine_ids[shine_tic]);
+ shine_tic = (shine_tic + 1) % shine_ids.size();
+ } else
+ {
+ glBindTexture(GL_TEXTURE_2D, flare_ids[flares[i].type]);
+ }
+
+ /* position = center + flare[i].loc * axis */
+ const Vector3f position = center + flares[i].loc * axis;
+ Vector3f tmp;
+
+ glBegin(GL_QUADS);
+ glTexCoord2f(0.0, 0.0);
+ tmp = position + sx;
+ tmp = tmp + sy;
+ glVertex3fv(tmp.data());
+
+ glTexCoord2f(1.0, 0.0);
+ tmp = position - sx;
+ tmp = tmp + sy;
+ glVertex3fv(tmp.data());
+
+ glTexCoord2f(1.0, 1.0);
+ tmp = position - sx;
+ tmp = tmp - sy;
+ glVertex3fv(tmp.data());
+
+ glTexCoord2f(0.0, 1.0);
+ tmp = position + sx;
+ tmp = tmp - sy;
+ glVertex3fv(tmp.data());
+ glEnd();
+ }
+ ot2?glEnable(GL_TEXTURE_2D):glDisable(GL_TEXTURE_2D);
+ ob?glEnable(GL_BLEND):glDisable(GL_BLEND);
+ odt?glEnable(GL_DEPTH_TEST):glDisable(GL_DEPTH_TEST);
+ ocm?glEnable(GL_COLOR_MATERIAL):glDisable(GL_COLOR_MATERIAL);
+ ol?glEnable(GL_LIGHTING):glDisable(GL_LIGHTING);
+ glBlendFunc(obsa,obda);
+ glDepthFunc(odf);
+ glDepthMask(odwm);
+}
diff --git a/xs/src/igl/opengl2/lens_flare.h b/xs/src/igl/opengl2/lens_flare.h
new file mode 100644
index 000000000..280c27b69
--- /dev/null
+++ b/xs/src/igl/opengl2/lens_flare.h
@@ -0,0 +1,93 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_LENS_FLARE_H
+#define IGL_OPENGL2_LENS_FLARE_H
+
+#include "../igl_inline.h"
+#include "gl.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ namespace opengl2
+ {
+
+ struct Flare{
+ int type; /* flare texture index, 0..5 */
+ float scale;
+ float loc; /* position on axis */
+ float color[3];
+ Flare():
+ type(-1),
+ scale(0),
+ loc(0)
+ {}
+ Flare(int type, float location, float scale, const float color[3], float colorScale) :
+ type(type),
+ scale(scale),
+ loc(location)
+ {
+ this->color[0] = color[0] * colorScale;
+ this->color[1] = color[1] * colorScale;
+ this->color[2] = color[2] * colorScale;
+ }
+ };
+
+
+ // Initialize shared data for lens flates
+ //
+ // Inputs:
+ // start_id starting texture id location (should have at least id:id+16 free)
+ // Outputs:
+ // shine list of texture ids for shines
+ // flare list of texture ids for flares
+ IGL_INLINE void lens_flare_load_textures(
+ std::vector<GLuint> & shine_ids,
+ std::vector<GLuint> & flare_ids);
+
+ // Create a set of lens flares
+ //
+ // Inputs:
+ // A primary color
+ // B secondary color
+ // C secondary color
+ // Outputs:
+ // flares list of flare objects
+ IGL_INLINE void lens_flare_create(
+ const float * A,
+ const float * B,
+ const float * C,
+ std::vector<Flare> & flares);
+
+ // Draw lens flares
+ //
+ // Inputs:
+ // flares list of Flare objects
+ // shine_ids list of shine textures
+ // flare_ids list of flare texture ids
+ // light position of light
+ // near_clip near clipping plane
+ // shine_tic current "tic" in shine textures
+ // Outputs:
+ // shine_tic current "tic" in shine textures
+ IGL_INLINE void lens_flare_draw(
+ const std::vector<Flare> & flares,
+ const std::vector<GLuint> & shine_ids,
+ const std::vector<GLuint> & flare_ids,
+ const Eigen::Vector3f & light,
+ const float near_clip,
+ int & shine_tic);
+ }
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "lens_flare.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl2/model_proj_viewport.cpp b/xs/src/igl/opengl2/model_proj_viewport.cpp
new file mode 100644
index 000000000..9fec32a49
--- /dev/null
+++ b/xs/src/igl/opengl2/model_proj_viewport.cpp
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "model_proj_viewport.h"
+#include "gl.h"
+
+template <typename Derivedmodel, typename Derivedproj, typename Derivedviewport>
+IGL_INLINE void igl::opengl2::model_proj_viewport(
+ Eigen::PlainObjectBase<Derivedmodel> & model,
+ Eigen::PlainObjectBase<Derivedproj> & proj,
+ Eigen::PlainObjectBase<Derivedviewport> & viewport)
+{
+ Eigen::Matrix4d MV,P;
+ Eigen::Vector4i VPi;
+ glGetDoublev(GL_MODELVIEW_MATRIX,MV.data());
+ glGetDoublev(GL_PROJECTION_MATRIX,P.data());
+ glGetIntegerv(GL_VIEWPORT,VPi.data());
+ viewport = VPi.cast<typename Derivedviewport::Scalar>();
+ model = MV.cast<typename Derivedmodel::Scalar>();
+ proj = P.cast<typename Derivedproj::Scalar>();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::opengl2::model_proj_viewport<Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<double, 4, 1, 0, 4, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 0, 4, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 0, 4, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> >&);
+template void igl::opengl2::model_proj_viewport<Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> >&);
+#endif
diff --git a/xs/src/igl/opengl2/model_proj_viewport.h b/xs/src/igl/opengl2/model_proj_viewport.h
new file mode 100644
index 000000000..025247ae7
--- /dev/null
+++ b/xs/src/igl/opengl2/model_proj_viewport.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_MODEL_PROJ_VIEW_H
+#define IGL_OPENGL2_MODEL_PROJ_VIEW_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace opengl2
+ {
+ // Collect the model-view, projection and viewport matrices
+ //
+ // Outputs:
+ // model 4x4 modelview matrix
+ // proj 4x4 projection matrix
+ // viewport 4x1 viewport vector
+ //
+ template <typename Derivedmodel, typename Derivedproj, typename Derivedviewport>
+ IGL_INLINE void model_proj_viewport(
+ Eigen::PlainObjectBase<Derivedmodel> & model,
+ Eigen::PlainObjectBase<Derivedproj> & proj,
+ Eigen::PlainObjectBase<Derivedviewport> & viewport);
+ }
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "model_proj_viewport.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl2/print_gl_get.cpp b/xs/src/igl/opengl2/print_gl_get.cpp
new file mode 100644
index 000000000..7182dc558
--- /dev/null
+++ b/xs/src/igl/opengl2/print_gl_get.cpp
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "print_gl_get.h"
+
+#include <cstdio>
+IGL_INLINE void igl::opengl2::print_gl_get(GLenum pname)
+{
+ double dM[16];
+
+ int rows = 4;
+ int cols = 4;
+ switch(pname)
+ {
+ case GL_MODELVIEW_MATRIX:
+ case GL_PROJECTION_MATRIX:
+ {
+ rows = 4;
+ cols = 4;
+ glGetDoublev(pname,dM);
+ for(int i = 0;i<rows;i++)
+ {
+ for(int j = 0;j<cols;j++)
+ {
+ printf("%lg ",dM[j*rows+i]);
+ }
+ printf("\n");
+ }
+ break;
+ }
+ default:
+ fprintf(stderr,"ERROR in print_gl_get(), gl enum not recognized.\n");
+ }
+}
diff --git a/xs/src/igl/opengl2/print_gl_get.h b/xs/src/igl/opengl2/print_gl_get.h
new file mode 100644
index 000000000..0db5298e9
--- /dev/null
+++ b/xs/src/igl/opengl2/print_gl_get.h
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_PRINT_GL_GET_H
+#define IGL_OPENGL2_PRINT_GL_GET_H
+#include "gl.h"
+#include "../igl_inline.h"
+
+namespace igl
+{
+ namespace opengl2
+ {
+ // Prints the value of pname found by issuing glGet*(pname,*)
+ // Inputs:
+ // pname enum key to gl parameter
+ IGL_INLINE void print_gl_get(GLenum pname);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "print_gl_get.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/opengl2/project.cpp b/xs/src/igl/opengl2/project.cpp
new file mode 100644
index 000000000..a953197b7
--- /dev/null
+++ b/xs/src/igl/opengl2/project.cpp
@@ -0,0 +1,73 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "project.h"
+#include "../project.h"
+#include "gl.h"
+#include "glu.h"
+#include <iostream>
+
+IGL_INLINE int igl::opengl2::project(
+ const double objX,
+ const double objY,
+ const double objZ,
+ double* winX,
+ double* winY,
+ double* winZ)
+{
+ using namespace std;
+ // Put model, projection, and viewport matrices into double arrays
+ double MV[16];
+ double P[16];
+ int VP[4];
+ glGetDoublev(GL_MODELVIEW_MATRIX, MV);
+ glGetDoublev(GL_PROJECTION_MATRIX, P);
+ glGetIntegerv(GL_VIEWPORT, VP);
+ int ret = gluProject(objX,objY,objZ,MV,P,VP,winX,winY,winZ);
+ return ret;
+}
+
+template <typename Derivedobj, typename Derivedwin>
+IGL_INLINE int igl::opengl2::project(
+ const Eigen::PlainObjectBase<Derivedobj> & obj,
+ Eigen::PlainObjectBase<Derivedwin> & win)
+{
+ assert(obj.size() >= 3);
+ Eigen::Vector3d dobj(obj(0),obj(1),obj(2));
+ Eigen::Vector3d dwin;
+ int ret = igl::opengl2::project(dobj(0),dobj(1),dobj(2),
+ &dwin.data()[0],
+ &dwin.data()[1],
+ &dwin.data()[2]);
+ win(0) = dwin(0);
+ win(1) = dwin(1);
+ win(2) = dwin(2);
+ return ret;
+}
+
+template <typename Derivedobj>
+IGL_INLINE Derivedobj igl::opengl2::project(
+ const Eigen::PlainObjectBase<Derivedobj> & obj)
+{
+ Derivedobj win;
+ igl::opengl2::project(obj,win);
+ return win;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template int igl::opengl2::project<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+template int igl::opengl2::project<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
+template int igl::opengl2::project<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template Eigen::Matrix<double, 3, 1, 0, 3, 1> igl::opengl2::project<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
+template Eigen::Matrix<float, 3, 1, 0, 3, 1> igl::opengl2::project<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
+template Eigen::Matrix<double, 1, -1, 1, 1, -1> igl::opengl2::project<Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&);
+template Eigen::Matrix<double, 1, 3, 1, 1, 3> igl::opengl2::project<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+template Eigen::Matrix<double, 1, 2, 1, 1, 2> igl::opengl2::project<Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
+template Eigen::Matrix<double, 2, 1, 0, 2, 1> igl::opengl2::project<Eigen::Matrix<double, 2, 1, 0, 2, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&);
+#endif
+
diff --git a/xs/src/igl/opengl2/project.h b/xs/src/igl/opengl2/project.h
new file mode 100644
index 000000000..befd09007
--- /dev/null
+++ b/xs/src/igl/opengl2/project.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_PROJECT_H
+#define IGL_OPENGL2_PROJECT_H
+#include "../igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ namespace opengl2
+ {
+ // Wrapper for gluProject that uses the current GL_MODELVIEW_MATRIX,
+ // GL_PROJECTION_MATRIX, and GL_VIEWPORT
+ // Inputs:
+ // obj* 3D objects' x, y, and z coordinates respectively
+ // Outputs:
+ // win* pointers to screen space x, y, and z coordinates respectively
+ // Returns return value of gluProject call
+ IGL_INLINE int project(
+ const double objX,
+ const double objY,
+ const double objZ,
+ double* winX,
+ double* winY,
+ double* winZ);
+ // Eigen wrapper
+ template <typename Derivedobj, typename Derivedwin>
+ IGL_INLINE int project(
+ const Eigen::PlainObjectBase<Derivedobj> & obj,
+ Eigen::PlainObjectBase<Derivedwin> & win);
+ // Eigen wrapper with return
+ template <typename Derivedobj>
+ IGL_INLINE Derivedobj project(
+ const Eigen::PlainObjectBase<Derivedobj> & obj);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "project.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/opengl2/right_axis.cpp b/xs/src/igl/opengl2/right_axis.cpp
new file mode 100644
index 000000000..a0b905176
--- /dev/null
+++ b/xs/src/igl/opengl2/right_axis.cpp
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "right_axis.h"
+#include "gl.h"
+
+IGL_INLINE void igl::opengl2::right_axis(double * x, double * y, double * z)
+{
+ double mv[16];
+ glGetDoublev(GL_MODELVIEW_MATRIX, mv);
+ igl::opengl2::right_axis(mv,x,y,z);
+}
+
+IGL_INLINE void igl::opengl2::right_axis(const double * mv,double * x, double * y, double * z)
+{
+ *x = -mv[0*4+0];
+ *y = -mv[1*4+0];
+ *z = -mv[2*4+0];
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/opengl2/right_axis.h b/xs/src/igl/opengl2/right_axis.h
new file mode 100644
index 000000000..4e6787cdd
--- /dev/null
+++ b/xs/src/igl/opengl2/right_axis.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_RIGHT_AXIS_H
+#define IGL_OPENGL2_RIGHT_AXIS_H
+#include "../igl_inline.h"
+namespace igl
+{
+ namespace opengl2
+ {
+ // Determines the right axis or depth axis of the current gl matrix
+ // Outputs:
+ // x pointer to x-coordinate in scene coordinates of the un-normalized
+ // right axis
+ // y pointer to y-coordinate in scene coordinates of the un-normalized
+ // right axis
+ // z pointer to z-coordinate in scene coordinates of the un-normalized
+ // right axis
+ // mv pointer to modelview matrix
+ //
+ // Note: Right axis is returned *UN-normalized*
+ IGL_INLINE void right_axis(double * x, double * y, double * z);
+ IGL_INLINE void right_axis(const double * mv, double * x, double * y, double * z);
+ }
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "right_axis.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/opengl2/shine_textures.h b/xs/src/igl/opengl2/shine_textures.h
new file mode 100644
index 000000000..05001989d
--- /dev/null
+++ b/xs/src/igl/opengl2/shine_textures.h
@@ -0,0 +1,66 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_SHINE_TEXTURES_H
+#define IGL_OPENGL2_SHINE_TEXTURES_H
+
+#include <cstdint>
+
+namespace igl
+{
+ namespace opengl2
+ {
+
+ const uint8_t SHINE_TEXTURE_0[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,7,20,15,7,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,36,36,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,12,20,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,28,36,36,0,0,0,0,0,0,0,0,0,0,0,12,28,20,12,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,39,28,31,28,0,0,0,0,0,0,0,0,0,0,0,28,28,20,15,28,28,12,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,44,31,36,28,0,0,0,0,0,0,0,0,0,0,15,31,28,20,36,36,20,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,0,0,0,0,0,0,0,0,12,12,7,12,12,47,47,44,44,36,0,0,0,0,0,0,0,0,0,0,31,36,28,28,44,28,12,0,0,0,12,23,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,15,15,15,20,20,47,47,44,44,23,0,0,0,0,0,0,7,12,7,20,36,36,28,44,39,20,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,39,23,0,0,0,0,0,0,0,12,15,12,12,12,47,47,44,44,15,0,0,0,0,0,0,12,12,12,36,36,36,44,52,28,7,0,0,7,20,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,39,7,0,0,0,0,0,0,12,20,20,0,0,47,47,47,47,7,0,0,0,0,0,12,15,15,23,36,44,44,60,44,20,0,0,0,28,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,0,0,0,0,0,12,23,23,12,12,52,52,52,52,0,0,0,0,0,0,20,23,23,39,47,47,60,60,28,0,0,0,28,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,44,12,0,0,0,0,0,0,28,31,31,23,52,60,52,52,0,0,0,0,0,0,28,28,36,44,60,55,68,44,12,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,52,36,0,0,0,0,0,0,31,39,52,36,60,68,52,52,0,0,0,0,0,20,28,36,44,60,63,76,60,23,0,0,23,47,36,12,0,0,0,0,0,0,0,0,0,0,0,12,23,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,52,20,0,0,15,15,0,36,44,60,36,71,76,55,52,0,0,0,0,0,31,36,44,52,71,76,76,36,0,0,23,47,39,12,0,7,12,0,0,0,0,0,0,0,7,20,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,52,39,0,0,20,20,12,36,55,92,39,79,100,68,60,0,0,0,0,20,36,47,52,76,84,92,60,20,0,20,47,44,20,0,12,20,15,0,0,0,0,0,0,20,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,55,20,0,20,23,20,31,79,111,44,84,127,84,55,0,0,0,0,36,39,60,68,92,92,79,28,0,20,47,52,23,0,0,12,20,7,0,0,0,0,20,36,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,7,0,0,0,0,0,0,0,31,60,47,0,7,28,28,20,84,116,52,100,164,100,52,0,0,0,12,44,60,63,92,103,100,52,7,20,47,60,28,0,12,15,7,7,0,0,0,15,36,47,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,12,12,7,0,0,0,0,0,7,52,60,28,0,28,28,20,84,119,79,119,188,116,44,0,0,0,36,44,76,76,111,108,76,20,12,44,60,31,12,20,28,12,0,0,0,12,36,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,7,0,0,0,0,20,20,12,0,0,0,12,20,7,0,0,0,0,0,28,63,52,0,28,36,28,76,116,100,124,188,116,36,0,0,7,47,68,79,108,119,100,36,12,44,68,36,20,28,39,23,0,0,7,31,60,68,52,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,20,20,12,0,0,12,15,23,20,12,0,0,20,23,12,0,0,0,0,0,55,68,31,12,39,39,76,119,132,127,180,100,28,0,0,28,55,92,95,140,124,68,20,44,68,44,28,31,44,28,7,0,20,52,76,71,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,28,20,12,0,0,20,36,31,15,0,7,23,28,12,0,0,0,0,28,68,60,12,44,44,71,116,151,140,175,100,20,0,7,55,84,108,140,148,100,36,44,71,52,36,36,47,28,0,12,39,76,87,71,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,31,23,12,0,20,36,39,28,7,12,28,36,20,0,0,0,0,55,71,39,36,44,76,116,167,156,180,100,15,12,39,76,111,127,167,132,60,44,76,60,44,44,52,28,7,28,68,92,92,63,28,0,0,7,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,20,7,12,31,44,36,15,12,28,36,20,0,0,0,28,71,68,36,52,76,119,172,180,188,108,20,28,76,108,140,172,164,103,60,76,68,52,52,52,28,20,52,95,108,84,47,12,0,12,20,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,39,39,23,15,28,47,44,28,20,36,44,23,12,12,12,55,76,52,60,76,124,164,188,180,100,20,60,103,143,164,183,132,92,87,84,68,60,52,31,36,84,116,108,76,28,7,15,28,23,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,44,39,28,28,44,52,36,28,36,52,36,28,20,36,76,76,84,84,148,175,207,172,100,36,108,140,175,191,164,124,108,100,76,68,52,44,60,100,124,100,52,20,20,31,28,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,52,52,44,39,44,60,52,44,44,60,47,39,28,68,84,108,100,172,196,228,167,108,76,156,188,204,196,156,132,124,92,76,60,60,84,116,116,84,52,31,36,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,55,55,52,55,60,60,55,60,71,68,52,52,84,108,127,188,220,239,164,116,119,188,228,212,188,156,140,111,84,71,79,100,124,111,84,63,52,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,52,60,68,68,76,71,76,84,87,79,63,84,100,148,188,236,252,172,140,164,220,236,212,180,164,132,100,87,100,116,132,124,100,84,68,52,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,0,0,0,0,0,12,39,60,68,84,92,87,92,100,108,95,87,108,148,191,244,252,183,172,212,244,236,212,188,148,124,108,116,135,151,140,111,87,68,44,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,20,28,28,20,0,0,0,20,52,68,84,108,111,116,116,132,116,124,148,204,239,252,204,199,244,252,236,215,172,148,135,143,156,164,140,108,87,68,44,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,36,36,39,31,12,0,28,63,95,127,140,143,143,164,156,164,212,244,252,228,228,252,252,244,212,188,167,180,180,156,124,108,92,60,36,28,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,39,44,47,52,44,44,63,100,140,167,191,204,204,212,223,252,252,244,244,252,252,244,228,212,204,183,156,132,108,68,44,36,36,31,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,47,52,55,60,76,100,132,156,188,228,244,239,244,252,252,252,252,252,252,252,244,228,204,164,116,79,68,79,76,60,44,31,20,20,12,7,0,0,0,0,7,15,15,7,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,55,60,68,87,132,180,228,244,252,252,252,252,252,252,252,252,252,244,212,172,143,135,127,108,87,76,68,68,68,68,68,60,55,52,68,68,60,55,52,47,39,28,36,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,15,28,28,28,28,28,28,28,23,20,15,15,15,15,15,15,15,15,12,20,44,68,79,103,164,220,244,252,252,252,252,252,252,252,252,244,223,204,191,180,172,180,180,172,151,135,132,132,127,124,116,108,124,119,108,95,92,76,60,44,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,31,68,84,84,84,84,84,84,92,92,92,84,84,84,84,84,92,95,100,92,87,84,87,103,140,188,228,244,252,252,252,252,252,252,252,252,239,212,191,191,180,159,140,124,124,124,124,132,132,124,111,100,84,87,76,60,52,52,47,47,39,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,52,52,52,52,52,52,60,63,68,68,68,71,84,95,116,132,148,159,172,188,207,223,231,244,247,252,252,252,252,252,252,252,252,252,244,220,172,132,108,92,84,76,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,63,71,76,76,76,84,103,132,156,164,172,167,172,196,228,244,252,252,252,252,252,252,252,252,252,252,244,220,188,159,132,100,76,55,47,44,39,36,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,28,44,44,52,52,71,84,103,127,140,148,143,140,132,119,132,148,172,196,228,244,252,252,244,244,252,252,252,239,220,223,244,244,223,204,183,164,140,127,108,84,60,39,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,28,47,55,84,100,111,100,92,79,71,68,68,71,84,87,100,140,196,228,236,236,252,228,220,228,247,247,252,239,212,183,188,212,228,228,228,223,196,159,124,92,68,63,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,52,52,52,52,60,60,60,60,55,39,28,36,52,71,108,164,204,215,207,212,236,244,188,180,212,239,236,236,247,212,167,132,140,164,188,191,188,188,180,167,164,148,116,84,63,60,52,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,44,47,52,52,52,52,44,28,7,0,12,28,44,60,92,124,151,188,188,172,175,204,228,215,148,156,220,236,212,212,236,220,180,127,92,92,103,132,151,148,140,151,148,132,132,148,140,111,76,60,52,52,47,39,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,36,36,39,44,44,44,44,36,15,0,0,0,0,12,28,36,44,71,92,108,140,172,164,140,148,180,204,215,164,108,148,239,244,188,188,204,204,188,156,108,68,63,68,87,111,119,108,100,124,140,132,108,111,124,124,103,71,52,44,44,44,39,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,28,31,36,36,36,36,20,0,0,0,0,0,0,0,12,23,28,36,60,71,76,100,148,164,135,108,111,156,180,196,183,108,84,164,252,252,183,164,175,196,180,172,140,92,60,39,44,68,79,95,100,84,68,87,116,124,116,103,103,103,100,84,63,44,39,36,36,36,31,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,12,20,23,28,23,12,0,0,0,0,0,0,0,0,0,0,0,15,23,44,52,52,71,108,135,140,116,84,84,132,156,164,188,148,52,84,180,252,252,196,140,148,188,164,172,164,108,76,60,31,20,44,68,76,79,76,68,52,60,79,100,108,103,108,103,95,84,63,52,39,36,31,31,23,20,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,39,52,76,100,116,116,87,55,68,116,127,127,172,175,95,20,100,204,252,252,220,132,116,172,156,140,156,140,84,63,55,31,12,12,44,68,68,68,60,52,44,44,52,68,87,95,100,100,92,84,68,47,31,28,23,20,12,20,12,15,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,60,71,92,100,92,52,39,52,100,116,108,143,188,140,44,20,119,220,252,252,236,140,92,132,167,124,116,143,119,68,52,52,31,12,0,20,44,63,63,55,44,36,36,36,36,44,55,76,84,87,84,76,71,63,44,20,7,12,12,15,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,36,52,71,84,84,63,28,28,44,84,103,87,108,167,167,84,7,36,140,236,252,244,228,148,76,87,156,132,100,111,135,103,52,39,44,31,12,0,0,20,47,60,60,47,31,23,31,28,28,28,28,36,52,68,71,68,68,60,52,36,12,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,52,60,71,60,36,12,20,36,76,92,79,76,127,172,116,28,0,60,151,236,231,220,204,143,68,52,116,156,100,79,116,124,84,39,28,39,28,12,0,0,0,28,52,60,55,39,20,12,20,28,20,20,12,0,12,36,55,60,55,52,44,36,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,36,52,63,55,39,12,0,12,36,60,84,76,60,87,151,132,60,0,0,68,148,220,212,204,188,148,68,31,79,140,119,79,68,116,108,68,28,20,28,23,12,0,0,0,0,28,52,52,52,36,12,0,12,20,12,0,0,0,0,7,28,44,44,39,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,52,39,20,0,0,12,28,52,71,76,44,55,116,143,87,20,0,0,76,143,196,196,183,183,143,76,28,52,100,132,87,52,68,116,95,52,20,12,20,12,0,0,0,0,0,7,28,47,47,44,28,7,0,0,0,0,0,0,0,0,0,0,20,28,28,20,15,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,52,39,20,0,0,0,7,23,39,60,71,44,28,76,132,103,44,0,0,12,71,132,183,188,156,167,140,84,44,23,76,116,95,60,44,79,108,84,44,15,0,0,12,12,0,0,0,0,0,12,28,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,23,0,0,0,0,7,20,28,52,68,44,12,44,100,116,68,12,0,0,20,71,132,167,172,132,140,116,100,52,0,55,79,100,71,36,39,84,100,68,36,12,0,12,12,0,0,0,0,0,0,0,12,31,44,39,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,31,12,0,0,0,0,0,12,20,44,63,44,12,20,63,108,84,36,0,0,0,12,60,124,148,164,124,119,100,108,52,0,28,68,92,76,60,20,52,92,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,36,20,0,0,0,0,0,0,0,12,36,60,47,15,0,44,87,92,52,7,0,0,0,20,60,124,140,156,116,100,92,108,47,15,0,55,68,76,60,36,15,60,92,68,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,31,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,23,12,0,0,0,0,0,0,0,0,23,52,47,20,0,28,63,95,68,28,0,0,0,0,20,52,135,135,148,111,84,100,108,47,36,0,36,60,68,52,47,20,20,68,84,52,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,28,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,12,0,0,0,0,0,0,0,0,0,20,47,52,20,0,12,44,84,76,44,0,0,0,0,0,23,44,124,116,108,108,71,108,92,52,44,0,7,55,60,47,44,36,0,28,76,79,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,15,44,52,23,0,0,36,60,84,55,20,0,0,0,0,0,28,44,108,87,76,103,68,108,71,60,44,0,0,36,55,52,36,44,20,0,39,79,68,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,0,0,0,0,0,0,0,12,36,52,28,0,0,20,44,76,63,36,0,0,0,0,0,0,28,52,76,68,55,100,68,108,60,71,44,7,0,12,52,52,31,36,36,0,0,52,84,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,7,28,47,28,0,0,12,36,60,68,52,12,0,0,0,0,0,0,15,52,63,55,44,92,63,100,52,84,36,23,0,0,36,52,36,28,36,20,0,12,60,79,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,28,0,0,0,28,44,63,52,28,0,0,0,0,0,0,0,12,60,52,47,39,79,60,84,52,76,36,36,0,0,12,52,47,20,28,28,7,0,23,68,76,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,28,7,0,0,12,36,52,55,44,7,0,0,0,0,0,0,7,20,68,47,44,36,68,60,68,47,60,31,31,0,0,0,36,47,28,15,28,20,0,0,31,68,63,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,7,0,0,0,28,36,52,44,20,0,0,0,0,0,0,0,0,12,60,47,36,28,52,52,44,47,52,28,28,0,0,0,15,44,44,12,20,20,0,0,0,36,76,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,15,28,44,44,36,0,0,0,0,0,0,0,0,0,0,52,47,23,28,52,47,31,47,44,28,20,7,0,0,0,36,44,20,7,20,12,0,0,7,47,76,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,0,0,0,0,20,28,44,39,15,0,0,0,0,0,0,0,0,0,0,44,44,12,28,47,44,28,47,44,36,20,15,0,0,0,20,39,36,0,12,12,12,0,0,15,52,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,12,20,31,36,28,0,0,0,0,0,0,0,0,0,0,0,44,39,0,28,47,52,36,52,44,36,12,12,0,0,0,0,36,36,15,0,12,12,0,0,0,20,60,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,12,15,20,36,36,12,0,0,0,0,0,0,0,0,0,0,0,39,39,0,23,44,47,28,52,39,39,12,12,0,0,0,0,20,36,28,0,0,0,0,0,0,0,28,55,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,15,20,28,31,20,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,20,36,44,20,44,36,36,7,7,0,0,0,0,0,31,36,12,0,0,0,0,0,0,0,31,52,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,12,20,28,28,0,0,0,0,0,0,0,0,0,0,0,0,23,36,36,0,15,36,28,12,20,28,28,0,7,0,0,0,0,0,20,31,23,0,0,0,0,0,0,0,7,31,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,7,7,23,28,15,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,15,36,15,0,0,28,28,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,12,31,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,15,0,15,36,23,0,0,23,23,7,0,0,0,0,0,0,0,20,28,20,0,0,0,0,0,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,15,0,12,28,28,12,12,31,31,20,0,0,0,0,0,0,0,7,28,23,0,0,0,0,0,0,0,0,0,7,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,28,28,20,20,23,23,20,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,20,20,7,7,15,20,20,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,23,20,0,0,12,28,28,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,28,20,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,31,28,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,20,12,0,0,0,15,15,7,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_1[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,20,20,7,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,12,0,0,0,0,12,12,12,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,20,20,15,0,0,0,0,12,12,0,0,0,0,12,12,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,12,20,20,0,0,0,0,12,15,15,0,0,12,20,20,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,20,20,0,0,0,0,28,31,28,0,0,0,12,12,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,20,20,0,0,0,12,36,44,28,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,28,28,20,0,0,20,47,60,28,0,0,7,7,0,20,20,20,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,28,31,28,0,0,15,44,68,36,0,0,20,20,12,20,20,12,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,15,36,36,0,0,12,44,68,36,0,0,28,28,12,23,23,12,0,0,0,12,12,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,36,36,0,0,0,44,68,36,0,0,23,23,0,28,28,0,0,0,0,12,7,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,28,31,15,36,36,12,0,0,28,60,36,0,0,20,20,12,28,28,0,0,0,12,12,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,28,7,0,0,0,0,0,12,12,0,0,0,0,0,0,0,23,36,28,36,36,28,0,0,28,60,36,0,0,20,20,28,36,36,0,0,0,20,20,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,36,23,12,0,0,0,0,0,15,12,0,0,0,0,0,0,12,36,36,36,44,39,0,0,44,52,20,0,12,36,36,36,36,36,0,0,15,20,20,0,0,0,15,28,23,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,28,12,0,0,0,0,15,15,0,0,0,0,0,0,0,36,36,31,44,44,0,12,52,60,28,0,28,36,36,39,39,20,0,0,28,28,12,0,0,0,28,31,12,0,0,0,0,0,0,0,12,20,15,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,44,44,28,7,0,0,0,7,20,12,0,0,0,0,0,0,36,39,36,44,44,0,0,52,84,55,12,44,39,39,44,44,7,0,0,28,28,0,0,0,20,36,28,0,0,0,0,0,0,0,12,31,28,12,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,44,39,31,20,0,0,0,12,20,12,0,0,0,0,0,20,44,44,47,44,20,0,52,92,71,15,47,31,39,44,44,0,0,20,31,28,0,0,7,36,36,12,0,0,0,0,0,0,12,36,44,20,7,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,28,52,52,36,20,7,0,12,28,28,0,0,0,0,0,0,44,44,55,52,36,12,60,100,84,12,52,36,55,44,44,0,0,31,36,12,0,0,28,39,28,0,0,0,0,0,0,7,28,52,28,12,20,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,63,52,44,28,0,0,20,36,23,0,0,0,0,0,44,44,63,52,52,23,76,108,87,0,52,44,76,47,44,0,12,36,36,0,0,12,44,44,12,0,0,0,0,0,7,36,52,36,20,20,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,76,68,52,28,7,0,36,36,12,0,0,0,0,31,47,63,52,52,20,68,124,108,0,44,44,76,52,36,0,28,44,36,0,0,28,44,28,0,0,0,0,0,0,36,60,44,20,20,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,79,71,52,28,7,20,44,36,0,0,0,0,12,52,55,60,52,28,63,140,116,0,47,47,68,52,20,0,44,44,20,0,12,44,44,12,0,0,0,0,0,36,68,52,28,23,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,76,87,84,60,28,12,44,52,28,0,0,0,0,52,52,79,55,44,60,143,124,0,52,55,60,52,0,12,44,44,0,0,36,52,28,0,0,0,0,0,36,76,71,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,68,92,95,92,60,20,28,60,52,12,0,0,0,44,52,92,55,71,71,159,124,0,52,71,60,52,0,36,47,39,0,20,52,47,12,0,0,0,0,31,76,84,55,36,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,79,103,108,100,60,20,52,68,39,0,0,0,20,55,92,60,71,68,164,119,20,60,92,60,55,0,47,52,20,0,44,55,28,0,0,0,0,28,79,92,68,44,47,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,84,116,116,108,60,36,68,68,20,0,0,0,60,76,76,68,68,164,124,47,76,108,60,47,15,52,52,0,23,60,52,7,0,0,0,23,76,100,76,52,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,52,100,132,140,108,52,55,76,52,0,0,0,52,63,103,63,92,172,140,76,92,119,60,36,39,52,44,0,52,60,28,0,0,0,20,71,103,87,63,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,63,108,148,156,108,60,71,76,28,0,0,36,60,119,63,116,180,159,92,92,124,60,23,55,60,20,28,63,52,0,0,0,20,68,108,92,68,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,76,124,172,167,103,68,76,60,12,0,12,63,116,76,127,172,172,111,108,116,63,28,60,60,12,55,68,28,0,0,15,63,108,103,76,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,84,148,196,167,100,84,79,44,0,0,60,100,103,124,156,180,127,127,116,68,47,60,44,36,68,52,0,0,12,60,108,111,84,55,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,100,180,212,164,100,92,76,20,0,44,84,132,124,156,188,140,148,108,68,60,63,36,60,68,28,0,20,68,108,119,95,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,132,212,220,151,108,92,55,0,20,76,140,124,172,196,148,159,100,76,68,63,47,71,52,0,20,76,119,132,108,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,60,148,220,212,156,124,87,31,0,68,148,148,183,199,175,180,100,87,68,68,68,71,28,20,76,124,143,119,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,68,159,223,212,167,124,68,12,60,135,164,191,199,204,196,108,87,76,76,76,52,20,71,132,159,132,76,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,71,167,228,212,172,111,44,36,124,183,207,212,228,191,127,79,92,79,76,44,71,140,167,140,84,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,15,84,180,223,212,164,92,36,100,180,220,220,231,183,148,84,116,92,84,79,156,196,156,84,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,12,0,20,92,188,220,220,151,68,84,172,239,236,244,204,164,108,124,116,108,156,212,180,95,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,7,15,31,36,23,7,28,100,191,236,212,127,84,148,236,244,252,228,172,143,132,151,164,212,191,108,31,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,20,20,12,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,28,36,44,39,23,36,111,199,239,188,111,135,223,252,252,236,183,172,180,188,207,188,108,31,0,0,0,0,15,20,15,7,0,0,0,0,0,0,0,0,12,20,20,12,7,20,28,44,44,39,36,28,23,20,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,31,20,0,0,0,0,0,12,20,28,28,39,44,52,52,39,52,124,204,228,156,143,196,252,252,236,212,204,220,215,188,108,31,0,0,12,28,28,23,20,12,0,0,0,0,0,20,31,36,36,44,60,63,60,52,52,44,44,36,36,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,39,44,44,44,28,7,0,0,20,28,36,44,68,76,68,60,76,140,212,204,172,188,247,252,236,236,231,236,188,108,31,0,20,39,44,36,28,15,0,0,7,28,44,52,60,76,84,92,87,84,76,63,52,44,44,44,36,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,39,44,47,60,71,76,76,60,36,23,28,39,47,68,92,100,92,111,172,212,207,212,244,252,247,247,236,188,103,44,36,52,52,44,39,28,20,36,60,79,100,116,124,108,103,100,92,76,60,52,47,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,76,84,84,84,84,84,76,76,76,76,100,132,143,164,204,223,236,244,252,252,236,188,116,84,76,76,68,68,71,76,92,111,124,132,132,132,124,116,84,68,60,52,36,23,20,15,12,0,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,84,84,84,87,100,127,143,156,172,196,215,236,252,252,252,244,212,159,132,140,148,148,132,119,119,124,132,140,148,143,135,119,108,92,71,52,44,31,36,44,44,39,28,23,39,52,47,44,44,44,55,60,52,55,52,36,23,28,47,39,28,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,92,100,108,132,172,212,244,247,252,252,252,244,215,196,207,228,212,196,196,204,204,196,188,175,164,148,143,143,148,148,140,140,140,116,108,108,103,100,84,76,76,79,68,60,60,60,60,60,55,55,52,36,23,28,47,39,28,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,12,12,20,20,20,20,20,44,60,76,76,76,76,76,76,76,76,76,76,76,71,68,68,76,76,84,92,92,92,92,92,92,92,92,92,92,92,100,111,132,156,180,199,223,244,252,252,252,252,247,244,244,252,247,247,252,247,231,204,175,156,156,156,159,164,167,164,151,132,116,108,84,76,68,68,71,71,68,63,63,60,60,60,55,52,52,44,44,36,23,12,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,12,12,12,20,23,23,20,20,20,39,60,68,68,68,76,84,92,92,100,103,108,135,159,167,172,172,164,156,164,180,180,175,172,164,164,156,151,151,156,172,188,204,220,236,244,247,252,252,252,252,252,252,252,252,252,247,244,239,220,188,164,124,92,63,44,28,28,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,23,28,36,39,68,92,100,100,100,84,68,68,84,84,79,76,84,100,116,124,127,124,127,148,175,204,220,228,236,252,252,252,252,252,252,252,252,247,244,228,199,164,135,124,108,92,68,52,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,7,0,0,0,12,31,52,60,68,68,68,68,76,100,132,164,172,164,164,183,215,236,244,244,244,252,252,252,252,252,239,212,196,188,188,172,140,108,79,60,52,47,44,36,36,28,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,55,60,60,60,63,68,71,92,116,132,132,116,108,111,135,156,183,215,236,220,215,239,252,252,252,252,252,239,220,191,164,148,148,135,108,68,28,12,20,28,36,36,28,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,44,47,52,52,52,52,55,60,60,60,60,76,92,100,100,100,100,92,95,111,132,164,212,236,196,175,204,244,252,252,252,252,252,252,228,196,164,140,132,143,156,143,116,76,36,12,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,36,39,44,44,44,47,52,52,44,28,15,23,44,68,84,100,100,100,87,63,52,76,108,140,164,199,220,188,140,156,215,228,236,252,252,252,252,252,231,215,196,151,103,92,116,143,164,159,140,100,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,20,23,28,28,36,36,39,44,36,20,0,0,0,20,36,52,60,68,76,92,84,63,31,20,47,100,127,140,156,180,204,183,116,116,167,220,188,212,252,252,252,252,252,236,204,196,188,156,92,52,60,92,135,164,172,156,124,84,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,15,20,20,23,23,20,12,0,0,0,0,0,20,36,44,47,52,55,60,52,39,23,7,0,36,84,124,132,127,132,164,196,175,100,71,135,183,188,143,188,244,236,236,236,236,252,223,188,164,172,156,100,39,20,39,79,124,156,172,159,132,95,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,0,7,0,0,0,0,0,0,0,12,28,36,36,44,44,44,39,20,12,0,0,0,23,68,116,140,124,100,103,148,191,167,95,44,87,180,172,148,127,167,228,220,220,199,220,247,247,212,164,143,156,156,108,44,0,0,28,63,100,140,159,156,116,84,55,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,31,36,36,28,12,0,0,0,0,0,12,47,95,132,132,100,68,87,140,172,148,92,28,44,127,180,148,108,132,156,212,204,204,164,191,228,252,247,207,148,116,148,148,108,44,0,0,0,15,52,79,108,132,132,108,76,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,28,20,12,0,0,0,0,0,0,0,31,79,116,124,108,68,44,79,132,159,127,84,28,20,76,156,140,127,84,116,132,180,196,188,151,148,191,244,252,244,204,132,100,124,132,100,47,15,0,0,0,12,31,60,79,100,108,95,68,44,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,23,23,20,0,0,0,0,0,0,0,0,0,20,55,92,119,108,68,28,20,68,132,148,116,68,28,0,44,108,159,108,100,76,84,100,140,180,180,148,100,156,220,252,252,244,196,119,76,95,116,103,60,20,0,0,0,0,0,28,44,63,76,84,76,52,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,7,0,0,0,0,0,0,0,0,0,0,12,39,71,100,100,79,36,12,15,68,116,119,84,44,20,0,20,76,140,132,87,84,76,52,76,103,148,172,143,71,108,172,244,252,252,244,196,108,60,76,108,100,68,28,0,0,0,0,0,0,15,36,52,60,68,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,60,79,92,76,44,15,0,15,60,108,111,68,28,0,0,0,52,95,135,100,68,71,71,44,76,84,127,172,151,79,55,127,204,236,244,252,244,188,100,52,55,92,92,71,36,12,0,0,0,0,0,0,12,28,44,52,55,55,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,76,52,20,0,0,20,55,92,92,68,36,7,0,0,28,68,116,103,63,60,68,60,44,76,76,100,151,159,92,23,79,156,215,228,244,244,228,164,84,36,44,84,87,71,39,20,0,0,0,0,0,0,0,0,20,36,36,39,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,68,68,52,28,12,0,0,20,52,79,71,47,36,20,0,0,0,52,84,108,76,28,63,68,44,44,76,68,63,108,151,103,20,36,108,180,212,223,231,212,188,135,63,28,36,68,76,68,44,23,0,0,0,0,0,0,0,0,0,12,28,31,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,39,60,68,52,31,12,0,0,0,23,55,68,52,28,20,12,0,0,0,28,63,100,84,55,12,68,68,20,44,68,55,39,71,148,119,28,7,60,132,180,196,212,199,172,151,116,52,20,28,52,68,68,47,28,7,0,0,0,0,0,0,0,0,0,12,20,28,28,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,44,55,52,36,20,0,0,0,0,28,52,60,36,12,12,7,0,0,0,12,52,76,92,68,28,20,63,63,0,44,60,31,20,47,132,127,44,0,20,84,140,172,196,204,172,143,127,100,44,12,20,44,60,60,47,28,12,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,44,36,20,7,0,0,0,0,28,52,52,28,0,0,0,0,0,0,0,36,60,79,68,52,0,44,63,55,0,44,60,15,0,20,103,124,60,0,0,39,100,148,172,191,180,140,116,108,92,44,12,12,36,47,44,39,23,7,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,31,28,28,20,12,0,0,0,0,0,28,52,44,20,0,0,0,0,0,0,0,12,52,60,76,63,28,0,55,60,36,0,47,60,20,7,0,76,116,76,7,0,12,68,124,143,172,183,148,111,100,100,84,36,0,7,20,31,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,20,12,0,0,0,0,0,0,7,28,52,36,15,0,0,0,0,0,0,0,0,36,52,68,63,55,0,0,60,60,12,0,52,60,23,15,0,60,103,84,23,0,0,36,92,124,143,172,164,116,84,87,87,76,28,0,0,12,20,15,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,7,0,0,0,0,0,0,12,31,52,31,12,0,0,0,0,0,0,0,0,20,52,52,68,60,31,0,20,60,60,0,0,52,60,23,20,0,44,84,92,31,0,0,7,60,103,116,148,164,140,87,68,76,76,63,23,0,0,0,0,7,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,28,7,0,0,0,0,0,0,0,0,0,36,47,52,60,52,0,0,36,55,52,0,0,52,52,12,12,0,20,68,84,28,0,0,0,28,76,108,111,148,156,108,68,60,68,71,60,23,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,39,23,0,0,0,0,0,0,0,0,0,0,20,44,39,52,55,36,0,0,52,52,36,0,0,52,52,0,0,0,0,55,76,28,0,0,0,0,47,92,92,116,140,132,76,52,52,68,68,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,36,20,0,0,0,0,0,0,0,0,0,0,0,36,44,36,52,52,12,0,0,52,52,12,0,0,52,52,0,0,0,0,52,68,44,7,0,0,0,28,68,92,84,119,132,100,60,44,44,63,47,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,0,0,0,0,0,0,0,0,0,0,0,20,39,28,44,52,36,0,0,12,52,52,0,0,0,52,52,0,0,0,0,44,60,52,0,0,0,0,0,44,76,76,92,116,111,68,36,28,36,44,28,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,20,12,0,0,0,0,0,0,0,0,0,0,0,7,36,36,28,52,52,12,0,0,36,47,44,0,0,0,47,47,0,0,0,0,28,52,52,0,0,0,0,0,20,52,79,68,87,108,87,44,28,28,36,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,20,31,47,36,0,0,0,44,47,28,0,0,0,44,44,0,0,0,0,7,47,47,0,0,0,0,0,0,36,63,68,68,84,92,63,36,20,20,36,52,44,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,31,15,44,44,15,0,0,0,44,44,12,0,0,0,44,44,0,0,0,0,0,44,44,12,0,0,0,0,0,15,44,68,52,63,76,76,39,20,20,28,31,44,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,31,15,23,44,36,0,0,0,12,44,44,0,0,0,0,44,44,0,0,0,0,0,44,44,28,0,0,0,0,0,0,36,52,60,52,60,71,55,28,20,12,20,28,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,7,39,44,20,0,0,0,28,39,36,0,0,0,0,44,44,0,0,0,0,0,28,44,39,0,0,0,0,0,0,12,36,60,44,52,60,68,44,20,12,12,15,15,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,20,39,36,0,0,0,0,36,39,28,0,0,0,0,39,39,0,0,0,0,0,12,39,39,0,0,0,0,0,0,0,28,44,52,36,44,52,52,20,7,0,0,0,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,31,36,20,0,0,0,0,36,36,12,0,0,0,0,36,36,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,12,36,52,39,36,39,44,31,12,0,0,0,15,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,12,36,31,0,0,0,0,12,36,36,0,0,0,0,0,28,28,0,0,0,0,0,0,36,36,20,0,0,0,0,0,0,0,20,36,44,28,36,36,36,15,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,28,36,20,0,0,0,0,15,28,28,0,0,0,0,0,12,12,0,0,0,0,0,0,28,36,28,0,0,0,0,0,0,0,12,28,44,36,31,31,36,28,7,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,12,31,31,0,0,0,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,31,0,0,0,0,0,0,0,0,20,28,36,23,28,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,20,28,20,0,0,0,0,0,23,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,23,31,28,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,12,23,28,15,15,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,20,0,0,0,0,0,12,20,20,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,20,20,20,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,12,20,20,15,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,12,15,12,7,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,15,20,20,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_2[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,7,7,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,7,23,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,7,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,12,12,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,12,12,0,0,0,0,20,23,20,0,0,0,0,12,12,0,0,7,7,0,0,0,0,0,0,0,15,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,12,15,12,0,0,0,15,23,23,0,0,0,0,28,28,0,0,20,20,0,0,0,0,0,0,0,28,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,20,20,0,0,0,12,23,23,0,0,0,0,36,36,0,20,28,28,0,0,0,0,12,12,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,7,0,0,0,0,28,28,12,0,0,0,28,28,0,0,0,0,36,36,0,20,20,20,0,0,0,7,12,12,28,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,20,0,0,0,0,20,28,23,0,0,0,28,28,12,0,0,0,36,36,0,23,28,20,0,0,0,20,20,20,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,36,12,0,0,0,0,28,28,0,0,0,36,36,28,0,0,0,36,36,0,36,36,23,0,0,0,15,15,28,39,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,28,36,20,0,0,28,44,44,0,0,0,36,36,0,36,36,12,0,0,0,12,12,36,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,28,39,20,0,0,0,20,36,31,0,0,20,44,52,12,0,0,36,36,0,36,36,0,0,0,12,20,28,44,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,0,0,12,44,39,12,0,0,0,36,36,12,0,0,44,52,12,0,0,36,36,0,39,39,0,0,0,20,20,39,44,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,28,44,28,0,0,0,36,39,28,0,0,44,60,28,0,0,36,36,7,44,44,0,0,7,31,36,52,47,20,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,12,44,44,20,0,0,20,44,39,0,0,44,71,55,12,0,44,44,20,44,44,0,0,20,36,55,52,47,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,20,36,20,0,0,0,28,52,39,0,0,0,44,44,15,0,39,68,68,15,0,52,52,31,44,44,0,0,36,36,68,52,31,0,0,12,12,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,12,0,0,0,0,0,0,0,0,0,28,39,20,0,0,0,44,52,28,0,0,31,44,36,0,28,68,76,20,0,60,60,44,52,52,0,0,36,52,60,52,12,0,12,20,12,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,7,31,39,20,0,0,20,52,47,12,0,12,52,47,0,12,76,92,44,0,60,60,47,52,47,0,23,44,76,52,44,0,0,28,28,7,0,0,0,0,0,0,0,0,20,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,23,12,0,0,0,0,0,0,0,12,36,44,20,0,0,36,55,36,0,0,47,52,23,0,68,100,60,0,60,60,52,60,36,7,44,52,84,55,23,0,20,28,20,0,0,0,0,0,0,0,7,28,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,31,20,0,0,0,0,0,0,0,20,44,44,15,0,15,52,55,20,0,31,52,44,0,60,108,84,0,60,60,52,68,36,20,52,76,71,55,0,12,36,31,0,0,0,0,0,0,0,12,28,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,28,7,0,0,0,0,0,0,31,52,39,12,0,36,60,44,0,12,55,55,12,52,116,108,23,60,63,55,76,31,39,60,100,60,44,0,28,36,20,0,0,0,0,0,0,12,36,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,36,15,0,0,0,0,12,28,52,60,36,7,12,52,60,28,0,52,60,36,36,124,127,44,60,76,60,84,36,60,79,108,60,15,20,44,36,0,0,0,0,0,0,20,39,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,44,28,0,0,0,12,23,44,55,60,36,0,28,68,55,12,28,60,55,20,116,140,68,60,87,68,92,52,79,103,92,55,12,39,44,15,0,0,0,0,0,20,44,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,52,36,12,0,0,12,28,52,68,60,31,7,52,68,39,12,60,60,28,100,135,84,68,108,87,108,87,100,124,76,36,36,52,31,0,0,0,0,0,28,52,47,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,44,23,0,0,12,36,63,76,60,28,23,68,68,20,52,63,47,84,135,100,79,124,108,132,116,124,124,68,39,60,52,12,0,0,0,0,28,55,52,20,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,60,36,12,0,15,44,76,87,60,28,44,76,52,31,68,63,76,132,116,92,132,116,148,135,156,108,63,60,76,36,0,0,0,0,36,60,52,20,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,52,60,47,20,0,20,52,87,100,60,36,68,76,39,68,68,76,132,124,108,143,124,164,143,164,87,68,84,60,7,0,0,12,39,68,52,20,0,7,12,20,12,0,7,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,63,60,31,7,20,60,100,108,52,52,76,63,60,71,87,124,127,124,156,135,188,175,156,95,84,84,36,0,0,12,44,71,52,20,0,20,31,28,15,12,12,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,28,20,20,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,60,68,44,20,28,76,111,108,60,71,79,68,76,84,124,124,140,172,167,212,204,140,111,108,76,12,0,15,52,76,52,20,12,28,36,36,28,23,23,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,23,36,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,28,55,76,60,36,36,87,124,111,76,84,79,100,84,140,124,156,188,196,236,199,140,124,108,44,0,20,55,79,60,28,28,44,44,39,36,31,28,23,12,0,0,0,7,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,36,39,44,36,15,0,0,0,0,0,0,0,0,0,0,15,47,76,71,44,47,100,140,116,100,92,124,103,156,132,172,199,223,244,188,156,132,92,20,28,60,100,68,52,47,52,52,52,44,36,31,20,0,0,12,23,28,23,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,12,0,7,20,36,39,44,44,44,47,39,20,0,0,0,0,0,0,0,0,0,36,68,84,63,68,119,156,132,116,132,148,172,172,204,220,236,228,188,164,140,60,36,76,108,100,68,63,68,68,60,44,36,28,12,12,28,36,36,31,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,20,20,20,28,28,28,36,44,47,52,52,52,47,28,7,0,0,0,0,0,0,28,60,84,79,92,140,159,148,135,172,196,220,236,244,247,220,204,172,116,68,92,124,124,100,92,92,87,63,47,36,28,31,44,44,36,36,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,28,28,36,44,52,52,47,39,44,52,60,60,55,55,60,60,55,36,12,0,0,0,0,12,52,84,92,111,156,172,164,183,215,244,252,252,252,228,212,156,108,119,159,156,124,124,124,100,68,55,52,52,52,47,44,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,12,20,20,15,28,44,55,60,68,68,84,79,84,84,92,92,79,68,63,68,60,44,20,0,0,0,36,76,103,132,172,188,204,228,252,252,252,252,236,196,148,148,196,196,172,156,132,116,103,92,68,52,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,7,20,20,20,28,52,52,52,60,76,92,92,100,108,108,111,124,132,132,119,100,84,76,68,52,28,7,28,63,108,156,196,223,239,252,252,252,252,231,191,180,212,236,212,180,156,148,124,84,63,60,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,7,20,20,15,20,36,28,28,36,52,76,84,108,127,148,156,156,140,132,132,151,167,164,143,124,108,92,68,52,68,108,172,228,247,252,252,252,252,228,215,228,252,252,228,204,172,124,84,76,55,36,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,44,44,44,47,52,63,84,108,132,156,172,180,188,196,204,212,212,196,167,135,111,116,156,207,244,252,252,252,252,244,244,252,252,244,215,180,159,132,84,55,36,28,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,28,44,52,44,20,20,44,60,60,60,60,60,68,84,95,100,100,100,108,116,132,156,180,196,204,223,244,247,236,204,180,180,212,244,252,252,252,252,252,252,252,252,239,207,156,111,68,47,44,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,28,44,52,44,20,20,44,60,60,68,68,60,68,68,71,68,68,76,76,92,103,116,132,159,196,231,244,252,252,252,252,244,244,247,252,252,252,252,252,252,252,252,236,204,172,140,103,76,68,60,60,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,68,76,100,111,132,140,140,143,156,180,204,215,236,252,252,252,252,252,252,252,252,252,252,252,252,252,252,239,215,188,159,148,132,116,100,87,68,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,44,55,76,79,95,103,116,140,159,172,172,172,199,228,239,239,244,252,252,252,252,252,252,252,252,244,236,231,223,196,156,127,100,92,87,84,84,84,76,63,47,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,44,68,84,84,92,92,87,84,100,132,164,183,172,180,207,239,252,252,252,252,252,252,252,252,244,231,212,196,188,188,188,172,156,140,111,92,84,84,84,84,84,79,79,76,71,60,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,23,28,36,44,52,63,84,111,132,140,127,116,116,132,156,196,236,252,252,252,252,252,252,252,252,247,236,207,183,164,156,159,156,148,116,100,95,95,92,79,76,79,79,79,79,79,79,76,76,76,71,55,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,20,23,28,36,36,47,71,95,108,108,108,100,100,100,116,164,220,247,252,252,252,252,252,239,239,244,252,252,239,196,143,124,116,111,124,135,140,124,95,71,63,60,47,36,28,36,52,68,76,76,76,71,60,60,55,36,28,31,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,12,12,0,0,20,52,79,100,108,100,79,60,60,76,111,140,188,223,247,239,239,252,252,252,228,215,220,236,236,239,228,196,148,100,84,79,71,76,92,116,124,108,84,63,60,55,47,28,12,0,0,12,23,36,47,52,36,28,31,20,12,20,12,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,47,63,76,84,84,60,28,31,60,79,108,124,156,196,236,228,220,228,252,252,252,228,188,172,199,204,204,220,204,188,156,108,79,60,44,47,60,63,71,92,108,92,68,55,52,52,47,36,20,0,0,0,0,0,0,12,12,12,20,12,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,52,60,60,52,28,7,12,44,68,79,100,108,132,172,220,231,196,196,223,244,252,252,244,180,143,143,156,164,172,196,183,164,140,116,84,68,47,23,23,44,55,55,60,68,84,76,60,52,44,44,44,39,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,47,47,36,15,0,0,28,52,68,71,84,92,108,148,204,244,204,172,180,220,220,239,252,244,188,124,100,132,127,140,140,164,164,148,124,108,92,71,63,36,12,0,28,44,52,52,47,52,60,60,52,44,44,39,36,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,36,44,39,20,0,0,0,12,39,60,63,60,68,84,95,116,180,236,228,156,156,180,191,172,220,244,236,196,116,84,100,116,108,116,124,140,135,127,108,95,84,71,68,55,31,0,0,7,28,44,44,44,39,39,39,39,36,36,36,36,36,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,31,36,36,23,12,0,0,0,0,23,52,60,52,47,60,84,84,92,140,204,228,175,127,164,183,156,132,199,231,212,188,116,71,60,95,95,92,100,108,116,108,108,100,84,71,63,63,60,52,23,0,0,0,12,28,39,36,36,36,31,23,20,28,31,31,28,28,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,28,28,28,12,0,0,0,0,0,12,36,52,55,36,36,52,84,60,60,100,172,212,196,124,116,183,159,119,116,196,212,180,172,116,60,39,68,87,84,76,92,92,100,84,84,76,84,63,52,52,60,60,44,20,0,0,0,0,12,28,36,31,28,28,20,7,7,15,23,20,20,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,23,15,0,0,0,0,0,0,0,23,44,52,44,23,28,55,76,52,31,60,124,175,196,140,76,127,188,124,84,108,188,204,172,172,116,63,44,28,68,76,76,63,84,84,84,68,60,60,84,68,44,39,52,55,52,36,12,0,0,0,0,0,12,28,28,20,12,15,12,7,0,0,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,12,28,44,44,28,12,28,60,76,44,20,39,92,135,180,164,87,68,156,172,84,63,103,172,188,164,180,108,79,44,20,36,63,68,60,52,71,68,76,63,44,47,71,76,52,28,31,52,52,44,28,0,0,0,0,0,0,0,0,12,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,36,15,0,31,63,68,36,12,31,79,108,156,175,116,39,84,172,143,52,55,100,156,175,164,172,103,87,36,15,12,36,63,63,47,52,60,63,68,60,36,31,60,76,60,28,15,36,44,44,36,20,0,0,0,0,0,0,0,0,12,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,20,0,0,36,68,60,31,0,28,60,84,124,172,148,60,28,116,175,116,28,52,100,151,164,164,156,108,84,36,20,0,0,36,68,52,36,52,52,52,60,60,31,20,44,68,60,28,0,12,36,44,39,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,23,12,0,12,36,68,55,28,0,20,52,68,87,143,164,92,12,44,140,159,76,20,52,100,148,156,156,148,119,60,44,28,0,0,0,44,60,36,28,52,44,44,52,60,31,12,28,52,52,28,12,0,15,36,36,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,12,39,63,47,20,0,12,44,60,63,103,156,116,36,0,79,164,140,44,31,47,100,148,148,148,143,132,44,60,28,0,0,0,15,52,55,28,23,44,36,39,47,60,36,7,15,36,44,31,12,0,0,20,31,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,7,0,0,0,15,44,60,39,12,0,12,36,52,52,76,140,132,60,0,20,108,164,100,15,39,44,92,143,140,132,140,127,47,60,23,15,0,0,0,28,52,44,15,20,44,36,28,44,60,36,7,0,20,36,28,15,0,0,0,20,28,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,20,44,55,36,7,0,0,28,52,36,44,108,140,87,20,0,55,132,148,60,0,44,44,79,140,140,111,135,119,60,44,20,15,0,0,0,0,31,52,31,7,23,44,28,23,36,55,36,12,0,12,28,28,20,0,0,0,0,20,28,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,20,44,52,28,0,0,0,23,44,31,36,79,132,108,44,0,0,84,148,116,36,0,44,44,68,140,140,100,132,119,76,36,20,7,0,0,0,0,12,39,47,20,0,20,36,20,20,36,52,36,12,0,0,20,28,20,0,0,0,0,7,20,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,47,44,23,0,0,0,20,39,31,15,39,103,124,63,7,0,20,100,143,76,15,0,28,28,52,132,135,92,119,124,84,28,28,0,0,0,0,0,0,20,44,39,12,0,20,36,20,12,28,47,36,12,0,0,12,15,12,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,39,20,0,0,0,12,36,31,15,20,71,108,84,23,0,0,52,108,124,44,0,0,28,28,39,124,132,84,100,124,79,20,20,0,0,0,0,0,0,0,23,44,28,0,0,20,23,7,0,28,44,36,12,0,0,0,7,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,36,12,0,0,0,0,20,28,15,12,44,92,92,44,0,0,0,71,116,92,28,0,12,36,36,36,116,124,68,76,116,68,20,20,0,0,0,0,0,0,0,0,28,39,20,0,0,12,7,0,0,20,39,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,28,12,0,0,0,0,12,23,12,0,20,68,100,68,12,0,0,20,84,116,55,12,0,15,23,23,36,116,119,52,60,111,60,20,12,0,0,0,0,0,0,0,0,12,36,36,12,0,0,0,0,0,0,20,36,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,20,0,0,0,0,0,15,20,7,0,0,39,84,79,28,0,0,0,44,84,100,36,0,0,20,20,20,36,108,116,44,47,108,63,36,12,12,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,7,0,0,15,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,20,0,0,0,0,0,0,20,12,0,0,12,63,84,52,0,0,0,0,60,92,68,23,0,0,20,20,12,20,84,103,39,44,95,68,36,7,7,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,12,7,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,44,84,68,15,0,0,0,15,60,84,39,12,0,0,20,20,0,0,52,92,39,44,76,68,36,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,0,0,0,0,0,0,0,0,0,0,0,20,68,79,36,0,0,0,0,31,55,68,20,0,0,0,0,0,0,0,39,79,36,31,52,60,28,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,44,76,52,0,0,0,0,0,39,55,44,12,0,0,0,0,0,0,0,36,76,36,28,36,55,23,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,63,20,0,0,0,0,7,36,52,15,0,0,0,0,7,7,0,0,36,68,28,20,36,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,52,63,36,0,0,0,0,0,20,36,39,7,0,0,0,0,0,0,0,12,47,68,28,7,36,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,44,0,0,0,0,0,0,31,39,28,7,0,0,0,0,0,0,0,15,52,68,28,0,20,36,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,47,52,20,0,0,0,0,0,12,31,36,0,0,0,0,0,0,0,0,0,12,52,63,28,0,15,28,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,47,28,0,0,0,0,0,0,20,28,23,0,0,0,0,0,0,0,0,0,12,47,47,12,0,20,23,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,36,7,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,44,36,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,12,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,15,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_3[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,28,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,20,7,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,0,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,20,20,15,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,31,28,28,20,20,12,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,31,44,28,23,15,7,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,36,36,44,36,31,20,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,12,12,0,0,0,0,0,0,0,0,0,7,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,52,39,52,44,39,28,12,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,12,12,20,12,12,12,0,0,0,0,0,0,12,0,0,0,39,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,52,55,52,52,44,36,20,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,12,20,20,20,20,12,0,0,0,0,0,12,12,0,0,39,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,55,60,52,44,28,7,12,23,15,0,0,0,0,0,0,0,7,12,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,12,0,0,0,0,0,0,0,0,0,0,7,7,0,0,28,36,20,15,28,28,20,20,0,0,0,0,12,15,20,12,0,44,44,23,28,23,0,0,0,0,0,0,0,0,0,0,0,44,68,71,63,60,55,36,12,15,28,20,0,0,0,0,0,0,0,7,20,15,20,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,15,0,0,0,0,0,0,0,0,0,7,12,12,0,15,36,36,20,28,28,31,23,12,0,0,0,0,12,28,12,0,44,44,36,44,44,0,0,0,0,0,0,0,0,0,0,20,60,87,71,71,60,47,28,20,36,36,12,0,0,0,0,0,0,0,12,20,23,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,20,36,39,23,0,0,0,0,0,0,0,0,0,7,20,12,7,20,44,31,23,31,36,28,28,0,0,0,0,20,36,15,0,44,44,44,47,44,0,0,0,0,0,0,0,0,0,0,47,79,92,79,76,60,36,28,44,44,20,0,0,0,0,0,0,15,15,15,23,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,0,0,15,36,44,28,12,0,0,0,0,0,0,0,0,15,28,28,12,36,44,31,31,36,44,28,12,0,0,0,20,44,31,12,44,47,52,52,39,0,0,0,0,0,0,0,0,0,28,68,100,84,84,68,52,36,44,52,23,0,0,0,0,0,0,20,31,28,31,36,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,12,31,47,36,20,0,0,0,0,0,0,0,12,36,44,31,28,44,44,36,36,47,36,28,0,0,0,20,44,44,23,44,52,60,52,36,0,0,0,0,0,0,0,0,0,60,100,108,92,87,60,44,44,60,31,0,0,0,0,0,0,20,28,39,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,15,0,0,0,0,0,28,47,44,23,0,0,0,0,0,0,0,15,47,60,36,36,52,47,47,52,55,36,12,0,0,12,44,60,31,36,52,68,47,28,0,0,0,0,0,0,0,0,28,92,124,108,100,79,52,55,60,44,12,0,0,0,0,12,23,36,36,44,36,20,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,12,0,0,0,0,23,47,52,31,7,0,0,0,0,0,0,23,60,60,36,47,60,60,52,60,44,31,0,0,7,39,71,36,36,52,71,47,28,0,0,0,0,0,0,0,0,68,116,132,116,100,76,68,68,52,20,0,0,0,0,20,36,47,47,44,31,15,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,15,28,28,23,12,0,0,0,20,44,55,39,20,0,0,0,0,0,0,36,68,60,44,55,68,68,60,68,44,15,0,0,36,76,47,36,52,76,52,28,0,0,0,0,0,0,0,31,100,148,132,116,92,76,79,68,28,0,0,0,0,23,44,60,60,47,28,12,0,0,7,15,12,7,12,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,20,7,0,0,0,12,20,31,36,20,7,0,0,12,36,60,52,23,0,0,0,0,0,12,44,76,63,52,60,79,76,84,55,36,0,0,39,84,68,47,60,84,60,28,0,0,0,0,0,0,0,71,132,151,132,108,87,92,84,36,0,0,0,7,28,52,63,63,47,28,0,0,0,15,20,20,20,20,23,28,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,20,12,0,0,0,15,31,36,36,20,0,0,0,31,60,60,36,0,0,0,0,0,15,60,87,68,63,79,95,84,79,47,12,0,39,92,84,52,60,92,60,28,0,0,0,0,0,0,36,108,167,159,132,108,103,92,52,7,0,0,12,36,63,68,68,44,20,0,0,20,28,28,28,28,28,36,39,31,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,28,28,15,0,0,7,23,36,44,36,15,0,0,28,52,68,44,23,20,15,0,0,23,76,95,84,79,103,103,100,68,36,0,28,87,95,60,60,92,60,28,0,0,0,7,12,15,76,148,180,156,124,116,108,63,15,0,0,15,39,76,76,68,44,20,0,12,28,36,36,36,36,39,47,44,28,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,20,0,0,12,31,44,44,28,12,0,20,47,68,60,44,28,20,7,0,36,92,100,87,92,119,108,100,55,12,20,79,108,68,63,100,63,28,0,0,0,12,15,39,119,191,188,148,135,124,84,23,0,0,20,52,84,84,68,36,12,7,28,44,44,52,44,44,55,52,36,20,12,7,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,36,36,20,0,0,20,44,47,44,23,0,12,44,68,68,52,31,20,0,0,52,108,111,103,119,132,124,79,36,20,84,124,84,76,108,63,20,0,0,12,20,31,84,172,220,188,156,148,108,36,0,0,28,63,92,92,68,31,12,20,39,47,60,55,60,63,63,44,28,20,12,20,20,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,39,28,7,12,31,47,52,44,20,7,36,68,76,60,44,23,15,12,68,119,124,116,148,148,124,60,28,76,148,108,95,108,60,20,0,0,28,28,60,140,220,215,183,159,124,55,0,0,36,76,100,100,60,28,20,36,52,60,68,71,71,76,55,36,23,20,23,23,20,20,12,0,0,7,12,15,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,44,28,12,20,44,52,52,36,15,28,60,76,71,60,39,20,20,84,132,132,143,172,164,92,44,68,156,132,116,116,63,28,7,12,31,44,100,191,239,212,180,140,71,12,12,44,92,111,100,52,28,28,52,68,76,84,84,87,68,44,31,31,31,28,28,23,12,0,12,20,20,20,15,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,52,36,23,28,52,60,52,31,28,52,84,87,76,52,23,36,95,140,148,188,199,148,68,60,148,148,140,124,68,36,20,31,36,79,143,228,239,212,164,87,20,12,52,108,119,95,47,36,44,68,84,100,100,100,76,60,44,44,36,36,31,28,12,12,23,28,28,23,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,12,36,52,52,52,39,36,44,60,63,52,36,47,76,100,92,63,36,52,108,148,180,204,196,108,76,132,172,159,140,84,39,20,44,55,119,196,244,236,188,108,31,20,68,124,124,92,52,47,68,92,111,116,108,92,71,60,52,39,36,36,28,23,28,36,36,28,28,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,23,20,0,0,0,12,36,52,52,60,52,52,55,68,63,52,52,71,103,103,84,44,68,119,167,204,215,167,95,124,172,180,164,108,44,44,47,95,156,236,244,212,124,47,31,92,140,132,87,60,63,92,124,135,132,116,100,76,60,44,44,39,36,36,36,36,36,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,20,28,28,28,28,20,7,0,12,36,55,60,60,60,63,68,68,68,68,76,108,124,108,63,84,140,196,223,220,132,124,167,196,196,140,60,76,68,140,196,252,228,156,68,47,108,156,140,92,76,92,132,159,159,140,132,108,84,55,47,52,55,52,44,44,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,36,39,44,39,28,12,12,36,60,60,63,76,84,79,76,76,84,119,148,135,92,100,172,220,239,183,148,164,212,215,156,63,100,108,180,236,239,180,87,63,119,164,148,108,100,132,172,188,188,172,140,100,68,68,71,68,52,52,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,47,55,60,52,47,31,20,36,60,68,76,95,100,87,87,100,132,164,156,116,132,196,239,228,167,172,212,228,159,84,116,164,212,244,196,116,84,132,172,164,132,140,175,196,207,204,172,119,92,92,87,68,52,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,60,76,79,84,60,44,52,68,71,84,111,116,100,116,148,175,164,140,164,215,247,196,188,199,236,172,124,140,204,236,212,140,108,140,180,175,172,188,212,231,220,188,148,124,116,92,68,55,52,47,28,0,0,0,0,0,12,12,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,52,76,95,95,100,100,84,79,84,92,111,132,132,132,156,188,172,164,191,231,223,212,212,247,196,172,188,236,223,172,135,159,196,196,196,220,244,239,220,188,156,124,92,68,60,52,36,12,0,15,28,39,44,39,39,36,36,28,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,7,7,0,0,12,12,12,20,44,63,84,100,108,108,108,108,124,132,127,143,159,164,175,196,196,196,228,247,231,231,252,228,223,228,236,199,172,188,220,215,220,236,252,244,228,188,132,92,68,60,44,36,36,55,71,84,87,84,76,68,52,44,36,28,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,12,20,20,20,44,39,36,39,36,28,39,60,92,124,132,124,119,132,156,180,196,204,207,212,228,228,236,252,247,247,252,244,244,247,231,204,212,236,239,239,252,247,228,188,140,103,84,84,76,84,92,100,100,100,95,92,92,84,68,52,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,20,31,28,28,47,60,68,84,87,92,92,95,111,135,156,167,175,199,220,236,236,244,247,252,252,252,252,252,252,252,252,236,236,244,252,252,236,212,188,164,148,132,116,103,100,100,100,100,100,100,87,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,28,36,44,44,44,52,71,92,103,108,116,140,175,204,220,236,244,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,239,220,196,164,132,108,100,100,100,100,87,71,52,31,12,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,12,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,15,15,15,15,15,15,15,15,15,15,15,12,0,0,0,0,0,0,0,7,20,36,52,60,60,68,79,108,132,148,156,188,228,252,252,252,252,252,252,252,252,252,252,252,252,252,252,236,212,172,143,132,135,132,116,100,84,68,60,60,63,68,63,68,68,63,63,63,60,31,28,36,36,36,36,36,28,28,20,12,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,23,28,36,36,36,36,36,44,44,44,36,36,39,44,47,47,47,52,55,60,60,60,63,71,84,100,116,132,156,183,212,231,236,244,252,252,252,252,252,252,252,252,252,252,252,236,220,204,188,164,151,148,132,124,124,119,100,84,76,68,68,68,68,63,63,63,60,31,28,36,36,36,36,36,28,28,20,12,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,15,15,20,23,28,28,28,28,36,39,44,44,44,44,52,52,52,52,60,68,84,100,116,132,156,175,196,212,228,244,252,252,252,252,252,252,252,252,252,236,223,220,228,244,228,191,156,148,132,124,116,116,100,76,68,63,60,52,52,52,44,44,44,36,15,12,28,36,28,28,28,28,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,36,52,60,76,92,111,127,148,164,175,180,180,199,231,252,252,252,252,252,252,252,252,247,231,199,183,180,172,159,140,116,95,100,100,92,84,76,60,52,55,60,52,52,52,52,44,44,44,36,15,12,28,36,28,28,28,28,23,20,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,47,52,52,68,87,108,124,156,183,204,207,199,183,175,183,204,220,244,252,244,239,239,252,252,252,252,247,231,196,140,108,103,116,116,92,68,60,52,52,47,44,44,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,12,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,36,36,36,39,44,52,71,92,108,111,124,143,159,159,164,159,143,132,132,148,156,172,196,228,247,244,207,204,228,236,236,252,252,252,247,220,172,132,100,76,71,68,63,52,44,39,44,44,44,36,28,23,20,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,12,20,20,20,20,44,60,76,87,92,92,92,95,100,100,103,108,103,92,84,84,92,100,100,124,164,196,220,244,236,188,156,180,220,204,204,247,244,244,252,252,231,180,116,68,60,60,63,60,60,52,28,0,0,0,12,20,20,15,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,15,12,20,36,52,52,52,60,47,47,52,68,68,76,76,76,60,47,44,44,47,60,68,76,100,140,156,164,188,215,220,172,116,140,204,212,172,180,244,220,212,228,231,239,236,196,135,68,28,28,47,60,55,52,52,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,28,28,23,28,36,36,44,52,55,60,47,39,20,23,28,31,20,12,36,55,63,68,84,108,116,108,124,156,196,199,156,87,84,164,223,167,140,172,236,188,172,180,196,215,228,236,196,148,92,44,0,7,28,47,52,44,44,39,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,20,20,20,20,23,28,36,31,20,15,12,20,12,20,7,0,0,20,44,60,60,63,76,84,84,76,95,116,132,164,172,132,63,47,116,196,204,116,108,180,204,156,135,132,167,172,204,228,223,183,148,103,60,15,0,0,12,31,44,44,36,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,20,20,12,12,0,0,0,0,0,12,0,0,0,0,0,28,44,52,55,60,60,63,60,60,76,84,100,116,148,140,100,44,28,76,156,220,164,63,92,196,180,140,103,108,140,140,156,196,228,212,164,132,100,68,28,0,0,0,0,15,31,36,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,47,52,52,52,44,44,52,55,63,68,68,84,108,127,116,76,28,7,36,108,191,212,119,28,100,196,156,124,84,108,100,127,124,148,196,231,188,132,100,92,68,36,12,0,0,0,0,0,15,28,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,47,44,28,28,39,47,52,55,52,52,76,100,108,100,60,20,0,12,60,148,220,175,76,15,108,196,140,92,79,92,71,108,108,116,135,188,199,132,79,68,68,60,44,20,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,44,44,36,15,15,31,44,44,44,36,28,52,68,92,92,84,44,12,0,0,28,92,172,212,127,31,20,116,180,108,60,76,68,63,76,100,100,103,124,164,156,100,60,44,47,52,44,20,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,36,36,20,0,12,28,36,36,39,28,20,20,52,63,79,76,68,28,7,0,0,7,52,119,183,164,84,0,31,116,180,84,28,63,55,55,60,79,87,100,87,108,140,132,84,44,20,28,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,28,31,36,28,12,0,7,20,31,36,36,20,12,0,20,39,60,68,63,47,23,0,0,0,0,20,76,140,172,119,44,0,44,119,172,71,20,52,52,47,52,60,76,92,87,71,108,132,124,76,36,0,7,20,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,15,0,0,0,15,28,28,31,20,0,0,0,20,36,47,55,52,36,15,0,0,0,0,0,47,108,148,143,84,12,0,52,116,164,60,7,28,52,47,28,60,60,68,100,76,60,108,124,116,60,20,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,23,20,7,0,0,0,12,20,23,23,15,0,0,0,0,20,36,47,36,28,15,12,0,0,0,0,0,28,76,116,143,116,52,0,0,60,100,140,60,0,0,44,44,15,52,55,44,79,92,55,55,108,116,100,52,12,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,0,0,0,0,0,7,12,15,20,15,0,0,0,0,0,20,36,44,36,20,0,0,0,0,0,0,0,7,52,92,108,124,84,15,0,0,63,76,100,55,0,0,44,44,23,28,52,44,44,92,76,39,60,108,108,92,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,20,36,31,20,12,12,0,0,0,0,0,0,0,36,68,84,103,100,60,0,0,0,60,60,68,52,0,0,28,39,36,0,44,44,28,60,92,60,28,63,103,100,84,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,7,20,31,23,7,0,0,0,0,0,0,0,0,0,15,52,76,68,100,84,23,0,0,0,60,60,52,47,0,0,12,36,36,0,28,44,36,20,76,87,39,28,60,92,84,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,0,0,0,36,60,52,68,87,63,0,0,0,7,60,60,44,47,0,0,0,31,31,7,0,39,39,12,39,84,71,20,23,60,84,68,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,12,0,0,0,0,0,0,0,0,0,0,0,20,52,47,28,76,79,36,0,0,0,20,60,60,44,44,0,0,0,28,28,20,0,23,36,28,0,52,76,47,7,28,60,68,52,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,39,52,23,36,76,68,0,0,0,0,28,55,60,36,39,0,0,0,15,20,20,0,7,36,36,7,15,60,68,31,0,23,52,55,47,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,36,7,63,76,44,0,0,0,0,39,52,52,28,36,0,0,0,0,20,20,0,0,20,28,20,0,28,60,52,15,0,20,44,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,44,15,28,76,68,12,0,0,0,0,44,52,44,28,36,0,0,0,0,12,12,0,0,0,28,28,0,0,28,52,36,0,0,20,44,39,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,55,76,47,0,0,0,0,0,47,47,31,28,36,0,0,0,0,12,12,12,0,0,15,20,12,0,0,36,44,20,0,0,20,39,36,28,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,7,20,68,68,20,0,0,0,0,0,44,44,20,23,28,0,0,0,0,0,0,0,0,0,0,20,20,0,0,12,39,39,12,0,0,20,36,28,28,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,0,44,68,52,0,0,0,0,0,0,44,44,7,20,23,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,20,44,28,0,0,0,20,36,28,23,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,0,12,68,68,28,0,0,0,0,0,0,44,44,0,15,20,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,28,36,20,0,0,0,20,23,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,36,68,60,0,0,0,0,0,0,0,39,39,0,15,20,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,12,31,31,12,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,20,0,0,60,68,31,0,0,0,0,0,0,15,36,36,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,20,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,28,63,60,0,0,0,0,0,0,0,28,36,36,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,44,60,36,0,0,0,0,0,0,0,28,28,28,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,7,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,12,47,47,12,0,0,0,0,0,0,0,28,28,20,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,31,44,28,0,0,0,0,0,0,0,0,31,31,20,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,7,36,36,7,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,23,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,0,0,0,7,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_4[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,20,23,12,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,15,0,31,31,7,0,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,36,36,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,20,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,12,23,36,36,0,0,0,28,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,28,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,36,36,28,0,0,7,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,28,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,23,0,39,39,12,0,0,23,36,28,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,44,44,0,0,0,36,36,12,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,39,31,28,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,12,36,36,28,44,44,0,0,20,44,36,0,0,0,0,7,12,12,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,20,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,44,44,36,20,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,20,28,28,44,44,31,0,0,39,44,20,0,0,0,0,20,20,7,0,0,7,20,20,12,0,0,0,0,0,0,0,0,12,28,36,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,52,47,36,7,0,0,0,0,0,0,15,20,20,12,12,0,0,0,0,28,31,28,47,47,12,0,20,44,44,0,0,0,0,20,28,12,0,0,0,15,20,15,12,0,0,0,0,0,0,0,20,36,44,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,52,60,44,28,0,0,0,0,0,0,7,20,28,12,12,0,0,0,0,36,36,36,52,52,0,0,36,44,28,0,0,0,12,28,23,0,0,0,12,15,20,15,12,0,0,0,0,0,7,28,44,47,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,63,60,44,15,0,0,0,0,0,0,28,28,12,7,0,0,0,0,44,44,52,52,47,0,12,52,52,12,0,0,7,28,36,12,0,0,20,20,12,20,15,0,0,0,0,0,15,36,60,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,60,71,60,36,0,0,0,0,0,0,31,31,28,15,0,0,0,0,44,44,55,52,36,0,36,52,36,0,0,0,28,36,20,0,0,28,44,31,23,15,0,0,0,0,0,23,52,63,55,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,52,68,76,52,23,0,0,0,0,0,36,36,60,28,12,0,0,0,47,52,55,55,20,0,52,52,20,0,0,20,39,36,7,0,28,44,44,28,20,0,0,0,0,12,36,63,68,52,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,68,79,76,47,12,0,0,0,0,28,36,76,36,28,0,0,20,52,68,60,60,0,28,55,47,0,0,12,36,39,20,0,28,47,44,36,23,12,0,0,0,20,52,76,68,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,60,76,87,68,36,0,0,0,0,12,44,76,36,36,0,0,52,68,92,60,55,0,52,60,28,0,0,36,52,28,12,28,52,52,44,28,12,0,0,7,36,68,84,68,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,68,92,95,60,20,0,0,0,0,44,71,47,39,0,0,68,71,100,60,44,28,60,55,0,0,28,52,52,23,31,52,60,52,28,12,0,0,20,52,84,87,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,60,84,100,92,52,12,0,0,0,44,63,68,44,0,0,68,76,100,60,23,52,60,36,0,20,52,60,39,39,60,68,60,36,12,0,0,31,76,100,84,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,76,100,116,87,44,12,0,0,44,55,92,44,0,0,68,84,92,68,28,63,63,12,7,44,76,52,44,68,76,68,36,12,0,12,55,100,111,79,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,52,92,124,124,92,44,7,0,28,52,100,52,7,28,84,124,79,63,47,68,52,0,36,76,76,68,76,87,76,36,12,0,28,79,124,111,76,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,23,68,111,140,124,76,28,0,7,52,108,60,20,60,108,156,71,63,68,68,23,23,71,87,84,84,92,84,44,15,12,52,100,127,108,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,20,12,0,0,12,7,0,0,0,0,0,0,0,0,31,95,140,156,127,60,12,0,60,116,76,36,71,111,156,71,68,71,60,20,60,95,100,92,108,92,44,20,28,76,124,132,92,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,31,28,20,12,15,12,0,0,0,0,0,0,12,52,127,175,172,116,39,0,52,116,100,52,100,140,143,84,76,76,44,47,100,119,108,124,103,52,23,44,100,140,124,76,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,15,0,0,0,12,20,31,36,39,44,31,28,28,23,12,0,0,0,0,0,20,84,164,207,172,87,20,44,108,124,63,132,180,135,108,76,79,52,100,132,132,135,111,60,36,68,119,140,108,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,36,28,31,28,12,7,7,20,47,68,60,60,44,36,36,23,7,0,0,0,0,36,124,207,220,148,60,28,100,135,84,148,212,140,132,84,92,108,148,164,159,124,68,52,87,132,127,84,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,44,63,68,55,36,12,20,47,68,79,76,76,60,47,39,20,0,0,0,0,68,164,228,212,116,36,92,143,108,164,228,164,135,111,124,172,191,188,148,87,76,108,132,108,60,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,15,20,36,60,68,71,76,76,63,47,44,60,84,92,100,92,76,60,36,15,0,0,20,103,199,244,175,76,87,148,140,172,231,191,140,151,183,220,220,175,124,103,124,127,92,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,20,20,20,15,12,12,15,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,28,36,60,84,84,84,84,84,79,76,71,76,92,108,124,124,92,63,36,12,0,44,140,223,223,132,95,140,164,188,231,199,164,188,236,244,204,151,127,132,116,68,20,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,36,31,28,28,39,52,52,44,31,31,28,20,20,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,20,28,31,44,47,63,103,124,124,108,92,84,92,100,108,116,132,148,140,100,63,28,12,68,164,228,188,124,143,191,212,239,212,204,223,244,220,180,151,132,95,44,0,0,0,0,0,0,0,0,0,20,36,44,44,44,44,52,63,84,92,92,84,79,68,60,47,36,31,23,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,44,52,76,76,87,116,143,148,132,108,108,124,148,148,156,164,148,108,60,36,84,180,220,159,164,204,236,252,236,236,244,228,196,164,119,71,20,0,0,0,0,0,0,20,39,52,52,55,68,84,100,116,124,116,95,87,84,79,79,79,63,47,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,71,79,79,92,119,151,164,156,148,164,183,183,188,188,156,108,76,116,196,196,196,212,252,252,252,252,247,220,172,108,52,12,0,0,0,28,44,68,76,92,100,116,135,140,140,119,100,92,92,92,84,79,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,79,84,100,124,164,188,196,204,212,228,228,204,148,124,156,196,228,228,252,252,252,252,228,180,100,39,12,28,52,76,100,124,143,159,164,156,143,124,108,92,92,87,79,68,44,28,12,0,0,0,0,0,12,20,15,7,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,7,0,12,23,31,36,47,60,76,111,143,164,183,191,204,220,236,252,231,191,180,207,239,247,252,252,244,212,164,116,87,84,108,132,148,156,164,167,164,148,132,124,116,111,100,87,71,60,52,52,60,68,76,76,52,39,47,60,52,39,20,12,0,15,31,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,7,0,12,23,31,36,44,52,52,76,100,116,143,172,204,228,239,252,252,247,228,228,244,252,252,252,236,204,164,148,159,183,207,223,228,207,196,183,172,164,148,140,132,135,140,148,151,148,148,140,148,135,119,108,76,60,68,103,108,76,44,36,20,28,44,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,44,47,63,84,92,100,100,116,140,164,196,220,239,252,252,252,252,252,252,236,220,215,236,247,252,252,244,228,207,199,196,204,204,204,204,204,207,204,199,196,191,175,156,156,135,108,84,60,44,44,71,76,44,20,20,20,20,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,52,63,76,84,92,92,92,108,127,143,156,172,180,196,220,244,252,252,252,252,252,252,252,252,252,252,252,239,236,236,236,228,212,207,204,204,191,172,156,140,127,124,108,92,84,76,68,52,36,28,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,39,52,60,71,84,87,92,92,92,92,92,92,92,95,108,132,148,167,188,191,188,172,164,180,204,228,244,252,252,252,252,252,252,252,252,252,252,252,236,215,196,172,156,140,143,148,148,132,116,92,84,79,76,76,71,76,76,63,63,60,52,44,36,44,36,28,28,15,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,12,44,60,52,36,55,84,92,92,92,92,92,92,92,92,92,92,92,103,124,140,148,143,135,124,116,108,108,103,108,119,148,175,204,228,247,252,252,252,252,247,247,252,252,252,252,252,228,196,164,140,116,100,87,76,60,44,44,52,52,52,60,60,60,60,52,44,44,44,31,23,20,36,36,28,28,15,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,28,20,28,60,79,60,39,55,84,92,92,87,84,76,68,68,71,84,92,87,79,76,76,76,76,76,76,68,52,52,68,100,132,172,196,215,236,252,244,236,236,252,228,228,231,252,252,252,252,244,220,188,148,116,92,76,55,52,44,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,28,28,28,20,23,47,60,44,28,23,28,20,12,20,36,52,60,68,68,68,68,68,71,71,68,52,31,12,0,20,60,103,132,159,172,172,172,204,236,252,212,204,212,236,220,191,196,236,252,252,247,231,207,191,167,127,100,87,84,71,52,28,20,15,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,12,7,0,0,0,0,0,12,28,36,36,44,44,52,60,60,68,68,63,52,31,12,0,0,0,0,28,60,92,124,148,156,148,124,132,167,212,244,244,172,167,199,220,204,172,148,188,244,247,236,228,220,196,164,148,132,92,60,44,44,44,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,23,28,36,36,36,44,44,52,44,28,12,0,0,0,0,0,0,0,28,60,84,108,124,132,124,100,84,108,143,180,215,244,212,132,140,212,196,180,180,116,124,199,244,231,212,204,196,188,159,132,108,87,60,44,28,20,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,20,20,20,20,23,28,36,28,12,0,0,0,0,0,0,0,0,0,0,7,31,55,76,100,108,100,92,84,68,63,95,140,164,175,212,236,164,95,132,220,175,156,188,108,92,124,212,236,204,183,188,188,180,156,124,95,76,55,31,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,20,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,68,84,92,76,68,63,55,47,52,87,143,156,148,180,220,204,116,60,132,212,148,148,180,132,84,63,143,220,220,188,151,164,180,172,135,108,84,68,52,39,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,47,60,71,76,60,52,47,47,44,36,39,87,148,151,132,143,183,212,156,63,31,124,180,103,127,156,140,84,52,63,164,220,204,143,108,116,156,167,148,108,76,52,39,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,52,60,60,39,28,31,36,36,36,20,31,92,156,148,116,119,156,180,172,108,23,28,127,156,60,95,140,127,92,68,20,79,172,207,164,111,71,76,124,156,156,124,76,36,23,28,28,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,39,44,44,31,20,15,12,20,23,28,20,12,31,95,156,140,95,100,140,151,172,140,63,0,28,116,140,44,68,132,108,100,84,31,20,100,180,196,140,92,60,55,92,140,156,140,103,52,20,12,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,36,36,36,20,0,0,0,7,7,15,20,12,0,36,100,148,135,76,84,124,132,148,156,100,20,0,31,100,127,31,52,119,108,100,79,60,0,31,116,183,180,124,84,52,39,68,108,140,143,116,76,28,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,28,31,28,15,0,0,0,0,0,0,7,0,0,0,39,103,148,132,68,68,108,127,116,148,124,60,0,0,36,87,116,28,44,95,116,84,76,76,23,0,44,132,180,156,103,79,39,28,44,79,116,132,124,92,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,28,20,12,0,0,0,0,0,0,0,0,0,0,0,44,108,148,124,55,52,95,119,108,124,135,92,20,0,0,44,84,108,20,28,63,116,71,68,76,55,0,0,60,140,164,124,92,76,36,20,28,60,84,108,116,100,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,47,108,140,116,52,36,84,108,103,92,132,116,60,0,0,0,52,84,92,15,12,44,108,68,52,76,71,20,0,12,68,148,156,108,68,68,39,12,20,39,60,84,100,100,76,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,111,132,108,44,20,60,100,100,79,108,124,92,20,0,0,0,60,84,79,12,0,36,92,76,55,55,76,47,0,0,20,84,148,132,76,55,68,39,12,12,28,44,60,76,84,76,60,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,55,108,124,100,36,7,31,79,87,76,79,124,116,60,0,0,0,0,60,84,68,0,0,28,60,76,63,28,71,68,12,0,0,28,92,132,95,52,44,60,36,12,0,20,36,39,52,76,79,63,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,60,108,111,87,36,0,15,55,68,68,60,100,119,95,20,0,0,0,0,60,87,55,0,0,20,31,84,63,20,60,68,39,0,0,0,28,92,111,76,39,36,60,36,12,0,12,20,28,36,55,68,68,52,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,60,108,108,76,28,0,7,44,63,60,60,68,111,116,60,0,0,0,0,0,55,76,31,0,0,12,20,76,60,36,28,68,60,7,0,0,0,36,92,103,63,31,36,55,36,12,0,0,12,20,28,36,52,63,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,92,92,68,28,0,0,31,60,52,52,52,84,116,92,20,0,0,0,0,0,52,60,7,0,0,0,12,52,60,52,0,60,68,31,0,0,0,7,44,92,95,52,23,31,52,36,12,0,0,0,12,12,20,39,52,52,39,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,79,76,60,20,0,0,20,52,52,44,52,60,100,108,55,0,0,0,0,0,12,52,52,0,0,0,0,12,28,60,60,0,31,63,55,0,0,0,0,12,52,92,92,44,20,28,47,31,12,0,0,0,0,0,12,20,36,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,63,60,52,20,0,0,12,44,52,39,44,47,71,108,92,20,0,0,0,0,0,23,52,52,0,0,0,0,0,12,60,60,23,0,52,60,23,0,0,0,0,20,55,87,79,36,12,23,44,36,12,0,0,0,0,0,0,7,20,28,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,47,36,20,0,0,0,36,52,36,36,44,44,84,100,52,0,0,0,0,0,0,36,52,52,0,0,0,0,0,0,52,55,44,0,28,52,39,0,0,0,0,0,20,60,79,68,28,7,20,44,31,12,0,0,0,0,0,0,0,0,20,15,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,36,20,0,0,0,28,52,36,28,39,36,60,95,76,15,0,0,0,0,0,0,44,47,44,0,0,0,0,0,0,28,52,52,0,0,39,44,15,0,0,0,0,0,28,63,76,60,23,0,20,36,28,12,0,0,0,0,0,0,0,0,0,12,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,20,20,15,0,0,0,20,44,44,20,31,36,36,76,92,44,0,0,0,0,0,0,0,44,44,36,0,0,0,0,0,0,7,52,52,12,0,20,36,28,0,0,0,0,0,0,28,63,68,47,20,0,15,28,28,12,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,12,36,44,20,20,36,28,44,84,68,15,0,0,0,0,0,0,0,44,44,28,0,0,0,0,0,0,0,47,52,28,0,0,36,36,12,0,0,0,0,0,12,31,60,63,39,15,0,12,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,28,44,23,12,28,28,28,68,79,39,0,0,0,0,0,0,0,0,36,36,12,0,0,0,0,0,0,0,31,47,44,0,0,20,31,23,0,0,0,0,0,0,12,36,60,55,36,12,0,12,28,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,20,39,28,7,20,28,20,36,76,60,12,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,12,44,44,0,0,0,28,28,7,0,0,0,0,0,0,15,28,44,47,28,7,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,12,0,0,0,0,0,0,0,12,36,31,12,12,28,20,15,52,68,36,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,44,44,15,0,0,20,28,20,0,0,0,0,0,0,0,12,28,44,44,23,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,7,28,36,12,0,15,20,12,31,68,52,12,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,36,44,36,0,0,0,23,23,0,0,0,0,0,0,0,0,20,31,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,20,0,0,12,0,12,52,60,31,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,20,44,44,0,0,0,15,20,12,0,0,0,0,0,0,0,0,12,28,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,0,12,12,0,28,60,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,39,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,12,23,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,12,12,0,12,44,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,20,0,0,0,12,15,7,0,0,0,0,0,0,0,0,7,12,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,7,0,0,23,47,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,31,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,7,15,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,7,31,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,36,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,15,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_5[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,15,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,20,20,20,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,20,20,0,0,0,0,23,23,7,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,15,12,7,0,0,0,0,0,0,7,36,36,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,28,28,0,0,0,23,36,36,0,12,12,0,0,0,0,0,20,20,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,44,44,0,0,0,36,36,28,0,12,12,0,0,0,0,15,28,20,0,0,0,0,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,12,23,15,15,0,39,39,0,0,0,39,39,20,12,12,12,0,0,0,0,28,28,7,0,0,0,20,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,15,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,7,20,44,28,28,0,44,44,0,0,0,44,44,0,12,12,0,0,0,0,20,28,20,0,0,0,15,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,28,44,36,12,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,12,28,31,31,0,44,44,0,0,12,44,47,0,12,12,0,0,0,7,31,36,7,0,0,12,36,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,47,31,12,0,0,12,28,20,0,0,0,0,0,0,0,0,0,15,20,36,36,0,52,52,0,0,31,52,52,20,20,15,0,0,0,23,36,23,0,0,0,28,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,52,28,0,0,0,23,28,12,0,0,0,0,0,0,0,0,23,28,39,28,0,52,52,0,0,44,60,47,28,23,0,0,0,12,36,36,12,0,0,23,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,52,20,0,0,12,28,23,0,0,0,0,0,0,0,0,23,23,47,28,0,52,52,0,0,60,76,55,31,31,0,0,0,28,44,28,0,0,20,44,39,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,20,52,60,52,20,0,0,28,36,15,0,0,0,0,0,0,0,23,28,68,39,0,52,52,0,0,76,84,63,36,31,0,0,12,44,44,12,0,12,39,52,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,0,7,23,60,68,44,12,0,15,36,31,0,0,0,0,0,0,0,20,28,76,44,12,55,55,0,20,92,92,60,36,20,0,0,36,44,28,0,0,36,52,44,31,28,12,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,0,0,0,0,0,0,15,20,15,31,68,71,36,7,0,28,36,20,0,0,0,0,0,0,12,36,84,44,23,60,60,0,44,92,92,52,39,0,0,15,52,47,12,0,28,60,60,47,36,12,12,20,12,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,12,23,28,20,0,0,0,0,15,31,23,23,44,79,76,28,0,15,44,39,7,0,0,0,0,0,0,39,92,47,36,55,52,0,76,108,100,44,39,0,0,36,52,31,0,20,52,71,63,47,20,15,31,31,12,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,12,31,44,31,12,0,0,0,20,39,28,28,60,87,68,23,0,31,44,28,0,0,0,0,0,0,44,92,55,44,55,52,20,108,119,100,44,28,0,20,52,52,12,7,44,76,79,60,36,20,36,44,20,0,0,0,0,0,7,20,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,15,0,0,0,12,36,55,44,20,0,0,0,28,44,31,36,76,95,60,15,12,44,44,12,0,0,0,0,0,44,92,71,52,60,52,36,124,132,95,44,12,0,44,60,36,0,36,76,92,76,39,28,44,47,20,0,0,0,0,0,15,28,36,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,23,12,0,0,12,36,60,60,31,0,0,0,28,44,36,52,92,100,47,7,36,52,36,0,0,0,0,0,44,87,87,63,63,52,60,135,148,76,47,0,20,60,55,12,28,76,108,100,60,39,52,63,31,0,0,0,0,7,23,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,12,0,0,31,60,68,44,12,0,7,28,52,52,68,108,95,36,20,52,55,36,12,0,0,0,44,84,103,71,63,47,79,140,148,60,39,0,47,60,36,15,60,111,119,84,60,63,84,47,12,0,0,0,15,36,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,31,36,23,12,0,23,52,71,52,20,0,12,39,68,68,87,116,92,28,36,55,63,28,12,0,0,36,76,108,76,60,52,100,140,140,55,20,23,68,60,20,52,108,132,108,84,84,92,60,20,0,0,0,28,44,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,20,0,15,47,76,60,28,0,12,47,76,84,111,132,87,31,52,71,52,28,0,0,20,76,116,84,68,63,116,156,119,55,7,52,68,47,44,108,143,132,100,92,92,60,20,0,0,20,36,52,44,20,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,36,20,12,44,71,71,44,12,15,55,92,100,135,132,68,44,63,84,47,28,0,7,84,132,108,71,84,127,172,100,52,28,68,68,60,111,164,159,124,100,100,52,12,0,0,28,52,52,36,12,0,0,0,0,0,0,0,12,20,12,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,36,28,36,68,76,52,20,20,63,100,119,148,124,60,60,84,79,44,12,0,76,140,124,68,100,132,180,84,36,52,68,68,100,172,188,156,124,116,71,20,0,15,44,60,52,28,0,0,0,0,0,12,20,28,36,28,23,23,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,52,52,39,44,68,84,63,28,28,68,108,140,156,108,68,76,108,68,31,0,68,140,164,92,116,148,164,68,44,68,84,100,180,212,180,156,140,95,36,12,28,52,60,44,20,0,0,0,12,20,28,44,44,36,39,44,36,23,20,28,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,55,63,60,60,68,92,76,44,36,71,119,156,148,100,79,100,108,60,12,60,140,199,116,132,172,148,68,60,84,108,164,223,212,180,156,108,44,23,44,63,60,36,12,0,0,15,28,44,55,52,47,52,55,44,36,44,44,28,20,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,63,76,76,92,95,87,52,52,76,132,164,148,103,100,140,108,47,52,140,228,143,148,196,132,79,76,116,156,223,244,220,172,116,52,39,60,68,52,28,0,7,20,39,60,71,68,68,68,63,52,55,60,52,36,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,84,100,108,111,103,68,60,84,148,180,140,111,135,148,84,52,140,236,164,167,196,124,92,108,151,207,252,244,204,124,68,60,68,68,44,15,7,23,52,71,84,84,84,84,76,71,76,68,52,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,103,124,132,124,87,79,108,180,196,151,140,175,127,68,127,228,180,183,196,140,116,156,196,244,247,212,143,92,79,84,68,36,20,36,68,84,100,103,108,100,95,92,84,71,52,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,63,100,140,159,148,111,95,135,196,196,164,183,164,92,119,220,196,191,204,167,164,196,231,247,212,156,108,100,92,60,39,44,84,108,124,132,132,124,124,116,100,76,47,36,20,0,0,0,0,0,0,0,0,12,15,20,20,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,39,92,132,172,175,148,124,164,204,196,188,196,127,127,204,228,220,228,204,212,223,247,212,164,124,103,84,68,68,100,132,156,167,180,167,159,140,116,84,60,36,7,0,0,0,0,15,28,36,36,39,44,47,39,31,28,20,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,12,20,23,28,44,76,116,164,196,180,159,183,204,212,212,159,156,191,244,239,244,236,239,239,220,180,140,108,95,92,111,151,188,204,212,188,172,143,119,87,60,28,7,0,20,36,60,68,79,84,76,60,52,52,47,47,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,15,12,20,12,12,15,23,36,47,68,92,119,156,196,199,188,204,220,236,204,183,196,252,252,252,252,247,228,191,148,124,124,132,164,207,236,223,196,164,140,108,71,52,36,44,60,79,92,100,100,100,103,100,95,84,60,36,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,15,12,20,23,36,36,44,52,55,60,76,100,127,164,191,204,212,228,244,236,220,220,252,252,252,252,244,212,175,156,159,172,212,231,215,180,148,124,108,92,79,84,92,116,124,132,140,148,140,119,108,92,60,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,36,36,44,44,52,76,108,132,140,156,180,212,223,236,247,252,244,244,252,252,252,252,244,220,196,196,212,212,196,180,164,148,132,124,127,143,164,175,180,183,175,159,135,116,84,39,23,28,20,7,0,0,0,0,0,0,0,12,12,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,52,63,92,143,188,204,215,236,247,252,252,252,252,252,252,252,252,247,236,228,236,228,207,196,180,167,172,188,204,215,228,236,223,199,172,132,116,116,108,84,52,44,52,44,44,36,28,12,0,20,28,28,23,20,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,55,76,108,140,172,196,223,244,252,252,252,252,252,252,252,252,252,252,244,228,212,212,228,244,247,244,236,215,204,196,180,159,124,87,68,79,76,60,52,44,47,44,39,36,28,12,0,20,28,28,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,92,132,167,212,244,252,252,252,252,252,252,252,252,252,252,252,244,239,231,228,220,204,196,183,172,156,148,135,116,100,92,92,87,84,79,68,52,36,28,20,15,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,39,60,76,92,116,143,172,180,196,220,244,252,252,252,252,252,239,228,223,239,252,244,220,183,151,132,108,92,76,68,60,52,39,36,36,36,36,36,36,36,31,28,20,12,12,12,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,76,92,108,124,140,159,175,191,212,236,252,252,252,252,252,252,252,252,252,252,239,215,188,164,164,180,172,156,132,108,87,84,84,76,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,60,79,92,100,116,132,151,164,180,191,220,236,252,252,247,236,231,236,244,252,252,252,252,252,252,252,252,244,212,172,148,127,103,92,103,116,116,116,111,100,87,84,76,71,47,44,44,28,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,23,52,60,68,92,100,100,108,132,148,156,172,180,188,196,212,212,231,244,236,212,199,188,188,204,231,239,236,236,252,252,252,252,252,247,236,204,164,132,108,71,44,36,36,36,36,36,47,60,63,68,47,44,44,28,20,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,36,47,55,63,84,84,92,127,148,143,140,124,124,132,140,140,140,148,172,191,199,180,172,159,140,132,156,188,204,204,204,228,252,252,244,236,236,247,223,196,180,164,140,119,84,36,7,0,12,12,15,12,0,0,0,0,12,12,15,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,28,36,36,39,44,55,76,92,108,103,87,79,71,76,92,95,100,92,84,100,127,148,148,132,127,124,108,92,100,124,151,180,172,156,188,228,244,236,236,212,212,236,228,196,172,156,140,124,111,95,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,15,20,28,36,44,60,60,55,52,44,36,52,68,76,68,60,52,47,63,84,100,103,95,87,87,84,76,60,68,76,95,124,148,148,124,151,212,223,223,220,228,196,188,207,239,207,172,156,132,108,92,92,92,76,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,28,28,23,20,20,28,36,44,52,44,28,28,31,36,39,52,60,68,68,68,68,68,60,52,44,52,44,52,76,108,124,124,100,116,180,220,204,204,196,204,188,148,159,228,228,188,143,127,119,92,71,68,76,76,68,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,20,20,12,15,15,23,20,20,28,23,28,44,55,55,60,55,47,36,36,36,39,28,20,28,63,84,100,111,84,76,127,212,196,180,196,188,180,196,119,111,196,223,196,156,100,87,92,84,52,47,60,76,76,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,12,36,47,52,52,52,44,28,20,20,28,31,23,12,0,28,52,68,79,100,84,55,84,172,220,164,164,204,175,164,212,124,76,148,199,188,164,132,68,55,76,92,60,31,36,60,71,68,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,47,44,28,12,0,12,20,23,20,7,0,0,23,44,47,55,76,84,44,52,124,196,204,140,148,223,164,124,196,124,60,100,180,180,156,143,108,52,36,68,84,63,28,12,36,60,68,68,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,44,44,36,15,0,0,0,0,12,12,0,0,0,0,28,44,39,36,52,68,44,36,84,148,199,172,124,140,231,156,84,164,116,68,52,148,188,148,140,132,92,44,20,47,76,68,36,7,12,36,60,63,60,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,31,36,36,36,20,0,0,0,0,0,0,0,0,0,0,0,7,23,39,28,28,36,52,28,12,60,108,156,188,132,103,143,228,143,55,119,108,87,20,100,172,164,119,124,124,76,28,0,31,63,71,44,15,0,12,39,60,60,55,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,28,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,20,20,31,47,28,0,36,84,124,159,164,95,92,151,212,140,52,92,111,100,12,47,132,167,132,100,111,111,68,23,0,20,52,68,52,20,0,0,15,44,60,55,52,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,23,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,15,12,28,44,28,0,20,68,100,116,172,140,68,95,164,188,132,44,68,116,100,31,12,84,148,132,100,92,103,100,60,20,0,12,44,68,60,28,0,0,0,20,44,52,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,12,0,20,39,28,0,0,44,76,100,124,156,108,52,100,172,172,124,44,47,108,100,52,0,36,95,132,95,84,84,95,87,52,12,0,0,31,60,60,36,12,0,0,0,20,44,52,44,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,15,31,20,0,0,28,68,84,92,148,135,68,52,100,180,164,116,36,36,92,84,55,0,12,63,108,103,79,68,84,84,76,44,0,0,0,20,47,60,44,15,0,0,0,0,20,39,39,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,12,52,71,76,100,140,108,36,68,100,180,159,111,20,20,60,76,68,0,0,36,76,108,76,68,63,76,68,63,31,0,0,0,12,36,55,44,20,0,0,0,0,0,20,31,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,36,60,71,68,116,124,76,12,84,108,151,148,92,12,12,39,68,68,12,0,12,52,84,84,68,55,60,60,52,52,23,0,0,0,0,28,52,52,28,0,0,0,0,0,0,20,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,55,60,60,79,116,100,44,12,92,111,127,140,76,12,15,28,52,52,12,0,0,28,52,79,68,55,47,60,44,39,44,20,0,0,0,0,20,44,52,28,12,0,0,0,0,0,0,20,23,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,55,52,47,92,108,71,20,15,79,108,108,127,68,15,28,28,44,47,15,0,0,7,44,63,76,60,44,52,52,36,36,36,12,0,0,0,0,12,31,44,36,12,0,0,0,0,0,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,52,44,60,92,92,44,0,31,76,108,100,124,68,0,20,20,28,31,20,0,0,0,28,44,68,60,47,36,52,39,28,31,28,7,0,0,0,0,0,28,44,36,20,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,52,36,36,76,87,71,28,0,44,68,108,95,116,68,0,0,0,20,28,28,0,0,0,7,44,52,60,55,36,31,47,28,20,20,7,0,0,0,0,0,0,20,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,36,28,44,71,87,44,7,0,52,63,100,100,108,63,0,0,0,7,20,20,0,0,0,0,28,39,52,52,52,23,36,44,20,0,12,7,0,0,0,0,0,0,12,28,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,44,28,28,60,71,68,28,0,0,44,47,84,108,92,60,0,0,0,0,20,20,0,0,0,0,7,36,39,52,52,36,15,36,36,12,7,20,12,0,0,0,0,0,0,0,20,31,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,44,28,20,36,60,76,44,15,0,12,47,44,63,108,76,52,0,0,0,0,20,20,0,0,0,0,0,20,36,39,44,47,20,20,36,28,12,12,15,0,0,0,0,0,0,0,0,12,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,28,15,20,44,52,60,20,0,0,7,31,31,52,108,68,44,0,0,0,0,12,12,0,0,0,0,0,0,31,31,36,47,36,7,20,36,20,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,15,20,23,52,55,36,12,0,0,12,28,36,44,108,60,36,0,0,0,0,0,12,12,0,0,0,0,0,20,28,28,36,44,20,0,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,7,12,31,44,52,15,0,0,0,7,20,36,44,103,60,28,0,0,0,0,0,7,7,0,0,0,0,0,0,28,28,28,44,36,7,12,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,28,0,12,12,39,44,36,12,0,0,0,12,12,39,39,100,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,20,28,39,28,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,20,36,44,12,0,0,0,0,12,12,44,36,95,55,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,36,36,12,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,20,0,0,0,28,36,28,0,0,0,0,0,0,0,39,36,92,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,20,36,28,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,23,0,0,0,7,31,36,12,0,0,0,0,0,0,0,36,44,76,55,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,12,28,36,12,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,20,28,28,0,0,0,0,0,0,0,0,28,39,68,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,12,28,28,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,15,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,15,36,55,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,12,39,52,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,7,28,60,52,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,12,20,60,47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,7,52,47,47,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,52,47,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,12,12,55,44,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,12,12,52,44,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_6[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,23,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,44,0,0,0,0,0,0,0,7,12,7,0,7,7,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,44,0,0,0,0,0,0,0,12,12,0,0,7,7,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,36,0,0,0,0,0,0,0,12,12,0,12,12,7,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,31,0,0,12,12,0,0,0,12,12,0,12,12,0,0,0,0,20,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,47,20,0,28,28,0,0,12,20,20,0,20,20,0,0,0,12,23,20,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,76,44,0,44,39,7,0,20,20,20,20,28,23,0,0,0,23,28,12,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,68,84,60,0,39,36,0,0,23,23,15,20,20,12,0,0,12,28,28,0,0,0,12,12,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,60,76,63,0,36,28,0,0,28,28,20,28,28,0,0,0,28,31,15,0,0,15,20,7,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,52,76,68,12,44,28,0,0,28,28,28,36,28,0,0,12,36,36,0,0,12,23,15,0,0,0,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,7,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,44,84,76,20,52,36,0,12,31,28,44,44,28,0,0,28,36,20,0,7,28,28,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,28,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,39,92,92,20,68,44,12,31,44,44,47,47,12,0,12,36,36,0,0,23,31,15,0,0,0,0,0,0,0,20,28,12,0,0,0,0,7,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,36,95,95,28,79,60,20,44,47,55,52,52,0,0,31,44,28,0,20,36,28,0,0,0,0,0,0,0,20,31,15,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,44,23,0,0,0,0,0,0,0,0,0,0,31,31,12,0,28,100,100,44,84,60,20,60,60,63,52,44,0,12,44,44,12,12,36,36,12,0,0,0,0,0,12,28,36,20,0,0,0,0,20,23,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,44,20,0,0,0,0,0,0,0,0,0,28,36,28,0,15,100,100,60,87,60,23,60,63,60,52,23,0,36,47,36,0,28,39,20,0,0,0,0,0,12,31,39,20,0,0,0,12,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,44,20,0,0,0,0,0,0,0,0,12,36,36,0,7,100,100,68,84,52,36,68,79,60,55,0,12,47,47,12,20,44,36,0,0,0,0,0,12,36,44,23,0,0,0,20,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,23,52,44,20,0,0,0,0,0,0,0,0,39,39,12,0,95,100,84,84,52,52,68,100,60,55,0,36,52,36,12,39,44,20,0,0,0,0,12,36,44,23,0,0,12,28,39,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,0,0,0,0,0,0,0,0,28,60,44,15,0,0,0,0,0,0,0,36,44,28,0,87,100,95,95,60,68,76,111,71,44,12,52,55,20,31,52,28,0,0,0,0,15,36,44,20,0,0,20,36,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,36,68,44,20,0,0,0,0,0,0,23,44,44,0,79,100,111,111,68,68,92,116,84,36,36,60,44,28,52,44,12,0,0,0,20,44,44,20,0,7,28,44,52,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,12,0,0,0,0,0,0,12,44,68,55,28,7,0,0,0,0,7,52,52,0,68,100,124,132,100,76,119,124,92,28,55,60,36,47,55,23,0,0,0,28,47,52,28,0,15,36,60,52,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,20,31,36,20,7,0,0,0,0,0,20,52,79,63,28,0,0,0,0,0,52,55,28,60,100,132,124,108,84,143,124,87,52,60,52,44,60,39,0,0,0,28,52,52,28,0,28,52,68,60,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,12,0,0,0,0,0,12,28,36,36,15,0,0,0,0,0,23,68,87,68,23,0,0,0,0,47,63,52,47,100,143,124,124,108,188,135,84,63,68,52,60,55,20,12,12,28,55,60,28,12,36,68,76,63,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,23,15,0,0,0,0,7,28,44,44,28,7,0,0,0,0,31,76,92,68,20,0,0,0,36,76,71,44,100,151,124,135,135,204,132,84,68,71,60,63,31,12,28,52,68,60,31,23,52,84,84,60,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,31,20,7,0,0,0,28,52,55,36,20,7,0,0,0,39,92,100,60,12,0,0,15,84,87,60,100,156,124,148,175,212,127,84,71,76,71,52,28,36,68,79,68,36,36,68,92,84,55,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,31,36,36,28,12,0,0,28,52,68,55,31,7,0,12,20,52,108,108,52,7,0,0,79,100,84,108,156,124,164,199,188,132,79,92,76,76,47,52,76,84,63,52,52,92,108,84,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,39,39,31,20,12,23,52,76,76,44,28,20,28,31,68,124,111,47,0,0,60,100,108,116,159,140,180,220,172,127,92,100,87,76,60,92,95,71,60,76,116,116,76,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,39,44,47,39,28,20,52,84,92,71,52,44,36,44,87,140,111,36,0,28,95,124,140,175,167,196,220,164,116,116,108,108,87,108,108,84,76,103,132,116,68,23,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,52,52,47,44,47,76,100,92,76,60,52,63,116,148,100,23,0,84,140,180,199,196,212,204,164,116,135,124,124,135,132,108,100,127,143,108,55,20,12,15,7,0,12,12,12,12,0,0,0,0,7,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,52,52,60,60,60,76,103,119,108,79,68,84,140,148,79,12,63,140,212,228,228,223,204,164,151,151,164,164,167,148,135,140,140,92,44,23,20,20,28,31,31,23,20,12,12,20,28,20,20,15,7,12,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,60,68,76,92,116,135,132,108,92,116,164,140,60,44,127,220,244,244,236,212,180,191,196,207,196,188,172,151,124,84,47,36,36,47,52,44,36,28,36,39,39,36,28,28,20,20,20,15,20,12,20,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,15,20,7,0,0,0,0,0,0,31,60,76,84,108,132,143,148,140,140,164,191,132,60,108,207,252,252,244,231,220,228,244,239,223,188,151,116,76,55,60,76,79,68,60,68,71,60,44,36,36,39,52,55,60,60,55,44,44,36,31,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,23,28,36,44,52,52,44,28,12,0,0,12,44,76,100,116,148,164,167,172,196,220,204,116,119,188,252,252,252,247,244,244,252,236,196,156,124,92,87,111,124,116,116,116,92,68,60,68,84,95,100,95,92,84,84,79,60,44,39,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,60,63,76,79,92,84,68,44,28,28,60,92,124,159,191,204,212,236,244,191,172,196,252,252,252,252,252,252,236,212,175,148,140,156,172,175,172,151,140,127,132,132,132,119,103,100,95,95,92,84,76,55,31,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,0,12,20,20,12,0,0,0,0,0,12,28,44,68,76,92,92,95,95,95,92,87,87,108,124,148,188,228,247,252,236,220,223,252,252,252,252,252,247,231,204,188,196,207,220,228,228,212,188,172,148,124,108,100,100,95,84,68,47,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,28,20,0,0,12,28,44,44,28,31,44,52,44,44,36,36,44,44,47,47,47,52,52,68,84,100,103,103,116,116,116,127,148,164,183,204,231,247,252,244,244,252,252,252,252,252,247,236,231,236,244,244,231,212,180,143,119,108,103,92,68,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,20,15,0,0,0,12,36,44,39,47,68,76,79,84,79,92,124,140,135,132,140,143,140,132,124,119,119,132,164,175,196,212,212,196,191,207,231,247,252,252,252,252,252,252,252,252,252,252,236,220,188,164,140,116,100,84,68,47,28,20,15,15,15,15,15,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,20,31,36,36,36,39,39,44,44,63,92,116,124,132,151,164,164,164,156,156,151,148,151,164,204,231,252,252,252,244,244,247,252,252,252,252,252,252,252,252,252,252,228,191,156,124,92,71,60,60,60,52,47,44,44,36,36,28,23,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,20,44,76,87,71,76,100,119,132,156,172,180,183,199,220,236,244,247,247,252,252,252,252,252,252,252,252,252,236,212,164,124,84,60,52,47,44,36,28,28,20,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,20,47,60,39,44,60,84,108,132,148,164,180,199,204,196,191,207,236,252,252,252,252,252,252,252,252,252,252,236,196,156,108,76,60,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,12,20,31,44,60,79,100,124,148,167,180,172,164,148,148,164,204,228,244,244,252,252,252,247,228,223,236,252,252,239,220,183,148,108,76,60,52,47,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,71,92,108,140,172,191,204,191,167,135,108,92,92,116,164,220,220,220,236,252,244,244,247,220,188,180,212,236,228,215,204,204,188,164,135,100,71,52,44,44,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,60,68,84,108,140,180,204,204,188,156,132,100,68,44,47,68,108,164,212,199,180,196,244,252,228,228,252,231,175,124,132,167,191,188,188,188,188,175,151,116,103,103,92,68,44,36,36,23,20,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,28,60,100,132,164,175,172,156,143,116,92,60,28,7,20,47,76,108,156,204,196,148,151,207,252,252,196,199,244,236,196,119,71,76,116,140,143,140,148,148,148,143,132,100,68,60,68,71,60,36,20,20,20,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,84,108,124,116,116,116,108,84,55,23,0,0,0,31,60,76,108,148,196,204,140,108,164,236,247,236,164,172,212,231,196,156,79,36,36,76,108,124,111,100,108,103,87,92,108,103,76,52,47,44,44,36,23,15,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,71,84,87,92,87,76,60,36,12,0,0,0,0,20,44,60,71,92,143,204,212,148,76,108,188,231,228,220,148,148,172,220,196,172,124,60,12,15,47,76,100,103,84,68,84,87,76,68,76,92,84,60,44,39,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,36,55,68,71,76,68,55,39,23,0,0,0,0,0,0,12,28,52,55,60,79,140,212,220,148,60,68,127,188,212,204,204,148,119,148,196,191,172,148,100,52,7,0,28,60,76,84,84,60,52,60,68,68,60,60,68,68,60,44,36,36,31,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,39,36,44,60,47,36,28,15,0,0,0,0,0,0,0,0,20,39,47,47,44,63,132,204,223,156,63,36,95,148,156,196,183,188,156,95,116,180,172,164,159,116,87,44,0,0,7,36,60,68,76,63,44,36,44,52,60,55,52,52,52,47,39,31,28,28,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,28,28,36,20,20,20,12,0,0,0,0,0,0,0,0,0,12,28,39,44,31,36,60,124,188,212,164,68,15,60,116,140,124,188,175,172,167,87,79,148,156,156,148,132,95,76,36,0,0,0,20,44,60,60,55,44,36,31,28,28,39,47,47,44,44,36,28,23,23,20,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,15,31,36,36,20,23,60,111,164,196,164,76,12,28,92,111,100,119,183,172,159,172,92,47,111,148,124,132,135,95,84,71,28,0,0,0,0,28,52,55,52,44,31,28,23,20,20,28,39,44,44,44,36,23,12,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,31,20,12,20,63,100,143,172,156,79,20,0,60,92,84,60,124,188,164,140,180,100,20,84,148,108,116,127,108,76,76,63,23,0,0,0,0,12,36,52,52,36,28,20,20,20,12,0,12,28,39,39,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,20,12,0,20,60,92,132,156,143,79,20,0,28,76,76,44,44,132,188,140,124,183,108,12,68,116,116,100,100,124,79,60,76,55,20,0,0,0,0,0,20,36,47,44,28,15,12,12,12,0,0,0,15,31,36,36,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,12,0,0,20,60,84,116,140,140,84,23,0,0,60,76,44,28,52,127,183,111,103,188,116,12,44,84,132,84,79,108,103,52,52,76,47,12,0,0,0,0,0,0,20,39,44,31,15,0,7,0,0,0,0,0,0,20,31,31,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,7,12,44,68,95,124,132,84,28,0,0,28,68,60,12,20,68,127,183,92,87,183,116,20,15,68,124,84,76,76,108,76,39,47,71,44,7,0,0,0,0,0,0,12,28,36,36,23,7,0,0,0,0,0,0,0,0,12,20,28,28,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,55,79,116,119,84,28,0,0,0,55,68,36,0,12,79,132,167,76,76,180,108,31,0,60,87,108,68,55,84,95,52,31,47,68,36,0,0,0,0,0,0,0,0,15,28,36,28,12,0,0,0,0,0,0,0,0,0,0,12,20,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,55,71,100,108,84,31,0,0,0,28,63,55,0,0,7,92,135,140,60,68,167,100,39,0,39,68,108,68,52,60,92,76,36,28,52,60,28,0,0,0,0,0,0,0,0,0,20,28,28,20,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,60,92,103,84,36,0,0,0,7,52,60,28,0,0,15,92,135,108,60,68,159,92,47,0,12,60,92,76,60,36,68,84,52,20,20,52,55,23,0,0,0,0,0,0,0,0,0,7,20,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,63,92,87,36,0,0,0,0,31,60,52,0,0,0,28,95,140,84,55,68,156,92,52,0,0,55,68,92,63,36,44,76,71,36,12,23,52,52,20,0,0,0,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,31,68,84,36,0,0,0,0,12,52,60,23,0,0,0,52,84,132,63,44,60,140,95,55,0,0,36,60,87,60,52,20,55,76,52,23,0,28,52,44,12,0,0,0,0,0,0,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,20,52,76,39,0,0,0,0,0,36,55,44,0,0,0,0,60,76,108,52,28,44,103,84,55,0,0,12,55,68,68,60,20,36,60,60,28,12,0,28,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,15,15,28,52,36,0,0,0,0,0,12,52,52,20,0,0,0,0,68,68,68,44,12,36,68,60,52,0,0,0,52,55,68,55,44,12,47,60,36,12,0,0,28,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,15,36,47,20,7,0,0,0,0,0,36,52,36,0,0,0,0,20,63,68,52,39,0,36,47,52,52,0,0,0,36,52,60,55,52,12,28,52,52,23,12,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,52,36,0,0,0,0,0,0,12,47,47,12,0,0,0,0,36,60,71,44,36,0,36,39,52,52,0,0,0,12,47,52,52,52,31,0,39,52,36,7,0,0,7,28,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,28,7,0,0,0,0,0,0,31,44,28,0,0,0,0,0,52,60,68,36,36,0,36,44,52,47,0,0,0,0,44,47,47,52,47,0,20,44,47,20,7,0,0,12,28,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,31,28,0,0,0,0,0,0,0,12,44,44,12,0,0,0,0,0,52,55,44,28,23,0,36,52,60,44,12,0,0,0,31,44,44,44,52,23,0,28,44,36,0,0,0,0,12,28,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,0,0,0,0,0,0,31,44,28,0,0,0,0,0,7,52,52,28,20,20,0,28,52,71,44,20,0,0,0,12,44,44,31,47,44,0,12,39,44,15,0,0,0,0,12,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,39,36,0,0,0,0,0,0,28,52,52,28,28,15,0,12,36,68,44,28,0,0,0,0,39,44,28,44,44,15,0,20,39,31,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,20,0,0,0,0,0,0,44,52,44,20,20,0,0,0,15,52,31,28,0,0,0,0,28,39,36,28,44,31,0,0,28,36,20,0,0,0,0,0,0,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,28,0,0,0,0,0,0,0,47,52,28,12,12,0,0,0,12,44,31,28,0,0,0,0,7,36,36,12,44,39,7,0,12,36,31,0,0,0,0,0,0,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,12,0,0,0,0,0,0,0,47,47,12,12,12,0,0,0,7,31,28,28,0,0,0,0,0,36,36,15,31,36,23,0,0,20,31,20,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,12,47,47,0,12,12,0,0,0,0,28,36,36,0,0,0,0,0,23,36,28,12,36,36,0,0,7,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,0,31,44,44,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,7,31,31,0,31,36,15,0,0,15,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,44,44,31,0,0,0,0,0,0,0,0,23,23,0,0,0,0,0,0,28,28,12,15,36,28,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,7,0,0,0,0,0,0,0,0,44,44,12,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,20,28,23,0,31,31,12,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,28,28,0,20,28,20,0,0,0,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,20,39,39,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,23,23,12,0,28,28,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,31,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,15,20,20,0,20,28,15,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,15,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,20,20,0,7,23,23,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,31,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,20,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_7[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,12,12,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,7,0,0,0,0,0,0,0,0,0,0,0,28,28,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,12,15,7,0,0,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,12,0,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,7,15,15,0,0,0,0,0,20,20,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,47,28,0,0,0,0,0,0,0,0,0,0,36,36,20,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,12,28,20,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,44,12,0,0,0,0,0,0,0,0,0,36,36,36,0,0,0,0,0,0,0,0,20,20,12,0,0,0,0,31,28,12,0,0,0,0,12,23,20,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,60,31,0,0,0,0,0,0,0,0,0,31,39,39,0,0,0,0,0,0,0,0,20,20,12,0,0,0,20,36,28,0,0,0,0,0,23,28,12,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,52,15,0,0,0,0,0,0,0,0,20,44,44,0,0,0,0,0,0,0,0,28,23,0,0,0,12,36,36,20,0,0,0,0,20,28,20,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,52,68,36,0,0,0,0,0,0,0,0,7,44,44,0,0,0,0,0,0,0,15,28,28,7,7,0,20,47,36,7,0,0,0,12,31,28,12,20,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,28,68,60,15,0,0,0,0,0,0,0,0,44,44,0,0,0,0,0,0,0,23,31,28,7,7,12,36,52,31,0,0,0,0,28,36,20,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,15,12,0,0,0,0,0,0,12,55,76,44,0,0,0,0,0,0,0,0,47,47,12,0,0,0,0,0,0,44,44,36,12,12,12,52,44,20,0,0,0,20,36,28,20,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,7,12,7,0,0,0,0,0,0,31,76,68,20,0,0,0,0,0,0,0,47,47,28,0,0,0,0,0,7,60,60,28,12,12,36,60,44,0,0,0,12,36,36,28,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,7,0,0,15,20,0,0,0,0,0,12,63,92,55,0,0,0,0,0,0,0,47,52,44,0,0,0,0,0,23,63,68,20,15,23,60,63,28,0,0,0,28,44,36,28,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,0,20,36,20,0,0,0,0,0,36,92,84,23,0,0,0,0,0,0,39,52,52,0,0,0,0,0,52,76,84,20,23,36,76,55,12,0,0,20,44,44,36,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,7,20,28,12,0,0,0,0,12,68,100,60,0,0,0,0,0,0,28,52,52,0,0,0,0,0,68,84,84,28,39,60,79,44,0,0,7,39,44,44,39,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,7,20,28,20,7,0,0,0,36,92,92,28,0,0,0,0,0,12,55,55,0,0,0,0,0,79,84,71,31,44,84,71,23,0,0,28,52,52,44,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,15,15,36,39,28,12,0,0,12,76,111,76,0,0,0,0,0,0,60,60,0,0,0,0,12,84,100,60,44,60,92,60,0,0,20,52,60,52,52,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,20,20,44,39,28,15,7,0,36,108,108,36,0,0,0,0,0,60,60,20,0,0,0,31,84,119,52,60,84,92,36,0,0,44,60,60,52,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,39,23,28,47,44,28,12,0,7,84,119,76,0,0,0,0,0,60,60,36,0,0,0,52,92,132,52,79,100,79,20,0,31,60,68,60,52,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,44,28,36,52,44,36,20,0,36,108,108,36,0,0,0,0,55,60,47,0,0,0,68,108,127,76,92,108,60,12,28,60,76,71,76,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,15,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,44,36,44,60,60,39,20,7,76,119,84,12,12,12,0,47,63,60,0,0,0,84,132,116,108,111,108,44,23,60,71,84,87,76,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,23,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,44,52,68,63,39,15,31,108,111,39,15,15,12,36,68,63,0,0,12,87,156,108,132,124,92,31,52,76,92,100,100,63,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,31,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,31,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,60,52,60,76,71,36,20,76,116,84,28,28,20,20,68,68,0,0,28,95,164,111,140,124,76,44,79,100,124,124,84,28,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,36,44,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,47,68,63,71,84,76,31,36,103,108,52,28,28,12,68,68,12,0,44,116,164,140,132,116,60,76,100,124,140,124,44,0,0,0,0,0,0,0,0,0,0,0,0,7,28,44,44,44,28,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,52,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,76,76,84,92,71,36,71,116,87,44,36,20,68,68,23,0,68,148,167,164,124,103,68,103,132,156,148,76,12,0,0,0,0,0,0,0,0,0,0,0,28,44,47,44,28,12,0,0,0,0,0,7,12,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,52,63,68,60,36,12,0,0,0,0,0,0,0,0,0,12,15,36,60,84,84,100,100,68,52,103,111,71,36,36,68,71,39,0,84,172,180,164,132,92,108,132,172,156,92,23,0,0,0,0,0,0,0,7,7,12,28,47,52,52,36,15,0,0,0,0,7,20,28,23,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,60,71,76,76,52,20,0,0,0,0,0,0,0,7,12,20,36,68,87,92,116,108,63,84,116,100,60,44,76,76,52,0,103,180,196,148,132,103,140,172,180,124,39,0,0,0,0,0,0,12,20,20,36,52,60,52,39,20,0,0,0,0,20,28,28,28,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,39,63,84,92,87,68,28,0,0,0,0,0,0,0,12,28,52,76,100,111,135,116,84,108,108,92,52,92,84,68,20,124,191,199,148,140,143,180,196,156,71,7,0,0,0,0,12,28,39,60,68,63,60,47,23,0,0,0,20,36,36,36,28,28,20,7,0,0,0,0,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,71,92,95,92,76,44,12,0,0,0,0,0,20,39,63,84,116,135,156,124,108,116,124,71,100,92,76,44,140,215,196,164,156,188,212,180,108,28,0,0,0,12,28,52,76,87,84,68,52,28,0,0,20,36,44,39,36,36,28,12,0,0,0,12,20,20,20,20,15,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,92,95,100,84,52,20,0,0,0,0,20,44,76,100,132,164,172,132,132,124,108,116,119,92,60,164,236,199,191,204,228,207,140,44,0,0,0,28,60,95,116,108,79,60,31,7,12,36,47,44,44,44,36,20,0,0,20,36,36,31,23,20,20,20,20,12,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,84,100,100,92,68,28,0,0,0,20,44,84,108,148,180,172,148,132,148,135,159,108,79,180,236,212,220,244,231,164,68,7,0,20,60,116,148,140,100,71,36,23,36,52,52,52,47,44,31,20,20,36,44,39,36,36,36,36,36,23,23,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,79,95,100,95,76,39,12,0,15,44,92,127,180,204,180,164,164,164,183,124,100,204,239,236,236,236,180,84,15,12,47,108,156,164,140,92,55,44,55,68,71,63,52,52,44,44,44,44,44,44,44,52,63,63,47,36,28,15,12,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,71,92,100,100,84,52,23,28,60,100,148,212,212,199,180,196,212,140,124,220,244,244,236,188,92,28,36,87,140,172,156,116,84,79,87,100,92,92,92,84,63,55,52,52,63,76,84,79,60,44,36,36,36,31,28,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,20,12,12,0,0,0,0,0,0,0,0,0,0,0,28,60,92,100,100,95,84,76,84,124,180,231,228,220,223,236,159,151,236,252,244,196,108,52,68,124,167,172,156,127,111,108,116,132,148,132,100,84,84,92,103,108,95,76,55,44,44,44,39,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,20,20,20,23,36,36,36,36,39,36,23,12,0,0,0,0,0,0,15,52,84,100,116,132,132,135,164,204,236,244,244,252,188,188,247,247,207,135,87,108,164,204,212,183,156,148,156,172,175,159,140,132,124,124,111,92,68,52,52,47,44,36,20,0,0,0,0,0,0,12,12,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,36,36,36,36,39,44,44,47,52,52,52,52,36,20,7,0,12,44,84,116,140,164,183,204,228,244,252,252,220,220,252,223,172,135,151,204,236,231,220,212,220,220,212,180,156,140,124,108,79,63,60,55,47,36,28,28,36,39,39,36,36,28,12,12,20,28,20,7,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,44,47,52,52,55,60,60,60,60,68,68,68,63,84,119,164,196,215,231,244,252,252,244,244,247,220,188,196,231,252,252,244,236,220,196,175,164,151,132,124,116,108,92,68,60,52,52,52,47,44,44,44,39,36,36,28,12,12,20,28,20,7,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,60,60,60,68,68,68,76,87,108,140,188,228,252,252,252,252,252,252,247,236,236,247,252,252,252,244,228,196,175,156,127,108,84,68,60,60,60,55,52,52,52,52,47,44,44,39,36,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,52,63,71,76,100,132,175,215,239,252,252,252,252,252,252,252,244,228,207,188,159,127,100,84,71,68,68,68,60,60,52,39,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,44,52,63,76,92,100,111,124,124,124,119,116,132,183,228,252,252,252,252,252,252,252,244,223,196,156,116,68,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,47,52,52,55,60,68,84,100,124,140,140,140,140,135,132,132,124,124,132,151,180,220,244,252,252,252,252,252,252,252,247,236,199,156,127,108,95,92,87,76,52,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,28,36,36,39,44,44,44,47,60,71,87,100,108,111,116,119,124,132,135,124,108,100,84,68,60,68,92,124,156,196,236,252,252,252,252,252,252,252,236,220,212,199,175,148,119,100,92,92,92,92,92,87,79,63,44,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,7,12,20,28,31,28,28,36,44,60,76,84,84,92,92,92,84,76,68,63,55,55,55,52,44,28,12,0,0,36,76,119,164,204,236,239,239,247,252,252,252,252,252,252,236,212,180,172,180,167,132,100,76,68,71,84,92,87,87,87,84,84,84,76,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,15,20,7,12,28,36,44,44,44,52,44,44,36,36,36,39,44,44,44,36,28,12,0,0,0,0,0,0,12,44,84,127,159,191,207,220,212,212,228,247,252,252,252,244,244,247,244,228,188,148,140,172,196,180,132,87,52,23,15,31,52,68,84,84,84,84,60,60,44,44,36,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,12,12,0,0,12,12,12,20,20,20,23,36,36,28,15,0,0,0,0,0,0,0,0,0,0,0,20,52,84,124,156,180,183,180,172,164,172,204,236,252,252,244,244,220,220,236,231,236,228,180,116,100,127,180,196,172,124,84,55,28,0,0,0,12,28,47,44,52,44,44,39,36,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,84,116,148,156,156,148,140,132,124,132,172,220,244,247,252,220,220,196,196,228,207,212,236,223,180,108,68,84,124,164,180,156,111,76,60,36,12,0,0,0,0,0,0,7,20,23,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,68,84,108,132,132,116,116,108,108,103,100,100,156,204,228,231,247,252,188,188,172,172,220,196,180,196,220,212,188,108,52,44,84,124,148,156,140,100,71,55,39,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,68,84,100,124,116,84,84,84,79,84,84,71,84,140,204,220,212,220,244,244,167,167,156,148,199,207,164,156,183,196,199,180,119,52,20,39,84,116,132,127,116,87,68,52,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,68,76,95,108,95,68,60,63,63,68,71,68,52,68,124,199,215,188,188,204,220,223,148,148,156,119,167,228,164,135,143,156,156,180,180,132,60,12,12,44,84,108,111,100,92,76,60,52,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,55,68,84,92,76,52,44,44,52,52,60,52,47,36,52,116,196,220,180,159,172,180,188,196,119,124,159,92,124,215,196,124,108,124,116,132,167,175,140,68,12,0,15,44,76,92,92,76,68,63,52,44,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,52,68,71,60,44,36,36,36,44,47,39,31,28,28,44,100,180,204,164,132,148,156,156,167,164,92,111,164,68,76,175,228,143,92,92,100,87,124,156,172,148,79,20,0,0,20,44,68,76,71,52,44,44,44,39,36,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,28,36,47,52,44,36,31,23,28,36,44,39,28,15,20,12,31,100,167,196,156,116,116,148,132,140,156,135,71,108,172,71,36,132,220,180,100,71,87,76,71,116,148,172,156,92,28,0,0,0,15,36,52,60,52,28,12,28,36,36,31,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,36,31,28,28,20,15,23,36,39,28,12,0,12,0,20,92,164,180,140,84,84,119,132,108,124,156,108,60,108,180,76,12,100,183,204,132,60,71,71,52,68,108,132,164,156,92,36,0,0,0,0,12,28,36,36,28,12,0,15,28,28,28,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,7,12,23,15,0,12,28,36,31,15,0,0,0,0,20,76,151,180,135,79,63,87,132,108,92,111,148,76,36,108,183,84,0,68,140,212,159,79,44,76,60,44,68,100,116,148,148,100,39,0,0,0,0,0,12,28,28,28,20,7,0,7,20,28,23,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,23,20,0,0,0,0,0,12,63,135,164,132,84,44,60,108,108,79,84,103,135,60,20,108,164,60,0,36,108,191,180,124,36,52,71,44,36,71,87,95,127,140,100,44,0,0,0,0,0,0,12,28,23,20,12,0,0,0,12,15,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,12,60,119,140,116,84,36,44,76,116,79,47,87,108,108,55,0,108,143,44,0,12,92,156,183,148,63,28,63,68,28,36,71,84,79,108,132,100,44,7,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,12,52,108,124,103,84,44,28,60,100,92,63,31,92,124,76,52,0,108,140,36,0,0,71,119,172,156,100,20,36,68,52,15,36,76,71,68,100,116,92,39,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,44,100,108,92,71,44,20,44,68,100,68,36,44,84,124,60,44,0,108,148,47,0,0,44,100,156,148,127,55,7,47,63,36,0,36,71,68,60,84,100,79,39,12,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,92,100,79,68,47,20,20,60,84,84,60,12,68,84,108,52,28,0,108,148,44,7,0,12,92,132,132,143,84,15,20,55,55,20,0,44,68,60,47,76,87,76,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,84,92,76,55,47,28,0,44,63,84,60,36,12,84,87,79,47,7,0,108,140,39,12,0,0,76,108,132,127,108,44,0,28,60,44,7,12,44,68,52,36,60,76,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,71,84,68,52,44,28,0,23,55,71,68,52,7,31,84,95,55,44,0,0,108,132,28,0,0,0,44,100,132,100,119,68,12,0,39,60,31,0,12,44,68,44,31,52,68,55,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,68,76,63,44,44,31,12,0,44,55,68,52,31,0,60,84,95,44,44,0,0,92,108,20,0,0,0,15,92,116,95,111,84,36,0,15,47,52,20,0,12,44,60,36,28,44,52,52,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,76,63,28,28,28,12,0,28,52,52,44,39,12,0,76,84,79,39,36,0,0,76,92,15,0,0,0,0,76,100,108,84,95,55,0,0,28,52,44,7,0,15,44,60,31,20,36,47,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,68,60,31,23,28,12,0,12,44,47,39,31,23,0,20,84,84,52,36,20,0,0,68,84,15,0,0,0,0,44,100,116,63,92,60,28,0,0,36,52,28,0,0,20,44,55,28,15,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,52,44,23,20,20,12,0,0,28,47,36,28,23,7,0,47,84,76,36,36,0,0,0,68,87,20,0,0,0,0,15,92,100,71,68,68,44,0,0,12,44,44,15,0,0,20,47,52,20,12,20,23,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,47,39,12,20,20,12,0,0,15,44,44,20,15,12,0,0,68,84,60,36,36,0,0,0,68,87,20,0,0,0,0,0,71,87,84,44,76,44,20,0,0,20,44,36,0,0,0,20,52,44,20,7,20,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,52,36,12,0,12,12,0,0,0,31,44,23,0,0,0,0,12,79,84,44,31,31,0,0,0,68,87,20,0,0,0,0,0,44,84,84,44,60,52,36,0,0,0,28,39,20,0,0,0,23,47,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,44,39,20,12,0,12,0,0,0,15,39,36,0,0,0,0,0,36,79,76,36,28,23,0,0,0,68,84,15,0,0,0,0,0,15,76,76,47,36,60,44,20,0,0,12,36,36,12,0,0,0,23,47,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,15,7,0,0,0,0,0,0,31,36,15,0,0,0,0,0,60,76,60,20,20,12,0,0,0,68,84,15,0,0,0,0,0,0,60,76,60,28,52,44,36,0,0,0,15,36,28,0,0,0,0,23,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,0,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,0,0,71,76,28,12,12,0,0,0,0,68,92,20,0,0,0,0,0,0,39,76,68,36,36,52,36,12,0,0,0,20,36,20,0,0,0,0,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,7,31,31,12,0,0,0,0,0,20,68,68,12,12,12,0,0,0,0,60,87,28,0,0,0,0,0,0,15,60,60,36,20,39,36,28,0,0,0,7,28,28,12,0,0,0,0,28,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,23,12,0,0,0,0,0,0,0,0,20,28,20,0,0,0,0,0,0,44,68,52,0,12,12,0,0,0,0,44,60,15,0,0,0,0,0,0,0,44,55,36,20,28,39,36,12,0,0,0,12,28,20,0,0,0,0,0,23,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,12,7,0,0,0,0,0,0,0,0,12,28,28,0,0,0,0,0,0,0,60,68,36,7,7,0,0,0,0,0,23,28,0,0,0,0,0,0,0,0,20,36,36,15,15,36,28,20,0,0,0,0,15,23,12,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,12,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,12,52,52,12,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,7,28,28,15,12,20,28,28,0,0,0,0,0,20,20,7,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,20,15,0,0,0,0,0,0,0,28,47,44,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,23,28,12,12,12,28,28,15,0,0,0,0,7,20,15,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,28,31,20,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,12,28,20,12,12,20,23,23,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,12,0,0,0,0,0,0,0,0,36,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,15,20,12,0,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,7,20,20,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,20,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_8[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,12,23,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,12,39,39,0,0,0,0,12,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,7,7,0,0,0,0,7,44,44,7,0,0,0,15,20,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,12,7,0,0,0,7,7,44,44,20,0,0,0,15,20,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,23,12,7,0,0,7,7,47,47,36,0,0,0,15,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,28,12,12,0,0,12,12,60,63,60,0,0,0,15,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,20,12,0,0,0,12,44,68,68,0,0,0,15,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,36,20,12,0,0,20,31,68,68,0,0,0,15,36,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,12,31,36,23,20,0,0,20,23,84,71,20,0,0,12,28,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,28,36,47,28,12,0,20,20,84,71,36,0,0,0,28,23,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,7,7,0,0,0,0,0,0,0,23,36,55,28,23,0,12,20,84,71,55,0,0,0,20,28,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,15,12,0,0,0,0,0,12,15,44,47,44,31,0,7,31,84,76,68,0,0,0,28,39,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,7,12,12,0,0,0,0,12,12,39,36,63,36,15,0,31,68,84,76,0,0,0,28,52,28,28,0,0,0,0,0,0,0,0,0,0,0,0,7,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,0,0,20,20,12,0,0,0,0,20,36,44,68,44,31,0,36,52,100,76,12,0,0,36,52,28,28,0,7,7,0,0,0,0,0,0,0,0,0,28,39,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,7,0,12,28,23,0,0,0,0,20,20,52,52,63,36,0,28,44,111,76,28,0,0,36,44,12,12,0,12,12,0,0,0,0,0,0,0,0,12,39,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,12,0,20,31,20,0,0,0,12,23,47,47,84,44,20,20,36,116,76,44,0,0,36,44,12,12,0,12,12,0,0,0,0,0,0,0,0,31,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,28,36,15,0,0,0,20,36,60,76,60,36,0,39,108,84,60,0,0,36,63,28,28,12,12,12,0,0,0,0,0,0,0,15,44,44,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,28,12,12,36,31,7,0,0,12,28,63,60,84,44,7,44,92,95,71,0,0,44,79,44,28,20,20,12,0,0,0,0,0,0,0,36,47,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,28,12,23,44,28,0,0,0,28,52,68,95,55,28,39,76,116,76,0,0,44,84,44,23,20,20,0,0,0,0,0,0,0,20,52,44,0,0,0,0,0,0,0,0,0,0,12,20,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,28,15,36,44,20,0,0,15,36,76,84,76,44,28,60,124,76,12,0,47,92,44,23,28,28,0,0,0,0,0,0,0,44,52,23,0,0,0,0,0,0,0,0,0,7,28,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,47,28,20,44,44,12,0,0,36,68,84,100,52,23,52,132,84,31,0,47,92,47,28,36,36,0,0,0,0,0,0,28,55,44,0,0,0,0,0,0,0,0,0,12,39,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,47,28,31,52,36,0,0,23,52,92,108,71,36,52,127,95,47,0,47,92,47,39,36,36,0,0,0,0,0,12,52,55,23,0,0,0,0,0,0,0,0,20,52,63,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,44,47,36,44,55,28,0,0,44,87,103,100,52,52,116,116,68,0,52,100,52,44,36,31,0,0,0,0,0,36,60,44,0,0,0,0,0,0,0,0,20,60,76,60,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,44,44,52,52,20,0,28,68,108,119,68,60,100,132,76,0,55,108,52,44,44,20,0,0,0,0,15,60,60,20,0,0,0,0,0,0,0,28,63,76,60,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,55,47,52,60,44,7,12,52,108,132,95,63,92,148,87,12,60,111,60,44,44,12,0,0,0,0,44,68,44,0,0,0,0,0,0,0,36,87,108,68,20,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,63,52,60,63,36,0,36,87,135,124,71,92,156,108,23,60,116,68,47,47,15,15,12,0,20,68,63,20,0,0,0,0,0,0,36,92,116,84,31,0,0,0,0,0,0,0,0,0,0,12,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,44,68,60,68,60,23,15,68,132,156,95,100,159,127,44,60,116,84,52,52,12,12,0,0,52,68,44,0,0,0,0,0,7,47,100,108,79,36,7,0,0,0,0,0,0,0,0,15,28,28,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,52,68,71,76,52,12,44,124,183,132,108,148,140,60,60,119,103,52,60,20,20,0,28,71,68,12,0,0,0,0,12,60,116,127,84,31,0,0,0,0,0,0,0,0,15,31,36,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,60,76,84,76,44,28,103,196,183,132,151,156,76,68,124,116,55,68,31,28,0,60,76,44,0,0,0,0,12,68,135,148,100,36,0,0,0,0,0,0,0,20,36,36,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,7,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,28,68,84,92,68,36,68,172,220,156,164,156,95,79,140,124,60,63,36,15,36,76,68,15,0,0,0,20,76,156,164,108,36,0,0,0,0,0,0,20,39,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,20,23,20,7,0,0,0,12,12,0,0,12,7,12,12,12,7,0,0,0,0,0,36,76,100,95,60,47,124,220,196,188,164,116,103,156,124,71,52,39,15,68,84,47,7,0,0,23,79,156,172,116,44,7,0,7,0,0,20,44,52,47,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,28,28,28,15,0,0,0,0,0,20,28,28,15,20,15,20,20,0,0,0,0,44,92,108,95,55,87,180,228,207,188,132,132,180,124,92,52,44,44,92,92,36,12,0,23,87,159,164,100,39,15,15,12,12,28,52,63,60,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,31,31,31,36,28,12,0,0,20,28,39,39,36,28,36,36,28,15,0,0,12,68,119,132,92,76,140,228,220,212,143,148,191,124,116,52,44,84,111,84,44,28,39,95,164,159,92,36,23,28,20,31,60,79,84,68,36,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,39,44,39,39,39,28,12,12,28,36,52,60,55,55,55,44,28,7,0,31,92,148,135,87,116,191,236,236,164,167,204,132,116,55,68,116,124,71,52,68,116,164,151,87,44,36,36,44,68,92,100,84,60,28,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,44,55,52,52,44,39,28,28,36,52,68,71,76,71,63,39,20,0,52,116,159,132,108,156,231,247,180,183,212,148,108,76,103,148,116,76,92,135,167,143,87,52,44,55,76,92,100,100,71,31,0,0,0,0,12,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,44,71,79,71,60,52,44,44,44,60,84,95,100,87,68,31,20,60,132,172,140,148,204,252,207,207,220,172,103,111,148,159,116,116,148,167,140,92,63,68,92,108,100,95,76,39,7,0,12,28,31,23,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,31,44,68,92,95,84,68,63,60,68,84,111,124,124,92,52,36,71,156,180,167,188,239,236,236,236,191,124,143,180,172,156,172,172,148,100,84,100,116,111,100,79,39,12,20,36,39,36,36,31,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,68,92,111,116,95,92,92,100,116,151,159,135,92,60,95,172,188,196,223,252,252,244,196,164,180,215,204,196,196,151,124,119,127,116,100,84,52,36,44,47,44,44,39,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,68,108,140,148,140,140,140,148,167,188,188,132,100,124,180,220,228,252,252,247,204,199,220,236,228,212,180,164,151,140,108,92,76,63,55,52,52,47,44,31,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,47,79,116,148,164,172,175,188,204,223,212,172,140,156,207,244,252,252,247,228,228,244,244,231,212,191,164,140,124,116,103,92,76,68,52,36,15,12,12,20,20,12,0,0,0,0,0,0,0,0,0,7,20,20,15,15,28,28,15,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,36,68,100,132,156,167,188,228,244,239,204,180,199,236,252,252,252,247,247,252,247,228,212,191,172,156,140,124,124,108,92,68,47,44,36,36,28,23,28,31,36,44,52,47,47,44,44,36,31,36,36,28,20,15,28,28,15,0,0,12,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,15,23,20,12,12,20,20,12,7,0,12,36,68,100,140,180,228,244,247,228,220,236,252,252,252,252,252,252,252,239,220,196,180,175,188,183,167,140,116,103,100,100,103,100,87,79,68,63,52,52,52,47,44,44,44,36,31,36,36,28,20,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,23,28,28,28,15,0,15,31,52,60,76,68,60,76,103,119,116,108,100,92,87,79,84,108,148,188,212,236,247,247,247,252,252,252,252,252,252,252,239,236,236,236,220,204,196,196,180,159,132,108,84,68,60,60,60,55,55,52,52,47,39,31,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,23,23,28,28,28,12,0,15,31,44,52,63,68,60,76,103,124,119,116,116,116,116,116,124,132,156,183,212,236,252,252,252,252,252,252,252,252,252,247,244,244,244,244,236,215,188,164,132,100,76,60,52,39,28,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,36,44,52,60,68,76,84,84,92,92,100,100,108,116,132,156,191,228,244,252,252,252,252,252,252,252,252,252,252,252,239,220,188,151,116,100,63,31,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,20,44,60,71,76,76,76,76,84,84,84,84,84,84,84,84,84,84,84,87,95,116,132,156,164,167,180,207,236,252,252,252,252,252,252,252,252,252,252,252,247,239,212,164,108,71,68,52,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,23,47,47,23,0,20,52,76,84,79,76,76,76,84,84,84,84,84,76,76,68,76,92,100,100,92,92,87,100,124,151,183,212,236,252,252,252,252,252,252,236,236,252,252,252,247,228,204,191,172,132,87,63,52,52,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,23,47,47,23,0,20,44,60,55,47,36,31,20,20,12,7,20,36,52,55,60,60,60,63,68,92,116,132,135,127,140,180,212,220,231,239,244,252,252,228,204,204,252,244,244,244,228,204,172,151,140,116,92,71,60,44,44,36,36,31,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,52,52,52,55,60,60,68,84,100,92,76,68,68,95,132,151,167,183,196,204,220,239,252,244,183,159,188,244,223,223,228,228,212,180,148,132,124,108,71,31,20,31,36,36,31,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,44,44,44,44,47,52,52,52,52,55,55,52,52,55,60,60,76,84,92,95,124,148,148,156,188,220,239,247,220,127,127,188,228,188,196,191,204,220,220,172,124,100,92,95,84,52,12,0,0,12,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,20,23,23,28,36,36,36,44,44,44,36,20,20,28,44,44,47,52,52,52,44,44,60,68,76,100,116,108,92,116,156,196,223,244,236,167,79,103,172,188,172,172,164,172,172,212,231,188,119,76,68,76,79,71,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,20,20,23,23,28,36,28,15,0,0,12,28,36,36,44,44,44,44,36,20,28,52,68,71,84,92,92,76,63,84,124,180,196,212,223,204,108,52,95,143,140,172,156,143,151,135,148,215,244,204,132,68,44,60,76,76,68,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,12,20,20,20,20,15,12,0,0,0,0,12,23,23,28,36,36,36,36,23,0,0,28,52,63,68,71,76,71,63,60,44,55,108,164,188,172,191,212,156,52,44,95,108,84,164,164,116,132,127,100,148,220,244,212,156,84,31,31,60,76,71,68,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,15,20,28,28,23,28,28,15,0,0,0,28,52,60,63,60,60,52,52,55,44,28,44,103,143,164,148,156,199,188,95,12,55,87,84,60,148,180,108,84,124,84,76,148,191,207,199,159,92,36,7,28,55,68,68,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,15,20,23,20,12,0,0,0,0,28,52,60,60,55,44,36,44,52,44,23,20,47,103,124,140,124,132,172,204,140,44,0,60,71,44,31,124,196,116,44,76,87,60,63,124,156,180,188,151,108,52,12,0,23,52,63,60,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,12,7,0,0,0,0,0,12,28,47,52,55,52,31,28,36,44,44,28,7,15,52,100,116,116,103,108,148,204,180,84,7,0,55,55,12,12,100,188,140,52,28,71,68,39,52,108,132,148,164,148,116,60,20,0,0,20,44,60,60,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,47,52,44,20,12,23,36,36,28,12,0,20,52,100,100,100,92,92,116,180,204,124,28,0,12,52,52,0,0,79,167,156,76,0,36,68,52,23,52,95,116,124,143,140,124,76,31,0,0,0,20,44,60,55,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,44,44,36,15,0,12,28,31,28,15,0,0,28,60,92,92,84,79,84,92,148,204,156,68,0,0,28,44,44,0,0,60,132,164,103,12,7,52,68,31,15,47,87,100,108,124,127,124,84,44,7,0,0,0,20,44,52,47,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,44,31,12,0,7,20,28,28,15,0,0,0,28,60,84,76,68,68,76,76,116,180,180,100,20,0,0,36,44,44,0,0,47,100,175,119,36,0,23,60,60,15,20,44,76,84,92,103,116,119,95,60,20,0,0,0,0,15,36,47,47,44,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,36,36,28,7,0,0,7,20,20,20,0,0,0,0,31,60,76,68,52,60,68,60,84,140,172,119,44,0,0,0,39,39,28,0,0,28,71,164,124,68,0,0,36,60,39,0,20,44,68,68,76,87,103,111,103,68,28,0,0,0,0,0,15,36,47,44,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,31,31,31,20,0,0,0,0,0,7,15,7,0,0,0,7,36,60,68,60,44,52,60,52,68,116,156,135,76,12,0,0,0,36,36,12,0,0,12,60,132,124,84,0,0,12,52,60,23,0,20,44,60,55,68,76,92,100,103,76,39,0,0,0,0,0,0,15,36,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,28,28,28,15,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,60,44,31,44,55,52,52,92,135,140,92,36,0,0,0,0,36,36,0,0,0,0,52,103,127,100,23,0,0,28,52,44,7,0,20,39,52,44,60,68,79,92,100,84,52,12,0,0,0,0,0,0,12,28,36,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,44,36,20,31,47,52,36,68,116,132,103,60,7,0,0,0,12,28,28,0,0,0,0,52,76,124,103,44,0,0,0,36,52,28,0,0,20,36,36,36,52,60,68,76,92,87,60,23,0,0,0,0,0,0,0,12,28,36,36,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,15,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,52,36,20,12,23,39,52,28,47,100,119,111,76,28,0,0,0,0,15,20,20,0,0,0,0,44,55,103,92,52,0,0,0,12,44,44,15,0,0,12,20,20,28,44,52,60,68,84,87,68,36,0,0,0,0,0,0,0,0,12,23,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,44,28,12,7,12,36,52,28,36,84,108,108,84,44,0,0,0,0,0,15,15,12,0,0,0,0,28,44,87,84,68,15,0,0,0,28,44,36,0,0,0,0,15,28,28,36,39,52,60,71,84,68,36,0,0,0,0,0,0,0,0,0,7,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,39,20,0,0,12,28,47,28,20,63,100,100,87,63,20,0,0,0,0,0,15,15,0,0,0,0,0,12,44,76,76,76,36,0,0,0,0,36,44,20,0,0,0,15,28,20,20,20,31,44,52,60,68,63,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,36,15,0,0,0,20,44,28,12,44,92,92,84,68,36,0,0,0,0,0,0,7,7,0,0,0,0,0,0,36,55,60,76,39,0,0,0,0,15,36,36,7,0,0,0,12,23,20,12,12,23,36,44,44,52,60,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,36,28,12,0,0,0,20,36,28,12,31,76,92,71,71,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,44,55,71,44,12,0,0,0,0,23,36,20,0,0,0,0,12,12,0,0,0,15,28,39,36,44,52,44,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,23,7,0,0,0,12,36,28,12,15,63,92,68,63,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,36,60,63,55,23,0,0,0,0,7,28,31,12,0,0,0,0,0,0,0,0,0,7,23,28,23,28,44,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,23,20,0,0,0,0,12,28,28,12,0,47,84,68,52,60,44,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,52,47,60,31,0,0,0,0,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,12,23,20,28,28,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,7,0,0,0,0,0,12,20,12,0,36,76,71,39,52,52,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,23,36,23,52,28,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,12,20,23,20,20,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,0,0,0,7,12,0,0,20,63,76,44,31,52,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,15,36,28,7,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,7,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,12,20,7,0,0,47,76,52,20,44,44,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,28,28,20,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,7,7,12,0,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,15,12,0,0,36,71,60,15,28,44,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,36,20,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,20,60,68,28,12,36,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,44,68,44,0,28,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,60,52,12,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,44,52,20,0,28,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,44,28,0,12,28,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,0,0,23,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,31,31,12,0,12,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,15,0,0,23,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,12,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t SHINE_TEXTURE_9[16384] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,7,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,23,20,0,0,0,7,0,0,0,0,0,0,0,0,0,0,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,23,0,0,0,28,28,20,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,12,0,0,36,36,28,0,0,0,0,0,0,0,0,20,23,12,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,36,15,0,0,36,31,23,0,0,0,0,0,0,0,0,20,20,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,28,0,12,23,20,12,0,0,0,0,0,0,0,0,36,36,0,0,0,7,20,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,0,12,20,36,28,0,0,0,0,0,0,0,12,52,52,7,0,12,12,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,12,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,39,20,0,20,71,60,12,0,0,0,0,0,0,20,52,52,7,0,12,12,23,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,12,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,36,52,28,0,23,84,68,12,0,0,0,0,0,0,36,60,52,0,0,20,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,60,47,12,23,55,31,7,0,0,0,0,0,0,63,79,60,7,15,12,28,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,12,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,76,71,12,15,52,36,20,0,0,0,0,0,0,60,68,44,12,28,28,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,20,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,15,76,79,28,20,76,68,44,0,0,0,0,0,0,68,68,36,15,36,39,28,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,7,28,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,76,84,52,31,100,100,68,0,0,0,0,0,20,92,92,39,28,36,60,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,15,20,0,0,0,12,36,31,12,0,0,0,0,0,0,0,0,0,0,0,0,60,92,68,28,84,108,76,0,0,0,0,0,36,92,92,36,39,36,60,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,36,23,0,0,0,20,44,28,0,0,0,0,0,0,0,0,0,7,7,0,39,92,87,36,68,111,79,0,0,0,0,0,55,108,103,31,52,44,52,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,23,31,36,20,0,0,0,28,44,20,0,0,0,0,0,0,0,0,12,12,7,20,92,95,52,68,124,84,0,0,0,0,0,76,116,108,28,60,68,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,28,31,39,28,0,0,12,39,44,15,0,0,0,0,0,0,0,12,20,15,0,92,100,63,60,127,84,12,0,0,0,0,92,124,108,44,60,76,39,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,39,44,23,0,0,20,44,36,12,0,0,0,0,0,0,0,23,23,0,68,100,79,60,140,100,23,0,0,0,12,108,132,103,68,76,76,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,36,36,44,23,0,0,28,52,31,0,0,0,0,0,0,0,20,20,7,44,100,92,68,140,108,36,0,0,0,23,124,140,92,79,84,63,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,28,23,36,44,28,0,7,39,52,28,0,0,0,0,0,0,12,23,20,20,100,100,76,132,116,47,0,0,0,39,127,156,84,92,92,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,28,39,52,47,23,0,20,52,52,20,0,0,0,0,0,0,31,31,12,92,100,95,132,140,60,0,0,0,60,127,156,92,108,92,44,0,0,0,0,0,0,0,7,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,44,52,52,55,52,23,0,28,60,44,12,0,0,0,0,0,28,36,23,76,100,111,132,151,71,0,0,0,76,127,148,95,116,84,36,0,0,0,0,0,0,7,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,28,60,63,60,68,52,20,0,36,60,36,7,15,15,0,0,15,39,39,52,100,116,124,151,79,0,0,12,100,143,140,103,108,68,20,0,0,0,0,0,12,23,23,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,63,71,71,71,52,28,12,52,60,28,20,28,15,0,0,44,44,44,100,108,124,148,92,0,0,28,127,164,140,127,108,60,0,0,0,0,0,15,28,28,23,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,76,84,84,76,52,20,23,60,60,28,28,28,12,0,44,55,52,92,100,140,151,108,0,0,39,140,188,148,148,108,47,0,0,0,0,12,28,44,39,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,76,92,92,84,52,23,36,68,52,31,36,28,0,28,63,60,84,100,156,151,119,20,0,44,132,180,151,148,103,36,7,0,0,7,28,52,52,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,84,100,108,92,52,28,44,71,52,44,44,20,0,68,68,84,100,156,156,132,28,0,71,156,188,164,140,92,23,0,0,0,28,52,60,39,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,20,15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,7,0,0,0,0,0,12,36,87,111,116,100,55,39,60,68,60,52,44,7,52,76,87,100,151,164,140,39,0,100,183,204,191,148,76,23,0,0,20,52,71,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,28,23,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,20,20,15,12,12,0,0,0,36,92,124,127,108,60,52,68,76,76,60,36,23,76,84,108,140,180,140,52,20,119,204,220,196,148,60,12,0,12,44,76,71,31,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,44,36,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,20,28,36,36,36,28,12,0,0,36,92,132,135,111,60,60,76,84,84,68,20,68,79,124,124,196,140,63,31,132,228,236,199,132,44,0,0,36,76,84,44,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,55,52,44,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,52,60,47,28,7,0,36,92,132,148,116,71,76,87,108,92,52,47,79,127,116,199,140,76,44,148,244,244,196,108,28,0,28,76,95,68,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,60,60,52,31,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,63,76,76,52,23,0,31,87,148,180,148,92,84,108,116,84,44,76,116,127,196,156,87,60,164,252,244,188,87,12,15,68,103,92,44,12,0,0,0,0,0,0,0,0,0,0,0,0,28,52,68,68,60,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,60,92,100,84,44,20,28,95,175,204,156,108,103,132,116,68,76,92,151,183,180,100,76,180,252,244,164,68,7,55,111,116,68,28,7,0,0,0,0,0,0,0,0,0,0,36,68,84,76,68,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,52,87,116,116,84,36,36,100,180,207,164,124,132,143,100,79,84,164,188,204,111,87,188,252,228,132,36,36,108,140,92,39,12,0,0,0,0,0,0,0,0,7,39,76,92,92,79,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,36,76,124,148,124,68,55,100,180,204,172,140,156,143,95,100,148,196,220,124,100,204,252,199,100,36,100,159,132,60,12,0,0,0,0,0,0,0,12,44,84,100,100,87,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,20,60,116,156,151,108,76,108,180,196,180,164,172,132,116,132,212,228,132,116,220,244,164,71,76,156,156,92,28,0,0,0,0,0,0,12,47,84,103,108,92,63,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,15,12,0,36,92,140,164,135,116,132,180,204,196,196,191,148,140,204,231,148,132,231,223,127,76,140,180,124,39,0,0,0,0,0,12,52,87,103,103,92,60,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,20,20,20,31,36,31,44,76,124,151,159,151,156,196,212,223,236,188,172,196,244,159,156,244,188,116,119,188,156,60,12,0,0,0,20,55,92,103,103,92,55,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,20,36,39,36,44,60,71,84,116,148,164,172,196,228,244,252,228,196,199,239,180,180,236,164,135,172,172,84,20,0,0,20,60,92,103,103,87,52,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,20,12,12,12,0,0,0,0,0,0,0,0,0,12,12,12,20,23,47,68,76,76,84,100,127,159,180,196,228,244,252,252,228,228,244,204,204,220,172,167,172,100,23,0,23,63,92,108,108,87,47,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,20,12,15,28,28,28,28,36,39,36,28,12,0,0,0,0,12,20,31,36,52,76,103,124,124,140,172,207,228,244,252,252,244,244,244,228,228,212,199,172,116,39,28,68,100,124,124,100,52,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,28,28,28,28,36,39,44,44,44,47,52,52,52,47,36,31,36,44,44,52,76,108,151,175,196,220,244,252,252,252,252,252,244,244,231,196,132,76,79,119,140,140,116,63,28,0,0,0,0,0,0,0,7,20,20,28,28,31,23,15,12,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,7,20,36,44,44,44,47,52,52,52,55,60,60,68,76,84,95,108,103,111,132,164,204,231,252,252,252,252,252,252,252,231,188,140,132,148,148,124,76,44,31,28,31,44,52,52,52,52,52,52,52,47,52,52,52,28,15,20,44,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,28,15,0,0,0,20,36,44,44,55,71,92,103,108,116,124,127,124,132,127,127,143,164,180,204,228,244,252,252,252,252,252,252,236,207,188,188,180,156,124,108,103,116,124,132,132,124,116,108,103,100,92,87,76,68,60,39,12,0,7,15,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,23,28,39,36,20,15,28,47,68,71,76,84,87,95,95,100,124,159,180,188,207,220,223,223,220,212,212,228,244,252,252,252,252,252,252,244,244,236,212,188,175,180,196,204,215,220,228,223,196,167,148,132,124,108,100,95,92,92,76,60,36,20,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,20,28,28,36,36,44,52,60,68,76,84,100,108,124,127,140,172,207,228,228,236,244,239,244,236,236,247,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,236,212,175,156,124,100,87,84,84,84,84,84,84,84,84,68,44,36,23,0,0,0,0,0,0,0,0,12,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,44,68,84,60,31,47,84,100,100,92,92,92,92,92,92,100,108,124,143,164,164,172,172,172,196,207,220,223,236,244,244,252,252,252,252,252,252,252,252,252,236,212,204,215,236,252,236,215,180,159,140,116,87,76,76,71,60,44,36,28,28,28,28,31,20,0,0,0,0,0,0,0,0,12,20,20,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,28,60,76,44,12,28,60,84,84,84,84,84,87,84,76,76,68,63,60,68,92,127,148,143,140,148,172,188,196,215,244,252,252,252,252,252,252,252,252,252,236,212,183,164,156,164,188,212,223,223,191,156,119,103,92,79,60,52,52,47,44,44,36,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,20,44,52,31,7,12,20,20,12,0,0,0,7,7,12,20,28,52,68,79,79,84,95,119,140,140,124,140,167,204,236,247,236,236,231,236,252,252,247,247,244,228,191,156,140,119,108,116,135,148,151,143,124,111,100,92,76,76,71,68,60,52,44,39,36,28,28,31,23,15,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,52,60,60,63,68,79,100,108,92,79,100,124,140,159,204,228,231,207,212,207,212,244,244,236,220,212,220,212,196,180,148,111,76,60,60,60,63,60,68,76,76,60,44,28,28,39,52,47,44,39,28,28,31,23,15,12,23,12,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,39,52,52,52,55,60,60,60,68,68,63,68,76,92,95,116,140,167,188,228,196,172,196,188,180,223,228,220,191,156,167,172,172,180,188,180,156,116,68,28,15,28,39,39,36,36,36,39,36,31,20,12,0,0,0,0,12,12,12,12,23,12,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,39,44,44,47,52,52,47,36,31,44,52,60,60,60,60,68,84,108,124,140,156,212,215,148,148,204,172,148,204,196,188,180,124,100,132,140,140,148,164,180,188,159,111,68,31,0,0,12,28,31,28,20,15,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,28,36,36,39,44,44,44,36,20,7,20,39,52,52,55,47,36,44,68,84,100,108,116,132,180,215,172,108,143,228,156,124,188,164,156,167,124,76,68,111,116,111,111,132,148,175,180,148,100,68,36,7,0,0,0,0,12,12,12,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,20,28,36,36,36,36,23,0,0,0,20,39,44,47,52,36,15,23,52,76,79,84,92,100,116,159,204,188,108,92,164,244,143,100,156,140,124,124,143,84,44,55,95,103,100,87,95,111,127,156,156,132,92,68,36,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,28,20,20,23,23,12,0,0,0,7,20,36,39,44,44,28,0,0,36,68,76,68,68,79,84,95,140,188,191,132,60,92,188,215,116,76,119,143,92,95,132,116,60,20,52,84,92,84,76,76,76,87,108,132,140,116,84,60,39,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,15,15,20,20,12,0,0,0,0,0,12,20,28,36,36,36,20,0,0,20,52,68,68,52,60,76,76,76,124,175,188,143,76,36,108,196,180,84,44,100,143,68,84,92,124,84,31,7,44,76,76,71,68,68,60,60,76,95,116,119,108,76,55,36,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,12,0,0,0,0,0,0,0,0,15,23,28,28,23,12,0,0,0,36,60,68,52,39,47,76,68,63,103,164,180,148,92,28,52,124,180,151,55,20,92,124,76,68,68,100,92,60,12,0,36,68,68,60,55,63,52,44,44,63,84,95,100,87,63,44,31,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,20,23,15,0,0,0,0,20,44,63,60,36,28,47,76,60,47,76,148,164,148,108,52,0,68,140,148,116,23,0,87,100,92,52,52,68,92,68,36,0,0,28,60,68,52,44,60,60,36,28,36,60,68,71,76,68,52,36,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,31,52,60,47,20,20,52,76,52,36,60,132,143,132,116,76,12,15,76,156,124,92,12,0,79,92,100,47,44,52,76,76,60,23,0,0,23,52,68,44,36,44,52,44,23,15,28,44,55,52,52,52,44,28,20,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,20,44,55,52,31,7,20,52,71,47,28,47,116,132,124,116,92,36,0,44,79,164,116,63,7,0,63,92,100,44,39,31,52,68,60,47,12,0,0,20,47,63,39,28,31,52,47,28,12,12,28,28,36,36,44,44,28,20,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,52,52,44,20,0,23,52,68,39,12,36,95,124,108,108,100,60,0,0,60,92,151,111,39,0,0,44,92,92,44,39,20,44,55,60,55,36,0,0,0,12,39,60,44,20,20,44,44,31,12,0,0,12,20,36,28,28,28,23,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,36,52,44,28,0,0,28,55,60,36,0,20,68,116,108,92,100,76,20,0,12,68,111,127,108,12,0,0,23,87,87,44,36,20,23,44,52,47,52,20,0,0,0,12,36,60,44,15,12,28,44,36,20,0,0,0,12,15,20,20,20,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,44,44,36,12,0,0,28,60,55,28,0,12,44,92,100,76,92,92,44,0,0,36,68,124,108,92,0,0,0,7,87,87,47,31,28,0,36,39,39,47,39,12,0,0,0,0,28,52,44,20,0,20,36,36,23,7,0,0,0,0,12,12,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,31,44,39,20,0,0,0,31,55,52,23,0,0,28,76,92,68,79,92,63,7,0,0,52,63,119,100,76,0,0,0,0,84,87,52,28,28,0,20,36,36,31,44,28,0,0,0,0,0,28,44,44,20,0,12,28,36,28,12,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,36,39,28,12,0,0,12,36,55,44,20,0,0,20,60,84,68,60,84,79,28,0,0,0,60,63,100,87,52,0,0,0,0,68,87,68,20,23,12,0,28,36,28,36,44,20,0,0,0,0,0,20,39,39,20,0,0,15,23,20,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,28,36,31,20,0,0,0,12,36,52,36,12,0,0,12,36,68,71,47,68,84,44,0,0,0,28,60,63,84,79,36,0,0,0,0,47,87,79,12,15,15,0,12,28,28,20,36,31,7,0,0,0,0,0,12,36,39,20,0,0,0,12,12,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,28,31,20,7,0,0,0,12,36,52,31,12,0,0,12,28,52,68,39,44,76,63,12,0,0,0,44,60,52,71,71,15,0,0,0,0,28,84,84,12,12,12,0,0,20,23,12,20,36,20,0,0,0,0,0,0,12,28,36,20,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,28,23,12,0,0,0,0,15,36,44,28,0,0,0,7,23,52,63,44,28,55,63,28,0,0,0,0,52,55,36,60,60,0,0,0,0,0,12,84,84,20,0,0,0,0,7,20,20,12,28,31,12,0,0,0,0,0,0,7,23,36,20,0,0,0,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,23,15,0,0,0,0,0,15,36,44,20,0,0,0,0,7,31,60,47,20,31,55,39,0,0,0,0,20,52,52,20,44,44,0,0,0,0,0,0,84,84,44,0,0,0,0,0,12,20,12,12,28,28,0,0,0,0,0,0,0,0,20,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,20,7,0,0,0,0,0,12,31,36,20,0,0,0,0,0,15,44,52,28,15,44,44,12,0,0,0,0,36,52,44,20,36,31,0,0,0,0,0,0,68,84,60,0,0,0,0,0,0,12,12,0,12,20,12,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,7,0,0,0,0,0,0,12,28,20,12,0,0,0,0,0,12,31,47,28,0,28,44,28,0,0,0,0,0,47,52,20,23,28,20,0,0,0,0,0,0,52,84,76,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,20,28,20,0,0,0,0,0,0,7,28,47,36,12,15,39,36,0,0,0,0,0,12,47,47,0,20,20,7,0,0,0,0,0,0,31,84,79,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,31,20,7,0,0,0,0,0,0,15,39,36,12,0,31,36,15,0,0,0,0,0,28,44,44,0,12,12,0,0,0,0,0,0,0,12,76,76,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,28,36,20,0,20,36,23,0,0,0,0,0,0,44,44,23,0,12,12,0,0,0,0,0,0,0,0,60,60,28,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,20,36,20,0,7,28,28,7,0,0,0,0,0,0,44,44,0,0,7,7,0,0,0,0,0,0,0,0,44,55,44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,12,0,0,0,0,0,0,0,0,0,12,31,23,0,0,20,28,12,0,0,0,0,0,0,20,39,36,0,0,0,0,0,0,0,0,0,0,0,0,28,44,39,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,12,0,0,0,0,0,0,0,0,0,12,28,28,7,0,12,28,20,0,0,0,0,0,0,0,36,36,23,0,0,0,0,0,0,0,0,0,0,0,0,12,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,12,0,0,20,23,7,0,0,0,0,0,0,0,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,7,0,0,12,20,12,0,0,0,0,0,0,0,15,36,36,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,28,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,12,0,0,0,12,12,0,0,0,0,0,0,0,0,28,36,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,23,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,7,12,0,0,0,0,0,0,0,0,0,28,28,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,15,20,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,15,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,15,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,};
+ const uint8_t * SHINE_TEXTURES[10] = {
+ SHINE_TEXTURE_0,
+ SHINE_TEXTURE_1,
+ SHINE_TEXTURE_2,
+ SHINE_TEXTURE_3,
+ SHINE_TEXTURE_4,
+ SHINE_TEXTURE_5,
+ SHINE_TEXTURE_6,
+ SHINE_TEXTURE_7,
+ SHINE_TEXTURE_8,
+ SHINE_TEXTURE_9,
+ };
+ const int SHINE_TEXTURE_WIDTHS[10] = {
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ };
+ const int SHINE_TEXTURE_HEIGHTS[10] = {
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ 128,
+ };
+ }
+}
+#endif
diff --git a/xs/src/igl/opengl2/sort_triangles.cpp b/xs/src/igl/opengl2/sort_triangles.cpp
new file mode 100644
index 000000000..ae9671099
--- /dev/null
+++ b/xs/src/igl/opengl2/sort_triangles.cpp
@@ -0,0 +1,80 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sort_triangles.h"
+#include "project.h"
+#include "../sort_triangles.h"
+#include "gl.h"
+#include "../sort.h"
+#include "../slice.h"
+#include "../barycenter.h"
+#include <iostream>
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedI>
+void igl::opengl2::sort_triangles(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Put model, projection, and viewport matrices into double arrays
+ Matrix4d MV;
+ Matrix4d P;
+ glGetDoublev(GL_MODELVIEW_MATRIX, MV.data());
+ glGetDoublev(GL_PROJECTION_MATRIX, P.data());
+ if(V.cols() == 3)
+ {
+ Matrix<typename DerivedV::Scalar, DerivedV::RowsAtCompileTime,4> hV;
+ hV.resize(V.rows(),4);
+ hV.block(0,0,V.rows(),V.cols()) = V;
+ hV.col(3).setConstant(1);
+ return igl::sort_triangles(hV,F,MV,P,FF,I);
+ }else
+ {
+ return igl::sort_triangles(V,F,MV,P,FF,I);
+ }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedI>
+void igl::opengl2::sort_triangles_slow(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Barycenter, centroid
+ Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,1> D,sD;
+ Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,3> BC;
+ D.resize(F.rows(),3);
+ barycenter(V,F,BC);
+ for(int f = 0;f<F.rows();f++)
+ {
+ Eigen::Matrix<typename DerivedV::Scalar, 3,1> bc,pbc;
+ bc = BC.row(f);
+ project(bc,pbc);
+ D(f) = pbc(2);
+ }
+ sort(D,1,false,sD,I);
+ slice(F,I,1,FF);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::opengl2::sort_triangles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::opengl2::sort_triangles_slow<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/opengl2/sort_triangles.h b/xs/src/igl/opengl2/sort_triangles.h
new file mode 100644
index 000000000..53fd3e809
--- /dev/null
+++ b/xs/src/igl/opengl2/sort_triangles.h
@@ -0,0 +1,70 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_SORT_TRIANGLES_H
+#define IGL_OPENGL2_SORT_TRIANGLES_H
+
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace opengl2
+ {
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedI>
+ IGL_INLINE void sort_triangles(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedI>
+ IGL_INLINE void sort_triangles_slow(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I);
+ //template <
+ // typename DerivedV,
+ // typename DerivedF,
+ // typename DerivedMV,
+ // typename DerivedP,
+ // typename DerivedFF,
+ // typename DerivedI>
+ //IGL_INLINE void sort_triangles_robust(
+ // const Eigen::PlainObjectBase<DerivedV> & V,
+ // const Eigen::PlainObjectBase<DerivedF> & F,
+ // const Eigen::PlainObjectBase<DerivedMV> & MV,
+ // const Eigen::PlainObjectBase<DerivedP> & P,
+ // Eigen::PlainObjectBase<DerivedFF> & FF,
+ // Eigen::PlainObjectBase<DerivedI> & I);
+ //template <
+ // typename DerivedV,
+ // typename DerivedF,
+ // typename DerivedFF,
+ // typename DerivedI>
+ //IGL_INLINE void sort_triangles_robust(
+ // const Eigen::PlainObjectBase<DerivedV> & V,
+ // const Eigen::PlainObjectBase<DerivedF> & F,
+ // Eigen::PlainObjectBase<DerivedFF> & FF,
+ // Eigen::PlainObjectBase<DerivedI> & I);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "sort_triangles.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/opengl2/unproject.cpp b/xs/src/igl/opengl2/unproject.cpp
new file mode 100644
index 000000000..f6b0013fe
--- /dev/null
+++ b/xs/src/igl/opengl2/unproject.cpp
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject.h"
+#include "model_proj_viewport.h"
+#include "../unproject.h"
+#include "gl.h"
+
+#include <Eigen/Dense>
+#include <Eigen/LU>
+
+IGL_INLINE void igl::opengl2::unproject(
+ const double winX,
+ const double winY,
+ const double winZ,
+ double* objX,
+ double* objY,
+ double* objZ)
+{
+ Eigen::Vector3d obj;
+ igl::opengl2::unproject(Eigen::Vector3d(winX,winY,winZ),obj);
+ *objX = obj(0);
+ *objY = obj(1);
+ *objZ = obj(2);
+}
+
+template <typename Derivedwin, typename Derivedobj>
+IGL_INLINE void igl::opengl2::unproject(
+ const Eigen::PlainObjectBase<Derivedwin> & win,
+ Eigen::PlainObjectBase<Derivedobj> & obj)
+{
+ const auto ret = igl::opengl2::unproject(win);
+ obj = ret.template cast<typename Derivedobj::Scalar>();
+}
+
+
+template <typename Derivedwin>
+IGL_INLINE Derivedwin igl::opengl2::unproject(
+ const Eigen::PlainObjectBase<Derivedwin> & win)
+{
+ using namespace Eigen;
+ typedef typename Derivedwin::Scalar Scalar;
+ Matrix4d MV,P;
+ Vector4d VPd;
+ model_proj_viewport(MV,P,VPd);
+ Vector3d wind = win.template cast<double>();
+ Vector3d objd = igl::unproject(wind,MV,P,VPd);
+ return objd.template cast<Scalar>();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::opengl2::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
+template void igl::opengl2::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
+template Eigen::Matrix<float, 3, 1, 0, 3, 1> igl::opengl2::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&);
+template Eigen::Matrix<double, 3, 1, 0, 3, 1> igl::opengl2::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
+template void igl::opengl2::unproject<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+#endif
diff --git a/xs/src/igl/opengl2/unproject.h b/xs/src/igl/opengl2/unproject.h
new file mode 100644
index 000000000..00de13077
--- /dev/null
+++ b/xs/src/igl/opengl2/unproject.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_UNPROJECT_H
+#define IGL_OPENGL2_UNPROJECT_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace opengl2
+ {
+ // Wrapper for gluUnproject that uses the current GL_MODELVIEW_MATRIX,
+ // GL_PROJECTION_MATRIX, and GL_VIEWPORT
+ // Inputs:
+ // win* screen space x, y, and z coordinates respectively
+ // Outputs:
+ // obj* pointers to 3D objects' x, y, and z coordinates respectively
+ // Returns return value of gluUnProject call
+ IGL_INLINE void unproject(
+ const double winX,
+ const double winY,
+ const double winZ,
+ double* objX,
+ double* objY,
+ double* objZ);
+ template <typename Derivedwin, typename Derivedobj>
+ IGL_INLINE void unproject(
+ const Eigen::PlainObjectBase<Derivedwin> & win,
+ Eigen::PlainObjectBase<Derivedobj> & obj);
+ template <typename Derivedwin>
+ IGL_INLINE Derivedwin unproject(
+ const Eigen::PlainObjectBase<Derivedwin> & win);
+ }
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/opengl2/unproject_to_zero_plane.cpp b/xs/src/igl/opengl2/unproject_to_zero_plane.cpp
new file mode 100644
index 000000000..1c2945886
--- /dev/null
+++ b/xs/src/igl/opengl2/unproject_to_zero_plane.cpp
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject_to_zero_plane.h"
+
+#include "gl.h"
+
+#include "project.h"
+#include "unproject.h"
+
+IGL_INLINE void igl::opengl2::unproject_to_zero_plane(
+ const double winX,
+ const double winY,
+ double* objX,
+ double* objY,
+ double* objZ)
+{
+ double winOrigin[3];
+ igl::opengl2::project(0,0,0,&winOrigin[0],&winOrigin[1],&winOrigin[2]);
+ return igl::opengl2::unproject(winX, winY, winOrigin[2], objX, objY, objZ);
+}
+
+template <typename Derivedwin, typename Derivedobj>
+IGL_INLINE void igl::opengl2::unproject_to_zero_plane(
+ const Eigen::PlainObjectBase<Derivedwin> & win,
+ Eigen::PlainObjectBase<Derivedobj> & obj)
+{
+ return unproject_to_zero_plane(win(0),win(1),
+ &obj.data()[0],
+ &obj.data()[1],
+ &obj.data()[2]);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::opengl2::unproject_to_zero_plane<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+template void igl::opengl2::unproject_to_zero_plane<Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::opengl2::unproject_to_zero_plane<Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+#endif
+
diff --git a/xs/src/igl/opengl2/unproject_to_zero_plane.h b/xs/src/igl/opengl2/unproject_to_zero_plane.h
new file mode 100644
index 000000000..d76337e20
--- /dev/null
+++ b/xs/src/igl/opengl2/unproject_to_zero_plane.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_UNPROJECT_TO_ZERO_PLANE_H
+#define IGL_OPENGL2_UNPROJECT_TO_ZERO_PLANE_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ namespace opengl2
+ {
+ // Wrapper for gluUnproject that uses the current GL_MODELVIEW_MATRIX,
+ // GL_PROJECTION_MATRIX, and GL_VIEWPORT to unproject a screen position
+ // (winX,winY) to a 3d location at same depth as the current origin.
+ // Inputs:
+ // win* screen space x, y, and z coordinates respectively
+ // Outputs:
+ // obj* pointers to 3D objects' x, y, and z coordinates respectively
+ // Returns return value of gluUnProject call
+ IGL_INLINE void unproject_to_zero_plane(
+ const double winX,
+ const double winY,
+ double* objX,
+ double* objY,
+ double* objZ);
+ template <typename Derivedwin, typename Derivedobj>
+ IGL_INLINE void unproject_to_zero_plane(
+ const Eigen::PlainObjectBase<Derivedwin> & win,
+ Eigen::PlainObjectBase<Derivedobj> & obj);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject_to_zero_plane.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/opengl2/up_axis.cpp b/xs/src/igl/opengl2/up_axis.cpp
new file mode 100644
index 000000000..c6b3c02a0
--- /dev/null
+++ b/xs/src/igl/opengl2/up_axis.cpp
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "up_axis.h"
+#include "gl.h"
+
+IGL_INLINE void igl::opengl2::up_axis(double * x, double * y, double * z)
+{
+ double mv[16];
+ glGetDoublev(GL_MODELVIEW_MATRIX, mv);
+ igl::opengl2::up_axis(mv,x,y,z);
+}
+
+IGL_INLINE void igl::opengl2::up_axis(const double *mv, double * x, double * y, double * z)
+{
+ *x = -mv[0*4+1];
+ *y = -mv[1*4+1];
+ *z = -mv[2*4+1];
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+#endif
diff --git a/xs/src/igl/opengl2/up_axis.h b/xs/src/igl/opengl2/up_axis.h
new file mode 100644
index 000000000..2c042fb2c
--- /dev/null
+++ b/xs/src/igl/opengl2/up_axis.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_UP_AXIS_H
+#define IGL_OPENGL2_UP_AXIS_H
+#include "../igl_inline.h"
+namespace igl
+{
+ namespace opengl2
+ {
+ // Determines the up axis or depth axis of the current gl matrix
+ // Outputs:
+ // x pointer to x-coordinate in scene coordinates of the un-normalized
+ // up axis
+ // y pointer to y-coordinate in scene coordinates of the un-normalized
+ // up axis
+ // z pointer to z-coordinate in scene coordinates of the un-normalized
+ // up axis
+ // mv pointer to modelview matrix
+ //
+ // Note: Up axis is returned *UN-normalized*
+ IGL_INLINE void up_axis(double * x, double * y, double * z);
+ IGL_INLINE void up_axis(const double * mv, double * x, double * y, double * z);
+ }
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "up_axis.cpp"
+#endif
+#endif
+
+
diff --git a/xs/src/igl/opengl2/view_axis.cpp b/xs/src/igl/opengl2/view_axis.cpp
new file mode 100644
index 000000000..5145cd207
--- /dev/null
+++ b/xs/src/igl/opengl2/view_axis.cpp
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "view_axis.h"
+#include "gl.h"
+
+IGL_INLINE void igl::opengl2::view_axis(double * x, double * y, double * z)
+{
+ double mv[16];
+ glGetDoublev(GL_MODELVIEW_MATRIX, mv);
+ igl::opengl2::view_axis(mv,x,y,z);
+}
+
+IGL_INLINE void igl::opengl2::view_axis(const double * mv, double * x, double * y, double * z)
+{
+ *x = -mv[0*4+2];
+ *y = -mv[1*4+2];
+ *z = -mv[2*4+2];
+}
+
+template <typename DerivedV>
+IGL_INLINE void igl::opengl2::view_axis(Eigen::PlainObjectBase<DerivedV> & V)
+{
+ double x,y,z;
+ view_axis(&x,&y,&z);
+ V(0) = x;
+ V(1) = y;
+ V(2) = z;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::opengl2::view_axis<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+template void igl::opengl2::view_axis<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+#endif
diff --git a/xs/src/igl/opengl2/view_axis.h b/xs/src/igl/opengl2/view_axis.h
new file mode 100644
index 000000000..ab324cbad
--- /dev/null
+++ b/xs/src/igl/opengl2/view_axis.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OPENGL2_VIEW_AXIS_H
+#define IGL_OPENGL2_VIEW_AXIS_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace opengl2
+ {
+ // Determines the view axis or depth axis of the current gl matrix
+ // Inputs:
+ // mv pointer to modelview matrix
+ // Outputs:
+ // x pointer to x-coordinate in scene coordinates of the un-normalized
+ // viewing axis
+ // y pointer to y-coordinate in scene coordinates of the un-normalized
+ // viewing axis
+ // z pointer to z-coordinate in scene coordinates of the un-normalized
+ // viewing axis
+ //
+ // Note: View axis is returned *UN-normalized*
+ IGL_INLINE void view_axis(const double * mv, double * x, double * y, double * z);
+ // Extract mv from current GL state.
+ IGL_INLINE void view_axis(double * x, double * y, double * z);
+ template <typename DerivedV>
+ IGL_INLINE void view_axis(Eigen::PlainObjectBase<DerivedV> & V);
+ }
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "view_axis.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/orient_outward.cpp b/xs/src/igl/orient_outward.cpp
new file mode 100644
index 000000000..522745bc4
--- /dev/null
+++ b/xs/src/igl/orient_outward.cpp
@@ -0,0 +1,95 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "orient_outward.h"
+#include "per_face_normals.h"
+#include "barycenter.h"
+#include "doublearea.h"
+#include <iostream>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedC,
+ typename DerivedFF,
+ typename DerivedI>
+IGL_INLINE void igl::orient_outward(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(C.rows() == F.rows());
+ assert(F.cols() == 3);
+ assert(V.cols() == 3);
+
+ // number of faces
+ const int m = F.rows();
+ // number of patches
+ const int num_cc = C.maxCoeff()+1;
+ I.resize(num_cc);
+ if(&FF != &F)
+ {
+ FF = F;
+ }
+ DerivedV N,BC,BCmean;
+ Matrix<typename DerivedV::Scalar,Dynamic,1> A;
+ VectorXd totA(num_cc), dot(num_cc);
+ Matrix<typename DerivedV::Scalar,3,1> Z(1,1,1);
+ per_face_normals(V,F,Z.normalized(),N);
+ barycenter(V,F,BC);
+ doublearea(V,F,A);
+ BCmean.setConstant(num_cc,3,0);
+ dot.setConstant(num_cc,1,0);
+ totA.setConstant(num_cc,1,0);
+ // loop over faces
+ for(int f = 0;f<m;f++)
+ {
+ BCmean.row(C(f)) += A(f)*BC.row(f);
+ totA(C(f))+=A(f);
+ }
+ // take area weighted average
+ for(int c = 0;c<num_cc;c++)
+ {
+ BCmean.row(c) /= (typename DerivedV::Scalar) totA(c);
+ }
+ // subtract bcmean
+ for(int f = 0;f<m;f++)
+ {
+ BC.row(f) -= BCmean.row(C(f));
+ dot(C(f)) += A(f)*N.row(f).dot(BC.row(f));
+ }
+ // take area weighted average
+ for(int c = 0;c<num_cc;c++)
+ {
+ dot(c) /= (typename DerivedV::Scalar) totA(c);
+ if(dot(c) < 0)
+ {
+ I(c) = true;
+ }else
+ {
+ I(c) = false;
+ }
+ }
+ // flip according to I
+ for(int f = 0;f<m;f++)
+ {
+ if(I(C(f)))
+ {
+ FF.row(f) = FF.row(f).reverse().eval();
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::orient_outward<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
+
diff --git a/xs/src/igl/orient_outward.h b/xs/src/igl/orient_outward.h
new file mode 100644
index 000000000..197c8b950
--- /dev/null
+++ b/xs/src/igl/orient_outward.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ORIENT_OUTWARD_H
+#define IGL_ORIENT_OUTWARD_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Orient each component (identified by C) of a mesh (V,F) so the normals on
+ // average point away from the patch's centroid.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // C #F list of components (output of orientable_patches)
+ // Outputs:
+ // FF #F by 3 list of new triangle indices such that FF(~I,:) = F(~I,:) and
+ // FF(I,:) = fliplr(F(I,:)) (OK if &FF = &F)
+ // I max(C)+1 list of whether face has been flipped
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedC,
+ typename DerivedFF,
+ typename DerivedI>
+ IGL_INLINE void orient_outward(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "orient_outward.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/orientable_patches.cpp b/xs/src/igl/orientable_patches.cpp
new file mode 100644
index 000000000..fa2ea1bd4
--- /dev/null
+++ b/xs/src/igl/orientable_patches.cpp
@@ -0,0 +1,105 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "orientable_patches.h"
+#include "components.h"
+#include "sort.h"
+#include "unique_rows.h"
+#include <vector>
+#include <iostream>
+
+template <typename DerivedF, typename DerivedC, typename AScalar>
+IGL_INLINE void igl::orientable_patches(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::SparseMatrix<AScalar> & A)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ // simplex size
+ assert(F.cols() == 3);
+
+ // List of all "half"-edges: 3*#F by 2
+ Matrix<typename DerivedF::Scalar, Dynamic, 2> allE,sortallE,uE;
+ allE.resize(F.rows()*3,2);
+ Matrix<int,Dynamic,2> IX;
+ VectorXi IA,IC;
+ allE.block(0*F.rows(),0,F.rows(),1) = F.col(1);
+ allE.block(0*F.rows(),1,F.rows(),1) = F.col(2);
+ allE.block(1*F.rows(),0,F.rows(),1) = F.col(2);
+ allE.block(1*F.rows(),1,F.rows(),1) = F.col(0);
+ allE.block(2*F.rows(),0,F.rows(),1) = F.col(0);
+ allE.block(2*F.rows(),1,F.rows(),1) = F.col(1);
+ // Sort each row
+ sort(allE,2,true,sortallE,IX);
+ //IC(i) tells us where to find sortallE(i,:) in uE:
+ // so that sortallE(i,:) = uE(IC(i),:)
+ unique_rows(sortallE,uE,IA,IC);
+ // uE2FT(e,f) = 1 means face f is adjacent to unique edge e
+ vector<Triplet<AScalar> > uE2FTijv(IC.rows());
+ for(int e = 0;e<IC.rows();e++)
+ {
+ uE2FTijv[e] = Triplet<AScalar>(e%F.rows(),IC(e),1);
+ }
+ SparseMatrix<AScalar> uE2FT(F.rows(),uE.rows());
+ uE2FT.setFromTriplets(uE2FTijv.begin(),uE2FTijv.end());
+ // kill non-manifold edges
+ for(int j=0; j<(int)uE2FT.outerSize();j++)
+ {
+ int degree = 0;
+ for(typename SparseMatrix<AScalar>::InnerIterator it (uE2FT,j); it; ++it)
+ {
+ degree++;
+ }
+ // Iterate over inside
+ if(degree > 2)
+ {
+ for(typename SparseMatrix<AScalar>::InnerIterator it (uE2FT,j); it; ++it)
+ {
+ uE2FT.coeffRef(it.row(),it.col()) = 0;
+ }
+ }
+ }
+ // Face-face Adjacency matrix
+ SparseMatrix<AScalar> uE2F;
+ uE2F = uE2FT.transpose().eval();
+ A = uE2FT*uE2F;
+ // All ones
+ for(int j=0; j<A.outerSize();j++)
+ {
+ // Iterate over inside
+ for(typename SparseMatrix<AScalar>::InnerIterator it (A,j); it; ++it)
+ {
+ if(it.value() > 1)
+ {
+ A.coeffRef(it.row(),it.col()) = 1;
+ }
+ }
+ }
+ //% Connected components are patches
+ //%C = components(A); % alternative to graphconncomp from matlab_bgl
+ //[~,C] = graphconncomp(A);
+ // graph connected components
+ components(A,C);
+
+}
+
+template <typename DerivedF, typename DerivedC>
+IGL_INLINE void igl::orientable_patches(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ Eigen::SparseMatrix<typename DerivedF::Scalar> A;
+ return orientable_patches(F,C,A);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::orientable_patches<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::SparseMatrix<int, 0, int>&);
+template void igl::orientable_patches<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/orientable_patches.h b/xs/src/igl/orientable_patches.h
new file mode 100644
index 000000000..a74284ac5
--- /dev/null
+++ b/xs/src/igl/orientable_patches.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ORIENTABLE_PATCHES_H
+#define IGL_ORIENTABLE_PATCHES_H
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Compute connected components of facets connected by manifold edges.
+ //
+ // Known bugs: This will detect a moebius strip as a single patch (manifold,
+ // non-orientable) and also non-manfiold, yet orientable patches.
+ //
+ // Q: Does this find exactly (manifold || orientable) patches?
+ //
+ // Inputs:
+ // F #F by simplex-size list of facets
+ // Outputs:
+ // C #F list of component ids
+ // A #F by #F adjacency matrix
+ //
+ template <typename DerivedF, typename DerivedC, typename AScalar>
+ IGL_INLINE void orientable_patches(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::SparseMatrix<AScalar> & A);
+ template <typename DerivedF, typename DerivedC>
+ IGL_INLINE void orientable_patches(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedC> & C);
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "orientable_patches.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/oriented_facets.cpp b/xs/src/igl/oriented_facets.cpp
new file mode 100644
index 000000000..722679335
--- /dev/null
+++ b/xs/src/igl/oriented_facets.cpp
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "oriented_facets.h"
+
+template <typename DerivedF, typename DerivedE>
+IGL_INLINE void igl::oriented_facets(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E)
+{
+ E.resize(F.rows()*F.cols(),F.cols()-1);
+ typedef typename DerivedE::Scalar EScalar;
+ switch(F.cols())
+ {
+ case 4:
+ E.block(0*F.rows(),0,F.rows(),1) = F.col(1).template cast<EScalar>();
+ E.block(0*F.rows(),1,F.rows(),1) = F.col(3).template cast<EScalar>();
+ E.block(0*F.rows(),2,F.rows(),1) = F.col(2).template cast<EScalar>();
+
+ E.block(1*F.rows(),0,F.rows(),1) = F.col(0).template cast<EScalar>();
+ E.block(1*F.rows(),1,F.rows(),1) = F.col(2).template cast<EScalar>();
+ E.block(1*F.rows(),2,F.rows(),1) = F.col(3).template cast<EScalar>();
+
+ E.block(2*F.rows(),0,F.rows(),1) = F.col(0).template cast<EScalar>();
+ E.block(2*F.rows(),1,F.rows(),1) = F.col(3).template cast<EScalar>();
+ E.block(2*F.rows(),2,F.rows(),1) = F.col(1).template cast<EScalar>();
+
+ E.block(3*F.rows(),0,F.rows(),1) = F.col(0).template cast<EScalar>();
+ E.block(3*F.rows(),1,F.rows(),1) = F.col(1).template cast<EScalar>();
+ E.block(3*F.rows(),2,F.rows(),1) = F.col(2).template cast<EScalar>();
+ return;
+ case 3:
+ E.block(0*F.rows(),0,F.rows(),1) = F.col(1).template cast<EScalar>();
+ E.block(0*F.rows(),1,F.rows(),1) = F.col(2).template cast<EScalar>();
+ E.block(1*F.rows(),0,F.rows(),1) = F.col(2).template cast<EScalar>();
+ E.block(1*F.rows(),1,F.rows(),1) = F.col(0).template cast<EScalar>();
+ E.block(2*F.rows(),0,F.rows(),1) = F.col(0).template cast<EScalar>();
+ E.block(2*F.rows(),1,F.rows(),1) = F.col(1).template cast<EScalar>();
+ return;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::oriented_facets<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::oriented_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::oriented_facets<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::oriented_facets<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::oriented_facets<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::oriented_facets<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+#endif
diff --git a/xs/src/igl/oriented_facets.h b/xs/src/igl/oriented_facets.h
new file mode 100644
index 000000000..b0a66ef08
--- /dev/null
+++ b/xs/src/igl/oriented_facets.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ORIENTED_FACETS_H
+#define IGL_ORIENTED_FACETS_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // ORIENTED_FACETS Determines all "directed
+ // [facets](https://en.wikipedia.org/wiki/Simplex#Elements)" of a given set
+ // of simplicial elements. For a manifold triangle mesh, this computes all
+ // half-edges. For a manifold tetrahedral mesh, this computes all half-faces.
+ //
+ // Inputs:
+ // F #F by simplex_size list of simplices
+ // Outputs:
+ // E #E by simplex_size-1 list of facets
+ //
+ // Note: this is not the same as igl::edges because this includes every
+ // directed edge including repeats (meaning interior edges on a surface will
+ // show up once for each direction and non-manifold edges may appear more than
+ // once for each direction).
+ //
+ // Note: This replaces the deprecated `all_edges` function
+ template <typename DerivedF, typename DerivedE>
+ IGL_INLINE void oriented_facets(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "oriented_facets.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/orth.cpp b/xs/src/igl/orth.cpp
new file mode 100644
index 000000000..467a4993e
--- /dev/null
+++ b/xs/src/igl/orth.cpp
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "orth.h"
+
+// Broken Implementation
+IGL_INLINE void igl::orth(const Eigen::MatrixXd &A, Eigen::MatrixXd &Q)
+{
+
+ //perform svd on A = U*S*V' (V is not computed and only the thin U is computed)
+ Eigen::JacobiSVD<Eigen::MatrixXd> svd(A, Eigen::ComputeThinU );
+ Eigen::MatrixXd U = svd.matrixU();
+ const Eigen::VectorXd S = svd.singularValues();
+
+ //get rank of A
+ int m = A.rows();
+ int n = A.cols();
+ double tol = std::max(m,n) * S.maxCoeff() * 2.2204e-16;
+ int r = 0;
+ for (int i = 0; i < S.rows(); ++r,++i)
+ {
+ if (S[i] < tol)
+ break;
+ }
+
+ //keep r first columns of U
+ Q = U.block(0,0,U.rows(),r);
+}
diff --git a/xs/src/igl/orth.h b/xs/src/igl/orth.h
new file mode 100644
index 000000000..a77cd6593
--- /dev/null
+++ b/xs/src/igl/orth.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ORTH_H
+#define IGL_ORTH_H
+
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // ORTH Orthogonalization.
+ // ORTH(A,Q) produces Q as an orthonormal basis for the range of A.
+ // That is, Q'*Q = I, the columns of Q span the same space as
+ // the columns of A, and the number of columns of Q is the
+ // rank of A.
+ //
+ //
+ // The algorithm uses singular value decomposition, SVD, instead of orthogonal
+ // factorization, QR. This doubles the computation time, but
+ // provides more reliable and consistent rank determination.
+ // Closely follows MATLAB implementation in orth.m
+ //
+ // Inputs:
+ // A m by n matrix
+ // Outputs:
+ // Q m by n matrix with orthonormal columns spanning same column space as
+ // A
+ //
+ // Known bugs: Implementation listed as "Broken"
+ IGL_INLINE void orth(const Eigen::MatrixXd &A, Eigen::MatrixXd &Q);
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "orth.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/ortho.cpp b/xs/src/igl/ortho.cpp
new file mode 100644
index 000000000..e634eed74
--- /dev/null
+++ b/xs/src/igl/ortho.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ortho.h"
+
+template < typename DerivedP>
+IGL_INLINE void igl::ortho(
+ const typename DerivedP::Scalar left,
+ const typename DerivedP::Scalar right,
+ const typename DerivedP::Scalar bottom,
+ const typename DerivedP::Scalar top,
+ const typename DerivedP::Scalar nearVal,
+ const typename DerivedP::Scalar farVal,
+ Eigen::PlainObjectBase<DerivedP> & P)
+{
+ P.setIdentity();
+ P(0,0) = 2. / (right - left);
+ P(1,1) = 2. / (top - bottom);
+ P(2,2) = - 2./ (farVal - nearVal);
+ P(0,3) = - (right + left) / (right - left);
+ P(1,3) = - (top + bottom) / (top - bottom);
+ P(2,3) = - (farVal + nearVal) / (farVal - nearVal);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::ortho<Eigen::Matrix<float, 4, 4, 0, 4, 4> >(Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::Matrix<float, 4, 4, 0, 4, 4>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> >&);
+#endif
diff --git a/xs/src/igl/ortho.h b/xs/src/igl/ortho.h
new file mode 100644
index 000000000..70b9cab4d
--- /dev/null
+++ b/xs/src/igl/ortho.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ORTHO_H
+#define IGL_ORTHO_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Implementation of the deprecated glOrtho function.
+ //
+ // Inputs:
+ // left coordinate of left vertical clipping plane
+ // right coordinate of right vertical clipping plane
+ // bottom coordinate of bottom vertical clipping plane
+ // top coordinate of top vertical clipping plane
+ // nearVal distance to near plane
+ // farVal distance to far plane
+ // Outputs:
+ // P 4x4 perspective matrix
+ template < typename DerivedP>
+ IGL_INLINE void ortho(
+ const typename DerivedP::Scalar left,
+ const typename DerivedP::Scalar right,
+ const typename DerivedP::Scalar bottom,
+ const typename DerivedP::Scalar top,
+ const typename DerivedP::Scalar nearVal,
+ const typename DerivedP::Scalar farVal,
+ Eigen::PlainObjectBase<DerivedP> & P);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "ortho.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/outer_element.cpp b/xs/src/igl/outer_element.cpp
new file mode 100644
index 000000000..2ce837780
--- /dev/null
+++ b/xs/src/igl/outer_element.cpp
@@ -0,0 +1,280 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "outer_element.h"
+#include <iostream>
+#include <vector>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+IGL_INLINE void igl::outer_vertex(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v_index,
+ Eigen::PlainObjectBase<DerivedA> & A)
+{
+ // Algorithm:
+ // Find an outer vertex (i.e. vertex reachable from infinity)
+ // Return the vertex with the largest X value.
+ // If there is a tie, pick the one with largest Y value.
+ // If there is still a tie, pick the one with the largest Z value.
+ // If there is still a tie, then there are duplicated vertices within the
+ // mesh, which violates the precondition.
+ typedef typename DerivedF::Scalar Index;
+ const Index INVALID = std::numeric_limits<Index>::max();
+ const size_t num_selected_faces = I.rows();
+ std::vector<size_t> candidate_faces;
+ Index outer_vid = INVALID;
+ typename DerivedV::Scalar outer_val = 0;
+ for (size_t i=0; i<num_selected_faces; i++)
+ {
+ size_t f = I(i);
+ for (size_t j=0; j<3; j++)
+ {
+ Index v = F(f, j);
+ auto vx = V(v, 0);
+ if (outer_vid == INVALID || vx > outer_val)
+ {
+ outer_val = vx;
+ outer_vid = v;
+ candidate_faces = {f};
+ } else if (v == outer_vid)
+ {
+ candidate_faces.push_back(f);
+ } else if (vx == outer_val)
+ {
+ // Break tie.
+ auto vy = V(v,1);
+ auto vz = V(v, 2);
+ auto outer_y = V(outer_vid, 1);
+ auto outer_z = V(outer_vid, 2);
+ assert(!(vy == outer_y && vz == outer_z));
+ bool replace = (vy > outer_y) ||
+ ((vy == outer_y) && (vz > outer_z));
+ if (replace)
+ {
+ outer_val = vx;
+ outer_vid = v;
+ candidate_faces = {f};
+ }
+ }
+ }
+ }
+
+ assert(outer_vid != INVALID);
+ assert(candidate_faces.size() > 0);
+ v_index = outer_vid;
+ A.resize(candidate_faces.size());
+ std::copy(candidate_faces.begin(), candidate_faces.end(), A.data());
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+IGL_INLINE void igl::outer_edge(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v1,
+ IndexType & v2,
+ Eigen::PlainObjectBase<DerivedA> & A) {
+ // Algorithm:
+ // Find an outer vertex first.
+ // Find the incident edge with largest abs slope when projected onto XY plane.
+ // If there is a tie, check the signed slope and use the positive one.
+ // If there is still a tie, break it using the projected slope onto ZX plane.
+ // If there is still a tie, again check the signed slope and use the positive one.
+ // If there is still a tie, then there are multiple overlapping edges,
+ // which violates the precondition.
+ typedef typename DerivedV::Scalar Scalar;
+ typedef typename DerivedV::Index Index;
+ typedef typename Eigen::Matrix<Scalar, 3, 1> ScalarArray3;
+ typedef typename Eigen::Matrix<typename DerivedF::Scalar, 3, 1> IndexArray3;
+ const Index INVALID = std::numeric_limits<Index>::max();
+
+ Index outer_vid;
+ Eigen::Matrix<Index,Eigen::Dynamic,1> candidate_faces;
+ outer_vertex(V, F, I, outer_vid, candidate_faces);
+ const ScalarArray3& outer_v = V.row(outer_vid);
+ assert(candidate_faces.size() > 0);
+
+ auto get_vertex_index = [&](const IndexArray3& f, Index vid) -> Index
+ {
+ if (f[0] == vid) return 0;
+ if (f[1] == vid) return 1;
+ if (f[2] == vid) return 2;
+ assert(false);
+ return -1;
+ };
+
+ auto unsigned_value = [](Scalar v) -> Scalar {
+ if (v < 0) return v * -1;
+ else return v;
+ };
+
+ Scalar outer_slope_YX = 0;
+ Scalar outer_slope_ZX = 0;
+ Index outer_opp_vid = INVALID;
+ bool infinite_slope_detected = false;
+ std::vector<Index> incident_faces;
+ auto check_and_update_outer_edge = [&](Index opp_vid, Index fid) {
+ if (opp_vid == outer_opp_vid)
+ {
+ incident_faces.push_back(fid);
+ return;
+ }
+
+ const ScalarArray3 opp_v = V.row(opp_vid);
+ if (!infinite_slope_detected && outer_v[0] != opp_v[0])
+ {
+ // Finite slope
+ const ScalarArray3 diff = opp_v - outer_v;
+ const Scalar slope_YX = diff[1] / diff[0];
+ const Scalar slope_ZX = diff[2] / diff[0];
+ const Scalar u_slope_YX = unsigned_value(slope_YX);
+ const Scalar u_slope_ZX = unsigned_value(slope_ZX);
+ bool update = false;
+ if (outer_opp_vid == INVALID) {
+ update = true;
+ } else {
+ const Scalar u_outer_slope_YX = unsigned_value(outer_slope_YX);
+ if (u_slope_YX > u_outer_slope_YX) {
+ update = true;
+ } else if (u_slope_YX == u_outer_slope_YX &&
+ slope_YX > outer_slope_YX) {
+ update = true;
+ } else if (slope_YX == outer_slope_YX) {
+ const Scalar u_outer_slope_ZX =
+ unsigned_value(outer_slope_ZX);
+ if (u_slope_ZX > u_outer_slope_ZX) {
+ update = true;
+ } else if (u_slope_ZX == u_outer_slope_ZX &&
+ slope_ZX > outer_slope_ZX) {
+ update = true;
+ } else if (slope_ZX == u_outer_slope_ZX) {
+ assert(false);
+ }
+ }
+ }
+
+ if (update) {
+ outer_opp_vid = opp_vid;
+ outer_slope_YX = slope_YX;
+ outer_slope_ZX = slope_ZX;
+ incident_faces = {fid};
+ }
+ } else if (!infinite_slope_detected)
+ {
+ // Infinite slope
+ outer_opp_vid = opp_vid;
+ infinite_slope_detected = true;
+ incident_faces = {fid};
+ }
+ };
+
+ const size_t num_candidate_faces = candidate_faces.size();
+ for (size_t i=0; i<num_candidate_faces; i++)
+ {
+ const Index fid = candidate_faces(i);
+ const IndexArray3& f = F.row(fid);
+ size_t id = get_vertex_index(f, outer_vid);
+ Index next_vid = f((id+1)%3);
+ Index prev_vid = f((id+2)%3);
+ check_and_update_outer_edge(next_vid, fid);
+ check_and_update_outer_edge(prev_vid, fid);
+ }
+
+ v1 = outer_vid;
+ v2 = outer_opp_vid;
+ A.resize(incident_faces.size());
+ std::copy(incident_faces.begin(), incident_faces.end(), A.data());
+}
+
+template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedI,
+ typename IndexType
+ >
+IGL_INLINE void igl::outer_facet(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & f,
+ bool & flipped) {
+ // Algorithm:
+ // Find an outer edge.
+ // Find the incident facet with the largest absolute X normal component.
+ // If there is a tie, keep the one with positive X component.
+ // If there is still a tie, pick the face with the larger signed index
+ // (flipped face has negative index).
+ typedef typename DerivedV::Scalar Scalar;
+ typedef typename DerivedV::Index Index;
+ const size_t INVALID = std::numeric_limits<size_t>::max();
+
+ Index v1,v2;
+ Eigen::Matrix<Index,Eigen::Dynamic,1> incident_faces;
+ outer_edge(V, F, I, v1, v2, incident_faces);
+ assert(incident_faces.size() > 0);
+
+ auto generic_fabs = [&](const Scalar& val) -> const Scalar {
+ if (val >= 0) return val;
+ else return -val;
+ };
+
+ Scalar max_nx = 0;
+ size_t outer_fid = INVALID;
+ const size_t num_incident_faces = incident_faces.size();
+ for (size_t i=0; i<num_incident_faces; i++)
+ {
+ const auto& fid = incident_faces(i);
+ const Scalar nx = N(fid, 0);
+ if (outer_fid == INVALID) {
+ max_nx = nx;
+ outer_fid = fid;
+ } else {
+ if (generic_fabs(nx) > generic_fabs(max_nx)) {
+ max_nx = nx;
+ outer_fid = fid;
+ } else if (nx == -max_nx && nx > 0) {
+ max_nx = nx;
+ outer_fid = fid;
+ } else if (nx == max_nx) {
+ if ((max_nx >= 0 && outer_fid < fid) ||
+ (max_nx < 0 && outer_fid > fid)) {
+ max_nx = nx;
+ outer_fid = fid;
+ }
+ }
+ }
+ }
+
+ assert(outer_fid != INVALID);
+ f = outer_fid;
+ flipped = max_nx < 0;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::outer_facet<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 1, -1, -1>, unsigned long>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> > const&, unsigned long&, bool&);
+template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+template void igl::outer_facet<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int&, bool&);
+#endif
diff --git a/xs/src/igl/outer_element.h b/xs/src/igl/outer_element.h
new file mode 100644
index 000000000..6fbaf9c5d
--- /dev/null
+++ b/xs/src/igl/outer_element.h
@@ -0,0 +1,110 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_OUTER_ELEMENT_H
+#define IGL_OUTER_ELEMENT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Find a vertex that is reachable from infinite without crossing any faces.
+ // Such vertex is called "outer vertex."
+ //
+ // Precondition: The input mesh must have all self-intersection resolved and
+ // no duplicated vertices. See cgal::remesh_self_intersections.h for how to
+ // obtain such input.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // I #I list of facets to consider
+ // Outputs:
+ // v_index index of outer vertex
+ // A #A list of facets incident to the outer vertex
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+ IGL_INLINE void outer_vertex(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v_index,
+ Eigen::PlainObjectBase<DerivedA> & A);
+
+
+ // Find an edge that is reachable from infinity without crossing any faces.
+ // Such edge is called "outer edge."
+ //
+ // Precondition: The input mesh must have all self-intersection resolved and
+ // no duplicated vertices. The correctness of the output depends on the fact
+ // that there is no edge overlap. See cgal::remesh_self_intersections.h for
+ // how to obtain such input.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // I #I list of facets to consider
+ // Outputs:
+ // v1 index of the first end point of outer edge
+ // v2 index of the second end point of outer edge
+ // A #A list of facets incident to the outer edge
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedI,
+ typename IndexType,
+ typename DerivedA
+ >
+ IGL_INLINE void outer_edge(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & v1,
+ IndexType & v2,
+ Eigen::PlainObjectBase<DerivedA> & A);
+
+
+ // Find a facet that is reachable from infinity without crossing any faces.
+ // Such facet is called "outer facet."
+ //
+ // Precondition: The input mesh must have all self-intersection resolved. I.e
+ // there is no duplicated vertices, no overlapping edge and no intersecting
+ // faces (the only exception is there could be topologically duplicated faces).
+ // See cgal::remesh_self_intersections.h for how to obtain such input.
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices into V
+ // N #N by 3 list of face normals
+ // I #I list of facets to consider
+ // Outputs:
+ // f Index of the outer facet.
+ // flipped true iff the normal of f points inwards.
+ template<
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedI,
+ typename IndexType
+ >
+ IGL_INLINE void outer_facet(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const Eigen::PlainObjectBase<DerivedI> & I,
+ IndexType & f,
+ bool & flipped);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "outer_element.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/parallel_for.h b/xs/src/igl/parallel_for.h
new file mode 100644
index 000000000..458adace5
--- /dev/null
+++ b/xs/src/igl/parallel_for.h
@@ -0,0 +1,188 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PARALLEL_FOR_H
+#define IGL_PARALLEL_FOR_H
+#include "igl_inline.h"
+#include <functional>
+
+//#warning "Defining IGL_PARALLEL_FOR_FORCE_SERIAL"
+//#define IGL_PARALLEL_FOR_FORCE_SERIAL
+
+namespace igl
+{
+ // PARALLEL_FOR Functional implementation of a basic, open-mp style, parallel
+ // for loop. If the inner block of a for-loop can be rewritten/encapsulated in
+ // a single (anonymous/lambda) function call `func` so that the serial code
+ // looks like:
+ //
+ // for(int i = 0;i<loop_size;i++)
+ // {
+ // func(i);
+ // }
+ //
+ // then `parallel_for(loop_size,func,min_parallel)` will use as many threads as
+ // available on the current hardware to parallelize this for loop so long as
+ // loop_size<min_parallel, otherwise it will just use a serial for loop.
+ //
+ // Inputs:
+ // loop_size number of iterations. I.e. for(int i = 0;i<loop_size;i++) ...
+ // func function handle taking iteration index as only argument to compute
+ // inner block of for loop I.e. for(int i ...){ func(i); }
+ // min_parallel min size of loop_size such that parallel (non-serial)
+ // thread pooling should be attempted {0}
+ // Returns true iff thread pool was invoked
+ template<typename Index, typename FunctionType >
+ inline bool parallel_for(
+ const Index loop_size,
+ const FunctionType & func,
+ const size_t min_parallel=0);
+ // PARALLEL_FOR Functional implementation of an open-mp style, parallel for
+ // loop with accumulation. For example, serial code separated into n chunks
+ // (each to be parallelized with a thread) might look like:
+ //
+ // Eigen::VectorXd S;
+ // const auto & prep_func = [&S](int n){ S = Eigen:VectorXd::Zero(n); };
+ // const auto & func = [&X,&S](int i, int t){ S(t) += X(i); };
+ // const auto & accum_func = [&S,&sum](int t){ sum += S(t); };
+ // prep_func(n);
+ // for(int i = 0;i<loop_size;i++)
+ // {
+ // func(i,i%n);
+ // }
+ // double sum = 0;
+ // for(int t = 0;t<n;t++)
+ // {
+ // accum_func(t);
+ // }
+ //
+ // Inputs:
+ // loop_size number of iterations. I.e. for(int i = 0;i<loop_size;i++) ...
+ // prep_func function handle taking n >= number of threads as only
+ // argument
+ // func function handle taking iteration index i and thread id t as only
+ // arguments to compute inner block of for loop I.e.
+ // for(int i ...){ func(i,t); }
+ // accum_func function handle taking thread index as only argument, to be
+ // called after all calls of func, e.g., for serial accumulation across
+ // all n (potential) threads, see n in description of prep_func.
+ // min_parallel min size of loop_size such that parallel (non-serial)
+ // thread pooling should be attempted {0}
+ // Returns true iff thread pool was invoked
+ template<
+ typename Index,
+ typename PrepFunctionType,
+ typename FunctionType,
+ typename AccumFunctionType
+ >
+ inline bool parallel_for(
+ const Index loop_size,
+ const PrepFunctionType & prep_func,
+ const FunctionType & func,
+ const AccumFunctionType & accum_func,
+ const size_t min_parallel=0);
+}
+
+// Implementation
+
+#include <cmath>
+#include <cassert>
+#include <thread>
+#include <vector>
+#include <algorithm>
+
+template<typename Index, typename FunctionType >
+inline bool igl::parallel_for(
+ const Index loop_size,
+ const FunctionType & func,
+ const size_t min_parallel)
+{
+ using namespace std;
+ // no op preparation/accumulation
+ const auto & no_op = [](const size_t /*n/t*/){};
+ // two-parameter wrapper ignoring thread id
+ const auto & wrapper = [&func](Index i,size_t /*t*/){ func(i); };
+ return parallel_for(loop_size,no_op,wrapper,no_op,min_parallel);
+}
+
+template<
+ typename Index,
+ typename PreFunctionType,
+ typename FunctionType,
+ typename AccumFunctionType>
+inline bool igl::parallel_for(
+ const Index loop_size,
+ const PreFunctionType & prep_func,
+ const FunctionType & func,
+ const AccumFunctionType & accum_func,
+ const size_t min_parallel)
+{
+ assert(loop_size>=0);
+ if(loop_size==0) return false;
+ // Estimate number of threads in the pool
+ // http://ideone.com/Z7zldb
+ const static size_t sthc = std::thread::hardware_concurrency();
+ const size_t nthreads =
+#ifdef IGL_PARALLEL_FOR_FORCE_SERIAL
+ 0;
+#else
+ loop_size<min_parallel?0:(sthc==0?8:sthc);
+#endif
+ if(nthreads==0)
+ {
+ // serial
+ prep_func(1);
+ for(Index i = 0;i<loop_size;i++) func(i,0);
+ accum_func(0);
+ return false;
+ }else
+ {
+ // Size of a slice for the range functions
+ Index slice =
+ std::max(
+ (Index)std::round((loop_size+1)/static_cast<double>(nthreads)),(Index)1);
+
+ // [Helper] Inner loop
+ const auto & range = [&func](const Index k1, const Index k2, const size_t t)
+ {
+ for(Index k = k1; k < k2; k++) func(k,t);
+ };
+ prep_func(nthreads);
+ // Create pool and launch jobs
+ std::vector<std::thread> pool;
+ pool.reserve(nthreads);
+ // Inner range extents
+ Index i1 = 0;
+ Index i2 = std::min(0 + slice, loop_size);
+ {
+ size_t t = 0;
+ for (; t+1 < nthreads && i1 < loop_size; ++t)
+ {
+ pool.emplace_back(range, i1, i2, t);
+ i1 = i2;
+ i2 = std::min(i2 + slice, loop_size);
+ }
+ if (i1 < loop_size)
+ {
+ pool.emplace_back(range, i1, loop_size, t);
+ }
+ }
+ // Wait for jobs to finish
+ for (std::thread &t : pool) if (t.joinable()) t.join();
+ // Accumulate across threads
+ for(size_t t = 0;t<nthreads;t++)
+ {
+ accum_func(t);
+ }
+ return true;
+ }
+}
+
+//#ifndef IGL_STATIC_LIBRARY
+//#include "parallel_for.cpp"
+//#endif
+#endif
diff --git a/xs/src/igl/parallel_transport_angles.cpp b/xs/src/igl/parallel_transport_angles.cpp
new file mode 100644
index 000000000..0e3803df2
--- /dev/null
+++ b/xs/src/igl/parallel_transport_angles.cpp
@@ -0,0 +1,128 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include <igl/parallel_transport_angles.h>
+#include <Eigen/Geometry>
+
+template <typename DerivedV, typename DerivedF, typename DerivedK>
+IGL_INLINE void igl::parallel_transport_angles(
+const Eigen::PlainObjectBase<DerivedV>& V,
+const Eigen::PlainObjectBase<DerivedF>& F,
+const Eigen::PlainObjectBase<DerivedV>& FN,
+const Eigen::MatrixXi &E2F,
+const Eigen::MatrixXi &F2E,
+Eigen::PlainObjectBase<DerivedK> &K)
+{
+ int numE = E2F.rows();
+
+ Eigen::VectorXi isBorderEdge;
+ isBorderEdge.setZero(numE,1);
+ for(unsigned i=0; i<numE; ++i)
+ {
+ if ((E2F(i,0) == -1) || ((E2F(i,1) == -1)))
+ isBorderEdge[i] = 1;
+ }
+
+ K.setZero(numE);
+ // For every non-border edge
+ for (unsigned eid=0; eid<numE; ++eid)
+ {
+ if (!isBorderEdge[eid])
+ {
+ int fid0 = E2F(eid,0);
+ int fid1 = E2F(eid,1);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N0 = FN.row(fid0);
+// Eigen::Matrix<typename DerivedV::Scalar, 1, 3> N1 = FN.row(fid1);
+
+ // find common edge on triangle 0 and 1
+ int fid0_vc = -1;
+ int fid1_vc = -1;
+ for (unsigned i=0;i<3;++i)
+ {
+ if (F2E(fid0,i) == eid)
+ fid0_vc = i;
+ if (F2E(fid1,i) == eid)
+ fid1_vc = i;
+ }
+ assert(fid0_vc != -1);
+ assert(fid1_vc != -1);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> common_edge = V.row(F(fid0,(fid0_vc+1)%3)) - V.row(F(fid0,fid0_vc));
+ common_edge.normalize();
+
+ // Map the two triangles in a new space where the common edge is the x axis and the N0 the z axis
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 3> P;
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> o = V.row(F(fid0,fid0_vc));
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> tmp = -N0.cross(common_edge);
+ P << common_edge, tmp, N0;
+ // P.transposeInPlace();
+
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V0;
+ V0.row(0) = V.row(F(fid0,0)) -o;
+ V0.row(1) = V.row(F(fid0,1)) -o;
+ V0.row(2) = V.row(F(fid0,2)) -o;
+
+ V0 = (P*V0.transpose()).transpose();
+
+ // assert(V0(0,2) < 1e-10);
+ // assert(V0(1,2) < 1e-10);
+ // assert(V0(2,2) < 1e-10);
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 3> V1;
+ V1.row(0) = V.row(F(fid1,0)) -o;
+ V1.row(1) = V.row(F(fid1,1)) -o;
+ V1.row(2) = V.row(F(fid1,2)) -o;
+ V1 = (P*V1.transpose()).transpose();
+
+ // assert(V1(fid1_vc,2) < 10e-10);
+ // assert(V1((fid1_vc+1)%3,2) < 10e-10);
+
+ // compute rotation R such that R * N1 = N0
+ // i.e. map both triangles to the same plane
+ double alpha = -atan2(V1((fid1_vc+2)%3,2),V1((fid1_vc+2)%3,1));
+
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 3> R;
+ R << 1, 0, 0,
+ 0, cos(alpha), -sin(alpha) ,
+ 0, sin(alpha), cos(alpha);
+ V1 = (R*V1.transpose()).transpose();
+
+ // assert(V1(0,2) < 1e-10);
+ // assert(V1(1,2) < 1e-10);
+ // assert(V1(2,2) < 1e-10);
+
+ // measure the angle between the reference frames
+ // k_ij is the angle between the triangle on the left and the one on the right
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref0 = V0.row(1) - V0.row(0);
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> ref1 = V1.row(1) - V1.row(0);
+
+ ref0.normalize();
+ ref1.normalize();
+
+ double ktemp = atan2(ref1(1),ref1(0)) - atan2(ref0(1),ref0(0));
+
+ // just to be sure, rotate ref0 using angle ktemp...
+ Eigen::Matrix<typename DerivedV::Scalar,2,2> R2;
+ R2 << cos(ktemp), -sin(ktemp), sin(ktemp), cos(ktemp);
+
+// Eigen::Matrix<typename DerivedV::Scalar, 1, 2> tmp1 = R2*(ref0.head(2)).transpose();
+
+ // assert(tmp1(0) - ref1(0) < 1e-10);
+ // assert(tmp1(1) - ref1(1) < 1e-10);
+
+ K[eid] = ktemp;
+ }
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::parallel_transport_angles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/parallel_transport_angles.h b/xs/src/igl/parallel_transport_angles.h
new file mode 100644
index 000000000..e37d7f373
--- /dev/null
+++ b/xs/src/igl/parallel_transport_angles.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_PARALLEL_TRANSPORT_ANGLE
+#define IGL_PARALLEL_TRANSPORT_ANGLE
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl {
+ // Given the per-face local bases computed via igl::local_basis, this function
+ // computes the angle between the two reference frames across each edge.
+ // Any two vectors across the edge whose 2D representation only differs by
+ // this angle are considered to be parallel.
+
+ // Inputs:
+ // V #V by 3 list of mesh vertex coordinates
+ // F #F by 3 list of mesh faces (must be triangles)
+ // FN #F by 3 list of face normals
+ // E2F #E by 2 list of the edge-to-face relation (e.g. computed
+ // via igl::edge_topology)
+ // F2E #F by 3 list of the face-to-edge relation (e.g. computed
+ // via igl::edge_topology)
+ // Output:
+ // K #E by 1 list of the parallel transport angles (zero
+ // for all boundary edges)
+ //
+template <typename DerivedV, typename DerivedF, typename DerivedK>
+IGL_INLINE void parallel_transport_angles(
+const Eigen::PlainObjectBase<DerivedV>&V,
+const Eigen::PlainObjectBase<DerivedF>&F,
+const Eigen::PlainObjectBase<DerivedV>&FN,
+const Eigen::MatrixXi &E2F,
+const Eigen::MatrixXi &F2E,
+Eigen::PlainObjectBase<DerivedK>&K);
+
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "parallel_transport_angles.cpp"
+#endif
+
+
+#endif /* defined(IGL_PARALLEL_TRANSPORT_ANGLE) */
diff --git a/xs/src/igl/partition.cpp b/xs/src/igl/partition.cpp
new file mode 100644
index 000000000..d2ef34c94
--- /dev/null
+++ b/xs/src/igl/partition.cpp
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "partition.h"
+#include "mat_min.h"
+
+IGL_INLINE void igl::partition(
+ const Eigen::MatrixXd & W,
+ const int k,
+ Eigen::Matrix<int,Eigen::Dynamic,1> & G,
+ Eigen::Matrix<int,Eigen::Dynamic,1> & S,
+ Eigen::Matrix<double,Eigen::Dynamic,1> & D)
+{
+ // number of mesh vertices
+ int n = W.rows();
+
+ // Resize output
+ G.resize(n);
+ S.resize(k);
+
+ // "Randomly" choose first seed
+ // Pick a vertex farthest from 0
+ int s;
+ (W.array().square().matrix()).rowwise().sum().maxCoeff(&s);
+
+ S(0) = s;
+ // Initialize distance to closest seed
+ D = ((W.rowwise() - W.row(s)).array().square()).matrix().rowwise().sum();
+ G.setZero();
+
+ // greedily choose the remaining k-1 seeds
+ for(int i = 1;i<k;i++)
+ {
+ // Find maximum in D
+ D.maxCoeff(&s);
+ S(i) = s;
+ // distance to this seed
+ Eigen::Matrix<double,Eigen::Dynamic,1> Ds =
+ ((W.rowwise() - W.row(s)).array().square()).matrix().rowwise().sum();
+ // Concatenation of D and Ds: DDs = [D Ds];
+ Eigen::Matrix<double,Eigen::Dynamic,Eigen::Dynamic> DDs;
+ // Make space for two columns
+ DDs.resize(D.rows(),2);
+ DDs.col(0) = D;
+ DDs.col(1) = Ds;
+ // Update D
+ // get minimum of old D and distance to this seed, C == 1 if new distance
+ // was smaller
+ Eigen::Matrix<int,Eigen::Dynamic,1> C;
+ igl::mat_min(DDs,2,D,C);
+ G = (C.array() ==0).select(G,i);
+ }
+
+
+}
diff --git a/xs/src/igl/partition.h b/xs/src/igl/partition.h
new file mode 100644
index 000000000..167ebd0d7
--- /dev/null
+++ b/xs/src/igl/partition.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PARTITION_H
+#define IGL_PARTITION_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // PARTITION partition vertices into groups based on each
+ // vertex's vector: vertices with similar coordinates (close in
+ // space) will be put in the same group.
+ //
+ // Inputs:
+ // W #W by dim coordinate matrix
+ // k desired number of groups default is dim
+ // Output:
+ // G #W list of group indices (1 to k) for each vertex, such that vertex i
+ // is assigned to group G(i)
+ // S k list of seed vertices
+ // D #W list of squared distances for each vertex to it's corresponding
+ // closest seed
+ IGL_INLINE void partition(
+ const Eigen::MatrixXd & W,
+ const int k,
+ Eigen::Matrix<int,Eigen::Dynamic,1> & G,
+ Eigen::Matrix<int,Eigen::Dynamic,1> & S,
+ Eigen::Matrix<double,Eigen::Dynamic,1> & D);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "partition.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/parula.cpp b/xs/src/igl/parula.cpp
new file mode 100644
index 000000000..b3daaa5e7
--- /dev/null
+++ b/xs/src/igl/parula.cpp
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "parula.h"
+#include "colormap.h"
+
+template <typename T>
+IGL_INLINE void igl::parula(const T x, T * rgb)
+{
+ igl::colormap(igl::COLOR_MAP_TYPE_PARULA,x, rgb);
+}
+
+template <typename T>
+IGL_INLINE void igl::parula(const T f, T & r, T & g, T & b)
+{
+ igl::colormap(igl::COLOR_MAP_TYPE_PARULA, f, r, g, b);
+}
+
+
+template <typename DerivedZ, typename DerivedC>
+IGL_INLINE void igl::parula(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const bool normalize,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ igl::colormap(igl::COLOR_MAP_TYPE_PARULA, Z, normalize, C);
+}
+template <typename DerivedZ, typename DerivedC>
+IGL_INLINE void igl::parula(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const double min_z,
+ const double max_z,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ igl::colormap(igl::COLOR_MAP_TYPE_PARULA, Z, min_z, max_z, C);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::parula<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::parula<Eigen::Array<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Array<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::parula<double>(double, double*);
+template void igl::parula<double>(double, double&, double&, double&);
+template void igl::parula<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::parula<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::parula<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/parula.h b/xs/src/igl/parula.h
new file mode 100644
index 000000000..55cbd447f
--- /dev/null
+++ b/xs/src/igl/parula.h
@@ -0,0 +1,62 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PARULA_H
+#define IGL_PARULA_H
+#include "igl_inline.h"
+//#ifndef IGL_NO_EIGEN
+# include <Eigen/Dense>
+//#endif
+namespace igl
+{
+ // PARULA like MATLAB's parula
+ //
+ // Inputs:
+ // m number of colors
+ // Outputs:
+ // J m by list of RGB colors between 0 and 1
+ //
+ // Wrapper for directly computing [r,g,b] values for a given factor f between
+ // 0 and 1
+ //
+ // Inputs:
+ // f factor determining color value as if 0 was min and 1 was max
+ // Outputs:
+ // r red value
+ // g green value
+ // b blue value
+ template <typename T>
+ IGL_INLINE void parula(const T f, T * rgb);
+ template <typename T>
+ IGL_INLINE void parula(const T f, T & r, T & g, T & b);
+ // Inputs:
+ // 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
+ template <typename DerivedZ, typename DerivedC>
+ IGL_INLINE void parula(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const bool normalize,
+ Eigen::PlainObjectBase<DerivedC> & C);
+ // Inputs:
+ // min_Z value at blue
+ // max_Z value at red
+ template <typename DerivedZ, typename DerivedC>
+ IGL_INLINE void parula(
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ const double min_Z,
+ const double max_Z,
+ Eigen::PlainObjectBase<DerivedC> & C);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "parula.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/path_to_executable.cpp b/xs/src/igl/path_to_executable.cpp
new file mode 100644
index 000000000..509a763d6
--- /dev/null
+++ b/xs/src/igl/path_to_executable.cpp
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "path_to_executable.h"
+#ifdef __APPLE__
+# include <mach-o/dyld.h>
+#endif
+#if defined(_WIN32)
+# include <windows.h>
+#endif
+#include <stdint.h>
+IGL_INLINE std::string igl::path_to_executable()
+{
+ // http://pastebin.com/ffzzxPzi
+ using namespace std;
+ std::string path;
+ char buffer[1024];
+ uint32_t size = sizeof(buffer);
+#if defined (WIN32)
+ GetModuleFileName(nullptr,buffer,size);
+ path = buffer;
+#elif defined (__APPLE__)
+ if(_NSGetExecutablePath(buffer, &size) == 0)
+ {
+ path = buffer;
+ }
+#elif defined(UNIX)
+ if (readlink("/proc/self/exe", buffer, sizeof(buffer)) == -1)
+ {
+ path = buffer;
+ }
+#elif defined(__FreeBSD__)
+ int mib[4];
+ mib[0] = CTL_KERN;
+ mib[1] = KERN_PROC;
+ mib[2] = KERN_PROC_PATHNAME;
+ mib[3] = -1;
+ sysctl(mib, 4, buffer, sizeof(buffer), NULL, 0);
+ path = buffer;
+#elif defined(SUNOS)
+ path = getexecname();
+#endif
+ return path;
+}
+
diff --git a/xs/src/igl/path_to_executable.h b/xs/src/igl/path_to_executable.h
new file mode 100644
index 000000000..169c3400b
--- /dev/null
+++ b/xs/src/igl/path_to_executable.h
@@ -0,0 +1,21 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PATH_TO_EXECUTABLE_H
+#define IGL_PATH_TO_EXECUTABLE_H
+#include "igl_inline.h"
+#include <string>
+namespace igl
+{
+ // Return the path of the current executable.
+ // Note: Tested for Mac OS X
+ IGL_INLINE std::string path_to_executable();
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "path_to_executable.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/pathinfo.cpp b/xs/src/igl/pathinfo.cpp
new file mode 100644
index 000000000..110535cd8
--- /dev/null
+++ b/xs/src/igl/pathinfo.cpp
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "pathinfo.h"
+
+#include "dirname.h"
+#include "basename.h"
+// Verbose should be removed once everything working correctly
+#include "verbose.h"
+#include <algorithm>
+
+IGL_INLINE void igl::pathinfo(
+ const std::string & path,
+ std::string & dirname,
+ std::string & basename,
+ std::string & extension,
+ std::string & filename)
+{
+ dirname = igl::dirname(path);
+ basename = igl::basename(path);
+ std::string::reverse_iterator last_dot =
+ std::find(
+ basename.rbegin(),
+ basename.rend(), '.');
+ // Was a dot found?
+ if(last_dot == basename.rend())
+ {
+ // filename is same as basename
+ filename = basename;
+ // no extension
+ extension = "";
+ }else
+ {
+ // extension is substring of basename
+ extension = std::string(last_dot.base(),basename.end());
+ // filename is substring of basename
+ filename = std::string(basename.begin(),last_dot.base()-1);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/pathinfo.h b/xs/src/igl/pathinfo.h
new file mode 100644
index 000000000..b59e48157
--- /dev/null
+++ b/xs/src/igl/pathinfo.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PATHINFO_H
+#define IGL_PATHINFO_H
+#include "igl_inline.h"
+
+#include <string>
+
+namespace igl
+{
+ //// Decided not to use these
+ //const int PATHINFO_DIRNAME 01
+ //const int PATHINFO_BASENAME 02
+ //const int PATHINFO_EXTENSION 04
+ //const int PATHINFO_FILENAME 08
+
+ // Function like PHP's pathinfo
+ // returns information about path
+ // Input:
+ // path string containing input path
+ // Outputs:
+ // dirname string containing dirname (see dirname.h)
+ // basename string containing basename (see basename.h)
+ // extension string containing extension (characters after last '.')
+ // filename string containing filename (characters of basename before last
+ // '.')
+ //
+ //
+ // Examples:
+ //
+ // input | dirname basename ext filename
+ // "/" | "/" "" "" ""
+ // "//" | "/" "" "" ""
+ // "/foo" | "/" "foo" "" "foo"
+ // "/foo/" | "/" "foo" "" "foo"
+ // "/foo//" | "/" "foo" "" "foo"
+ // "/foo/./" | "/foo" "." "" ""
+ // "/foo/bar" | "/foo" "bar" "" "bar"
+ // "/foo/bar." | "/foo" "bar." "" "bar"
+ // "/foo/bar.txt" | "/foo" "bar.txt" "txt" "bar"
+ // "/foo/bar.txt.zip" | "/foo" "bar.txt.zip" "zip" "bar.txt"
+ // "/foo/bar.dir/" | "/foo" "bar.dir" "dir" "bar"
+ // "/foo/bar.dir/file" | "/foo/bar.dir" "file" "" "file"
+ // "/foo/bar.dir/file.txt" | "/foo/bar.dir" "file.txt" "txt" "file"
+ // See also: basename, dirname
+ IGL_INLINE void pathinfo(
+ const std::string & path,
+ std::string & dirname,
+ std::string & basename,
+ std::string & extension,
+ std::string & filename);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "pathinfo.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/per_corner_normals.cpp b/xs/src/igl/per_corner_normals.cpp
new file mode 100644
index 000000000..5d2aa6aff
--- /dev/null
+++ b/xs/src/igl/per_corner_normals.cpp
@@ -0,0 +1,111 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "per_corner_normals.h"
+
+#include "vertex_triangle_adjacency.h"
+#include "per_face_normals.h"
+#include "PI.h"
+
+template <typename DerivedV, typename DerivedF, typename DerivedCN>
+IGL_INLINE void igl::per_corner_normals(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const double corner_threshold,
+ Eigen::PlainObjectBase<DerivedCN> & CN)
+{
+ using namespace Eigen;
+ using namespace std;
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> FN;
+ per_face_normals(V,F,FN);
+ vector<vector<int> > VF,VFi;
+ vertex_triangle_adjacency(V,F,VF,VFi);
+ return per_corner_normals(V,F,FN,VF,corner_threshold,CN);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedCN>
+IGL_INLINE void igl::per_corner_normals(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedFN>& FN,
+ const double corner_threshold,
+ Eigen::PlainObjectBase<DerivedCN> & CN)
+{
+ using namespace Eigen;
+ using namespace std;
+ vector<vector<int> > VF,VFi;
+ vertex_triangle_adjacency(V,F,VF,VFi);
+ return per_corner_normals(V,F,FN,VF,corner_threshold,CN);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename IndexType,
+ typename DerivedCN>
+IGL_INLINE void igl::per_corner_normals(
+ const Eigen::PlainObjectBase<DerivedV>& /*V*/,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedFN>& FN,
+ const std::vector<std::vector<IndexType> >& VF,
+ const double corner_threshold,
+ Eigen::PlainObjectBase<DerivedCN> & CN)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ // number of faces
+ const int m = F.rows();
+ // valence of faces
+ const int n = F.cols();
+
+ // initialize output to ***zero***
+ CN.setZero(m*n,3);
+
+ // loop over faces
+ for(size_t i = 0;int(i)<m;i++)
+ {
+ // Normal of this face
+ Eigen::Matrix<typename DerivedV::Scalar,3,1> fn = FN.row(i);
+ // loop over corners
+ for(size_t j = 0;int(j)<n;j++)
+ {
+ const std::vector<IndexType> &incident_faces = VF[F(i,j)];
+ // loop over faces sharing vertex of this corner
+ for(int k = 0;k<(int)incident_faces.size();k++)
+ {
+ Eigen::Matrix<typename DerivedV::Scalar,3,1> ifn = FN.row(incident_faces[k]);
+ // dot product between face's normal and other face's normal
+ double dp = fn.dot(ifn);
+ // if difference in normal is slight then add to average
+ if(dp > cos(corner_threshold*PI/180))
+ {
+ // add to running sum
+ CN.row(i*n+j) += ifn;
+ // else ignore
+ }else
+ {
+ }
+ }
+ // normalize to take average
+ CN.row(i*n+j).normalize();
+ }
+ }
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_corner_normals<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/per_corner_normals.h b/xs/src/igl/per_corner_normals.h
new file mode 100644
index 000000000..f93f7eb46
--- /dev/null
+++ b/xs/src/igl/per_corner_normals.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PER_CORNER_NORMALS_H
+#define IGL_PER_CORNER_NORMALS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Compute vertex normals via vertex position list, face list
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigen Matrix of face (triangle) indices
+ // corner_threshold threshold in degrees on sharp angles
+ // Output:
+ // CN #F*3 by 3 eigen Matrix of mesh vertex 3D normals, where the normal
+ // for corner F(i,j) is at CN(i*3+j,:)
+ template <typename DerivedV, typename DerivedF, typename DerivedCN>
+ IGL_INLINE void per_corner_normals(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const double corner_threshold,
+ Eigen::PlainObjectBase<DerivedCN> & CN);
+ // Other Inputs:
+ // FN #F by 3 eigen Matrix of face normals
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedCN>
+ IGL_INLINE void per_corner_normals(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedFN>& FN,
+ const double corner_threshold,
+ Eigen::PlainObjectBase<DerivedCN> & CN);
+ // Other Inputs:
+ // VF map from vertices to list of incident faces
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename IndexType,
+ typename DerivedCN>
+ IGL_INLINE void per_corner_normals(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedFN>& FN,
+ const std::vector<std::vector<IndexType> >& VF,
+ const double corner_threshold,
+ Eigen::PlainObjectBase<DerivedCN> & CN);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "per_corner_normals.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/per_edge_normals.cpp b/xs/src/igl/per_edge_normals.cpp
new file mode 100644
index 000000000..8aa71791d
--- /dev/null
+++ b/xs/src/igl/per_edge_normals.cpp
@@ -0,0 +1,130 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "oriented_facets.h"
+#include "doublearea.h"
+#include "per_edge_normals.h"
+#include "get_seconds.h"
+#include "per_face_normals.h"
+#include "unique_simplices.h"
+#include <vector>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedN,
+ typename DerivedE,
+ typename DerivedEMAP>
+IGL_INLINE void igl::per_edge_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const PerEdgeNormalsWeightingType weighting,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
+
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(F.cols() == 3 && "Faces must be triangles");
+ // number of faces
+ const int m = F.rows();
+ // All occurrences of directed edges
+ MatrixXi allE;
+ oriented_facets(F,allE);
+ // Find unique undirected edges and mapping
+ VectorXi _;
+ unique_simplices(allE,E,_,EMAP);
+ // now sort(allE,2) == E(EMAP,:), that is, if EMAP(i) = j, then E.row(j) is
+ // the undirected edge corresponding to the directed edge allE.row(i).
+
+ Eigen::VectorXd W;
+ switch(weighting)
+ {
+ case PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM:
+ // Do nothing
+ break;
+ default:
+ assert(false && "Unknown weighting type");
+ case PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT:
+ case PER_EDGE_NORMALS_WEIGHTING_TYPE_AREA:
+ {
+ doublearea(V,F,W);
+ break;
+ }
+ }
+
+ N.setZero(E.rows(),3);
+ for(int f = 0;f<m;f++)
+ {
+ for(int c = 0;c<3;c++)
+ {
+ if(weighting == PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM)
+ {
+ N.row(EMAP(f+c*m)) += FN.row(f);
+ }else
+ {
+ N.row(EMAP(f+c*m)) += W(f) * FN.row(f);
+ }
+ }
+ }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedE,
+ typename DerivedEMAP>
+IGL_INLINE void igl::per_edge_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const PerEdgeNormalsWeightingType weighting,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
+{
+ Eigen::Matrix<typename DerivedN::Scalar,Eigen::Dynamic,3> FN;
+ per_face_normals(V,F,FN);
+ return per_edge_normals(V,F,weighting,FN,N,E,EMAP);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedE,
+ typename DerivedEMAP>
+IGL_INLINE void igl::per_edge_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP)
+{
+ return
+ per_edge_normals(V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT,N,E,EMAP);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::per_edge_normals<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::per_edge_normals<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::per_edge_normals<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::per_edge_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::per_edge_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::per_edge_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::per_edge_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::PerEdgeNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::per_edge_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::PerEdgeNormalsWeightingType, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::per_edge_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/per_edge_normals.h b/xs/src/igl/per_edge_normals.h
new file mode 100644
index 000000000..b40d72976
--- /dev/null
+++ b/xs/src/igl/per_edge_normals.h
@@ -0,0 +1,81 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PER_EDGE_NORMALS_H
+#define IGL_PER_EDGE_NORMALS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ enum PerEdgeNormalsWeightingType
+ {
+ // Incident face normals have uniform influence on edge normal
+ PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM = 0,
+ // Incident face normals are averaged weighted by area
+ PER_EDGE_NORMALS_WEIGHTING_TYPE_AREA = 1,
+ // Area weights
+ PER_EDGE_NORMALS_WEIGHTING_TYPE_DEFAULT = 2,
+ NUM_PER_EDGE_NORMALS_WEIGHTING_TYPE = 3
+ };
+ // Compute face normals via vertex position list, face list
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigen Matrix of face (triangle) indices
+ // weight weighting type
+ // FN #F by 3 matrix of 3D face normals per face
+ // Output:
+ // N #2 by 3 matrix of mesh edge 3D normals per row
+ // E #E by 2 matrix of edge indices per row
+ // EMAP #E by 1 matrix of indices from all edges to E
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedN,
+ typename DerivedE,
+ typename DerivedEMAP>
+ IGL_INLINE void per_edge_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const PerEdgeNormalsWeightingType weight,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedE,
+ typename DerivedEMAP>
+ IGL_INLINE void per_edge_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const PerEdgeNormalsWeightingType weight,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedE,
+ typename DerivedEMAP>
+ IGL_INLINE void per_edge_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "per_edge_normals.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/per_face_normals.cpp b/xs/src/igl/per_face_normals.cpp
new file mode 100644
index 000000000..d3de7ff95
--- /dev/null
+++ b/xs/src/igl/per_face_normals.cpp
@@ -0,0 +1,128 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "per_face_normals.h"
+#include <Eigen/Geometry>
+
+#define SQRT_ONE_OVER_THREE 0.57735026918962573
+template <typename DerivedV, typename DerivedF, typename DerivedZ, typename DerivedN>
+IGL_INLINE void igl::per_face_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ N.resize(F.rows(),3);
+ // loop over faces
+ int Frows = F.rows();
+#pragma omp parallel for if (Frows>10000)
+ for(int i = 0; i < Frows;i++)
+ {
+ const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v1 = V.row(F(i,1)) - V.row(F(i,0));
+ const Eigen::Matrix<typename DerivedV::Scalar, 1, 3> v2 = V.row(F(i,2)) - V.row(F(i,0));
+ N.row(i) = v1.cross(v2);//.normalized();
+ typename DerivedV::Scalar r = N.row(i).norm();
+ if(r == 0)
+ {
+ N.row(i) = Z;
+ }else
+ {
+ N.row(i) /= r;
+ }
+ }
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE void igl::per_face_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ using namespace Eigen;
+ Matrix<typename DerivedN::Scalar,3,1> Z(0,0,0);
+ return per_face_normals(V,F,Z,N);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE void igl::per_face_normals_stable(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ using namespace Eigen;
+ typedef Matrix<typename DerivedV::Scalar,1,3> RowVectorV3;
+ typedef typename DerivedV::Scalar Scalar;
+
+ const size_t m = F.rows();
+
+ N.resize(F.rows(),3);
+ // Grad all points
+ for(size_t f = 0;f<m;f++)
+ {
+ const RowVectorV3 p0 = V.row(F(f,0));
+ const RowVectorV3 p1 = V.row(F(f,1));
+ const RowVectorV3 p2 = V.row(F(f,2));
+ const RowVectorV3 n0 = (p1 - p0).cross(p2 - p0);
+ const RowVectorV3 n1 = (p2 - p1).cross(p0 - p1);
+ const RowVectorV3 n2 = (p0 - p2).cross(p1 - p2);
+
+ // careful sum
+ for(int d = 0;d<3;d++)
+ {
+ // This is a little _silly_ in terms of complexity, but its recursive
+ // implementation is clean looking...
+ const std::function<Scalar(Scalar,Scalar,Scalar)> sum3 =
+ [&sum3](Scalar a, Scalar b, Scalar c)->Scalar
+ {
+ if(fabs(c)>fabs(a))
+ {
+ return sum3(c,b,a);
+ }
+ // c < a
+ if(fabs(c)>fabs(b))
+ {
+ return sum3(a,c,b);
+ }
+ // c < a, c < b
+ if(fabs(b)>fabs(a))
+ {
+ return sum3(b,a,c);
+ }
+ return (a+b)+c;
+ };
+
+ N(f,d) = sum3(n0(d),n1(d),n2(d));
+ }
+ // sum better not be sure, or else NaN
+ N.row(f) /= N.row(f).norm();
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::per_face_normals<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::per_face_normals<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::per_face_normals<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, -1, 1, 1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_face_normals<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template void igl::per_face_normals<Eigen::Matrix<float, -1, -1, 1, -1, -1>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, -1, 1, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 1, -1, -1> >&);
+template void igl::per_face_normals<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+template void igl::per_face_normals<class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1> >(class Eigen::MatrixBase<class Eigen::Matrix<double,-1,3,0,-1,3> > const &,class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > &);
+template void igl::per_face_normals_stable<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_face_normals_stable<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_face_normals_stable<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/per_face_normals.h b/xs/src/igl/per_face_normals.h
new file mode 100644
index 000000000..220e5e9a6
--- /dev/null
+++ b/xs/src/igl/per_face_normals.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PER_FACE_NORMALS_H
+#define IGL_PER_FACE_NORMALS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute face normals via vertex position list, face list
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigen Matrix of face (triangle) indices
+ // Z 3 vector normal given to faces with degenerate normal.
+ // Output:
+ // N #F by 3 eigen Matrix of mesh face (triangle) 3D normals
+ //
+ // Example:
+ // // Give degenerate faces (1/3,1/3,1/3)^0.5
+ // per_face_normals(V,F,Vector3d(1,1,1).normalized(),N);
+ template <typename DerivedV, typename DerivedF, typename DerivedZ, typename DerivedN>
+ IGL_INLINE void per_face_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedZ> & Z,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Wrapper with Z = (0,0,0). Note that this means that row norms will be zero
+ // (i.e. not 1) for degenerate normals.
+ template <typename DerivedV, typename DerivedF, typename DerivedN>
+ IGL_INLINE void per_face_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Special version where order of face indices is guaranteed not to effect
+ // output.
+ template <typename DerivedV, typename DerivedF, typename DerivedN>
+ IGL_INLINE void per_face_normals_stable(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "per_face_normals.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/per_vertex_attribute_smoothing.cpp b/xs/src/igl/per_vertex_attribute_smoothing.cpp
new file mode 100644
index 000000000..ecf2b4e82
--- /dev/null
+++ b/xs/src/igl/per_vertex_attribute_smoothing.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "per_vertex_attribute_smoothing.h"
+#include <vector>
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::per_vertex_attribute_smoothing(
+ const Eigen::PlainObjectBase<DerivedV>& Ain,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedV> & Aout)
+{
+ std::vector<double> denominator(Ain.rows(), 0);
+ Aout = DerivedV::Zero(Ain.rows(), Ain.cols());
+ for (int i = 0; i < F.rows(); ++i) {
+ for (int j = 0; j < 3; ++j) {
+ int j1 = (j + 1) % 3;
+ int j2 = (j + 2) % 3;
+ Aout.row(F(i, j)) += Ain.row(F(i, j1)) + Ain.row(F(i, j2));
+ denominator[F(i, j)] += 2;
+ }
+ }
+ for (int i = 0; i < Ain.rows(); ++i)
+ Aout.row(i) /= denominator[i];
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::per_vertex_attribute_smoothing<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/per_vertex_attribute_smoothing.h b/xs/src/igl/per_vertex_attribute_smoothing.h
new file mode 100644
index 000000000..662810236
--- /dev/null
+++ b/xs/src/igl/per_vertex_attribute_smoothing.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PER_VERTEX_ATTRIBUTE_SMOOTHING_H
+#define IGL_PER_VERTEX_ATTRIBUTE_SMOOTHING_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Smooth vertex attributes using uniform Laplacian
+ // Inputs:
+ // Ain #V by #A eigen Matrix of mesh vertex attributes (each vertex has #A attributes)
+ // F #F by 3 eigne Matrix of face (triangle) indices
+ // Output:
+ // Aout #V by #A eigen Matrix of mesh vertex attributes
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void per_vertex_attribute_smoothing(
+ const Eigen::PlainObjectBase<DerivedV>& Ain,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedV> & Aout);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "per_vertex_attribute_smoothing.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/per_vertex_normals.cpp b/xs/src/igl/per_vertex_normals.cpp
new file mode 100644
index 000000000..c3bbda193
--- /dev/null
+++ b/xs/src/igl/per_vertex_normals.cpp
@@ -0,0 +1,133 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "per_vertex_normals.h"
+
+#include "get_seconds.h"
+#include "per_face_normals.h"
+#include "doublearea.h"
+#include "parallel_for.h"
+#include "internal_angles.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN>
+IGL_INLINE void igl::per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const igl::PerVertexNormalsWeightingType weighting,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> PFN;
+ igl::per_face_normals(V,F,PFN);
+ return per_vertex_normals(V,F,weighting,PFN,N);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE void igl::per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ return per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT,N);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedFN, typename DerivedN>
+IGL_INLINE void igl::per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const igl::PerVertexNormalsWeightingType weighting,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ using namespace std;
+ // Resize for output
+ N.setZero(V.rows(),3);
+
+ Eigen::Matrix<typename DerivedN::Scalar,DerivedF::RowsAtCompileTime,3>
+ W(F.rows(),3);
+ switch(weighting)
+ {
+ case PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM:
+ W.setConstant(1.);
+ break;
+ default:
+ assert(false && "Unknown weighting type");
+ case PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT:
+ case PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA:
+ {
+ Eigen::Matrix<typename DerivedN::Scalar,DerivedF::RowsAtCompileTime,1> A;
+ doublearea(V,F,A);
+ W = A.replicate(1,3);
+ break;
+ }
+ case PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE:
+ internal_angles(V,F,W);
+ break;
+ }
+
+ // loop over faces
+ for(int i = 0;i<F.rows();i++)
+ {
+ // throw normal at each corner
+ for(int j = 0; j < 3;j++)
+ {
+ N.row(F(i,j)) += W(i,j) * FN.row(i);
+ }
+ }
+
+ //// loop over faces
+ //std::mutex critical;
+ //std::vector<DerivedN> NN;
+ //parallel_for(
+ // F.rows(),
+ // [&NN,&N](const size_t n){ NN.resize(n,DerivedN::Zero(N.rows(),3));},
+ // [&F,&W,&FN,&NN,&critical](const int i, const size_t t)
+ // {
+ // // throw normal at each corner
+ // for(int j = 0; j < 3;j++)
+ // {
+ // // Q: Does this need to be critical?
+ // // A: Yes. Different (i,j)'s could produce the same F(i,j)
+ // NN[t].row(F(i,j)) += W(i,j) * FN.row(i);
+ // }
+ // },
+ // [&N,&NN](const size_t t){ N += NN[t]; },
+ // 1000l);
+
+ // take average via normalization
+ N.rowwise().normalize();
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedN>
+IGL_INLINE void igl::per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ return
+ per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT,FN,N);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::per_vertex_normals<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_vertex_normals<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::per_vertex_normals<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::per_vertex_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::PerVertexNormalsWeightingType, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_vertex_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_vertex_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::per_vertex_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::PerVertexNormalsWeightingType, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::per_vertex_normals<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/per_vertex_normals.h b/xs/src/igl/per_vertex_normals.h
new file mode 100644
index 000000000..be4ba0461
--- /dev/null
+++ b/xs/src/igl/per_vertex_normals.h
@@ -0,0 +1,80 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PER_VERTEX_NORMALS_H
+#define IGL_PER_VERTEX_NORMALS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+// Note: It would be nice to support more or all of the methods here:
+// "A comparison of algorithms for vertex normal computation"
+namespace igl
+{
+ enum PerVertexNormalsWeightingType
+ {
+ // Incident face normals have uniform influence on vertex normal
+ PER_VERTEX_NORMALS_WEIGHTING_TYPE_UNIFORM = 0,
+ // Incident face normals are averaged weighted by area
+ PER_VERTEX_NORMALS_WEIGHTING_TYPE_AREA = 1,
+ // Incident face normals are averaged weighted by incident angle of vertex
+ PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE = 2,
+ // Area weights
+ PER_VERTEX_NORMALS_WEIGHTING_TYPE_DEFAULT = 3,
+ NUM_PER_VERTEX_NORMALS_WEIGHTING_TYPE = 4
+ };
+ // Compute vertex normals via vertex position list, face list
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 3 eigne Matrix of face (triangle) indices
+ // weighting Weighting type
+ // Output:
+ // N #V by 3 eigen Matrix of mesh vertex 3D normals
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN>
+ IGL_INLINE void per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const igl::PerVertexNormalsWeightingType weighting,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Without weighting
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN>
+ IGL_INLINE void per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Inputs:
+ // FN #F by 3 matrix of face (triangle) normals
+ template <typename DerivedV, typename DerivedF, typename DerivedFN, typename DerivedN>
+ IGL_INLINE void per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const PerVertexNormalsWeightingType weighting,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Without weighting
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedN>
+ IGL_INLINE void per_vertex_normals(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ Eigen::PlainObjectBase<DerivedN> & N);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "per_vertex_normals.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/per_vertex_point_to_plane_quadrics.cpp b/xs/src/igl/per_vertex_point_to_plane_quadrics.cpp
new file mode 100644
index 000000000..6d1be71b0
--- /dev/null
+++ b/xs/src/igl/per_vertex_point_to_plane_quadrics.cpp
@@ -0,0 +1,157 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "per_vertex_point_to_plane_quadrics.h"
+#include "quadric_binary_plus_operator.h"
+#include <Eigen/QR>
+#include <cassert>
+#include <cmath>
+
+
+IGL_INLINE void igl::per_vertex_point_to_plane_quadrics(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ std::vector<
+ std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> > & quadrics)
+{
+ using namespace std;
+ typedef std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> Quadric;
+ const int dim = V.cols();
+ //// Quadrics per face
+ //std::vector<Quadric> face_quadrics(F.rows());
+ // Initialize each vertex quadric to zeros
+ quadrics.resize(
+ V.rows(),
+ // gcc <=4.8 can't handle initializer lists correctly
+ Quadric{Eigen::MatrixXd::Zero(dim,dim),Eigen::RowVectorXd::Zero(dim),0});
+ Eigen::MatrixXd I = Eigen::MatrixXd::Identity(dim,dim);
+ // Rather initial with zeros, initial with a small amount of energy pull
+ // toward original vertex position
+ const double w = 1e-10;
+ for(int v = 0;v<V.rows();v++)
+ {
+ std::get<0>(quadrics[v]) = w*I;
+ Eigen::RowVectorXd Vv = V.row(v);
+ std::get<1>(quadrics[v]) = w*-Vv;
+ std::get<2>(quadrics[v]) = w*Vv.dot(Vv);
+ }
+ // Generic nD qslim from "Simplifying Surfaces with Color and Texture
+ // using Quadric Error Metric" (follow up to original QSlim)
+ for(int f = 0;f<F.rows();f++)
+ {
+ int infinite_corner = -1;
+ for(int c = 0;c<3;c++)
+ {
+ if(
+ std::isinf(V(F(f,c),0)) ||
+ std::isinf(V(F(f,c),1)) ||
+ std::isinf(V(F(f,c),2)))
+ {
+ assert(infinite_corner == -1 && "Should only be one infinite corner");
+ infinite_corner = c;
+ }
+ }
+ // Inputs:
+ // p 1 by n row point on the subspace
+ // S m by n matrix where rows coorespond to orthonormal spanning
+ // vectors of the subspace to which we're measuring distance (usually
+ // a plane, m=2)
+ // weight scalar weight
+ // Returns quadric triple {A,b,c} so that A-2*b+c measures the quadric
+ const auto subspace_quadric = [&I](
+ const Eigen::RowVectorXd & p,
+ const Eigen::MatrixXd & S,
+ const double weight)->Quadric
+ {
+ // Dimension of subspace
+ const int m = S.rows();
+ // Weight face's quadric (v'*A*v + 2*b'*v + c) by area
+ // e1 and e2 should be perpendicular
+ Eigen::MatrixXd A = I;
+ Eigen::RowVectorXd b = -p;
+ double c = p.dot(p);
+ for(int i = 0;i<m;i++)
+ {
+ Eigen::RowVectorXd ei = S.row(i);
+ for(int j = 0;j<i;j++) assert(std::abs(S.row(j).dot(ei)) < 1e-10);
+ A += -ei.transpose()*ei;
+ b += p.dot(ei)*ei;
+ c += -pow(p.dot(ei),2);
+ }
+ // gcc <=4.8 can't handle initializer lists correctly: needs explicit
+ // cast
+ return Quadric{ weight*A, weight*b, weight*c };
+ };
+ if(infinite_corner == -1)
+ {
+ // Finite (non-boundary) face
+ Eigen::RowVectorXd p = V.row(F(f,0));
+ Eigen::RowVectorXd q = V.row(F(f,1));
+ Eigen::RowVectorXd r = V.row(F(f,2));
+ Eigen::RowVectorXd pq = q-p;
+ Eigen::RowVectorXd pr = r-p;
+ // Gram Determinant = squared area of parallelogram
+ double area = sqrt(pq.squaredNorm()*pr.squaredNorm()-pow(pr.dot(pq),2));
+ Eigen::RowVectorXd e1 = pq.normalized();
+ Eigen::RowVectorXd e2 = (pr-e1.dot(pr)*e1).normalized();
+ Eigen::MatrixXd S(2,V.cols());
+ S<<e1,e2;
+ Quadric face_quadric = subspace_quadric(p,S,area);
+ // Throw at each corner
+ for(int c = 0;c<3;c++)
+ {
+ quadrics[F(f,c)] = quadrics[F(f,c)] + face_quadric;
+ }
+ }else
+ {
+ // cth corner is infinite --> edge opposite cth corner is boundary
+ // Boundary edge vector
+ const Eigen::RowVectorXd p = V.row(F(f,(infinite_corner+1)%3));
+ Eigen::RowVectorXd ev = V.row(F(f,(infinite_corner+2)%3)) - p;
+ const double length = ev.norm();
+ ev /= length;
+ // Face neighbor across boundary edge
+ int e = EMAP(f+F.rows()*infinite_corner);
+ int opp = EF(e,0) == f ? 1 : 0;
+ int n = EF(e,opp);
+ int nc = EI(e,opp);
+ assert(
+ ((F(f,(infinite_corner+1)%3) == F(n,(nc+1)%3) &&
+ F(f,(infinite_corner+2)%3) == F(n,(nc+2)%3)) ||
+ (F(f,(infinite_corner+1)%3) == F(n,(nc+2)%3)
+ && F(f,(infinite_corner+2)%3) == F(n,(nc+1)%3))) &&
+ "Edge flaps not agreeing on shared edge");
+ // Edge vector on opposite face
+ const Eigen::RowVectorXd eu = V.row(F(n,nc)) - p;
+ assert(!std::isinf(eu(0)));
+ // Matrix with vectors spanning plane as columns
+ Eigen::MatrixXd A(ev.size(),2);
+ A<<ev.transpose(),eu.transpose();
+ // Use QR decomposition to find basis for orthogonal space
+ Eigen::HouseholderQR<Eigen::MatrixXd> qr(A);
+ const Eigen::MatrixXd Q = qr.householderQ();
+ const Eigen::MatrixXd N =
+ Q.topRightCorner(ev.size(),ev.size()-2).transpose();
+ assert(N.cols() == ev.size());
+ assert(N.rows() == ev.size()-2);
+ Eigen::MatrixXd S(N.rows()+1,ev.size());
+ S<<ev,N;
+ Quadric boundary_edge_quadric = subspace_quadric(p,S,length);
+ for(int c = 0;c<3;c++)
+ {
+ if(c != infinite_corner)
+ {
+ quadrics[F(f,c)] = quadrics[F(f,c)] + boundary_edge_quadric;
+ }
+ }
+ }
+ }
+}
+
diff --git a/xs/src/igl/per_vertex_point_to_plane_quadrics.h b/xs/src/igl/per_vertex_point_to_plane_quadrics.h
new file mode 100644
index 000000000..3e9eb3abf
--- /dev/null
+++ b/xs/src/igl/per_vertex_point_to_plane_quadrics.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PER_VERTEX_POINT_TO_PLANE_QUADRICS_H
+#define IGL_PER_VERTEX_POINT_TO_PLANE_QUADRICS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include <tuple>
+namespace igl
+{
+ // Compute quadrics per vertex of a "closed" triangle mesh (V,F). Rather than
+ // follow the qslim paper, this implements the lesser-known _follow up_
+ // "Simplifying Surfaces with Color and Texture using Quadric Error Metrics".
+ // This allows V to be n-dimensional (where the extra coordiantes store
+ // texture UVs, color RGBs, etc.
+ //
+ // Inputs:
+ // V #V by n list of vertex positions. Assumes that vertices with
+ // infinite coordinates are "points at infinity" being used to close up
+ // boundary edges with faces. This allows special subspace quadrice for
+ // boundary edges: There should never be more than one "point at
+ // infinity" in a single triangle.
+ // F #F by 3 list of triangle 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).
+ // Outputs:
+ // quadrics #V list of quadrics, where a quadric is a tuple {A,b,c} such
+ // that the quadratic energy of moving this vertex to position x is
+ // given by x'Ax - 2b + c
+ //
+ IGL_INLINE void per_vertex_point_to_plane_quadrics(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ std::vector<
+ std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> > & quadrics);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "per_vertex_point_to_plane_quadrics.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/piecewise_constant_winding_number.cpp b/xs/src/igl/piecewise_constant_winding_number.cpp
new file mode 100644
index 000000000..4bf7d76f8
--- /dev/null
+++ b/xs/src/igl/piecewise_constant_winding_number.cpp
@@ -0,0 +1,82 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "piecewise_constant_winding_number.h"
+#include "unique_edge_map.h"
+#include "PI.h"
+
+template <
+ typename DerivedF,
+ typename DeriveduE,
+ typename uE2EType>
+IGL_INLINE bool igl::piecewise_constant_winding_number(
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E)
+{
+ const size_t num_faces = F.rows();
+ const size_t num_edges = uE.rows();
+ const auto edge_index_to_face_index = [&](size_t ei)
+ {
+ return ei % num_faces;
+ };
+ const auto is_consistent = [&](size_t fid, size_t s, size_t d)
+ {
+ if ((size_t)F(fid, 0) == s && (size_t)F(fid, 1) == d) return true;
+ if ((size_t)F(fid, 1) == s && (size_t)F(fid, 2) == d) return true;
+ if ((size_t)F(fid, 2) == s && (size_t)F(fid, 0) == d) return true;
+
+ if ((size_t)F(fid, 0) == d && (size_t)F(fid, 1) == s) return false;
+ if ((size_t)F(fid, 1) == d && (size_t)F(fid, 2) == s) return false;
+ if ((size_t)F(fid, 2) == d && (size_t)F(fid, 0) == s) return false;
+ throw "Invalid face!!";
+ };
+ for (size_t i=0; i<num_edges; i++)
+ {
+ const size_t s = uE(i,0);
+ const size_t d = uE(i,1);
+ int count=0;
+ for (const auto& ei : uE2E[i])
+ {
+ const size_t fid = edge_index_to_face_index(ei);
+ if (is_consistent(fid, s, d))
+ {
+ count++;
+ }
+ else
+ {
+ count--;
+ }
+ }
+ if (count != 0)
+ {
+ return false;
+ }
+ }
+ return true;
+}
+template <typename DerivedF>
+IGL_INLINE bool igl::piecewise_constant_winding_number(
+ const Eigen::MatrixBase<DerivedF>& F)
+{
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,2> E, uE;
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> EMAP;
+ std::vector<std::vector<size_t> > uE2E;
+ unique_edge_map(F, E, uE, EMAP, uE2E);
+ return piecewise_constant_winding_number(F,uE,uE2E);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::piecewise_constant_winding_number<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&);
+template bool igl::piecewise_constant_winding_number<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&);
+#ifdef WIN32
+template bool igl::piecewise_constant_winding_number<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &);
+template bool igl::piecewise_constant_winding_number<class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &);
+#endif
+#endif
diff --git a/xs/src/igl/piecewise_constant_winding_number.h b/xs/src/igl/piecewise_constant_winding_number.h
new file mode 100644
index 000000000..ebbeb6e98
--- /dev/null
+++ b/xs/src/igl/piecewise_constant_winding_number.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PIECEWISE_CONSTANT_WINDING_NUMBER_H
+#define IGL_PIECEWISE_CONSTANT_WINDING_NUMBER_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ // PIECEWISE_CONSTANT_WINDING_NUMBER Determine if a given mesh induces a
+ // piecewise constant winding number field: Is this mesh valid input to solid
+ // set operations. **Assumes** that `(V,F)` contains no self-intersections
+ // (including degeneracies and co-incidences). If there are co-planar and
+ // co-incident vertex placements, a mesh could _fail_ this combinatorial test
+ // but still induce a piecewise-constant winding number _geometrically_. For
+ // example, consider a hemisphere with boundary and then pinch the boundary
+ // "shut" along a line segment. The **_bullet-proof_** check is to first
+ // resolve all self-intersections in `(V,F) -> (SV,SF)` (i.e. what the
+ // `igl::copyleft::cgal::piecewise_constant_winding_number` overload does).
+ //
+ // Inputs:
+ // F #F by 3 list of triangle indices into some (abstract) list of
+ // vertices V
+ // uE #uE by 2 list of unique edges indices into V
+ // uE2E #uE list of lists of indices into directed edges (#F * 3)
+ // Returns true if the mesh _combinatorially_ induces a piecewise constant
+ // winding number field.
+ //
+ template <
+ typename DerivedF,
+ typename DeriveduE,
+ typename uE2EType>
+ IGL_INLINE bool piecewise_constant_winding_number(
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DeriveduE>& uE,
+ const std::vector<std::vector<uE2EType> >& uE2E);
+ template <typename DerivedF>
+ IGL_INLINE bool piecewise_constant_winding_number(
+ const Eigen::MatrixBase<DerivedF>& F);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "piecewise_constant_winding_number.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/pinv.cpp b/xs/src/igl/pinv.cpp
new file mode 100644
index 000000000..acf6a1913
--- /dev/null
+++ b/xs/src/igl/pinv.cpp
@@ -0,0 +1,35 @@
+#include "pinv.h"
+#include <limits>
+#include <cmath>
+
+template <typename DerivedA, typename DerivedX>
+void igl::pinv(
+ const Eigen::MatrixBase<DerivedA> & A,
+ typename DerivedA::Scalar tol,
+ Eigen::PlainObjectBase<DerivedX> & X)
+{
+ Eigen::JacobiSVD<DerivedA> svd(A, Eigen::ComputeFullU | Eigen::ComputeFullV );
+ typedef typename DerivedA::Scalar Scalar;
+ const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & U = svd.matrixU();
+ const Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> & V = svd.matrixV();
+ const Eigen::Matrix<Scalar,Eigen::Dynamic,1> & S = svd.singularValues();
+ if(tol < 0)
+ {
+ const Scalar smax = S.array().abs().maxCoeff();
+ tol =
+ (Scalar)(std::max(A.rows(),A.cols())) *
+ (smax-std::nextafter(smax,std::numeric_limits<Scalar>::epsilon()));
+ }
+ const int rank = (S.array()>0).count();
+ X = (V.leftCols(rank).array().rowwise() *
+ (1.0/S.head(rank).array()).transpose()).matrix()*
+ U.leftCols(rank).transpose();
+}
+
+template <typename DerivedA, typename DerivedX>
+void igl::pinv(
+ const Eigen::MatrixBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedX> & X)
+{
+ return pinv(A,-1,X);
+}
diff --git a/xs/src/igl/pinv.h b/xs/src/igl/pinv.h
new file mode 100644
index 000000000..045a17da2
--- /dev/null
+++ b/xs/src/igl/pinv.h
@@ -0,0 +1,29 @@
+#ifndef IGL_PINV_H
+#define IGL_PINV_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute the Moore-Penrose pseudoinverse
+ //
+ // Inputs:
+ // A m by n matrix
+ // tol tolerance (if negative then default is used)
+ // Outputs:
+ // X n by m matrix so that A*X*A = A and X*A*X = X and A*X = (A*X)' and
+ // (X*A) = (X*A)'
+ template <typename DerivedA, typename DerivedX>
+ void pinv(
+ const Eigen::MatrixBase<DerivedA> & A,
+ typename DerivedA::Scalar tol,
+ Eigen::PlainObjectBase<DerivedX> & X);
+ // Wrapper using default tol
+ template <typename DerivedA, typename DerivedX>
+ void pinv(
+ const Eigen::MatrixBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedX> & X);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "pinv.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/planarize_quad_mesh.cpp b/xs/src/igl/planarize_quad_mesh.cpp
new file mode 100644
index 000000000..d3c06be62
--- /dev/null
+++ b/xs/src/igl/planarize_quad_mesh.cpp
@@ -0,0 +1,245 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "planarize_quad_mesh.h"
+#include "quad_planarity.h"
+#include <Eigen/Sparse>
+#include <Eigen/Eigenvalues>
+#include <iostream>
+
+namespace igl
+{
+ template <typename DerivedV, typename DerivedF>
+ class PlanarizerShapeUp
+ {
+ protected:
+ // number of faces, number of vertices
+ long numV, numF;
+ // references to the input faces and vertices
+ const Eigen::PlainObjectBase<DerivedV> &Vin;
+ const Eigen::PlainObjectBase<DerivedF> &Fin;
+
+ // vector consisting of the vertex positions stacked: [x;y;z;x;y;z...]
+ // vector consisting of a weight per face (currently all set to 1)
+ // vector consisting of the projected face vertices (might be different for the same vertex belonging to different faces)
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> Vv, weightsSqrt, P;
+
+ // Matrices as in the paper
+ // Q: lhs matrix
+ // Ni: matrix that subtracts the mean of a face from the 4 vertices of a face
+ Eigen::SparseMatrix<typename DerivedV::Scalar > Q, Ni;
+ Eigen::SimplicialLDLT<Eigen::SparseMatrix<typename DerivedV::Scalar > > solver;
+
+ int maxIter;
+ double threshold;
+ const int ni = 4;
+
+ // Matrix assemblers
+ inline void assembleQ();
+ inline void assembleP();
+ inline void assembleNi();
+
+ // Selects out of Vv the 4 vertices belonging to face fi
+ inline void assembleSelector(int fi,
+ Eigen::SparseMatrix<typename DerivedV::Scalar > &S);
+
+
+ public:
+ // Init - assemble stacked vector and lhs matrix, factorize
+ inline PlanarizerShapeUp(const Eigen::PlainObjectBase<DerivedV> &V_,
+ const Eigen::PlainObjectBase<DerivedF> &F_,
+ const int maxIter_,
+ const double &threshold_);
+ // Planarization - output to Vout
+ inline void planarize(Eigen::PlainObjectBase<DerivedV> &Vout);
+ };
+}
+
+//Implementation
+
+template <typename DerivedV, typename DerivedF>
+inline igl::PlanarizerShapeUp<DerivedV, DerivedF>::PlanarizerShapeUp(const Eigen::PlainObjectBase<DerivedV> &V_,
+ const Eigen::PlainObjectBase<DerivedF> &F_,
+ const int maxIter_,
+ const double &threshold_):
+numV(V_.rows()),
+numF(F_.rows()),
+Vin(V_),
+Fin(F_),
+weightsSqrt(Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1>::Ones(numF,1)),
+maxIter(maxIter_),
+threshold(threshold_)
+{
+ // assemble stacked vertex position vector
+ Vv.setZero(3*numV,1);
+ for (int i =0;i<numV;++i)
+ Vv.segment(3*i,3) = Vin.row(i);
+ // assemble and factorize lhs matrix
+ assembleQ();
+};
+
+template <typename DerivedV, typename DerivedF>
+inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleQ()
+{
+ std::vector<Eigen::Triplet<typename DerivedV::Scalar> > tripletList;
+
+ // assemble the Ni matrix
+ assembleNi();
+
+ for (int fi = 0; fi< numF; fi++)
+ {
+ Eigen::SparseMatrix<typename DerivedV::Scalar > Sfi;
+ assembleSelector(fi, Sfi);
+
+ // the final matrix per face
+ Eigen::SparseMatrix<typename DerivedV::Scalar > Qi = weightsSqrt(fi)*Ni*Sfi;
+ // put it in the correct block of Q
+ // todo: this can be made faster by omitting the selector matrix
+ for (int k=0; k<Qi.outerSize(); ++k)
+ for (typename Eigen::SparseMatrix<typename DerivedV::Scalar >::InnerIterator it(Qi,k); it; ++it)
+ {
+ typename DerivedV::Scalar val = it.value();
+ int row = it.row();
+ int col = it.col();
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(row+3*ni*fi,col,val));
+ }
+ }
+
+ Q.resize(3*ni*numF,3*numV);
+ Q.setFromTriplets(tripletList.begin(), tripletList.end());
+ // the actual lhs matrix is Q'*Q
+ // prefactor that matrix
+ solver.compute(Q.transpose()*Q);
+ if(solver.info()!=Eigen::Success)
+ {
+ std::cerr << "Cholesky failed - PlanarizerShapeUp.cpp" << std::endl;
+ assert(0);
+ }
+}
+
+template <typename DerivedV, typename DerivedF>
+inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleNi()
+{
+ std::vector<Eigen::Triplet<typename DerivedV::Scalar>> tripletList;
+ for (int ii = 0; ii< ni; ii++)
+ {
+ for (int jj = 0; jj< ni; jj++)
+ {
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+0,3*jj+0,-1./ni));
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+1,3*jj+1,-1./ni));
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+2,3*jj+2,-1./ni));
+ }
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+0,3*ii+0,1.));
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+1,3*ii+1,1.));
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*ii+2,3*ii+2,1.));
+ }
+ Ni.resize(3*ni,3*ni);
+ Ni.setFromTriplets(tripletList.begin(), tripletList.end());
+}
+
+//assumes V stacked [x;y;z;x;y;z...];
+template <typename DerivedV, typename DerivedF>
+inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleSelector(int fi,
+ Eigen::SparseMatrix<typename DerivedV::Scalar > &S)
+{
+
+ std::vector<Eigen::Triplet<typename DerivedV::Scalar>> tripletList;
+ for (int fvi = 0; fvi< ni; fvi++)
+ {
+ int vi = Fin(fi,fvi);
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+0,3*vi+0,1.));
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+1,3*vi+1,1.));
+ tripletList.push_back(Eigen::Triplet<typename DerivedV::Scalar>(3*fvi+2,3*vi+2,1.));
+ }
+
+ S.resize(3*ni,3*numV);
+ S.setFromTriplets(tripletList.begin(), tripletList.end());
+
+}
+
+//project all faces to their closest planar face
+template <typename DerivedV, typename DerivedF>
+inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::assembleP()
+{
+ P.setZero(3*ni*numF);
+ for (int fi = 0; fi< numF; fi++)
+ {
+ // todo: this can be made faster by omitting the selector matrix
+ Eigen::SparseMatrix<typename DerivedV::Scalar > Sfi;
+ assembleSelector(fi, Sfi);
+ Eigen::SparseMatrix<typename DerivedV::Scalar > NSi = Ni*Sfi;
+
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> Vi = NSi*Vv;
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> CC(3,ni);
+ for (int i = 0; i <ni; ++i)
+ CC.col(i) = Vi.segment(3*i, 3);
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 3> C = CC*CC.transpose();
+
+ // Alec: Doesn't compile
+ Eigen::EigenSolver<Eigen::Matrix<typename DerivedV::Scalar, 3, 3>> es(C);
+ // the real() is for compilation purposes
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 1> lambda = es.eigenvalues().real();
+ Eigen::Matrix<typename DerivedV::Scalar, 3, 3> U = es.eigenvectors().real();
+ int min_i;
+ lambda.cwiseAbs().minCoeff(&min_i);
+ U.col(min_i).setZero();
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, Eigen::Dynamic> PP = U*U.transpose()*CC;
+ for (int i = 0; i <ni; ++i)
+ P.segment(3*ni*fi+3*i, 3) = weightsSqrt[fi]*PP.col(i);
+
+ }
+}
+
+
+template <typename DerivedV, typename DerivedF>
+inline void igl::PlanarizerShapeUp<DerivedV, DerivedF>::planarize(Eigen::PlainObjectBase<DerivedV> &Vout)
+{
+ Eigen::Matrix<typename DerivedV::Scalar, Eigen::Dynamic, 1> planarity;
+ Vout = Vin;
+
+ for (int iter =0; iter<maxIter; ++iter)
+ {
+ igl::quad_planarity(Vout, Fin, planarity);
+ typename DerivedV::Scalar nonPlanarity = planarity.cwiseAbs().maxCoeff();
+ //std::cerr<<"iter #"<<iter<<": max non-planarity: "<<nonPlanarity<<std::endl;
+ if (nonPlanarity<threshold)
+ break;
+ assembleP();
+ Vv = solver.solve(Q.transpose()*P);
+ if(solver.info()!=Eigen::Success)
+ {
+ std::cerr << "Linear solve failed - PlanarizerShapeUp.cpp" << std::endl;
+ assert(0);
+ }
+ for (int i =0;i<numV;++i)
+ Vout.row(i) << Vv.segment(3*i,3).transpose();
+ }
+ // set the mean of Vout to the mean of Vin
+ Eigen::Matrix<typename DerivedV::Scalar, 1, 3> oldMean, newMean;
+ oldMean = Vin.colwise().mean();
+ newMean = Vout.colwise().mean();
+ Vout.rowwise() += (oldMean - newMean);
+
+};
+
+
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::planarize_quad_mesh(const Eigen::PlainObjectBase<DerivedV> &Vin,
+ const Eigen::PlainObjectBase<DerivedF> &Fin,
+ const int maxIter,
+ const double &threshold,
+ Eigen::PlainObjectBase<DerivedV> &Vout)
+{
+ PlanarizerShapeUp<DerivedV, DerivedF> planarizer(Vin, Fin, maxIter, threshold);
+ planarizer.planarize(Vout);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::planarize_quad_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, double const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/planarize_quad_mesh.h b/xs/src/igl/planarize_quad_mesh.h
new file mode 100644
index 000000000..0de7bf389
--- /dev/null
+++ b/xs/src/igl/planarize_quad_mesh.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PLANARIZE_QUAD_MESH_H
+#define IGL_PLANARIZE_QUAD_MESH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Planarizes a given quad mesh using the algorithm described in the paper
+ // "Shape-Up: Shaping Discrete Geometry with Projections" by S. Bouaziz,
+ // M. Deuss, Y. Schwartzburg, T. Weise, M. Pauly, Computer Graphics Forum,
+ // Volume 31, Issue 5, August 2012, p. 1657-1667
+ // (http://dl.acm.org/citation.cfm?id=2346802).
+ // The algorithm iterates between projecting each quad to its closest planar
+ // counterpart and stitching those quads together via a least squares
+ // optimization. It stops whenever all quads' non-planarity is less than a
+ // given threshold (suggested value: 0.01), or a maximum number of iterations
+ // is reached.
+
+
+ // Inputs:
+ // Vin #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 4 eigen Matrix of face (quad) indices
+ // maxIter maximum numbers of iterations
+ // threshold minimum allowed threshold for non-planarity
+ // Output:
+ // Vout #V by 3 eigen Matrix of planar mesh vertex 3D positions
+ //
+
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void planarize_quad_mesh(const Eigen::PlainObjectBase<DerivedV> &Vin,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ const int maxIter,
+ const double &threshold,
+ Eigen::PlainObjectBase<DerivedV> &Vout);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "planarize_quad_mesh.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/ply.h b/xs/src/igl/ply.h
new file mode 100644
index 000000000..60f2b29de
--- /dev/null
+++ b/xs/src/igl/ply.h
@@ -0,0 +1,3168 @@
+#ifndef IGL_PLY_H
+#define IGL_PLY_H
+/*
+
+Header for PLY polygon files.
+
+- Greg Turk, March 1994
+
+A PLY file contains a single polygonal _object_.
+
+An object is composed of lists of _elements_. Typical elements are
+vertices, faces, edges and materials.
+
+Each type of element for a given object has one or more _properties_
+associated with the element type. For instance, a vertex element may
+have as properties three floating-point values x,y,z and three unsigned
+chars for red, green and blue.
+
+---------------------------------------------------------------
+
+Copyright (c) 1994 The Board of Trustees of The Leland Stanford
+Junior University. All rights reserved.
+
+Permission to use, copy, modify and distribute this software and its
+documentation for any purpose is hereby granted without fee, provided
+that the above copyright notice and this permission notice appear in
+all copies of this software and that you do not sell the software.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+--------------------------------------------------------------------------------
+Joao Fradinho Oliveira, July 2005
+Copyright (c) 2005 University College London
+copyright conditions as above
+
+update for ply reading of multi OS ply files, in any OS (Unix, Macintosh, PC)
+--------------------------------------------------------------------------------
+
+ply_open_for_reading
+
+* was changed to always open files in binary mode, files written in ascii can also be
+read with this binary mode.
+
+* allows opening of filenames that are alias files in macintosh
+
+* code tested on pc and mac
+
+
+get_words
+
+* was changed to handle line breaks in UNIX, MACINTOSH, PC, it resets the file pointer
+accordingly for the next read.
+
+
+NOTES:
+The ply file, has always an ascii part for the header, and a binary or ascii
+part for the data.
+The header part in ascii, dictates that linebreaks are used, this make models
+operating system dependent, as a line break in unix is indicated with the escape character \n,
+on a macintosh, with \r, and on a pc with \r\n <--2 unsigned chars, 2 bytes, instead of 1 byte.
+
+get_words allows reading of any OS, text editors such as BBEdit do not save the linebreaks
+properly to target OSs with binary files.
+
+*/
+
+#ifndef __PLY_H__
+#define __PLY_H__
+
+
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stddef.h>
+#include <string.h>
+
+namespace igl {
+ namespace ply {
+
+#define PLY_ASCII 1 /* ascii PLY file */
+#define PLY_BINARY_BE 2 /* binary PLY file, big endian */
+#define PLY_BINARY_LE 3 /* binary PLY file, little endian */
+#define PLY_BINARY_NATIVE 4 /* binary PLY file, same endianness as
+ current architecture */
+
+#define PLY_OKAY 0 /* ply routine worked okay */
+#define PLY_ERROR -1 /* error in ply routine */
+
+/* scalar data types supported by PLY format */
+
+#define PLY_START_TYPE 0
+#define PLY_CHAR 1
+#define PLY_SHORT 2
+#define PLY_INT 3
+#define PLY_UCHAR 4
+#define PLY_USHORT 5
+#define PLY_UINT 6
+#define PLY_FLOAT 7
+#define PLY_DOUBLE 8
+#define PLY_END_TYPE 9
+
+#define PLY_SCALAR 0
+#define PLY_LIST 1
+
+
+
+
+typedef struct PlyProperty { /* description of a property */
+
+ const char *name; /* property name */
+ int external_type; /* file's data type */
+ int internal_type; /* program's data type */
+ int offset; /* offset bytes of prop in a struct */
+
+ int is_list; /* 1 = list, 0 = scalar */
+ int count_external; /* file's count type */
+ int count_internal; /* program's count type */
+ int count_offset; /* offset byte for list count */
+
+} PlyProperty;
+
+typedef struct PlyElement { /* description of an element */
+ const char *name; /* element name */
+ int num; /* number of elements in this object */
+ int size; /* size of element (bytes) or -1 if variable */
+ int nprops; /* number of properties for this element */
+ PlyProperty **props; /* list of properties in the file */
+ char *store_prop; /* flags: property wanted by user? */
+ int other_offset; /* offset to un-asked-for props, or -1 if none*/
+ int other_size; /* size of other_props structure */
+} PlyElement;
+
+typedef struct PlyOtherProp { /* describes other properties in an element */
+ const char *name; /* element name */
+ int size; /* size of other_props */
+ int nprops; /* number of properties in other_props */
+ PlyProperty **props; /* list of properties in other_props */
+} PlyOtherProp;
+
+typedef struct OtherData { /* for storing other_props for an other element */
+ void *other_props;
+} OtherData;
+
+typedef struct OtherElem { /* data for one "other" element */
+ char *elem_name; /* names of other elements */
+ int elem_count; /* count of instances of each element */
+ OtherData **other_data; /* actual property data for the elements */
+ PlyOtherProp *other_props; /* description of the property data */
+} OtherElem;
+
+typedef struct PlyOtherElems { /* "other" elements, not interpreted by user */
+ int num_elems; /* number of other elements */
+ OtherElem *other_list; /* list of data for other elements */
+} PlyOtherElems;
+
+typedef struct PlyFile { /* description of PLY file */
+ FILE *fp; /* file pointer */
+ int file_type; /* ascii or binary */
+ float version; /* version number of file */
+ int nelems; /* number of elements of object */
+ PlyElement **elems; /* list of elements */
+ int num_comments; /* number of comments */
+ char **comments; /* list of comments */
+ int num_obj_info; /* number of items of object information */
+ char **obj_info; /* list of object info items */
+ PlyElement *which_elem; /* which element we're currently writing */
+ PlyOtherElems *other_elems; /* "other" elements from a PLY file */
+} PlyFile;
+
+/* memory allocation */
+extern char *my_alloc();
+#define myalloc(mem_size) my_alloc((mem_size), __LINE__, __FILE__)
+
+#ifndef ALLOCN
+#define REALLOCN(PTR,TYPE,OLD_N,NEW_N) \
+ { \
+ if ((OLD_N) == 0) \
+ { ALLOCN((PTR),TYPE,(NEW_N));} \
+ else \
+ { \
+ (PTR) = (TYPE *)realloc((PTR),(NEW_N)*sizeof(TYPE)); \
+ if (((PTR) == NULL) && ((NEW_N) != 0)) \
+ { \
+ fprintf(stderr, "Memory reallocation failed on line %d in %s\n", \
+ __LINE__, __FILE__); \
+ fprintf(stderr, " tried to reallocate %d->%d\n", \
+ (OLD_N), (NEW_N)); \
+ exit(-1); \
+ } \
+ if ((NEW_N)>(OLD_N)) \
+ memset((char *)(PTR)+(OLD_N)*sizeof(TYPE), 0, \
+ ((NEW_N)-(OLD_N))*sizeof(TYPE)); \
+ } \
+ }
+
+#define ALLOCN(PTR,TYPE,N) \
+ { (PTR) = (TYPE *) calloc(((unsigned)(N)),sizeof(TYPE));\
+ if ((PTR) == NULL) { \
+ fprintf(stderr, "Memory allocation failed on line %d in %s\n", \
+ __LINE__, __FILE__); \
+ exit(-1); \
+ } \
+ }
+
+
+#define FREE(PTR) { free((PTR)); (PTR) = NULL; }
+#endif
+
+
+/*** delcaration of routines ***/
+
+inline int get_native_binary_type2();
+
+inline PlyFile *ply_write(FILE *, int,const char **, int);
+inline PlyFile *ply_open_for_writing(char *, int,const char **, int, float *);
+inline void ply_describe_element(PlyFile *, const char *, int, int, PlyProperty *);
+inline void ply_describe_property(PlyFile *, const char *, PlyProperty *);
+inline void ply_element_count(PlyFile *, const char *, int);
+inline void ply_header_complete(PlyFile *);
+inline void ply_put_element_setup(PlyFile *, const char *);
+inline void ply_put_element(PlyFile *, void *, int*);
+inline void ply_put_comment(PlyFile *, char *);
+inline void ply_put_obj_info(PlyFile *, char *);
+inline PlyFile *ply_read(FILE *, int *, char ***);
+inline PlyFile *ply_open_for_reading( const char *, int *, char ***, int *, float *);
+inline PlyProperty **ply_get_element_description(PlyFile *, const char *, int*, int*);
+inline void ply_get_element_setup( PlyFile *, const char *, int, PlyProperty *);
+inline void ply_get_property(PlyFile *, const char *, PlyProperty *);
+inline PlyOtherProp *ply_get_other_properties(PlyFile *, const char *, int);
+inline void ply_get_element(PlyFile *, void *, int *);
+inline char **ply_get_comments(PlyFile *, int *);
+inline char **ply_get_obj_info(PlyFile *, int *);
+inline void ply_close(PlyFile *);
+inline void ply_get_info(PlyFile *, float *, int *);
+inline PlyOtherElems *ply_get_other_element (PlyFile *, const char *, int);
+inline void ply_describe_other_elements ( PlyFile *, PlyOtherElems *);
+inline void ply_put_other_elements (PlyFile *);
+inline void ply_free_other_elements (PlyOtherElems *);
+inline void ply_describe_other_properties(PlyFile *, PlyOtherProp *, int);
+
+inline int equal_strings(const char *, const char *);
+
+
+}
+}
+#endif /* !__PLY_H__ */
+/*
+
+The interface routines for reading and writing PLY polygon files.
+
+Greg Turk, February 1994
+
+---------------------------------------------------------------
+
+A PLY file contains a single polygonal _object_.
+
+An object is composed of lists of _elements_. Typical elements are
+vertices, faces, edges and materials.
+
+Each type of element for a given object has one or more _properties_
+associated with the element type. For instance, a vertex element may
+have as properties the floating-point values x,y,z and the three unsigned
+chars representing red, green and blue.
+
+---------------------------------------------------------------
+
+Copyright (c) 1994 The Board of Trustees of The Leland Stanford
+Junior University. All rights reserved.
+
+Permission to use, copy, modify and distribute this software and its
+documentation for any purpose is hereby granted without fee, provided
+that the above copyright notice and this permission notice appear in
+all copies of this software and that you do not sell the software.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND,
+EXPRESS, IMPLIED OR OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY
+WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
+
+*/
+
+/*
+--------------------------------------------------------------------------------
+Joao Fradinho Oliveira, July 2005
+University College London
+
+update for ply reading of multi OS ply files, in any OS (Unix, Macintosh, PC)
+--------------------------------------------------------------------------------
+
+ply_open_for_reading
+
+* was changed to always open files in binary mode, files written in ascii can also be
+read with this binary mode.
+
+* allows opening of filenames that are alias files in macintosh
+
+* code tested on pc and mac
+
+
+get_words
+
+* was changed to handle line breaks in UNIX, MACINTOSH, PC, it resets the file pointer
+accordingly for the next read.
+
+
+NOTES:
+The ply file, has always an ascii part for the header, and a binary or ascii
+part for the data.
+The header part in ascii, dictates that linebreaks are used, this make models
+operating system dependent, as a line break in unix is indicated with the escape character \n,
+on a macintosh, with \r, and on a pc with \r\n <--2 unsigned chars, 2 bytes, instead of 1 byte.
+
+get_words allows reading of any OS, text editors such as BBEdit do not save the linebreaks
+properly to target OSs with binary files.
+
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <string.h>
+//#include "ply.h"
+
+
+namespace igl {
+ namespace ply {
+
+
+// Use unnamed namespace to avoid duplicate symbols
+/*
+namespace
+{
+const char *type_names[] = {
+"invalid",
+"char", "short", "int",
+"uchar", "ushort", "uint",
+"float", "double",
+};
+
+// names of scalar types
+const char *alt_type_names[] = {
+"invalid",
+"int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64",
+};
+
+int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+};
+}
+
+typedef union
+{
+ int int_value;
+ char byte_values[sizeof(int)];
+} endian_test_type;
+
+
+namespace
+{
+static int native_binary_type = -1;
+static int types_checked = 0;
+}
+*/
+
+#define NO_OTHER_PROPS -1
+
+#define DONT_STORE_PROP 0
+#define STORE_PROP 1
+
+#define OTHER_PROP 0
+#define NAMED_PROP 1
+
+/* returns 1 if strings are equal, 0 if not */
+inline int equal_strings(const char *, const char *);
+
+/* find an element in a plyfile's list */
+inline PlyElement *find_element(PlyFile *, const char *);
+
+/* find a property in an element's list */
+inline PlyProperty *find_property(PlyElement *, const char *, int *);
+
+/* write to a file the word describing a PLY file data type */
+inline void write_scalar_type (FILE *, int);
+
+/* read a line from a file and break it up into separate words */
+inline char **get_words(FILE *, int *, char **);
+inline char **old_get_words(FILE *, int *);
+
+/* write an item to a file */
+inline void write_binary_item(FILE *, int, int, unsigned int, double, int, int*);
+inline void write_ascii_item(FILE *, int, unsigned int, double, int);
+inline double old_write_ascii_item(FILE *, char *, int);
+
+/* add information to a PLY file descriptor */
+inline void add_element(PlyFile *, char **);
+inline void add_property(PlyFile *, char **);
+inline void add_comment(PlyFile *, char *);
+inline void add_obj_info(PlyFile *, char *);
+
+/* copy a property */
+inline void copy_property(PlyProperty *, PlyProperty *);
+
+/* store a value into where a pointer and a type specify */
+inline void store_item(char *, int, int, unsigned int, double);
+
+/* return the value of a stored item */
+inline void get_stored_item( void *, int, int *, unsigned int *, double *);
+
+/* return the value stored in an item, given ptr to it and its type */
+inline double get_item_value(char *, int);
+
+/* get binary or ascii item and store it according to ptr and type */
+inline void get_ascii_item(char *, int, int *, unsigned int *, double *);
+inline void get_binary_item(FILE *, int, int, int *, unsigned int *, double *, int*);
+
+/* get a bunch of elements from a file */
+inline void ascii_get_element(PlyFile *, char *);
+inline void binary_get_element(PlyFile *, char *, int*);
+
+/* memory allocation */
+inline char *my_alloc(int, int, const char *);
+
+/* byte ordering */
+inline void get_native_binary_type(int*);
+inline void swap_bytes(char *, int);
+
+inline int check_types();
+
+
+/*************/
+/* Writing */
+/*************/
+
+
+/******************************************************************************
+Given a file pointer, get ready to write PLY data to the file.
+
+Entry:
+ fp - the given file pointer
+ nelems - number of elements in object
+ elem_names - list of element names
+ file_type - file type, either ascii or binary
+
+Exit:
+ returns a pointer to a PlyFile, used to refer to this file, or NULL if error
+******************************************************************************/
+
+inline PlyFile *ply_write(
+ FILE *fp,
+ int nelems,
+ const char **elem_names,
+ int file_type
+)
+{
+ int i;
+ PlyFile *plyfile;
+ PlyElement *elem;
+
+ /* check for NULL file pointer */
+ if (fp == NULL)
+ return (NULL);
+
+ int native_binary_type = -1;
+ int types_checked = 0;
+ if (native_binary_type == -1)
+ native_binary_type = get_native_binary_type2();
+ if (!types_checked)
+ types_checked = check_types();
+
+ /* create a record for this object */
+
+ plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
+ if (file_type == PLY_BINARY_NATIVE)
+ plyfile->file_type = native_binary_type;
+ else
+ plyfile->file_type = file_type;
+ plyfile->num_comments = 0;
+ plyfile->num_obj_info = 0;
+ plyfile->nelems = nelems;
+ plyfile->version = 1.0;
+ plyfile->fp = fp;
+ plyfile->other_elems = NULL;
+
+ /* tuck aside the names of the elements */
+
+ plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *) * nelems);
+ for (i = 0; i < nelems; i++) {
+ elem = (PlyElement *) myalloc (sizeof (PlyElement));
+ plyfile->elems[i] = elem;
+ elem->name = strdup (elem_names[i]);
+ elem->num = 0;
+ elem->nprops = 0;
+ }
+
+ /* return pointer to the file descriptor */
+ return (plyfile);
+}
+
+
+/******************************************************************************
+Open a polygon file for writing.
+
+Entry:
+ filename - name of file to read from
+ nelems - number of elements in object
+ elem_names - list of element names
+ file_type - file type, either ascii or binary
+
+Exit:
+ version - version number of PLY file
+ returns a file identifier, used to refer to this file, or NULL if error
+******************************************************************************/
+
+inline PlyFile *ply_open_for_writing(
+ const char *filename,
+ int nelems,
+ const char **elem_names,
+ int file_type,
+ float *version
+)
+{
+ PlyFile *plyfile;
+ char *name;
+ FILE *fp;
+
+ /* tack on the extension .ply, if necessary */
+
+ name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
+ strcpy (name, filename);
+ if (strlen (name) < 4 ||
+ strcmp (name + strlen (name) - 4, ".ply") != 0)
+ strcat (name, ".ply");
+
+ /* open the file for writing */
+
+ fp = fopen (name, "w");
+ if (fp == NULL) {
+ return (NULL);
+ }
+
+ /* create the actual PlyFile structure */
+
+ plyfile = ply_write (fp, nelems, elem_names, file_type);
+ if (plyfile == NULL)
+ return (NULL);
+
+ /* say what PLY file version number we're writing */
+ *version = plyfile->version;
+
+ /* return pointer to the file descriptor */
+ return (plyfile);
+}
+
+
+/******************************************************************************
+Describe an element, including its properties and how many will be written
+to the file.
+
+Entry:
+ plyfile - file identifier
+ elem_name - name of element that information is being specified about
+ nelems - number of elements of this type to be written
+ nprops - number of properties contained in the element
+ prop_list - list of properties
+******************************************************************************/
+
+inline void ply_describe_element(
+ PlyFile *plyfile,
+ const char *elem_name,
+ int nelems,
+ int nprops,
+ PlyProperty *prop_list
+)
+{
+ int i;
+ PlyElement *elem;
+ PlyProperty *prop;
+
+ /* look for appropriate element */
+ elem = find_element (plyfile, elem_name);
+ if (elem == NULL) {
+ fprintf(stderr,"ply_describe_element: can't find element '%s'\n",elem_name);
+ exit (-1);
+ }
+
+ elem->num = nelems;
+
+ /* copy the list of properties */
+
+ elem->nprops = nprops;
+ elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *) * nprops);
+ elem->store_prop = (char *) myalloc (sizeof (char) * nprops);
+
+ for (i = 0; i < nprops; i++) {
+ prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
+ elem->props[i] = prop;
+ elem->store_prop[i] = NAMED_PROP;
+ copy_property (prop, &prop_list[i]);
+ }
+}
+
+
+/******************************************************************************
+Describe a property of an element.
+
+Entry:
+ plyfile - file identifier
+ elem_name - name of element that information is being specified about
+ prop - the new property
+******************************************************************************/
+
+inline void ply_describe_property(
+ PlyFile *plyfile,
+ const char *elem_name,
+ PlyProperty *prop
+)
+{
+ PlyElement *elem;
+ PlyProperty *elem_prop;
+
+ /* look for appropriate element */
+ elem = find_element (plyfile, elem_name);
+ if (elem == NULL) {
+ fprintf(stderr, "ply_describe_property: can't find element '%s'\n",
+ elem_name);
+ return;
+ }
+
+ /* create room for new property */
+
+ if (elem->nprops == 0) {
+ elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
+ elem->store_prop = (char *) myalloc (sizeof (char));
+ elem->nprops = 1;
+ }
+ else {
+ elem->nprops++;
+ elem->props = (PlyProperty **)
+ realloc (elem->props, sizeof (PlyProperty *) * elem->nprops);
+ elem->store_prop = (char *)
+ realloc (elem->store_prop, sizeof (char) * elem->nprops);
+ }
+
+ /* copy the new property */
+
+ elem_prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
+ elem->props[elem->nprops - 1] = elem_prop;
+ elem->store_prop[elem->nprops - 1] = NAMED_PROP;
+ copy_property (elem_prop, prop);
+}
+
+
+/******************************************************************************
+Describe what the "other" properties are that are to be stored, and where
+they are in an element.
+******************************************************************************/
+
+inline void ply_describe_other_properties(
+ PlyFile *plyfile,
+ PlyOtherProp *other,
+ int offset
+)
+{
+ int i;
+ PlyElement *elem;
+ PlyProperty *prop;
+
+ /* look for appropriate element */
+ elem = find_element (plyfile, other->name);
+ if (elem == NULL) {
+ fprintf(stderr, "ply_describe_other_properties: can't find element '%s'\n",
+ other->name);
+ return;
+ }
+
+ /* create room for other properties */
+
+ if (elem->nprops == 0) {
+ elem->props = (PlyProperty **)
+ myalloc (sizeof (PlyProperty *) * other->nprops);
+ elem->store_prop = (char *) myalloc (sizeof (char) * other->nprops);
+ elem->nprops = 0;
+ }
+ else {
+ int newsize;
+ newsize = elem->nprops + other->nprops;
+ elem->props = (PlyProperty **)
+ realloc (elem->props, sizeof (PlyProperty *) * newsize);
+ elem->store_prop = (char *)
+ realloc (elem->store_prop, sizeof (char) * newsize);
+ }
+
+ /* copy the other properties */
+
+ for (i = 0; i < other->nprops; i++) {
+ prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
+ copy_property (prop, other->props[i]);
+ elem->props[elem->nprops] = prop;
+ elem->store_prop[elem->nprops] = OTHER_PROP;
+ elem->nprops++;
+ }
+
+ /* save other info about other properties */
+ elem->other_size = other->size;
+ elem->other_offset = offset;
+}
+
+
+/******************************************************************************
+State how many of a given element will be written.
+
+Entry:
+ plyfile - file identifier
+ elem_name - name of element that information is being specified about
+ nelems - number of elements of this type to be written
+******************************************************************************/
+
+inline void ply_element_count(
+ PlyFile *plyfile,
+ const char *elem_name,
+ int nelems
+)
+{
+ PlyElement *elem;
+
+ /* look for appropriate element */
+ elem = find_element (plyfile, elem_name);
+ if (elem == NULL) {
+ fprintf(stderr,"ply_element_count: can't find element '%s'\n",elem_name);
+ exit (-1);
+ }
+
+ elem->num = nelems;
+}
+
+
+/******************************************************************************
+Signal that we've described everything a PLY file's header and that the
+header should be written to the file.
+
+Entry:
+ plyfile - file identifier
+******************************************************************************/
+
+inline void ply_header_complete(PlyFile *plyfile)
+{
+ int i,j;
+ FILE *fp = plyfile->fp;
+ PlyElement *elem;
+ PlyProperty *prop;
+
+ fprintf (fp, "ply\n");
+
+ switch (plyfile->file_type) {
+ case PLY_ASCII:
+ fprintf (fp, "format ascii 1.0\n");
+ break;
+ case PLY_BINARY_BE:
+ fprintf (fp, "format binary_big_endian 1.0\n");
+ break;
+ case PLY_BINARY_LE:
+ fprintf (fp, "format binary_little_endian 1.0\n");
+ break;
+ default:
+ fprintf (stderr, "ply_header_complete: bad file type = %d\n",
+ plyfile->file_type);
+ exit (-1);
+ }
+
+ /* write out the comments */
+
+ for (i = 0; i < plyfile->num_comments; i++)
+ fprintf (fp, "comment %s\n", plyfile->comments[i]);
+
+ /* write out object information */
+
+ for (i = 0; i < plyfile->num_obj_info; i++)
+ fprintf (fp, "obj_info %s\n", plyfile->obj_info[i]);
+
+ /* write out information about each element */
+
+ for (i = 0; i < plyfile->nelems; i++) {
+
+ elem = plyfile->elems[i];
+ fprintf (fp, "element %s %d\n", elem->name, elem->num);
+
+ /* write out each property */
+ for (j = 0; j < elem->nprops; j++) {
+ prop = elem->props[j];
+ if (prop->is_list) {
+ fprintf (fp, "property list ");
+ write_scalar_type (fp, prop->count_external);
+ fprintf (fp, " ");
+ write_scalar_type (fp, prop->external_type);
+ fprintf (fp, " %s\n", prop->name);
+ }
+ else {
+ fprintf (fp, "property ");
+ write_scalar_type (fp, prop->external_type);
+ fprintf (fp, " %s\n", prop->name);
+ }
+ }
+ }
+
+ fprintf (fp, "end_header\n");
+}
+
+
+/******************************************************************************
+Specify which elements are going to be written. This should be called
+before a call to the routine ply_put_element().
+
+Entry:
+ plyfile - file identifier
+ elem_name - name of element we're talking about
+******************************************************************************/
+
+inline void ply_put_element_setup(PlyFile *plyfile, const char *elem_name)
+{
+ PlyElement *elem;
+
+ elem = find_element (plyfile, elem_name);
+ if (elem == NULL) {
+ fprintf(stderr, "ply_elements_setup: can't find element '%s'\n", elem_name);
+ exit (-1);
+ }
+
+ plyfile->which_elem = elem;
+}
+
+
+/******************************************************************************
+Write an element to the file. This routine assumes that we're
+writing the type of element specified in the last call to the routine
+ply_put_element_setup().
+
+Entry:
+ plyfile - file identifier
+ elem_ptr - pointer to the element
+******************************************************************************/
+
+inline void ply_put_element(PlyFile *plyfile, void *elem_ptr, int *native_binary_type)
+{
+ int j,k;
+ FILE *fp = plyfile->fp;
+ PlyElement *elem;
+ PlyProperty *prop;
+ char *elem_data,*item;
+ char **item_ptr;
+ int list_count;
+ int item_size;
+ int int_val;
+ unsigned int uint_val;
+ double double_val;
+ char **other_ptr;
+
+ elem = plyfile->which_elem;
+ elem_data = (char *)elem_ptr;
+ other_ptr = (char **) (((char *) elem_ptr) + elem->other_offset);
+
+ /* write out either to an ascii or binary file */
+ int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+ };
+
+ if (plyfile->file_type == PLY_ASCII) {
+
+ /* write an ascii file */
+
+ /* write out each property of the element */
+ for (j = 0; j < elem->nprops; j++) {
+ prop = elem->props[j];
+ if (elem->store_prop[j] == OTHER_PROP)
+ elem_data = *other_ptr;
+ else
+ elem_data = (char *)elem_ptr;
+ if (prop->is_list) {
+ item = elem_data + prop->count_offset;
+ get_stored_item ((void *) item, prop->count_internal,
+ &int_val, &uint_val, &double_val);
+ write_ascii_item (fp, int_val, uint_val, double_val,
+ prop->count_external);
+ list_count = uint_val;
+ item_ptr = (char **) (elem_data + prop->offset);
+ item = item_ptr[0];
+ item_size = ply_type_size[prop->internal_type];
+ for (k = 0; k < list_count; k++) {
+ get_stored_item ((void *) item, prop->internal_type,
+ &int_val, &uint_val, &double_val);
+ write_ascii_item (fp, int_val, uint_val, double_val,
+ prop->external_type);
+ item += item_size;
+ }
+ }
+ else {
+ item = elem_data + prop->offset;
+ get_stored_item ((void *) item, prop->internal_type,
+ &int_val, &uint_val, &double_val);
+ write_ascii_item (fp, int_val, uint_val, double_val,
+ prop->external_type);
+ }
+ }
+
+ fprintf (fp, "\n");
+ }
+ else {
+
+ /* write a binary file */
+
+ /* write out each property of the element */
+ for (j = 0; j < elem->nprops; j++) {
+ prop = elem->props[j];
+ if (elem->store_prop[j] == OTHER_PROP)
+ elem_data = *other_ptr;
+ else
+ elem_data = (char *)elem_ptr;
+ if (prop->is_list) {
+ item = elem_data + prop->count_offset;
+ item_size = ply_type_size[prop->count_internal];
+ get_stored_item ((void *) item, prop->count_internal,
+ &int_val, &uint_val, &double_val);
+ write_binary_item (fp, plyfile->file_type, int_val, uint_val,
+ double_val, prop->count_external, native_binary_type);
+ list_count = uint_val;
+ item_ptr = (char **) (elem_data + prop->offset);
+ item = item_ptr[0];
+ item_size = ply_type_size[prop->internal_type];
+ for (k = 0; k < list_count; k++) {
+ get_stored_item ((void *) item, prop->internal_type,
+ &int_val, &uint_val, &double_val);
+ write_binary_item (fp, plyfile->file_type, int_val, uint_val,
+ double_val, prop->external_type, native_binary_type);
+ item += item_size;
+ }
+ }
+ else {
+ item = elem_data + prop->offset;
+ item_size = ply_type_size[prop->internal_type];
+ get_stored_item ((void *) item, prop->internal_type,
+ &int_val, &uint_val, &double_val);
+ write_binary_item (fp, plyfile->file_type, int_val, uint_val,
+ double_val, prop->external_type, native_binary_type);
+ }
+ }
+
+ }
+}
+
+
+/******************************************************************************
+Specify a comment that will be written in the header.
+
+Entry:
+ plyfile - file identifier
+ comment - the comment to be written
+******************************************************************************/
+
+inline void ply_put_comment(PlyFile *plyfile, char *comment)
+{
+ /* (re)allocate space for new comment */
+ if (plyfile->num_comments == 0)
+ plyfile->comments = (char **) myalloc (sizeof (char *));
+ else
+ plyfile->comments = (char **) realloc (plyfile->comments,
+ sizeof (char *) * (plyfile->num_comments + 1));
+
+ /* add comment to list */
+ plyfile->comments[plyfile->num_comments] = strdup (comment);
+ plyfile->num_comments++;
+}
+
+
+/******************************************************************************
+Specify a piece of object information (arbitrary text) that will be written
+in the header.
+
+Entry:
+ plyfile - file identifier
+ obj_info - the text information to be written
+******************************************************************************/
+
+inline void ply_put_obj_info(PlyFile *plyfile, char *obj_info)
+{
+ /* (re)allocate space for new info */
+ if (plyfile->num_obj_info == 0)
+ plyfile->obj_info = (char **) myalloc (sizeof (char *));
+ else
+ plyfile->obj_info = (char **) realloc (plyfile->obj_info,
+ sizeof (char *) * (plyfile->num_obj_info + 1));
+
+ /* add info to list */
+ plyfile->obj_info[plyfile->num_obj_info] = strdup (obj_info);
+ plyfile->num_obj_info++;
+}
+
+
+
+
+
+
+
+/*************/
+/* Reading */
+/*************/
+
+
+
+/******************************************************************************
+Given a file pointer, get ready to read PLY data from the file.
+
+Entry:
+ fp - the given file pointer
+
+Exit:
+ nelems - number of elements in object
+ elem_names - list of element names
+ returns a pointer to a PlyFile, used to refer to this file, or NULL if error
+******************************************************************************/
+
+inline PlyFile *ply_read(FILE *fp, int *nelems, char ***elem_names)
+{
+ int i,j;
+ PlyFile *plyfile;
+ int nwords;
+ char **words;
+ char **elist;
+ PlyElement *elem;
+ char *orig_line;
+
+ /* check for NULL file pointer */
+ if (fp == NULL)
+ return (NULL);
+
+ int native_binary_type = -1;
+ int types_checked = 0;
+
+ if (native_binary_type == -1)
+ native_binary_type = get_native_binary_type2();
+ if (!types_checked)
+ types_checked = check_types();
+
+ /* create record for this object */
+
+ plyfile = (PlyFile *) myalloc (sizeof (PlyFile));
+ plyfile->nelems = 0;
+ plyfile->comments = NULL;
+ plyfile->num_comments = 0;
+ plyfile->obj_info = NULL;
+ plyfile->num_obj_info = 0;
+ plyfile->fp = fp;
+ plyfile->other_elems = NULL;
+
+ /* read and parse the file's header */
+
+ words = get_words (plyfile->fp, &nwords, &orig_line);
+ if (nwords == 0 || !words || !equal_strings (words[0], "ply"))
+ {
+ if (words)
+ free(words);
+
+
+ return (NULL);
+ }
+
+ while (words) {
+
+ /* parse words */
+
+ if (equal_strings (words[0], "format")) {
+ if (nwords != 3) {
+ free(words);
+ return (NULL);
+ }
+ if (equal_strings (words[1], "ascii"))
+ plyfile->file_type = PLY_ASCII;
+ else if (equal_strings (words[1], "binary_big_endian"))
+ plyfile->file_type = PLY_BINARY_BE;
+ else if (equal_strings (words[1], "binary_little_endian"))
+ plyfile->file_type = PLY_BINARY_LE;
+ else {
+ free(words);
+ return (NULL);
+ }
+ plyfile->version = atof (words[2]);
+ }
+ else if (equal_strings (words[0], "element"))
+ add_element (plyfile, words);
+ else if (equal_strings (words[0], "property"))
+ add_property (plyfile, words);
+ else if (equal_strings (words[0], "comment"))
+ add_comment (plyfile, orig_line);
+ else if (equal_strings (words[0], "obj_info"))
+ add_obj_info (plyfile, orig_line);
+ else if (equal_strings (words[0], "end_header")) {
+ free(words);
+ break;
+ }
+
+ /* free up words space */
+ free (words);
+
+ words = get_words (plyfile->fp, &nwords, &orig_line);
+ }
+
+ /* create tags for each property of each element, to be used */
+ /* later to say whether or not to store each property for the user */
+
+ for (i = 0; i < plyfile->nelems; i++) {
+ elem = plyfile->elems[i];
+ elem->store_prop = (char *) myalloc (sizeof (char) * elem->nprops);
+ for (j = 0; j < elem->nprops; j++)
+ elem->store_prop[j] = DONT_STORE_PROP;
+ elem->other_offset = NO_OTHER_PROPS; /* no "other" props by default */
+ }
+
+ /* set return values about the elements */
+
+ elist = (char **) myalloc (sizeof (char *) * plyfile->nelems);
+ for (i = 0; i < plyfile->nelems; i++)
+ elist[i] = strdup (plyfile->elems[i]->name);
+
+ *elem_names = elist;
+ *nelems = plyfile->nelems;
+
+ /* return a pointer to the file's information */
+
+ return (plyfile);
+}
+
+
+/******************************************************************************
+Open a polygon file for reading.
+
+Entry:
+ filename - name of file to read from
+
+Exit:
+ nelems - number of elements in object
+ elem_names - list of element names
+ file_type - file type, either ascii or binary
+ version - version number of PLY file
+ returns a file identifier, used to refer to this file, or NULL if error
+******************************************************************************/
+
+inline PlyFile *ply_open_for_reading(
+ char *filename,
+ int *nelems,
+ char ***elem_names,
+ int *file_type,
+ float *version
+)
+{
+ FILE *fp;
+ PlyFile *plyfile;
+ //char *name;
+
+
+
+ /* tack on the extension .ply, if necessary */
+
+ // removing below, to handle also macintosh alias filenames
+ //name = (char *) myalloc (sizeof (char) * (strlen (filename) + 5));
+ //strcpy (name, filename);
+ //if (strlen (name) < 4 ||
+ // strcmp (name + strlen (name) - 4, ".ply") != 0)
+ // strcat (name, ".ply");
+
+ /* open the file for reading */
+
+ //fp = fopen (name, "r");
+
+ //opening file in binary, ascii data can be read in binary with get_words
+ fp = fopen (filename, "rb");
+
+ if (fp == NULL)
+ return (NULL);
+
+ /* create the PlyFile data structure */
+
+ plyfile = ply_read (fp, nelems, elem_names);
+
+ /* determine the file type and version */
+
+ *file_type = plyfile->file_type;
+ *version = plyfile->version;
+
+ /* return a pointer to the file's information */
+
+ return (plyfile);
+}
+
+
+/******************************************************************************
+Get information about a particular element.
+
+Entry:
+ plyfile - file identifier
+ elem_name - name of element to get information about
+
+Exit:
+ nelems - number of elements of this type in the file
+ nprops - number of properties
+ returns a list of properties, or NULL if the file doesn't contain that elem
+******************************************************************************/
+
+inline PlyProperty **ply_get_element_description(
+ PlyFile *plyfile,
+ const char *elem_name,
+ int *nelems,
+ int *nprops
+)
+{
+ int i;
+ PlyElement *elem;
+ PlyProperty *prop;
+ PlyProperty **prop_list;
+
+ /* find information about the element */
+ elem = find_element (plyfile, elem_name);
+ if (elem == NULL)
+ return (NULL);
+
+ *nelems = elem->num;
+ *nprops = elem->nprops;
+
+ /* make a copy of the element's property list */
+ prop_list = (PlyProperty **) myalloc (sizeof (PlyProperty *) * elem->nprops);
+ for (i = 0; i < elem->nprops; i++) {
+ prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
+ copy_property (prop, elem->props[i]);
+ prop_list[i] = prop;
+ }
+
+ /* return this duplicate property list */
+ return (prop_list);
+}
+
+
+/******************************************************************************
+Specify which properties of an element are to be returned. This should be
+called before a call to the routine ply_get_element().
+
+Entry:
+ plyfile - file identifier
+ elem_name - which element we're talking about
+ nprops - number of properties
+ prop_list - list of properties
+******************************************************************************/
+
+inline void ply_get_element_setup(
+ PlyFile *plyfile,
+ const char *elem_name,
+ int nprops,
+ PlyProperty *prop_list
+)
+{
+ int i;
+ PlyElement *elem;
+ PlyProperty *prop;
+ int index;
+
+ /* find information about the element */
+ elem = find_element (plyfile, elem_name);
+ plyfile->which_elem = elem;
+
+ /* deposit the property information into the element's description */
+ for (i = 0; i < nprops; i++) {
+
+ /* look for actual property */
+ prop = find_property (elem, prop_list[i].name, &index);
+ if (prop == NULL) {
+ fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
+ prop_list[i].name, elem_name);
+ continue;
+ }
+
+ /* store its description */
+ prop->internal_type = prop_list[i].internal_type;
+ prop->offset = prop_list[i].offset;
+ prop->count_internal = prop_list[i].count_internal;
+ prop->count_offset = prop_list[i].count_offset;
+
+ /* specify that the user wants this property */
+ elem->store_prop[index] = STORE_PROP;
+ }
+}
+
+
+/******************************************************************************
+Specify a property of an element that is to be returned. This should be
+called (usually multiple times) before a call to the routine ply_get_element().
+This routine should be used in preference to the less flexible old routine
+called ply_get_element_setup().
+
+Entry:
+ plyfile - file identifier
+ elem_name - which element we're talking about
+ prop - property to add to those that will be returned
+******************************************************************************/
+
+inline void ply_get_property(
+ PlyFile *plyfile,
+ const char *elem_name,
+ PlyProperty *prop
+)
+{
+ PlyElement *elem;
+ PlyProperty *prop_ptr;
+ int index;
+
+ /* find information about the element */
+ elem = find_element (plyfile, elem_name);
+ plyfile->which_elem = elem;
+
+ /* deposit the property information into the element's description */
+
+ prop_ptr = find_property (elem, prop->name, &index);
+ if (prop_ptr == NULL) {
+ fprintf (stderr, "Warning: Can't find property '%s' in element '%s'\n",
+ prop->name, elem_name);
+ return;
+ }
+ prop_ptr->internal_type = prop->internal_type;
+ prop_ptr->offset = prop->offset;
+ prop_ptr->count_internal = prop->count_internal;
+ prop_ptr->count_offset = prop->count_offset;
+
+ /* specify that the user wants this property */
+ elem->store_prop[index] = STORE_PROP;
+}
+
+
+/******************************************************************************
+Read one element from the file. This routine assumes that we're reading
+the type of element specified in the last call to the routine
+ply_get_element_setup().
+
+Entry:
+ plyfile - file identifier
+ elem_ptr - pointer to location where the element information should be put
+******************************************************************************/
+
+inline void ply_get_element(PlyFile *plyfile, void *elem_ptr, int *native_binary_type)
+{
+ if (plyfile->file_type == PLY_ASCII)
+ ascii_get_element (plyfile, (char *) elem_ptr);
+ else
+ binary_get_element (plyfile, (char *) elem_ptr, native_binary_type);
+}
+
+
+/******************************************************************************
+Extract the comments from the header information of a PLY file.
+
+Entry:
+ plyfile - file identifier
+
+Exit:
+ num_comments - number of comments returned
+ returns a pointer to a list of comments
+******************************************************************************/
+
+inline char **ply_get_comments(PlyFile *plyfile, int *num_comments)
+{
+ *num_comments = plyfile->num_comments;
+ return (plyfile->comments);
+}
+
+
+/******************************************************************************
+Extract the object information (arbitrary text) from the header information
+of a PLY file.
+
+Entry:
+ plyfile - file identifier
+
+Exit:
+ num_obj_info - number of lines of text information returned
+ returns a pointer to a list of object info lines
+******************************************************************************/
+
+inline char **ply_get_obj_info(PlyFile *plyfile, int *num_obj_info)
+{
+ *num_obj_info = plyfile->num_obj_info;
+ return (plyfile->obj_info);
+}
+
+
+/******************************************************************************
+Make ready for "other" properties of an element-- those properties that
+the user has not explicitly asked for, but that are to be stashed away
+in a special structure to be carried along with the element's other
+information.
+
+Entry:
+ plyfile - file identifier
+ elem - element for which we want to save away other properties
+******************************************************************************/
+
+inline void setup_other_props(PlyElement *elem)
+{
+ int i;
+ PlyProperty *prop;
+ int size = 0;
+ int type_size;
+
+ /* Examine each property in decreasing order of size. */
+ /* We do this so that all data types will be aligned by */
+ /* word, half-word, or whatever within the structure. */
+ int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+ };
+
+ for (type_size = 8; type_size > 0; type_size /= 2) {
+
+ /* add up the space taken by each property, and save this information */
+ /* away in the property descriptor */
+
+ for (i = 0; i < elem->nprops; i++) {
+
+ /* don't bother with properties we've been asked to store explicitly */
+ if (elem->store_prop[i])
+ continue;
+
+ prop = elem->props[i];
+
+ /* internal types will be same as external */
+ prop->internal_type = prop->external_type;
+ prop->count_internal = prop->count_external;
+
+ /* check list case */
+ if (prop->is_list) {
+
+ /* pointer to list */
+ if (type_size == sizeof (void *)) {
+ prop->offset = size;
+ size += sizeof (void *); /* always use size of a pointer here */
+ }
+
+ /* count of number of list elements */
+ if (type_size == ply_type_size[prop->count_external]) {
+ prop->count_offset = size;
+ size += ply_type_size[prop->count_external];
+ }
+ }
+ /* not list */
+ else if (type_size == ply_type_size[prop->external_type]) {
+ prop->offset = size;
+ size += ply_type_size[prop->external_type];
+ }
+ }
+
+ }
+
+ /* save the size for the other_props structure */
+ elem->other_size = size;
+}
+
+
+/******************************************************************************
+Specify that we want the "other" properties of an element to be tucked
+away within the user's structure. The user needn't be concerned for how
+these properties are stored.
+
+Entry:
+ plyfile - file identifier
+ elem_name - name of element that we want to store other_props in
+ offset - offset to where other_props will be stored inside user's structure
+
+Exit:
+ returns pointer to structure containing description of other_props
+******************************************************************************/
+
+inline PlyOtherProp *ply_get_other_properties(
+ PlyFile *plyfile,
+ const char *elem_name,
+ int offset
+)
+{
+ int i;
+ PlyElement *elem;
+ PlyOtherProp *other;
+ PlyProperty *prop;
+ int nprops;
+
+ /* find information about the element */
+ elem = find_element (plyfile, elem_name);
+ if (elem == NULL) {
+ fprintf (stderr, "ply_get_other_properties: Can't find element '%s'\n",
+ elem_name);
+ return (NULL);
+ }
+
+ /* remember that this is the "current" element */
+ plyfile->which_elem = elem;
+
+ /* save the offset to where to store the other_props */
+ elem->other_offset = offset;
+
+ /* place the appropriate pointers, etc. in the element's property list */
+ setup_other_props (elem);
+
+ /* create structure for describing other_props */
+ other = (PlyOtherProp *) myalloc (sizeof (PlyOtherProp));
+ other->name = strdup (elem_name);
+#if 0
+ if (elem->other_offset == NO_OTHER_PROPS) {
+ other->size = 0;
+ other->props = NULL;
+ other->nprops = 0;
+ return (other);
+ }
+#endif
+ other->size = elem->other_size;
+ other->props = (PlyProperty **) myalloc (sizeof(PlyProperty) * elem->nprops);
+
+ /* save descriptions of each "other" property */
+ nprops = 0;
+ for (i = 0; i < elem->nprops; i++) {
+ if (elem->store_prop[i])
+ continue;
+ prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
+ copy_property (prop, elem->props[i]);
+ other->props[nprops] = prop;
+ nprops++;
+ }
+ other->nprops = nprops;
+
+#if 1
+ /* set other_offset pointer appropriately if there are NO other properties */
+ if (other->nprops == 0) {
+ elem->other_offset = NO_OTHER_PROPS;
+ }
+#endif
+
+ /* return structure */
+ return (other);
+}
+
+
+
+
+/*************************/
+/* Other Element Stuff */
+/*************************/
+
+
+
+
+/******************************************************************************
+Grab all the data for an element that a user does not want to explicitly
+read in.
+
+Entry:
+ plyfile - pointer to file
+ elem_name - name of element whose data is to be read in
+ elem_count - number of instances of this element stored in the file
+
+Exit:
+ returns pointer to ALL the "other" element data for this PLY file
+******************************************************************************/
+
+inline PlyOtherElems *ply_get_other_element (
+ PlyFile *plyfile,
+ char *elem_name,
+ int elem_count
+)
+{
+ int i;
+ PlyElement *elem;
+ PlyOtherElems *other_elems;
+ OtherElem *other;
+
+ /* look for appropriate element */
+ elem = find_element (plyfile, elem_name);
+ if (elem == NULL) {
+ fprintf (stderr,
+ "ply_get_other_element: can't find element '%s'\n", elem_name);
+ exit (-1);
+ }
+
+ /* create room for the new "other" element, initializing the */
+ /* other data structure if necessary */
+
+ if (plyfile->other_elems == NULL) {
+ plyfile->other_elems = (PlyOtherElems *) myalloc (sizeof (PlyOtherElems));
+ other_elems = plyfile->other_elems;
+ other_elems->other_list = (OtherElem *) myalloc (sizeof (OtherElem));
+ other = &(other_elems->other_list[0]);
+ other_elems->num_elems = 1;
+ }
+ else {
+ other_elems = plyfile->other_elems;
+ other_elems->other_list = (OtherElem *) realloc (other_elems->other_list,
+ sizeof (OtherElem) * (other_elems->num_elems + 1));
+ other = &(other_elems->other_list[other_elems->num_elems]);
+ other_elems->num_elems++;
+ }
+
+ /* count of element instances in file */
+ other->elem_count = elem_count;
+
+ /* save name of element */
+ other->elem_name = strdup (elem_name);
+
+ /* create a list to hold all the current elements */
+ other->other_data = (OtherData **)
+ malloc (sizeof (OtherData *) * other->elem_count);
+
+ /* set up for getting elements */
+ other->other_props = ply_get_other_properties (plyfile, elem_name,
+ offsetof(OtherData,other_props));
+
+ /* grab all these elements */
+ int native_binary_type = get_native_binary_type2();
+ for (i = 0; i < other->elem_count; i++) {
+ /* grab and element from the file */
+ other->other_data[i] = (OtherData *) malloc (sizeof (OtherData));
+ ply_get_element (plyfile, (void *) other->other_data[i], &native_binary_type);
+ }
+
+ /* return pointer to the other elements data */
+ return (other_elems);
+}
+
+
+/******************************************************************************
+Pass along a pointer to "other" elements that we want to save in a given
+PLY file. These other elements were presumably read from another PLY file.
+
+Entry:
+ plyfile - file pointer in which to store this other element info
+ other_elems - info about other elements that we want to store
+******************************************************************************/
+
+inline void ply_describe_other_elements (
+ PlyFile *plyfile,
+ PlyOtherElems *other_elems
+)
+{
+ int i;
+ OtherElem *other;
+ PlyElement *elem;
+
+ /* ignore this call if there is no other element */
+ if (other_elems == NULL)
+ return;
+
+ /* save pointer to this information */
+ plyfile->other_elems = other_elems;
+
+ /* describe the other properties of this element */
+ /* store them in the main element list as elements with
+ only other properties */
+
+ REALLOCN(plyfile->elems, PlyElement *,
+ plyfile->nelems, plyfile->nelems + other_elems->num_elems);
+ for (i = 0; i < other_elems->num_elems; i++) {
+ other = &(other_elems->other_list[i]);
+ elem = (PlyElement *) myalloc (sizeof (PlyElement));
+ plyfile->elems[plyfile->nelems++] = elem;
+ elem->name = strdup (other->elem_name);
+ elem->num = other->elem_count;
+ elem->nprops = 0;
+ ply_describe_other_properties (plyfile, other->other_props,
+ offsetof(OtherData,other_props));
+ }
+}
+
+
+/******************************************************************************
+Write out the "other" elements specified for this PLY file.
+
+Entry:
+ plyfile - pointer to PLY file to write out other elements for
+******************************************************************************/
+
+inline void ply_put_other_elements (PlyFile *plyfile, int *native_binary_type)
+{
+ int i,j;
+ OtherElem *other;
+
+ /* make sure we have other elements to write */
+ if (plyfile->other_elems == NULL)
+ return;
+
+ /* write out the data for each "other" element */
+
+ for (i = 0; i < plyfile->other_elems->num_elems; i++) {
+
+ other = &(plyfile->other_elems->other_list[i]);
+ ply_put_element_setup (plyfile, other->elem_name);
+
+ /* write out each instance of the current element */
+ for (j = 0; j < other->elem_count; j++)
+ ply_put_element (plyfile, (void *) other->other_data[j], native_binary_type);
+ }
+}
+
+
+/******************************************************************************
+Free up storage used by an "other" elements data structure.
+
+Entry:
+ other_elems - data structure to free up
+******************************************************************************/
+
+inline void ply_free_other_elements (PlyOtherElems *other_elems)
+{
+ // Alec:
+ //other_elems = other_elems;
+ delete(other_elems);
+}
+
+
+
+/*******************/
+/* Miscellaneous */
+/*******************/
+
+
+
+/******************************************************************************
+Close a PLY file.
+
+Entry:
+ plyfile - identifier of file to close
+******************************************************************************/
+
+inline void ply_close(PlyFile *plyfile)
+{
+ fclose (plyfile->fp);
+ // Alec:
+ plyfile->fp = NULL;
+
+ /* free up memory associated with the PLY file */
+ free (plyfile);
+}
+
+
+/******************************************************************************
+Get version number and file type of a PlyFile.
+
+Entry:
+ ply - pointer to PLY file
+
+Exit:
+ version - version of the file
+ file_type - PLY_ASCII, PLY_BINARY_BE, or PLY_BINARY_LE
+******************************************************************************/
+
+inline void ply_get_info(PlyFile *ply, float *version, int *file_type)
+{
+ if (ply == NULL)
+ return;
+
+ *version = ply->version;
+ *file_type = ply->file_type;
+}
+
+
+/******************************************************************************
+Compare two strings. Returns 1 if they are the same, 0 if not.
+******************************************************************************/
+
+inline int equal_strings(const char *s1, const char *s2)
+{
+
+ while (*s1 && *s2)
+ if (*s1++ != *s2++)
+ return (0);
+
+ if (*s1 != *s2)
+ return (0);
+ else
+ return (1);
+}
+
+
+/******************************************************************************
+Find an element from the element list of a given PLY object.
+
+Entry:
+ plyfile - file id for PLY file
+ element - name of element we're looking for
+
+Exit:
+ returns the element, or NULL if not found
+******************************************************************************/
+
+inline PlyElement *find_element(PlyFile *plyfile, const char *element)
+{
+ int i;
+
+ for (i = 0; i < plyfile->nelems; i++)
+ if (equal_strings (element, plyfile->elems[i]->name))
+ return (plyfile->elems[i]);
+
+ return (NULL);
+}
+
+
+/******************************************************************************
+Find a property in the list of properties of a given element.
+
+Entry:
+ elem - pointer to element in which we want to find the property
+ prop_name - name of property to find
+
+Exit:
+ index - index to position in list
+ returns a pointer to the property, or NULL if not found
+******************************************************************************/
+
+inline PlyProperty *find_property(PlyElement *elem, const char *prop_name, int *index)
+{
+ int i;
+
+ for (i = 0; i < elem->nprops; i++)
+ if (equal_strings (prop_name, elem->props[i]->name)) {
+ *index = i;
+ return (elem->props[i]);
+ }
+
+ *index = -1;
+ return (NULL);
+}
+
+
+/******************************************************************************
+Read an element from an ascii file.
+
+Entry:
+ plyfile - file identifier
+ elem_ptr - pointer to element
+******************************************************************************/
+
+inline void ascii_get_element(PlyFile *plyfile, char *elem_ptr)
+{
+ int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+ };
+
+ int j,k;
+ PlyElement *elem;
+ PlyProperty *prop;
+ char **words;
+ int nwords;
+ int which_word;
+ char *elem_data,*item=NULL;
+ char *item_ptr;
+ int item_size;
+ int int_val;
+ unsigned int uint_val;
+ double double_val;
+ int list_count;
+ int store_it;
+ char **store_array;
+ char *orig_line;
+ char *other_data=NULL;
+ int other_flag;
+
+ /* the kind of element we're reading currently */
+ elem = plyfile->which_elem;
+
+ /* do we need to setup for other_props? */
+
+ if (elem->other_offset != NO_OTHER_PROPS) {
+ char **ptr;
+ other_flag = 1;
+ /* make room for other_props */
+ other_data = (char *) myalloc (elem->other_size);
+ /* store pointer in user's structure to the other_props */
+ ptr = (char **) (elem_ptr + elem->other_offset);
+ *ptr = other_data;
+ }
+ else
+ other_flag = 0;
+
+ /* read in the element */
+
+ words = get_words (plyfile->fp, &nwords, &orig_line);
+ if (words == NULL) {
+ fprintf (stderr, "ply_get_element: unexpected end of file\n");
+ exit (-1);
+ }
+
+ which_word = 0;
+
+ for (j = 0; j < elem->nprops; j++) {
+
+ prop = elem->props[j];
+ store_it = (elem->store_prop[j] | other_flag);
+
+ /* store either in the user's structure or in other_props */
+ // if (elem->store_prop[j])
+ elem_data = elem_ptr;
+ //else
+ //elem_data = other_data;
+
+ if (prop->is_list) { /* a list */
+
+ /* get and store the number of items in the list */
+ get_ascii_item (words[which_word++], prop->count_external,
+ &int_val, &uint_val, &double_val);
+ if (store_it) {
+ item = elem_data + prop->count_offset;
+ store_item(item, prop->count_internal, int_val, uint_val, double_val);
+ }
+
+ /* allocate space for an array of items and store a ptr to the array */
+ list_count = int_val;
+ item_size = ply_type_size[prop->internal_type];
+ store_array = (char **) (elem_data + prop->offset);
+
+ if (list_count == 0) {
+ if (store_it)
+ *store_array = NULL;
+ }
+ else {
+ if (store_it) {
+ item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
+
+ item = item_ptr;
+ *store_array = item_ptr;
+ }
+
+ /* read items and store them into the array */
+ for (k = 0; k < list_count; k++) {
+ get_ascii_item (words[which_word++], prop->external_type,
+ &int_val, &uint_val, &double_val);
+ if (store_it) {
+ store_item (item, prop->internal_type,
+ int_val, uint_val, double_val);
+ item += item_size;
+ }
+ }
+ }
+
+ }
+ else { /* not a list */
+ get_ascii_item (words[which_word++], prop->external_type,
+ &int_val, &uint_val, &double_val);
+ if (store_it) {
+ item = elem_data + prop->offset;
+ store_item (item, prop->internal_type, int_val, uint_val, double_val);
+ }
+ }
+
+ }
+
+ free (words);
+}
+
+
+/******************************************************************************
+Read an element from a binary file.
+
+Entry:
+ plyfile - file identifier
+ elem_ptr - pointer to an element
+******************************************************************************/
+
+inline void binary_get_element(PlyFile *plyfile, char *elem_ptr, int *native_binary_type)
+{
+ int j,k;
+ PlyElement *elem;
+ PlyProperty *prop;
+ FILE *fp = plyfile->fp;
+ char *elem_data,*item=NULL;
+ char *item_ptr;
+ int item_size;
+ int int_val;
+ unsigned int uint_val;
+ double double_val;
+ int list_count;
+ int store_it;
+ char **store_array;
+ char *other_data=NULL;
+ int other_flag;
+
+ int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+ };
+
+
+ /* the kind of element we're reading currently */
+ elem = plyfile->which_elem;
+
+ /* do we need to setup for other_props? */
+
+ if (elem->other_offset != NO_OTHER_PROPS) {
+ char **ptr;
+ other_flag = 1;
+ /* make room for other_props */
+ other_data = (char *) myalloc (elem->other_size);
+ /* store pointer in user's structure to the other_props */
+ ptr = (char **) (elem_ptr + elem->other_offset);
+ *ptr = other_data;
+ }
+ else
+ other_flag = 0;
+
+ /* read in a number of elements */
+
+ for (j = 0; j < elem->nprops; j++) {
+
+ prop = elem->props[j];
+ store_it = (elem->store_prop[j] | other_flag);
+
+ /* store either in the user's structure or in other_props */
+// if (elem->store_prop[j])
+ elem_data = elem_ptr;
+// else
+// elem_data = other_data;
+
+ if (prop->is_list) { /* a list */
+
+ /* get and store the number of items in the list */
+ get_binary_item (fp, plyfile->file_type, prop->count_external,
+ &int_val, &uint_val, &double_val, native_binary_type);
+ if (store_it) {
+ item = elem_data + prop->count_offset;
+ store_item(item, prop->count_internal, int_val, uint_val, double_val);
+ }
+
+ /* allocate space for an array of items and store a ptr to the array */
+ list_count = int_val;
+
+ item_size = ply_type_size[prop->internal_type];
+ store_array = (char **) (elem_data + prop->offset);
+ if (list_count == 0) {
+ if (store_it)
+ *store_array = NULL;
+ }
+ else {
+ if (store_it) {
+ item_ptr = (char *) myalloc (sizeof (char) * item_size * list_count);
+
+ item = item_ptr;
+ *store_array = item_ptr;
+ }
+
+ // read items and store them into the array
+ for (k = 0; k < list_count; k++) {
+ get_binary_item (fp, plyfile->file_type, prop->external_type,
+ &int_val, &uint_val, &double_val, native_binary_type);
+ if (store_it) {
+ store_item (item, prop->internal_type,
+ int_val, uint_val, double_val);
+ item += item_size;
+ }
+ }
+
+
+
+ }
+
+ }
+ else { /* not a list */
+ get_binary_item (fp, plyfile->file_type, prop->external_type,
+ &int_val, &uint_val, &double_val, native_binary_type);
+ if (store_it) {
+ item = elem_data + prop->offset;
+ store_item (item, prop->internal_type, int_val, uint_val, double_val);
+ }
+ }
+
+ }
+}
+
+
+/******************************************************************************
+Write to a file the word that represents a PLY data type.
+
+Entry:
+ fp - file pointer
+ code - code for type
+******************************************************************************/
+
+inline void write_scalar_type (FILE *fp, int code)
+{
+ /* make sure this is a valid code */
+
+ if (code <= PLY_START_TYPE || code >= PLY_END_TYPE) {
+ fprintf (stderr, "write_scalar_type: bad data code = %d\n", code);
+ exit (-1);
+ }
+
+ /* write the code to a file */
+ const char *type_names[] = {
+ "invalid",
+ "char", "short", "int",
+ "uchar", "ushort", "uint",
+ "float", "double",
+ };
+
+
+ fprintf (fp, "%s", type_names[code]);
+}
+
+/******************************************************************************
+ Reverse the order in an array of bytes. This is the conversion from big
+ endian to little endian and vice versa
+
+Entry:
+ bytes - array of bytes to reverse (in place)
+ num_bytes - number of bytes in array
+******************************************************************************/
+
+inline void swap_bytes(char *bytes, int num_bytes)
+{
+ int i;
+ char temp;
+
+ for (i=0; i < num_bytes/2; i++)
+ {
+ temp = bytes[i];
+ bytes[i] = bytes[(num_bytes-1)-i];
+ bytes[(num_bytes-1)-i] = temp;
+ }
+}
+
+/******************************************************************************
+ Find out if this machine is big endian or little endian
+
+ Exit:
+ set global variable, native_binary_type =
+ either PLY_BINARY_BE or PLY_BINARY_LE
+
+******************************************************************************/
+
+inline void get_native_binary_type(int *native_binary_type)
+{
+ typedef union
+ {
+ int int_value;
+ char byte_values[sizeof(int)];
+ } endian_test_type;
+
+
+ endian_test_type test;
+
+ test.int_value = 0;
+ test.int_value = 1;
+ if (test.byte_values[0] == 1)
+ *native_binary_type = PLY_BINARY_LE;
+ else if (test.byte_values[sizeof(int)-1] == 1)
+ *native_binary_type = PLY_BINARY_BE;
+ else
+ {
+ fprintf(stderr, "ply: Couldn't determine machine endianness.\n");
+ fprintf(stderr, "ply: Exiting...\n");
+ exit(1);
+ }
+}
+
+inline int get_native_binary_type2()
+{
+ typedef union
+ {
+ int int_value;
+ char byte_values[sizeof(int)];
+ } endian_test_type;
+
+
+ endian_test_type test;
+
+ test.int_value = 0;
+ test.int_value = 1;
+ if (test.byte_values[0] == 1)
+ return PLY_BINARY_LE;
+ else if (test.byte_values[sizeof(int)-1] == 1)
+ return PLY_BINARY_BE;
+ else
+ {
+ fprintf(stderr, "ply: Couldn't determine machine endianness.\n");
+ fprintf(stderr, "ply: Exiting...\n");
+ exit(1);
+ }
+}
+
+/******************************************************************************
+ Verify that all the native types are the sizes we need
+
+
+******************************************************************************/
+
+inline int check_types()
+{
+ int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+ };
+
+ if ((ply_type_size[PLY_CHAR] != sizeof(char)) ||
+ (ply_type_size[PLY_SHORT] != sizeof(short)) ||
+ (ply_type_size[PLY_INT] != sizeof(int)) ||
+ (ply_type_size[PLY_UCHAR] != sizeof(unsigned char)) ||
+ (ply_type_size[PLY_USHORT] != sizeof(unsigned short)) ||
+ (ply_type_size[PLY_UINT] != sizeof(unsigned int)) ||
+ (ply_type_size[PLY_FLOAT] != sizeof(float)) ||
+ (ply_type_size[PLY_DOUBLE] != sizeof(double)))
+ {
+ fprintf(stderr, "ply: Type sizes do not match built-in types\n");
+ fprintf(stderr, "ply: Exiting...\n");
+ exit(1);
+ }
+
+ return 1;
+}
+
+/******************************************************************************
+Get a text line from a file and break it up into words.
+
+IMPORTANT: The calling routine call "free" on the returned pointer once
+finished with it.
+
+Entry:
+ fp - file to read from
+
+Exit:
+ nwords - number of words returned
+ orig_line - the original line of characters
+ returns a list of words from the line, or NULL if end-of-file
+******************************************************************************/
+
+inline char **get_words(FILE *fp, int *nwords, char **orig_line)
+{
+ #define BIG_STRING 4096
+ char str[BIG_STRING];
+ char str_copy[BIG_STRING];
+ char **words;
+ int max_words = 10;
+ int num_words = 0;
+ char *ptr,*ptr2;
+ char *result;
+
+ fpos_t pos; //keep track of file pointer
+ int nbytes;
+ int nonUNIX;
+ nonUNIX=0;
+ nbytes=0;
+ fgetpos(fp, &pos);
+
+ words = (char **) myalloc (sizeof (char *) * max_words);
+
+ /* read in a line */
+ result = fgets (str, BIG_STRING, fp);
+ if (result == NULL) {
+ *nwords = 0;
+ *orig_line = NULL;
+ return (NULL);
+ }
+
+ /* convert line-feed and tabs into spaces */
+ /* (this guarantees that there will be a space before the */
+ /* null character at the end of the string) */
+
+ str[BIG_STRING-2] = ' ';
+ str[BIG_STRING-1] = '\0';
+
+ for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
+ *ptr2 = *ptr;
+ nbytes++;
+ if (*ptr == '\t') {
+ *ptr = ' ';
+ *ptr2 = ' ';
+ }
+ else if (*ptr == '\n') {
+ *ptr = ' '; //has to have a space, to be caught later when grouping words
+ *ptr2 = '\0';
+ break;
+ }
+ else if (*ptr == '\r')
+ { //MAC line break
+ nonUNIX=1;
+ if(*(ptr+1)=='\n') //actuall PC line break
+ {
+ nbytes++;
+ }
+
+ *ptr = ' ';
+
+ *(ptr+1) = '\0'; //when reading mac, best end string here
+ *ptr2 = '\0'; //note a pc \r is followed by \n
+
+ break;
+ }
+ }
+
+
+ /*check to see if a PC or MAC header was detected instead of UNIX*/
+ if(nonUNIX==1)
+ {
+ fsetpos(fp, &pos);
+ fseek(fp, nbytes, SEEK_CUR);
+ }
+
+ /* find the words in the line */
+
+ ptr = str;
+ while (*ptr != '\0') {
+
+ /* jump over leading spaces */
+ while (*ptr == ' ')
+ ptr++;
+
+ /* break if we reach the end */
+ if (*ptr == '\0')
+ break;
+
+ /* save pointer to beginning of word */
+ if (num_words >= max_words) {
+ max_words += 10;
+ words = (char **) realloc (words, sizeof (char *) * max_words);
+ }
+ words[num_words++] = ptr;
+
+ /* jump over non-spaces */
+ while (*ptr != ' ')
+ ptr++;
+
+ /* place a null character here to mark the end of the word */
+ *ptr++ = '\0';
+ }
+
+ /* return the list of words */
+ *nwords = num_words;
+ *orig_line = str_copy;
+ return (words);
+}
+
+/*
+char **get_words(FILE *fp, int *nwords, char **orig_line)
+{
+#define BIG_STRING 4096
+ static char str[BIG_STRING];
+ static char str_copy[BIG_STRING];
+ char **words;
+ int max_words = 10;
+ int num_words = 0;
+ char *ptr,*ptr2;
+ char *result;
+
+ words = (char **) myalloc (sizeof (char *) * max_words);
+
+ // read in a line
+ result = fgets (str, BIG_STRING, fp);
+ if (result == NULL) {
+ *nwords = 0;
+ *orig_line = NULL;
+ return (NULL);
+ }
+
+ // convert line-feed and tabs into spaces
+ // (this guarantees that there will be a space before the
+ // null character at the end of the string)
+
+ str[BIG_STRING-2] = ' ';
+ str[BIG_STRING-1] = '\0';
+
+ for (ptr = str, ptr2 = str_copy; *ptr != '\0'; ptr++, ptr2++) {
+ *ptr2 = *ptr;
+ if (*ptr == '\t') {
+ *ptr = ' ';
+ *ptr2 = ' ';
+ }
+ else if (*ptr == '\n') {
+ *ptr = ' ';
+ *ptr2 = '\0';
+ break;
+ }
+ else if (*ptr == '\r') {
+ *ptr = '\0';
+ *ptr2 = '\0'; //note don't break yet, on a pc \r is followed by \n
+ }
+ }
+
+ // find the words in the line
+
+ ptr = str;
+ while (*ptr != '\0') {
+
+ // jump over leading spaces
+ while (*ptr == ' ')
+ ptr++;
+
+ // break if we reach the end
+ if (*ptr == '\0')
+ break;
+
+ // save pointer to beginning of word
+ if (num_words >= max_words) {
+ max_words += 10;
+ words = (char **) realloc (words, sizeof (char *) * max_words);
+ }
+ words[num_words++] = ptr;
+
+ // jump over non-spaces
+ while (*ptr != ' ')
+ ptr++;
+
+ // place a null character here to mark the end of the word
+ *ptr++ = '\0';
+ }
+
+ // return the list of words
+ *nwords = num_words;
+ *orig_line = str_copy;
+ return (words);
+}*/
+
+/******************************************************************************
+Return the value of an item, given a pointer to it and its type.
+
+Entry:
+ item - pointer to item
+ type - data type that "item" points to
+
+Exit:
+ returns a double-precision float that contains the value of the item
+******************************************************************************/
+
+inline double get_item_value(char *item, int type)
+{
+ unsigned char *puchar;
+ char *pchar;
+ short int *pshort;
+ unsigned short int *pushort;
+ int *pint;
+ unsigned int *puint;
+ float *pfloat;
+ double *pdouble;
+ int int_value;
+ unsigned int uint_value;
+ double double_value;
+
+ switch (type) {
+ case PLY_CHAR:
+ pchar = (char *) item;
+ int_value = *pchar;
+ return ((double) int_value);
+ case PLY_UCHAR:
+ puchar = (unsigned char *) item;
+ int_value = *puchar;
+ return ((double) int_value);
+ case PLY_SHORT:
+ pshort = (short int *) item;
+ int_value = *pshort;
+ return ((double) int_value);
+ case PLY_USHORT:
+ pushort = (unsigned short int *) item;
+ int_value = *pushort;
+ return ((double) int_value);
+ case PLY_INT:
+ pint = (int *) item;
+ int_value = *pint;
+ return ((double) int_value);
+ case PLY_UINT:
+ puint = (unsigned int *) item;
+ uint_value = *puint;
+ return ((double) uint_value);
+ case PLY_FLOAT:
+ pfloat = (float *) item;
+ double_value = *pfloat;
+ return (double_value);
+ case PLY_DOUBLE:
+ pdouble = (double *) item;
+ double_value = *pdouble;
+ return (double_value);
+ default:
+ fprintf (stderr, "get_item_value: bad type = %d\n", type);
+ exit (-1);
+ }
+}
+
+
+/******************************************************************************
+Write out an item to a file as raw binary bytes.
+
+Entry:
+ fp - file to write to
+ int_val - integer version of item
+ uint_val - unsigned integer version of item
+ double_val - double-precision float version of item
+ type - data type to write out
+******************************************************************************/
+
+inline void write_binary_item(
+ FILE *fp,
+ int file_type,
+ int int_val,
+ unsigned int uint_val,
+ double double_val,
+ int type,
+ int *native_binary_type
+)
+{
+ unsigned char uchar_val;
+ char char_val;
+ unsigned short ushort_val;
+ short short_val;
+ float float_val;
+ void *value;
+
+ switch (type) {
+ case PLY_CHAR:
+ char_val = int_val;
+ value = &char_val;
+ break;
+ case PLY_SHORT:
+ short_val = int_val;
+ value = &short_val;
+ break;
+ case PLY_INT:
+ value = &int_val;
+ break;
+ case PLY_UCHAR:
+ uchar_val = uint_val;
+ value = &uchar_val;
+ break;
+ case PLY_USHORT:
+ ushort_val = uint_val;
+ value = &ushort_val;
+ break;
+ case PLY_UINT:
+ value = &uint_val;
+ break;
+ case PLY_FLOAT:
+ float_val = double_val;
+ value = &float_val;
+ break;
+ case PLY_DOUBLE:
+ value = &double_val;
+ break;
+ default:
+ fprintf (stderr, "write_binary_item: bad type = %d\n", type);
+ exit (-1);
+ }
+ int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+ };
+
+ if ((file_type != *native_binary_type) && (ply_type_size[type] > 1))
+ swap_bytes((char *)value, ply_type_size[type]);
+
+ if (fwrite (value, ply_type_size[type], 1, fp) != 1)
+ {
+ fprintf(stderr, "PLY ERROR: fwrite() failed -- aborting.\n");
+ exit(1);
+ }
+}
+
+
+/******************************************************************************
+Write out an item to a file as ascii characters.
+
+Entry:
+ fp - file to write to
+ int_val - integer version of item
+ uint_val - unsigned integer version of item
+ double_val - double-precision float version of item
+ type - data type to write out
+******************************************************************************/
+
+inline void write_ascii_item(
+ FILE *fp,
+ int int_val,
+ unsigned int uint_val,
+ double double_val,
+ int type
+)
+{
+ switch (type) {
+ case PLY_CHAR:
+ case PLY_SHORT:
+ case PLY_INT:
+ if (fprintf (fp, "%d ", int_val) <= 0)
+ {
+ fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
+ exit(1);
+ }
+ break;
+ case PLY_UCHAR:
+ case PLY_USHORT:
+ case PLY_UINT:
+ if (fprintf (fp, "%u ", uint_val) <= 0)
+ {
+ fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
+ exit(1);
+ }
+ break;
+ case PLY_FLOAT:
+ case PLY_DOUBLE:
+ if (fprintf (fp, "%g ", double_val) <= 0)
+ {
+ fprintf(stderr, "PLY ERROR: fprintf() failed -- aborting.\n");
+ exit(1);
+ }
+ break;
+ default:
+ fprintf (stderr, "write_ascii_item: bad type = %d\n", type);
+ exit (-1);
+ }
+}
+
+
+/******************************************************************************
+Write out an item to a file as ascii characters.
+
+Entry:
+ fp - file to write to
+ item - pointer to item to write
+ type - data type that "item" points to
+
+Exit:
+ returns a double-precision float that contains the value of the written item
+******************************************************************************/
+
+inline double old_write_ascii_item(FILE *fp, char *item, int type)
+{
+ unsigned char *puchar;
+ char *pchar;
+ short int *pshort;
+ unsigned short int *pushort;
+ int *pint;
+ unsigned int *puint;
+ float *pfloat;
+ double *pdouble;
+ int int_value;
+ unsigned int uint_value;
+ double double_value;
+
+ switch (type) {
+ case PLY_CHAR:
+ pchar = (char *) item;
+ int_value = *pchar;
+ fprintf (fp, "%d ", int_value);
+ return ((double) int_value);
+ case PLY_UCHAR:
+ puchar = (unsigned char *) item;
+ int_value = *puchar;
+ fprintf (fp, "%d ", int_value);
+ return ((double) int_value);
+ case PLY_SHORT:
+ pshort = (short int *) item;
+ int_value = *pshort;
+ fprintf (fp, "%d ", int_value);
+ return ((double) int_value);
+ case PLY_USHORT:
+ pushort = (unsigned short int *) item;
+ int_value = *pushort;
+ fprintf (fp, "%d ", int_value);
+ return ((double) int_value);
+ case PLY_INT:
+ pint = (int *) item;
+ int_value = *pint;
+ fprintf (fp, "%d ", int_value);
+ return ((double) int_value);
+ case PLY_UINT:
+ puint = (unsigned int *) item;
+ uint_value = *puint;
+ fprintf (fp, "%u ", uint_value);
+ return ((double) uint_value);
+ case PLY_FLOAT:
+ pfloat = (float *) item;
+ double_value = *pfloat;
+ fprintf (fp, "%g ", double_value);
+ return (double_value);
+ case PLY_DOUBLE:
+ pdouble = (double *) item;
+ double_value = *pdouble;
+ fprintf (fp, "%g ", double_value);
+ return (double_value);
+ default:
+ fprintf (stderr, "old_write_ascii_item: bad type = %d\n", type);
+ exit (-1);
+ }
+}
+
+
+/******************************************************************************
+Get the value of an item that is in memory, and place the result
+into an integer, an unsigned integer and a double.
+
+Entry:
+ ptr - pointer to the item
+ type - data type supposedly in the item
+
+Exit:
+ int_val - integer value
+ uint_val - unsigned integer value
+ double_val - double-precision floating point value
+******************************************************************************/
+
+inline void get_stored_item(
+ void *ptr,
+ int type,
+ int *int_val,
+ unsigned int *uint_val,
+ double *double_val
+)
+{
+ switch (type) {
+ case PLY_CHAR:
+ *int_val = *((char *) ptr);
+ *uint_val = *int_val;
+ *double_val = *int_val;
+ break;
+ case PLY_UCHAR:
+ *uint_val = *((unsigned char *) ptr);
+ *int_val = *uint_val;
+ *double_val = *uint_val;
+ break;
+ case PLY_SHORT:
+ *int_val = *((short int *) ptr);
+ *uint_val = *int_val;
+ *double_val = *int_val;
+ break;
+ case PLY_USHORT:
+ *uint_val = *((unsigned short int *) ptr);
+ *int_val = *uint_val;
+ *double_val = *uint_val;
+ break;
+ case PLY_INT:
+ *int_val = *((int *) ptr);
+ *uint_val = *int_val;
+ *double_val = *int_val;
+ break;
+ case PLY_UINT:
+ *uint_val = *((unsigned int *) ptr);
+ *int_val = *uint_val;
+ *double_val = *uint_val;
+ break;
+ case PLY_FLOAT:
+ *double_val = *((float *) ptr);
+ *int_val = (int) *double_val;
+ *uint_val = (unsigned int) *double_val;
+ break;
+ case PLY_DOUBLE:
+ *double_val = *((double *) ptr);
+ *int_val = (int) *double_val;
+ *uint_val = (unsigned int) *double_val;
+ break;
+ default:
+ fprintf (stderr, "get_stored_item: bad type = %d\n", type);
+ exit (-1);
+ }
+}
+
+
+/******************************************************************************
+Get the value of an item from a binary file, and place the result
+into an integer, an unsigned integer and a double.
+
+Entry:
+ fp - file to get item from
+ type - data type supposedly in the word
+
+Exit:
+ int_val - integer value
+ uint_val - unsigned integer value
+ double_val - double-precision floating point value
+******************************************************************************/
+
+inline void get_binary_item(
+ FILE *fp,
+ int file_type,
+ int type,
+ int *int_val,
+ unsigned int *uint_val,
+ double *double_val,
+ int *native_binary_type
+)
+{
+ char c[8];
+ void *ptr;
+
+ ptr = (void *) c;
+ int ply_type_size[] = {
+ 0, 1, 2, 4, 1, 2, 4, 4, 8
+ };
+
+ if (fread (ptr, ply_type_size[type], 1, fp) != 1)
+ {
+ fprintf(stderr, "PLY ERROR: fread() failed -- aborting.\n");
+ exit(1);
+ }
+
+
+ if ((file_type != *native_binary_type) && (ply_type_size[type] > 1))
+ swap_bytes((char *)ptr, ply_type_size[type]);
+
+ switch (type) {
+ case PLY_CHAR:
+ *int_val = *((char *) ptr);
+ *uint_val = *int_val;
+ *double_val = *int_val;
+ break;
+ case PLY_UCHAR:
+ *uint_val = *((unsigned char *) ptr);
+ *int_val = *uint_val;
+ *double_val = *uint_val;
+ break;
+ case PLY_SHORT:
+ *int_val = *((short int *) ptr);
+ *uint_val = *int_val;
+ *double_val = *int_val;
+ break;
+ case PLY_USHORT:
+ *uint_val = *((unsigned short int *) ptr);
+ *int_val = *uint_val;
+ *double_val = *uint_val;
+ break;
+ case PLY_INT:
+ *int_val = *((int *) ptr);
+ *uint_val = *int_val;
+ *double_val = *int_val;
+ break;
+ case PLY_UINT:
+ *uint_val = *((unsigned int *) ptr);
+ *int_val = *uint_val;
+ *double_val = *uint_val;
+ break;
+ case PLY_FLOAT:
+ *double_val = *((float *) ptr);
+ *int_val = (int) *double_val;
+ *uint_val = (unsigned int) *double_val;
+ break;
+ case PLY_DOUBLE:
+ *double_val = *((double *) ptr);
+ *int_val = (int) *double_val;
+ *uint_val = (unsigned int) *double_val;
+ break;
+ default:
+ fprintf (stderr, "get_binary_item: bad type = %d\n", type);
+ exit (-1);
+ }
+}
+
+
+/******************************************************************************
+Extract the value of an item from an ascii word, and place the result
+into an integer, an unsigned integer and a double.
+
+Entry:
+ word - word to extract value from
+ type - data type supposedly in the word
+
+Exit:
+ int_val - integer value
+ uint_val - unsigned integer value
+ double_val - double-precision floating point value
+******************************************************************************/
+
+inline void get_ascii_item(
+ char *word,
+ int type,
+ int *int_val,
+ unsigned int *uint_val,
+ double *double_val
+)
+{
+ switch (type) {
+ case PLY_CHAR:
+ case PLY_UCHAR:
+ case PLY_SHORT:
+ case PLY_USHORT:
+ case PLY_INT:
+ *int_val = atoi (word);
+ *uint_val = (unsigned int) *int_val;
+ *double_val = (double) *int_val;
+ break;
+
+ case PLY_UINT:
+ *uint_val = strtol (word, (char **) NULL, 10);
+ *int_val = (int) *uint_val;
+ *double_val = (double) *uint_val;
+ break;
+
+ case PLY_FLOAT:
+ case PLY_DOUBLE:
+ *double_val = atof (word);
+ *int_val = (int) *double_val;
+ *uint_val = (unsigned int) *double_val;
+ break;
+
+ default:
+ fprintf (stderr, "get_ascii_item: bad type = %d\n", type);
+ exit (-1);
+ }
+}
+
+
+/******************************************************************************
+Store a value into a place being pointed to, guided by a data type.
+
+Entry:
+ item - place to store value
+ type - data type
+ int_val - integer version of value
+ uint_val - unsigned integer version of value
+ double_val - double version of value
+
+Exit:
+ item - pointer to stored value
+******************************************************************************/
+
+inline void store_item (
+ char *item,
+ int type,
+ int int_val,
+ unsigned int uint_val,
+ double double_val
+)
+{
+ unsigned char *puchar;
+ short int *pshort;
+ unsigned short int *pushort;
+ int *pint;
+ unsigned int *puint;
+ float *pfloat;
+ double *pdouble;
+
+ switch (type) {
+ case PLY_CHAR:
+ *item = int_val;
+ break;
+ case PLY_UCHAR:
+ puchar = (unsigned char *) item;
+ *puchar = uint_val;
+ break;
+ case PLY_SHORT:
+ pshort = (short *) item;
+ *pshort = int_val;
+ break;
+ case PLY_USHORT:
+ pushort = (unsigned short *) item;
+ *pushort = uint_val;
+ break;
+ case PLY_INT:
+ pint = (int *) item;
+ *pint = int_val;
+ break;
+ case PLY_UINT:
+ puint = (unsigned int *) item;
+ *puint = uint_val;
+ break;
+ case PLY_FLOAT:
+ pfloat = (float *) item;
+ *pfloat = double_val;
+ break;
+ case PLY_DOUBLE:
+ pdouble = (double *) item;
+ *pdouble = double_val;
+ break;
+ default:
+ fprintf (stderr, "store_item: bad type = %d\n", type);
+ exit (-1);
+ }
+}
+
+
+/******************************************************************************
+Add an element to a PLY file descriptor.
+
+Entry:
+ plyfile - PLY file descriptor
+ words - list of words describing the element
+ nwords - number of words in the list
+******************************************************************************/
+
+inline void add_element (PlyFile *plyfile, char **words)
+{
+ PlyElement *elem;
+
+ /* create the new element */
+ elem = (PlyElement *) myalloc (sizeof (PlyElement));
+ elem->name = strdup (words[1]);
+ elem->num = atoi (words[2]);
+ elem->nprops = 0;
+
+ /* make room for new element in the object's list of elements */
+ if (plyfile->nelems == 0)
+ plyfile->elems = (PlyElement **) myalloc (sizeof (PlyElement *));
+ else
+ plyfile->elems = (PlyElement **) realloc (plyfile->elems,
+ sizeof (PlyElement *) * (plyfile->nelems + 1));
+
+ /* add the new element to the object's list */
+ plyfile->elems[plyfile->nelems] = elem;
+ plyfile->nelems++;
+}
+
+
+/******************************************************************************
+Return the type of a property, given the name of the property.
+
+Entry:
+ name - name of property type
+
+Exit:
+ returns integer code for property, or 0 if not found
+******************************************************************************/
+
+inline int get_prop_type(char *type_name)
+{
+ int i;
+ const char *type_names[] = {
+ "invalid",
+ "char", "short", "int",
+ "uchar", "ushort", "uint",
+ "float", "double",
+ };
+
+ const char *alt_type_names[] = {
+ "invalid",
+ "int8", "int16", "int32", "uint8", "uint16", "uint32", "float32", "float64",
+ };
+
+
+ for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
+ if (equal_strings (type_name, type_names[i]))
+ return (i);
+
+ for (i = PLY_START_TYPE + 1; i < PLY_END_TYPE; i++)
+ if (equal_strings (type_name, alt_type_names[i]))
+ return (i);
+
+ /* if we get here, we didn't find the type */
+ return (0);
+}
+
+
+/******************************************************************************
+Add a property to a PLY file descriptor.
+
+Entry:
+ plyfile - PLY file descriptor
+ words - list of words describing the property
+ nwords - number of words in the list
+******************************************************************************/
+
+inline void add_property (PlyFile *plyfile, char **words)
+{
+ PlyProperty *prop;
+ PlyElement *elem;
+
+ /* create the new property */
+
+ prop = (PlyProperty *) myalloc (sizeof (PlyProperty));
+
+ if (equal_strings (words[1], "list")) { /* is a list */
+ prop->count_external = get_prop_type (words[2]);
+ prop->external_type = get_prop_type (words[3]);
+ prop->name = strdup (words[4]);
+ prop->is_list = 1;
+ }
+ else { /* not a list */
+ prop->external_type = get_prop_type (words[1]);
+ prop->name = strdup (words[2]);
+ prop->is_list = 0;
+ }
+
+ /* add this property to the list of properties of the current element */
+
+ elem = plyfile->elems[plyfile->nelems - 1];
+
+ if (elem->nprops == 0)
+ elem->props = (PlyProperty **) myalloc (sizeof (PlyProperty *));
+ else
+ elem->props = (PlyProperty **) realloc (elem->props,
+ sizeof (PlyProperty *) * (elem->nprops + 1));
+
+ elem->props[elem->nprops] = prop;
+ elem->nprops++;
+}
+
+
+/******************************************************************************
+Add a comment to a PLY file descriptor.
+
+Entry:
+ plyfile - PLY file descriptor
+ line - line containing comment
+******************************************************************************/
+
+inline void add_comment (PlyFile *plyfile, char *line)
+{
+ int i;
+
+ /* skip over "comment" and leading spaces and tabs */
+ i = 7;
+ while (line[i] == ' ' || line[i] == '\t')
+ i++;
+
+ ply_put_comment (plyfile, &line[i]);
+}
+
+
+/******************************************************************************
+Add a some object information to a PLY file descriptor.
+
+Entry:
+ plyfile - PLY file descriptor
+ line - line containing text info
+******************************************************************************/
+
+inline void add_obj_info (PlyFile *plyfile, char *line)
+{
+ int i;
+
+ /* skip over "obj_info" and leading spaces and tabs */
+ i = 8;
+ while (line[i] == ' ' || line[i] == '\t')
+ i++;
+
+ ply_put_obj_info (plyfile, &line[i]);
+}
+
+
+/******************************************************************************
+Copy a property.
+******************************************************************************/
+
+inline void copy_property(PlyProperty *dest, PlyProperty *src)
+{
+ dest->name = strdup (src->name);
+ dest->external_type = src->external_type;
+ dest->internal_type = src->internal_type;
+ dest->offset = src->offset;
+
+ dest->is_list = src->is_list;
+ dest->count_external = src->count_external;
+ dest->count_internal = src->count_internal;
+ dest->count_offset = src->count_offset;
+}
+
+
+/******************************************************************************
+Allocate some memory.
+
+Entry:
+ size - amount of memory requested (in bytes)
+ lnum - line number from which memory was requested
+ fname - file name from which memory was requested
+******************************************************************************/
+
+inline char *my_alloc(int size, int lnum, const char *fe)
+{
+ char *ptr;
+
+ ptr = (char *) malloc (size);
+
+ if (ptr == 0) {
+ fprintf(stderr, "Memory allocation bombed on line %d in %s\n", lnum, fe);
+ }
+
+ return (ptr);
+}
+
+}
+}
+#endif
diff --git a/xs/src/igl/png/readPNG.cpp b/xs/src/igl/png/readPNG.cpp
new file mode 100644
index 000000000..8d42ad8d9
--- /dev/null
+++ b/xs/src/igl/png/readPNG.cpp
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readPNG.h"
+#include <igl_stb_image.h>
+
+IGL_INLINE bool igl::png::readPNG(
+ const std::string png_file,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A
+)
+{
+ int cols,rows,n;
+ unsigned char *data = stbi_load(png_file.c_str(), &cols, &rows, &n, 4);
+ if(data == NULL) {
+ return false;
+ }
+
+ R.resize(cols,rows);
+ G.resize(cols,rows);
+ B.resize(cols,rows);
+ A.resize(cols,rows);
+
+ for (unsigned i=0; i<rows; ++i) {
+ for (unsigned j=0; j<cols; ++j) {
+ R(j,rows-1-i) = data[4*(j + cols * i) + 0];
+ G(j,rows-1-i) = data[4*(j + cols * i) + 1];
+ B(j,rows-1-i) = data[4*(j + cols * i) + 2];
+ A(j,rows-1-i) = data[4*(j + cols * i) + 3];
+ }
+ }
+
+ igl::stbi_image_free(data);
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+#endif
diff --git a/xs/src/igl/png/readPNG.h b/xs/src/igl/png/readPNG.h
new file mode 100644
index 000000000..65adf2c6c
--- /dev/null
+++ b/xs/src/igl/png/readPNG.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PNG_READ_PNG_H
+#define IGL_PNG_READ_PNG_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+ namespace png
+ {
+ // Read an image from a .png file into 4 memory buffers
+ //
+ // Input:
+ // png_file path to .png file
+ // Output:
+ // R,G,B,A texture channels
+ // Returns true on success, false on failure
+ //
+ IGL_INLINE bool readPNG(const std::string png_file,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A
+ );
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readPNG.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/png/render_to_png.cpp b/xs/src/igl/png/render_to_png.cpp
new file mode 100644
index 000000000..6533ad9ab
--- /dev/null
+++ b/xs/src/igl/png/render_to_png.cpp
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "render_to_png.h"
+#include <igl_stb_image.h>
+
+#include "../opengl/gl.h"
+
+IGL_INLINE bool igl::png::render_to_png(
+ const std::string png_file,
+ const int width,
+ const int height,
+ const bool alpha,
+ const bool fast)
+{
+ unsigned char * data = new unsigned char[4*width*height];
+ glReadPixels(
+ 0,
+ 0,
+ width,
+ height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data);
+ //img->flip();
+ if(!alpha)
+ {
+ for(int i = 0;i<width;i++)
+ for(int j = 0;j<height;j++)
+ {
+ data[4*(i+j*width)+3] = 255;
+ }
+ }
+ bool ret = igl::stbi_write_png(png_file.c_str(), width, height, 4, data, 4*width*sizeof(unsigned char));
+ delete [] data;
+ return ret;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/png/render_to_png.h b/xs/src/igl/png/render_to_png.h
new file mode 100644
index 000000000..508e12b1f
--- /dev/null
+++ b/xs/src/igl/png/render_to_png.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PNG_RENDER_TO_PNG_H
+#define IGL_PNG_RENDER_TO_PNG_H
+#include <igl/igl_inline.h>
+
+#include <string>
+namespace igl
+{
+ namespace png
+ {
+ //
+ // Render current open GL image to .png file
+ // Inputs:
+ // png_file path to output .png file
+ // width width of scene and resulting image
+ // height height of scene and resulting image
+ // alpha whether to include alpha channel
+ // fast sacrifice compression ratio for speed
+ // Returns true only if no errors occurred
+ //
+ // See also: igl/render_to_tga which is faster but writes .tga files
+ IGL_INLINE bool render_to_png(
+ const std::string png_file,
+ const int width,
+ const int height,
+ const bool alpha = true,
+ const bool fast = false);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "render_to_png.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/png/render_to_png_async.cpp b/xs/src/igl/png/render_to_png_async.cpp
new file mode 100644
index 000000000..033701e63
--- /dev/null
+++ b/xs/src/igl/png/render_to_png_async.cpp
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "render_to_png_async.h"
+#include "../opengl/gl.h"
+#include <igl_stb_image.h>
+
+static IGL_INLINE bool render_to_png_async_helper(
+ unsigned char * img, int width, int height,
+ const std::string png_file,
+ const bool alpha,
+ const bool fast)
+{
+ //img->flip();
+ if(!alpha)
+ {
+ for(int i = 0;i<width;i++)
+ for(int j = 0;j<height;j++)
+ {
+ img[4*(i+j*width)+3] = 255;
+ }
+ }
+
+ bool ret = igl::stbi_write_png(png_file.c_str(), width, height, 4, img, width*sizeof(unsigned char));
+ delete [] img;
+ return ret;
+}
+
+IGL_INLINE std::thread igl::png::render_to_png_async(
+ const std::string png_file,
+ const int width,
+ const int height,
+ const bool alpha,
+ const bool fast)
+{
+ // Part that should serial
+ unsigned char * data = new unsigned char[width*height];
+ glReadPixels(
+ 0,
+ 0,
+ width,
+ height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data);
+ // Part that should be asynchronous
+ std::thread t(render_to_png_async_helper,data,width,height,png_file,alpha,fast);
+ t.detach();
+ return t;
+}
diff --git a/xs/src/igl/png/render_to_png_async.h b/xs/src/igl/png/render_to_png_async.h
new file mode 100644
index 000000000..c4ac07c64
--- /dev/null
+++ b/xs/src/igl/png/render_to_png_async.h
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PNG_RENDER_TO_PNG_ASYNC_H
+#define IGL_PNG_RENDER_TO_PNG_ASYNC_H
+#include <igl/igl_inline.h>
+#include <thread>
+//#include <boost/thread/thread.hpp>
+
+#include <string>
+namespace igl
+{
+ namespace png
+ {
+ // History:
+ // added multithreaded parameter and support, Alec Sept 3, 2012
+ //
+ // Render current open GL image to .png file
+ // Inputs:
+ // png_file path to output .png file
+ // width width of scene and resulting image
+ // height height of scene and resulting image
+ // alpha whether to include alpha channel
+ // fast sacrifice compression ratio for speed
+ // Returns true only if no errors occurred
+ //
+ // See also: igl/render_to_tga which is faster but writes .tga files
+ IGL_INLINE std::thread render_to_png_async(
+ const std::string png_file,
+ const int width,
+ const int height,
+ const bool alpha = true,
+ const bool fast = false);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "render_to_png_async.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/png/texture_from_file.cpp b/xs/src/igl/png/texture_from_file.cpp
new file mode 100644
index 000000000..60e8c795c
--- /dev/null
+++ b/xs/src/igl/png/texture_from_file.cpp
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "texture_from_file.h"
+
+#include "texture_from_png.h"
+#include "../STR.h"
+#include "../pathinfo.h"
+#include "../opengl/report_gl_error.h"
+//#include "../opengl2/texture_from_tga.h"
+#include <string>
+#include <algorithm>
+#include <iostream>
+
+IGL_INLINE bool igl::png::texture_from_file(const std::string filename, GLuint & id)
+{
+ using namespace igl::opengl;
+ using namespace std;
+ // dirname, basename, extension and filename
+ string d,b,ext,f;
+ pathinfo(filename,d,b,ext,f);
+ // Convert extension to lower case
+ transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+ //if(ext == "tga")
+ //{
+ // return texture_from_tga(filename,id);
+ //}else
+ if(ext == "png")
+ {
+ return texture_from_png(filename,id);
+ }else
+ {
+#ifdef __APPLE__
+ // Convert to a temporary png file
+ string tmp = "/var/tmp/.texture_from_file.png";
+#define PATH_TO_CONVERT "/opt/local/bin/convert"
+ string command = STR(PATH_TO_CONVERT<<" \""<<filename<<"\" \""<<tmp<<"\"");
+ try
+ {
+ if(system(command.c_str())==0)
+ {
+ return texture_from_file(tmp.c_str(),id);
+ }else
+ {
+ cerr<<"texture_from_file: calling to convert ('"<<command<<"') failed..."<<endl;
+ return false;
+ }
+ }catch(int e)
+ {
+ cerr<<"^"<<__FUNCTION__<<": Calling to convert crashed..."<<endl;
+ return false;
+ }
+#else
+ return false;
+#endif
+ }
+}
diff --git a/xs/src/igl/png/texture_from_file.h b/xs/src/igl/png/texture_from_file.h
new file mode 100644
index 000000000..8852d101e
--- /dev/null
+++ b/xs/src/igl/png/texture_from_file.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PNG_TEXTURE_FROM_FILE_H
+#define IGL_PNG_TEXTURE_FROM_FILE_H
+#include "../igl_inline.h"
+#include "../opengl/gl.h"
+
+#include <string>
+
+namespace igl
+{
+ namespace png
+ {
+ // Read an image from an image file and use it as a texture. Officially,
+ // only <del>.tga and</del> .png are supported. Any filetype read by
+ // ImageMagick's `convert` will work via an unsafe system call.
+ //
+ // Input:
+ // filename path to image file
+ // Output:
+ // id of generated openGL texture
+ // Returns true on success, false on failure
+ IGL_INLINE bool texture_from_file(const std::string filename, GLuint & id);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "texture_from_file.cpp"
+#endif
+
+#endif
+
+
+
diff --git a/xs/src/igl/png/texture_from_png.cpp b/xs/src/igl/png/texture_from_png.cpp
new file mode 100644
index 000000000..fde3c002c
--- /dev/null
+++ b/xs/src/igl/png/texture_from_png.cpp
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "texture_from_png.h"
+
+#include "../opengl/report_gl_error.h"
+#include <igl_stb_image.h>
+
+IGL_INLINE bool igl::png::texture_from_png(const std::string png_file, const bool flip, GLuint & id)
+{
+ int width,height,n;
+ unsigned char *data = igl::stbi_load(png_file.c_str(), &width, &height, &n, 4);
+ if(data == NULL) {
+ return false;
+ }
+
+ // Why do I need to flip?
+ /*if(flip)
+ {
+ yimg.flip();
+ }*/
+
+ glGenTextures(1, &id);
+ glBindTexture(GL_TEXTURE_2D, id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexImage2D(
+ GL_TEXTURE_2D, 0, GL_RGB,
+ width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
+ glBindTexture(GL_TEXTURE_2D, 0);
+
+ igl::stbi_image_free(data);
+
+ return true;
+}
+
+IGL_INLINE bool igl::png::texture_from_png(const std::string png_file, GLuint & id)
+{
+ return texture_from_png(png_file,false,id);
+}
+
+
+IGL_INLINE bool igl::png::texture_from_png(
+ const std::string png_file,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A
+)
+{
+ int width,height,n;
+ unsigned char *data = igl::stbi_load(png_file.c_str(), &width, &height, &n, 4);
+ if(data == NULL) {
+ return false;
+ }
+
+ R.resize(height,width);
+ G.resize(height,width);
+ B.resize(height,width);
+ A.resize(height,width);
+
+ for (unsigned j=0; j<height; ++j) {
+ for (unsigned i=0; i<width; ++i) {
+ // used to flip with libPNG, but I'm not sure if
+ // simply j*width + i wouldn't be better
+ // stb_image uses horizontal scanline an starts top-left corner
+ R(i,j) = data[4*( (width-1-i) + width * (height-1-j) )];
+ G(i,j) = data[4*( (width-1-i) + width * (height-1-j) ) + 1];
+ B(i,j) = data[4*( (width-1-i) + width * (height-1-j) ) + 2];
+ //A(i,j) = data[4*( (width-1-i) + width * (height-1-j) ) + 3];
+ }
+ }
+
+ igl::stbi_image_free(data);
+
+ return true;
+}
diff --git a/xs/src/igl/png/texture_from_png.h b/xs/src/igl/png/texture_from_png.h
new file mode 100644
index 000000000..db8c1988e
--- /dev/null
+++ b/xs/src/igl/png/texture_from_png.h
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PNG_TEXTURE_FROM_PNG_H
+#define IGL_PNG_TEXTURE_FROM_PNG_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+
+#include "../opengl/gl.h"
+
+namespace igl
+{
+ namespace png
+ {
+ // Read an image from a .png file and use it as a texture
+ //
+ // Input:
+ // png_file path to .png file
+ // flip whether to flip the image vertically (A --> ∀)
+ // Output:
+ // id of generated openGL texture
+ // Returns true on success, false on failure
+ IGL_INLINE bool texture_from_png(const std::string png_file, const bool flip, GLuint & id);
+ IGL_INLINE bool texture_from_png(const std::string png_file, GLuint & id);
+
+ // Read an image from a .png file and use it as a texture
+ //
+ // Input:
+ // png_file path to .png file
+ // Output:
+ // R,G,B,A texture channels
+ // Returns true on success, false on failure
+ //
+ // Todo: this is an inappropriate function name. This is really just
+ // reading a png.... Not necessarily as a texture.
+ IGL_INLINE bool texture_from_png(const std::string png_file,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A
+ );
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "texture_from_png.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/png/writePNG.cpp b/xs/src/igl/png/writePNG.cpp
new file mode 100644
index 000000000..9ab68d775
--- /dev/null
+++ b/xs/src/igl/png/writePNG.cpp
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writePNG.h"
+#include <igl_stb_image.h>
+#include <vector>
+
+IGL_INLINE bool igl::png::writePNG(
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A,
+ const std::string png_file
+)
+{
+ assert((R.rows() == G.rows()) && (G.rows() == B.rows()) && (B.rows() == A.rows()));
+ assert((R.cols() == G.cols()) && (G.cols() == B.cols()) && (B.cols() == A.cols()));
+
+ const int comp = 4; // 4 Channels Red, Green, Blue, Alpha
+ const int stride_in_bytes = R.rows()*comp; // Length of one row in bytes
+ std::vector<unsigned char> data(R.size()*comp,0); // The image itself;
+
+ for (unsigned i = 0; i<R.rows();++i)
+ {
+ for (unsigned j = 0; j < R.cols(); ++j)
+ {
+ data[(j * R.rows() * comp) + (i * comp) + 0] = R(i,R.cols()-1-j);
+ data[(j * R.rows() * comp) + (i * comp) + 1] = G(i,R.cols()-1-j);
+ data[(j * R.rows() * comp) + (i * comp) + 2] = B(i,R.cols()-1-j);
+ data[(j * R.rows() * comp) + (i * comp) + 3] = A(i,R.cols()-1-j);
+ }
+ }
+
+ igl::stbi_write_png(png_file.c_str(), R.rows(), R.cols(), comp, data.data(), stride_in_bytes);
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+#endif
diff --git a/xs/src/igl/png/writePNG.h b/xs/src/igl/png/writePNG.h
new file mode 100644
index 000000000..b0623249f
--- /dev/null
+++ b/xs/src/igl/png/writePNG.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PNG_WRITE_PNG_H
+#define IGL_PNG_WRITE_PNG_H
+#include "../igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+ namespace png
+ {
+ // Writes an image to a png file
+ //
+ // Input:
+ // R,G,B,A texture channels
+ // Output:
+ // png_file path to .png file
+ // Returns true on success, false on failure
+ //
+ IGL_INLINE bool writePNG
+ (
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& R,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& G,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& B,
+ const Eigen::Matrix<unsigned char,Eigen::Dynamic,Eigen::Dynamic>& A,
+ const std::string png_file
+ );
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writePNG.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/point_in_circle.cpp b/xs/src/igl/point_in_circle.cpp
new file mode 100644
index 000000000..9c26d8c0d
--- /dev/null
+++ b/xs/src/igl/point_in_circle.cpp
@@ -0,0 +1,18 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_in_circle.h"
+
+IGL_INLINE bool igl::point_in_circle(
+ const double qx,
+ const double qy,
+ const double cx,
+ const double cy,
+ const double r)
+{
+ return (qx-cx)*(qx-cx) + (qy-cy)*(qy-cy) - r*r < 0;
+}
diff --git a/xs/src/igl/point_in_circle.h b/xs/src/igl/point_in_circle.h
new file mode 100644
index 000000000..f19344c40
--- /dev/null
+++ b/xs/src/igl/point_in_circle.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POINT_IN_CIRCLE_H
+#define IGL_POINT_IN_CIRCLE_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Determine if 2d point is in a circle
+ // Inputs:
+ // qx x-coordinate of query point
+ // qy y-coordinate of query point
+ // cx x-coordinate of circle center
+ // cy y-coordinate of circle center
+ // r radius of circle
+ // Returns true if query point is in circle, false otherwise
+ IGL_INLINE bool point_in_circle(
+ const double qx,
+ const double qy,
+ const double cx,
+ const double cy,
+ const double r);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "point_in_circle.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/point_in_poly.cpp b/xs/src/igl/point_in_poly.cpp
new file mode 100644
index 000000000..f0b07edf9
--- /dev/null
+++ b/xs/src/igl/point_in_poly.cpp
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_in_poly.h"
+
+bool IGL_INLINE igl::point_in_poly( const std::vector<std::vector<unsigned int > >&poly,
+ const unsigned int xt,
+ const unsigned int yt)
+{
+ int npoints= poly.size();
+ unsigned int xnew,ynew;
+ unsigned int xold,yold;
+ unsigned int x1,y1;
+ unsigned int x2,y2;
+ int i;
+ int inside=0;
+
+ if (npoints < 3) {
+ return(0);
+ }
+ xold=poly[npoints-1][0];
+ yold=poly[npoints-1][1];
+ for (i=0 ; i < npoints ; i++) {
+ xnew=poly[i][0];
+ ynew=poly[i][1];
+ if (xnew > xold) {
+ x1=xold;
+ x2=xnew;
+ y1=yold;
+ y2=ynew;
+ }
+ else {
+ x1=xnew;
+ x2=xold;
+ y1=ynew;
+ y2=yold;
+ }
+ if ((xnew < xt) == (xt <= xold) /* edge "open" at one end */
+ && ((long)yt-(long)y1)*(long)(x2-x1)
+ < ((long)y2-(long)y1)*(long)(xt-x1)) {
+ inside=!inside;
+ }
+ xold=xnew;
+ yold=ynew;
+ }
+ return (inside != 0);
+}
diff --git a/xs/src/igl/point_in_poly.h b/xs/src/igl/point_in_poly.h
new file mode 100644
index 000000000..2b9c6e51b
--- /dev/null
+++ b/xs/src/igl/point_in_poly.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POINT_IN_POLY_H
+#define IGL_POINT_IN_POLY_H
+#include "igl_inline.h"
+
+#include <vector>
+
+namespace igl
+{
+ // Determine if 2d point is inside a 2D polygon
+ // Inputs:
+ // poly vector of polygon points, [0]=x, [1]=y.
+ // Polyline need not be closed (i.e. first point != last point),
+ // the line segment between last and first selected points is constructed
+ // within this function.
+ // x x-coordinate of query point
+ // y y-coordinate of query point
+ // Returns true if query point is in polygon, false otherwise
+ // from http://www.visibone.com/inpoly/
+bool IGL_INLINE point_in_poly( const std::vector<std::vector<unsigned int > >&poly,
+ const unsigned int xt,
+ const unsigned int yt);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "point_in_poly.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/point_mesh_squared_distance.cpp b/xs/src/igl/point_mesh_squared_distance.cpp
new file mode 100644
index 000000000..57dd9aa14
--- /dev/null
+++ b/xs/src/igl/point_mesh_squared_distance.cpp
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_mesh_squared_distance.h"
+#include "AABB.h"
+#include <cassert>
+
+template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+IGL_INLINE void igl::point_mesh_squared_distance(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::MatrixXi & Ele,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ using namespace std;
+ const size_t dim = P.cols();
+ assert((dim == 2 || dim == 3) && "P.cols() should be 2 or 3");
+ assert(P.cols() == V.cols() && "P.cols() should equal V.cols()");
+ switch(dim)
+ {
+ default:
+ assert(false && "Unsupported dim");
+ // fall-through and pray
+ case 3:
+ {
+ AABB<DerivedV,3> tree;
+ tree.init(V,Ele);
+ return tree.squared_distance(V,Ele,P,sqrD,I,C);
+ }
+ case 2:
+ {
+ AABB<DerivedV,2> tree;
+ tree.init(V,Ele);
+ return tree.squared_distance(V,Ele,P,sqrD,I,C);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::point_mesh_squared_distance<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::point_mesh_squared_distance<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::point_mesh_squared_distance<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/point_mesh_squared_distance.h b/xs/src/igl/point_mesh_squared_distance.h
new file mode 100644
index 000000000..0635288a3
--- /dev/null
+++ b/xs/src/igl/point_mesh_squared_distance.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POINT_MESH_SQUARED_DISTANCE_H
+#define IGL_POINT_MESH_SQUARED_DISTANCE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Compute distances from a set of points P to a triangle mesh (V,F)
+ //
+ // Inputs:
+ // P #P by 3 list of query point positions
+ // V #V by 3 list of vertex positions
+ // Ele #Ele by (3|2|1) list of (triangle|edge|point) indices
+ // Outputs:
+ // sqrD #P list of smallest squared distances
+ // I #P list of primitive indices corresponding to smallest distances
+ // C #P by 3 list of closest points
+ //
+ // Known bugs: This only computes distances to given primitivess. So
+ // unreferenced vertices are ignored. However, degenerate primitives are
+ // handled correctly: triangle [1 2 2] is treated as a segment [1 2], and
+ // triangle [1 1 1] is treated as a point. So one _could_ add extra
+ // combinatorially degenerate rows to Ele for all unreferenced vertices to
+ // also get distances to points.
+ template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedsqrD,
+ typename DerivedI,
+ typename DerivedC>
+ IGL_INLINE void point_mesh_squared_distance(
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::MatrixXi & Ele,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "point_mesh_squared_distance.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/point_simplex_squared_distance.cpp b/xs/src/igl/point_simplex_squared_distance.cpp
new file mode 100644
index 000000000..2b98bd285
--- /dev/null
+++ b/xs/src/igl/point_simplex_squared_distance.cpp
@@ -0,0 +1,181 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "point_simplex_squared_distance.h"
+#include "project_to_line_segment.h"
+#include "barycentric_coordinates.h"
+#include <Eigen/Geometry>
+#include <limits>
+#include <cassert>
+
+
+
+template <
+ int DIM,
+ typename Derivedp,
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedsqr_d,
+ typename Derivedc,
+ typename Derivedb>
+IGL_INLINE void igl::point_simplex_squared_distance(
+ const Eigen::MatrixBase<Derivedp> & p,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const typename DerivedEle::Index primitive,
+ Derivedsqr_d & sqr_d,
+ Eigen::MatrixBase<Derivedc> & c,
+ Eigen::PlainObjectBase<Derivedb> & bary)
+{
+ typedef typename Derivedp::Scalar Scalar;
+ typedef typename Eigen::Matrix<Scalar,1,DIM> Vector;
+ typedef Vector Point;
+ //typedef Derivedb BaryPoint;
+ typedef Eigen::Matrix<typename Derivedb::Scalar,1,3> BaryPoint;
+
+ const auto & Dot = [](const Point & a, const Point & b)->Scalar
+ {
+ return a.dot(b);
+ };
+ // Real-time collision detection, Ericson, Chapter 5
+ const auto & ClosestBaryPtPointTriangle =
+ [&Dot](Point p, Point a, Point b, Point c, BaryPoint& bary_out )->Point
+ {
+ // Check if P in vertex region outside A
+ Vector ab = b - a;
+ Vector ac = c - a;
+ Vector ap = p - a;
+ Scalar d1 = Dot(ab, ap);
+ Scalar d2 = Dot(ac, ap);
+ if (d1 <= 0.0 && d2 <= 0.0) {
+ // barycentric coordinates (1,0,0)
+ bary_out << 1, 0, 0;
+ return a;
+ }
+ // Check if P in vertex region outside B
+ Vector bp = p - b;
+ Scalar d3 = Dot(ab, bp);
+ Scalar d4 = Dot(ac, bp);
+ if (d3 >= 0.0 && d4 <= d3) {
+ // barycentric coordinates (0,1,0)
+ bary_out << 0, 1, 0;
+ return b;
+ }
+ // Check if P in edge region of AB, if so return projection of P onto AB
+ Scalar vc = d1*d4 - d3*d2;
+ if( a != b)
+ {
+ if (vc <= 0.0 && d1 >= 0.0 && d3 <= 0.0) {
+ Scalar v = d1 / (d1 - d3);
+ // barycentric coordinates (1-v,v,0)
+ bary_out << 1-v, v, 0;
+ return a + v * ab;
+ }
+ }
+ // Check if P in vertex region outside C
+ Vector cp = p - c;
+ Scalar d5 = Dot(ab, cp);
+ Scalar d6 = Dot(ac, cp);
+ if (d6 >= 0.0 && d5 <= d6) {
+ // barycentric coordinates (0,0,1)
+ bary_out << 0, 0, 1;
+ return c;
+ }
+ // Check if P in edge region of AC, if so return projection of P onto AC
+ Scalar vb = d5*d2 - d1*d6;
+ if (vb <= 0.0 && d2 >= 0.0 && d6 <= 0.0) {
+ Scalar w = d2 / (d2 - d6);
+ // barycentric coordinates (1-w,0,w)
+ bary_out << 1-w, 0, w;
+ return a + w * ac;
+ }
+ // Check if P in edge region of BC, if so return projection of P onto BC
+ Scalar va = d3*d6 - d5*d4;
+ if (va <= 0.0 && (d4 - d3) >= 0.0 && (d5 - d6) >= 0.0) {
+ Scalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
+ // barycentric coordinates (0,1-w,w)
+ bary_out << 0, 1-w, w;
+ return b + w * (c - b);
+ }
+ // P inside face region. Compute Q through its barycentric coordinates (u,v,w)
+ Scalar denom = 1.0 / (va + vb + vc);
+ Scalar v = vb * denom;
+ Scalar w = vc * denom;
+ bary_out << 1.0-v-w, v, w;
+ return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = 1.0-v-w
+ };
+
+ assert(p.size() == DIM);
+ assert(V.cols() == DIM);
+ assert(Ele.cols() <= DIM+1);
+ assert(Ele.cols() <= 3 && "Only simplices up to triangles are considered");
+
+ assert((Derivedb::RowsAtCompileTime == 1 || Derivedb::ColsAtCompileTime == 1) && "bary must be Eigen Vector or Eigen RowVector");
+ assert(
+ ((Derivedb::RowsAtCompileTime == -1 || Derivedb::ColsAtCompileTime == -1) ||
+ (Derivedb::RowsAtCompileTime == Ele.cols() || Derivedb::ColsAtCompileTime == Ele.cols())
+ ) && "bary must be Dynamic or size of Ele.cols()");
+
+ BaryPoint tmp_bary;
+ c = (const Derivedc &)ClosestBaryPtPointTriangle(
+ p,
+ V.row(Ele(primitive,0)),
+ // modulo is a HACK to handle points, segments and triangles. Because of
+ // this, we need 3d buffer for bary
+ V.row(Ele(primitive,1%Ele.cols())),
+ V.row(Ele(primitive,2%Ele.cols())),
+ tmp_bary);
+ bary.resize( Derivedb::RowsAtCompileTime == 1 ? 1 : Ele.cols(), Derivedb::ColsAtCompileTime == 1 ? 1 : Ele.cols());
+ bary.head(Ele.cols()) = tmp_bary.head(Ele.cols());
+ sqr_d = (p-c).squaredNorm();
+}
+
+template <
+ int DIM,
+ typename Derivedp,
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedsqr_d,
+ typename Derivedc>
+IGL_INLINE void igl::point_simplex_squared_distance(
+ const Eigen::MatrixBase<Derivedp> & p,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const typename DerivedEle::Index primitive,
+ Derivedsqr_d & sqr_d,
+ Eigen::MatrixBase<Derivedc> & c)
+{
+ // Use Dynamic because we don't know Ele.cols() at compile time.
+ Eigen::Matrix<typename Derivedc::Scalar,1,Eigen::Dynamic> b;
+ point_simplex_squared_distance<DIM>( p, V, Ele, primitive, sqr_d, c, b );
+}
+
+namespace igl
+{
+ template <> IGL_INLINE void point_simplex_squared_distance<2>(Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, float&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&) {assert(false);};
+ template <> IGL_INLINE void point_simplex_squared_distance<2>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) {assert(false);};
+ template <> IGL_INLINE void point_simplex_squared_distance<2>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&) {assert(false);};
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 0, -1, 3>::Index, float&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Matrix<int, -1, 3, 1, -1, 3>::Index, float&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, float&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::point_simplex_squared_distance<2, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::point_simplex_squared_distance<3, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 1, 1, 3> >&);
+template void igl::point_simplex_squared_distance<2, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
+template void igl::point_simplex_squared_distance<2, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1>::Index, double&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 1, 1, 2> >&);
+#endif
diff --git a/xs/src/igl/point_simplex_squared_distance.h b/xs/src/igl/point_simplex_squared_distance.h
new file mode 100644
index 000000000..0cc871cf0
--- /dev/null
+++ b/xs/src/igl/point_simplex_squared_distance.h
@@ -0,0 +1,72 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POINT_SIMPLEX_SQUARED_DISTANCE_H
+#define IGL_POINT_SIMPLEX_SQUARED_DISTANCE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Determine squared distance from a point to linear simplex.
+ //
+ // Inputs:
+ // p d-long query point
+ // V #V by d list of vertices
+ // Ele #Ele by ss<=d+1 list of simplex indices into V
+ // i index into Ele of simplex
+ // Outputs:
+ // sqr_d squared distance of Ele(i) to p
+ // c closest point on Ele(i)
+ //
+ template <
+ int DIM,
+ typename Derivedp,
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedsqr_d,
+ typename Derivedc>
+ IGL_INLINE void point_simplex_squared_distance(
+ const Eigen::MatrixBase<Derivedp> & p,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const typename DerivedEle::Index i,
+ Derivedsqr_d & sqr_d,
+ Eigen::MatrixBase<Derivedc> & c);
+ // Determine squared distance from a point to linear simplex.
+ // Also return barycentric coordinate of closest point.
+ //
+ // Inputs:
+ // p d-long query point
+ // V #V by d list of vertices
+ // Ele #Ele by ss<=d+1 list of simplex indices into V
+ // i index into Ele of simplex
+ // Outputs:
+ // sqr_d squared distance of Ele(i) to p
+ // c closest point on Ele(i)
+ // b barycentric coordinates of closest point on Ele(i)
+ //
+ template <
+ int DIM,
+ typename Derivedp,
+ typename DerivedV,
+ typename DerivedEle,
+ typename Derivedsqr_d,
+ typename Derivedc,
+ typename Derivedb>
+ IGL_INLINE void point_simplex_squared_distance(
+ const Eigen::MatrixBase<Derivedp> & p,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedEle> & Ele,
+ const typename DerivedEle::Index i,
+ Derivedsqr_d & sqr_d,
+ Eigen::MatrixBase<Derivedc> & c,
+ Eigen::PlainObjectBase<Derivedb> & b);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "point_simplex_squared_distance.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/polar_dec.cpp b/xs/src/igl/polar_dec.cpp
new file mode 100644
index 000000000..cdd358a07
--- /dev/null
+++ b/xs/src/igl/polar_dec.cpp
@@ -0,0 +1,97 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "polar_dec.h"
+#include "polar_svd.h"
+#ifdef _WIN32
+#else
+# include <fenv.h>
+#endif
+#include <cmath>
+#include <Eigen/Eigenvalues>
+#include <iostream>
+#include <cfenv>
+
+// From Olga's CGAL mentee's ARAP code
+template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT,
+ typename DerivedU,
+ typename DerivedS,
+ typename DerivedV>
+IGL_INLINE void igl::polar_dec(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedV> & V)
+{
+ using namespace std;
+ using namespace Eigen;
+ typedef typename DerivedA::Scalar Scalar;
+
+ const Scalar th = std::sqrt(Eigen::NumTraits<Scalar>::dummy_precision());
+
+ Eigen::SelfAdjointEigenSolver<DerivedA> eig;
+ feclearexcept(FE_UNDERFLOW);
+ eig.computeDirect(A.transpose()*A);
+ if(fetestexcept(FE_UNDERFLOW) || eig.eigenvalues()(0)/eig.eigenvalues()(2)<th)
+ {
+ cout<<"resorting to svd 1..."<<endl;
+ return polar_svd(A,R,T,U,S,V);
+ }
+
+ S = eig.eigenvalues().cwiseSqrt();
+
+ V = eig.eigenvectors();
+ U = A * V;
+ R = U * S.asDiagonal().inverse() * V.transpose();
+ T = V * S.asDiagonal() * V.transpose();
+
+ S = S.reverse().eval();
+ V = V.rowwise().reverse().eval();
+ U = U.rowwise().reverse().eval() * S.asDiagonal().inverse();
+
+ if(R.determinant() < 0)
+ {
+ // Annoyingly the .eval() is necessary
+ auto W = V.eval();
+ const auto & SVT = S.asDiagonal() * V.adjoint();
+ W.col(V.cols()-1) *= -1.;
+ R = U*W.transpose();
+ T = W*SVT;
+ }
+
+ if(std::fabs(R.squaredNorm()-3.) > th)
+ {
+ cout<<"resorting to svd 2..."<<endl;
+ return polar_svd(A,R,T,U,S,V);
+ }
+}
+
+template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT>
+IGL_INLINE void igl::polar_dec(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T)
+{
+ DerivedA U;
+ DerivedA V;
+ Eigen::Matrix<typename DerivedA::Scalar,DerivedA::RowsAtCompileTime,1> S;
+ return igl::polar_dec(A,R,T,U,S,V);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::polar_dec<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::polar_dec<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/polar_dec.h b/xs/src/igl/polar_dec.h
new file mode 100644
index 000000000..2b995eabe
--- /dev/null
+++ b/xs/src/igl/polar_dec.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POLAR_DEC
+#define IGL_POLAR_DEC
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Computes the polar decomposition (R,T) of a matrix A
+ // Inputs:
+ // A 3 by 3 matrix to be decomposed
+ // Outputs:
+ // R 3 by 3 orthonormal matrix part of decomposition
+ // T 3 by 3 stretch matrix part of decomposition
+ // U 3 by 3 left-singular vectors
+ // S 3 by 1 singular values
+ // V 3 by 3 right-singular vectors
+ //
+ //
+ template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT,
+ typename DerivedU,
+ typename DerivedS,
+ typename DerivedV>
+ IGL_INLINE void polar_dec(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedV> & V);
+ template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT>
+ IGL_INLINE void polar_dec(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "polar_dec.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/polar_svd.cpp b/xs/src/igl/polar_svd.cpp
new file mode 100644
index 000000000..962a754fb
--- /dev/null
+++ b/xs/src/igl/polar_svd.cpp
@@ -0,0 +1,80 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "polar_svd.h"
+#include <Eigen/SVD>
+#include <Eigen/Geometry>
+#include <iostream>
+
+// Adapted from Olga's CGAL mentee's ARAP code
+template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT>
+IGL_INLINE void igl::polar_svd(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T)
+{
+ DerivedA U;
+ DerivedA V;
+ Eigen::Matrix<typename DerivedA::Scalar,DerivedA::RowsAtCompileTime,1> S;
+ return igl::polar_svd(A,R,T,U,S,V);
+}
+
+template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT,
+ typename DerivedU,
+ typename DerivedS,
+ typename DerivedV>
+IGL_INLINE void igl::polar_svd(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedV> & V)
+{
+ using namespace std;
+ Eigen::JacobiSVD<DerivedA> svd;
+ svd.compute(A, Eigen::ComputeFullU | Eigen::ComputeFullV );
+ U = svd.matrixU();
+ V = svd.matrixV();
+ S = svd.singularValues();
+ R = U*V.transpose();
+ const auto & SVT = S.asDiagonal() * V.adjoint();
+ // Check for reflection
+ if(R.determinant() < 0)
+ {
+ // Annoyingly the .eval() is necessary
+ auto W = V.eval();
+ W.col(V.cols()-1) *= -1.;
+ R = U*W.transpose();
+ T = W*SVT;
+ }else
+ {
+ T = V*SVT;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::polar_svd<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::polar_svd<Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 2, 0, 2, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&);
+template void igl::polar_svd<Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 3, 3, 0, 3, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> >&);
+template void igl::polar_svd<Eigen::Matrix<float, 2, 2, 0, 2, 2>, Eigen::Matrix<float, 2, 2, 0, 2, 2>, Eigen::Matrix<float, 2, 2, 0, 2, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> >&);
+template void igl::polar_svd<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 2, 0, 2, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&);
+template void igl::polar_svd<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::polar_svd<Eigen::Matrix<float,3,3,0,3,3>,Eigen::Matrix<float,3,3,0,3,3>,Eigen::Matrix<float,3,3,0,3,3>,Eigen::Matrix<float,3,3,0,3,3>,Eigen::Matrix<float,3,1,0,3,1>,Eigen::Matrix<float,3,3,0,3,3> >(Eigen::PlainObjectBase<Eigen::Matrix<float,3,3,0,3,3> > const &,Eigen::PlainObjectBase<Eigen::Matrix<float,3,3,0,3,3> > &,Eigen::PlainObjectBase<Eigen::Matrix<float,3,3,0,3,3> > &,Eigen::PlainObjectBase<Eigen::Matrix<float,3,3,0,3,3> > &,Eigen::PlainObjectBase<Eigen::Matrix<float,3,1,0,3,1> > &,Eigen::PlainObjectBase<Eigen::Matrix<float,3,3,0,3,3> >&);
+template void igl::polar_svd<Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 3, 3, 0, 3, 3>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 3, 0, 3, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 3, 0, 3, 3> >&);
+template void igl::polar_svd<Eigen::Matrix<float, 2, 2, 0, 2, 2>, Eigen::Matrix<float, 2, 2, 0, 2, 2>, Eigen::Matrix<float, 2, 2, 0, 2, 2>, Eigen::Matrix<float, 2, 2, 0, 2, 2>, Eigen::Matrix<float, 2, 1, 0, 2, 1>, Eigen::Matrix<float, 2, 2, 0, 2, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 2, 0, 2, 2> >&);
+template void igl::polar_svd<Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 1, 0, 2, 1>, Eigen::Matrix<double, 2, 2, 0, 2, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&);
+template void igl::polar_svd<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::polar_svd<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/polar_svd.h b/xs/src/igl/polar_svd.h
new file mode 100644
index 000000000..13d3f3873
--- /dev/null
+++ b/xs/src/igl/polar_svd.h
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POLAR_SVD
+#define IGL_POLAR_SVD
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Computes the polar decomposition (R,T) of a matrix A using SVD singular
+ // value decomposition
+ //
+ // Inputs:
+ // A 3 by 3 matrix to be decomposed
+ // Outputs:
+ // R 3 by 3 rotation matrix part of decomposition (**always rotataion**)
+ // T 3 by 3 stretch matrix part of decomposition
+ // U 3 by 3 left-singular vectors
+ // S 3 by 1 singular values
+ // V 3 by 3 right-singular vectors
+ //
+ //
+ template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT,
+ typename DerivedU,
+ typename DerivedS,
+ typename DerivedV>
+ IGL_INLINE void polar_svd(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedV> & V);
+ template <
+ typename DerivedA,
+ typename DerivedR,
+ typename DerivedT>
+ IGL_INLINE void polar_svd(
+ const Eigen::PlainObjectBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedT> & T);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "polar_svd.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/polar_svd3x3.cpp b/xs/src/igl/polar_svd3x3.cpp
new file mode 100644
index 000000000..c0d972aca
--- /dev/null
+++ b/xs/src/igl/polar_svd3x3.cpp
@@ -0,0 +1,113 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "polar_svd3x3.h"
+#include "svd3x3.h"
+#ifdef __SSE__
+# include "svd3x3_sse.h"
+#endif
+#ifdef __AVX__
+# include "svd3x3_avx.h"
+#endif
+
+template<typename Mat>
+IGL_INLINE void igl::polar_svd3x3(const Mat& A, Mat& R)
+{
+ // should be caught at compile time, but just to be 150% sure:
+ assert(A.rows() == 3 && A.cols() == 3);
+
+ Eigen::Matrix<typename Mat::Scalar, 3, 3> U, Vt;
+ Eigen::Matrix<typename Mat::Scalar, 3, 1> S;
+ svd3x3(A, U, S, Vt);
+ R = U * Vt.transpose();
+}
+
+#ifdef __SSE__
+template<typename T>
+IGL_INLINE void igl::polar_svd3x3_sse(const Eigen::Matrix<T, 3*4, 3>& A, Eigen::Matrix<T, 3*4, 3> &R)
+{
+ // should be caught at compile time, but just to be 150% sure:
+ assert(A.rows() == 3*4 && A.cols() == 3);
+
+ Eigen::Matrix<T, 3*4, 3> U, Vt;
+ Eigen::Matrix<T, 3*4, 1> S;
+ svd3x3_sse(A, U, S, Vt);
+
+ for (int k=0; k<4; k++)
+ {
+ R.block(3*k, 0, 3, 3) = U.block(3*k, 0, 3, 3) * Vt.block(3*k, 0, 3, 3).transpose();
+ }
+
+ //// test:
+ //for (int k=0; k<4; k++)
+ //{
+ // Eigen::Matrix3f Apart = A.block(3*k, 0, 3, 3);
+ // Eigen::Matrix3f Rpart;
+ // polar_svd3x3(Apart, Rpart);
+
+ // Eigen::Matrix3f Rpart_SSE = R.block(3*k, 0, 3, 3);
+ // Eigen::Matrix3f diff = Rpart - Rpart_SSE;
+ // float diffNorm = diff.norm();
+
+ // int hu = 1;
+ //}
+ //// eof test
+}
+#endif
+
+#ifdef __AVX__
+template<typename T>
+IGL_INLINE void igl::polar_svd3x3_avx(const Eigen::Matrix<T, 3*8, 3>& A, Eigen::Matrix<T, 3*8, 3> &R)
+{
+ // should be caught at compile time, but just to be 150% sure:
+ assert(A.rows() == 3*8 && A.cols() == 3);
+
+ Eigen::Matrix<T, 3*8, 3> U, Vt;
+ Eigen::Matrix<T, 3*8, 1> S;
+ svd3x3_avx(A, U, S, Vt);
+
+ for (int k=0; k<8; k++)
+ {
+ R.block(3*k, 0, 3, 3) = U.block(3*k, 0, 3, 3) * Vt.block(3*k, 0, 3, 3).transpose();
+ }
+
+ // test:
+ for (int k=0; k<8; k++)
+ {
+ Eigen::Matrix3f Apart = A.block(3*k, 0, 3, 3);
+ Eigen::Matrix3f Rpart;
+ polar_svd3x3(Apart, Rpart);
+
+ Eigen::Matrix3f Rpart_SSE = R.block(3*k, 0, 3, 3);
+ Eigen::Matrix3f diff = Rpart - Rpart_SSE;
+ float diffNorm = diff.norm();
+ if (std::abs(diffNorm) > 0.001)
+ {
+ printf("Huh: diffNorm = %15f (k = %i)\n", diffNorm, k);
+ }
+
+ // Unused
+ //int hu = 1;
+ }
+ // eof test
+}
+#endif
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::polar_svd3x3<Eigen::Matrix<double, 3, 3, 0, 3, 3> >(Eigen::Matrix<double, 3, 3, 0, 3, 3> const&, Eigen::Matrix<double, 3, 3, 0, 3, 3>&);
+template void igl::polar_svd3x3<Eigen::Matrix<float,3,3,0,3,3> >(Eigen::Matrix<float,3,3,0,3,3> const &,Eigen::Matrix<float,3,3,0,3,3> &);
+
+#ifdef __SSE__
+template void igl::polar_svd3x3_sse<float>(Eigen::Matrix<float, 12, 3, 0, 12, 3> const&, Eigen::Matrix<float, 12, 3, 0, 12, 3>&);
+#endif
+
+#ifdef __AVX__
+template void igl::polar_svd3x3_avx<float>(Eigen::Matrix<float, 24, 3, 0, 24, 3> const&, Eigen::Matrix<float, 24, 3, 0, 24, 3>&);
+#endif
+
+#endif
diff --git a/xs/src/igl/polar_svd3x3.h b/xs/src/igl/polar_svd3x3.h
new file mode 100644
index 000000000..a579774e0
--- /dev/null
+++ b/xs/src/igl/polar_svd3x3.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POLAR_SVD3X3_H
+#define IGL_POLAR_SVD3X3_H
+#include <Eigen/Core>
+#include "igl_inline.h"
+namespace igl
+{
+ // Computes the closest rotation to input matrix A using specialized 3x3 SVD
+ // singular value decomposition (WunderSVD3x3)
+ //
+ // Inputs:
+ // A 3 by 3 matrix to be decomposed
+ // Outputs:
+ // R 3 by 3 closest element in SO(3) (closeness in terms of Frobenius
+ // metric)
+ //
+ // This means that det(R) = 1. Technically it's not polar decomposition
+ // which guarantees positive semidefinite stretch factor (at the cost of
+ // having det(R) = -1). "• The orthogonal factors U and V will be true
+ // rotation matrices..." [McAdams, Selle, Tamstorf, Teran, Sefakis 2011]
+ //
+ template<typename Mat>
+ IGL_INLINE void polar_svd3x3(const Mat& A, Mat& R);
+ #ifdef __SSE__
+ template<typename T>
+ IGL_INLINE void polar_svd3x3_sse(const Eigen::Matrix<T, 3*4, 3>& A, Eigen::Matrix<T, 3*4, 3> &R);
+ #endif
+ #ifdef __AVX__
+ template<typename T>
+ IGL_INLINE void polar_svd3x3_avx(const Eigen::Matrix<T, 3*8, 3>& A, Eigen::Matrix<T, 3*8, 3> &R);
+ #endif
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "polar_svd3x3.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/polygon_mesh_to_triangle_mesh.cpp b/xs/src/igl/polygon_mesh_to_triangle_mesh.cpp
new file mode 100644
index 000000000..2ea43238b
--- /dev/null
+++ b/xs/src/igl/polygon_mesh_to_triangle_mesh.cpp
@@ -0,0 +1,76 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "polygon_mesh_to_triangle_mesh.h"
+#include "matrix_to_list.h"
+
+template <typename Index, typename DerivedF>
+IGL_INLINE void igl::polygon_mesh_to_triangle_mesh(
+ const std::vector<std::vector<Index> > & vF,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ using namespace std;
+ using namespace Eigen;
+ int m = 0;
+ // estimate of size
+ for(typename vector<vector<Index > >::const_iterator fit = vF.begin();
+ fit!=vF.end();
+ fit++)
+ {
+ if(fit->size() >= 3)
+ {
+ m += fit->size() - 2;
+ }
+ }
+ // Resize output
+ F.resize(m,3);
+ {
+ int k = 0;
+ for(typename vector<vector<Index > >::const_iterator fit = vF.begin();
+ fit!=vF.end();
+ fit++)
+ {
+ if(fit->size() >= 3)
+ {
+ typename vector<Index >::const_iterator cit = fit->begin();
+ cit++;
+ typename vector<Index >::const_iterator pit = cit++;
+ for(;
+ cit!=fit->end();
+ cit++,pit++)
+ {
+ F(k,0) = *(fit->begin());
+ F(k,1) = *pit;
+ F(k,2) = *cit;
+ k++;
+ }
+ }
+ }
+ assert(k==m);
+ }
+
+}
+
+template <typename DerivedP, typename DerivedF>
+IGL_INLINE void igl::polygon_mesh_to_triangle_mesh(
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ std::vector<std::vector<typename DerivedP::Scalar> > vP;
+ matrix_to_list(P,vP);
+ return polygon_mesh_to_triangle_mesh(vP,F);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::polygon_mesh_to_triangle_mesh<int, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::polygon_mesh_to_triangle_mesh<int, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::polygon_mesh_to_triangle_mesh<int, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::polygon_mesh_to_triangle_mesh<int, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/polygon_mesh_to_triangle_mesh.h b/xs/src/igl/polygon_mesh_to_triangle_mesh.h
new file mode 100644
index 000000000..7d8f16e82
--- /dev/null
+++ b/xs/src/igl/polygon_mesh_to_triangle_mesh.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_POLYGON_MESH_TO_TRIANGLE_MESH_H
+#define IGL_POLYGON_MESH_TO_TRIANGLE_MESH_H
+#include "igl_inline.h"
+
+#ifndef IGL_NO_EIGEN
+# include <Eigen/Core>
+#endif
+#include <vector>
+
+namespace igl
+{
+ // Triangulate a general polygonal mesh into a triangle mesh.
+ //
+ // Inputs:
+ // vF list of polygon index lists
+ // Outputs:
+ // F eigen int matrix #F by 3
+ //
+ // Example:
+ // vector<vector<double > > vV;
+ // vector<vector<int > > vF;
+ // read_triangle_mesh("poly.obj",vV,vF);
+ // MatrixXd V;
+ // MatrixXi F;
+ // list_to_matrix(vV,V);
+ // triangulate(vF,F);
+ template <typename Index, typename DerivedF>
+ IGL_INLINE void polygon_mesh_to_triangle_mesh(
+ const std::vector<std::vector<Index> > & vF,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ template <typename DerivedP, typename DerivedF>
+ IGL_INLINE void polygon_mesh_to_triangle_mesh(
+ const Eigen::PlainObjectBase<DerivedP>& P,
+ Eigen::PlainObjectBase<DerivedF>& F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "polygon_mesh_to_triangle_mesh.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/principal_curvature.cpp b/xs/src/igl/principal_curvature.cpp
new file mode 100644
index 000000000..5712130a0
--- /dev/null
+++ b/xs/src/igl/principal_curvature.cpp
@@ -0,0 +1,854 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "principal_curvature.h"
+#include <iostream>
+#include <fstream>
+#include <iomanip>
+#include <iostream>
+#include <queue>
+#include <list>
+#include <cmath>
+#include <limits>
+
+#include <Eigen/SparseCholesky>
+
+// Lib IGL includes
+#include <igl/adjacency_list.h>
+#include <igl/per_face_normals.h>
+#include <igl/per_vertex_normals.h>
+#include <igl/avg_edge_length.h>
+#include <igl/vertex_triangle_adjacency.h>
+
+typedef enum
+{
+ SPHERE_SEARCH,
+ K_RING_SEARCH
+} searchType;
+
+typedef enum
+{
+ AVERAGE,
+ PROJ_PLANE
+} normalType;
+
+class CurvatureCalculator
+{
+public:
+ /* Row number i represents the i-th vertex, whose columns are:
+ curv[i][0] : K2
+ curv[i][1] : K1
+ curvDir[i][0] : PD1
+ curvDir[i][1] : PD2
+ */
+ std::vector< std::vector<double> > curv;
+ std::vector< std::vector<Eigen::Vector3d> > curvDir;
+ bool curvatureComputed;
+ class Quadric
+ {
+ public:
+
+ IGL_INLINE Quadric ()
+ {
+ a() = b() = c() = d() = e() = 1.0;
+ }
+
+ IGL_INLINE Quadric(double av, double bv, double cv, double dv, double ev)
+ {
+ a() = av;
+ b() = bv;
+ c() = cv;
+ d() = dv;
+ e() = ev;
+ }
+
+ IGL_INLINE double& a() { return data[0];}
+ IGL_INLINE double& b() { return data[1];}
+ IGL_INLINE double& c() { return data[2];}
+ IGL_INLINE double& d() { return data[3];}
+ IGL_INLINE double& e() { return data[4];}
+
+ double data[5];
+
+ IGL_INLINE double evaluate(double u, double v)
+ {
+ return a()*u*u + b()*u*v + c()*v*v + d()*u + e()*v;
+ }
+
+ IGL_INLINE double du(double u, double v)
+ {
+ return 2.0*a()*u + b()*v + d();
+ }
+
+ IGL_INLINE double dv(double u, double v)
+ {
+ return 2.0*c()*v + b()*u + e();
+ }
+
+ IGL_INLINE double duv(double u, double v)
+ {
+ return b();
+ }
+
+ IGL_INLINE double duu(double u, double v)
+ {
+ return 2.0*a();
+ }
+
+ IGL_INLINE double dvv(double u, double v)
+ {
+ return 2.0*c();
+ }
+
+
+ IGL_INLINE static Quadric fit(const std::vector<Eigen::Vector3d> &VV)
+ {
+ assert(VV.size() >= 5);
+ if (VV.size() < 5)
+ {
+ std::cerr << "ASSERT FAILED! fit function requires at least 5 points: Only " << VV.size() << " were given." << std::endl;
+ exit(0);
+ }
+
+ Eigen::MatrixXd A(VV.size(),5);
+ Eigen::MatrixXd b(VV.size(),1);
+ Eigen::MatrixXd sol(5,1);
+
+ for(unsigned int c=0; c < VV.size(); ++c)
+ {
+ double u = VV[c][0];
+ double v = VV[c][1];
+ double n = VV[c][2];
+
+ A(c,0) = u*u;
+ A(c,1) = u*v;
+ A(c,2) = v*v;
+ A(c,3) = u;
+ A(c,4) = v;
+
+ b(c) = n;
+ }
+
+ sol=A.jacobiSvd(Eigen::ComputeThinU | Eigen::ComputeThinV).solve(b);
+
+ return Quadric(sol(0),sol(1),sol(2),sol(3),sol(4));
+ }
+ };
+
+public:
+
+ Eigen::MatrixXd vertices;
+ // Face list of current mesh (#F x 3) or (#F x 4)
+ // The i-th row contains the indices of the vertices that forms the i-th face in ccw order
+ Eigen::MatrixXi faces;
+
+ std::vector<std::vector<int> > vertex_to_vertices;
+ std::vector<std::vector<int> > vertex_to_faces;
+ std::vector<std::vector<int> > vertex_to_faces_index;
+ Eigen::MatrixXd face_normals;
+ Eigen::MatrixXd vertex_normals;
+
+ /* Size of the neighborhood */
+ double sphereRadius;
+ int kRing;
+
+ bool localMode; /* Use local mode */
+ bool projectionPlaneCheck; /* Check collected vertices on tangent plane */
+ bool montecarlo;
+ unsigned int montecarloN;
+
+ searchType st; /* Use either a sphere search or a k-ring search */
+ normalType nt;
+
+ double lastRadius;
+ double scaledRadius;
+ std::string lastMeshName;
+
+ /* Benchmark related variables */
+ bool expStep; /* True if we want the radius to increase exponentially */
+ int step; /* If expStep==false, by how much rhe radius increases on every step */
+ int maxSize; /* The maximum limit of the radius in the benchmark */
+
+ IGL_INLINE CurvatureCalculator();
+ IGL_INLINE void init(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F);
+
+ IGL_INLINE void finalEigenStuff(int, const std::vector<Eigen::Vector3d>&, Quadric&);
+ IGL_INLINE void fitQuadric(const Eigen::Vector3d&, const std::vector<Eigen::Vector3d>& ref, const std::vector<int>& , Quadric *);
+ IGL_INLINE void applyProjOnPlane(const Eigen::Vector3d&, const std::vector<int>&, std::vector<int>&);
+ IGL_INLINE void getSphere(const int, const double, std::vector<int>&, int min);
+ IGL_INLINE void getKRing(const int, const double,std::vector<int>&);
+ IGL_INLINE Eigen::Vector3d project(const Eigen::Vector3d&, const Eigen::Vector3d&, const Eigen::Vector3d&);
+ IGL_INLINE void computeReferenceFrame(int, const Eigen::Vector3d&, std::vector<Eigen::Vector3d>&);
+ IGL_INLINE void getAverageNormal(int, const std::vector<int>&, Eigen::Vector3d&);
+ IGL_INLINE void getProjPlane(int, const std::vector<int>&, Eigen::Vector3d&);
+ IGL_INLINE void applyMontecarlo(const std::vector<int>&,std::vector<int>*);
+ IGL_INLINE void computeCurvature();
+ IGL_INLINE void printCurvature(const std::string& outpath);
+ IGL_INLINE double getAverageEdge();
+
+ IGL_INLINE static int rotateForward (double *v0, double *v1, double *v2)
+ {
+ double t;
+
+ if (std::abs(*v2) >= std::abs(*v1) && std::abs(*v2) >= std::abs(*v0))
+ return 0;
+
+ t = *v0;
+ *v0 = *v2;
+ *v2 = *v1;
+ *v1 = t;
+
+ return 1 + rotateForward (v0, v1, v2);
+ }
+
+ IGL_INLINE static void rotateBackward (int nr, double *v0, double *v1, double *v2)
+ {
+ double t;
+
+ if (nr == 0)
+ return;
+
+ t = *v2;
+ *v2 = *v0;
+ *v0 = *v1;
+ *v1 = t;
+
+ rotateBackward (nr - 1, v0, v1, v2);
+ }
+
+ IGL_INLINE static Eigen::Vector3d chooseMax (Eigen::Vector3d n, Eigen::Vector3d abc, double ab)
+ {
+ int max_i;
+ double max_sp;
+ Eigen::Vector3d nt[8];
+
+ n.normalize ();
+ abc.normalize ();
+
+ max_sp = - std::numeric_limits<double>::max();
+
+ for (int i = 0; i < 4; ++i)
+ {
+ nt[i] = n;
+ if (ab > 0)
+ {
+ switch (i)
+ {
+ case 0:
+ break;
+
+ case 1:
+ nt[i][2] = -n[2];
+ break;
+
+ case 2:
+ nt[i][0] = -n[0];
+ nt[i][1] = -n[1];
+ break;
+
+ case 3:
+ nt[i][0] = -n[0];
+ nt[i][1] = -n[1];
+ nt[i][2] = -n[2];
+ break;
+ }
+ }
+ else
+ {
+ switch (i)
+ {
+ case 0:
+ nt[i][0] = -n[0];
+ break;
+
+ case 1:
+ nt[i][1] = -n[1];
+ break;
+
+ case 2:
+ nt[i][0] = -n[0];
+ nt[i][2] = -n[2];
+ break;
+
+ case 3:
+ nt[i][1] = -n[1];
+ nt[i][2] = -n[2];
+ break;
+ }
+ }
+
+ if (nt[i].dot(abc) > max_sp)
+ {
+ max_sp = nt[i].dot(abc);
+ max_i = i;
+ }
+ }
+ return nt[max_i];
+ }
+
+};
+
+class comparer
+{
+public:
+ IGL_INLINE bool operator() (const std::pair<int, double>& lhs, const std::pair<int, double>&rhs) const
+ {
+ return lhs.second>rhs.second;
+ }
+};
+
+IGL_INLINE CurvatureCalculator::CurvatureCalculator()
+{
+ this->localMode=true;
+ this->projectionPlaneCheck=true;
+ this->sphereRadius=5;
+ this->st=SPHERE_SEARCH;
+ this->nt=AVERAGE;
+ this->montecarlo=false;
+ this->montecarloN=0;
+ this->kRing=3;
+ this->curvatureComputed=false;
+ this->expStep=true;
+}
+
+IGL_INLINE void CurvatureCalculator::init(const Eigen::MatrixXd& V, const Eigen::MatrixXi& F)
+{
+ // Normalize vertices
+ vertices = V;
+
+// vertices = vertices.array() - vertices.minCoeff();
+// vertices = vertices.array() / vertices.maxCoeff();
+// vertices = vertices.array() * (1.0/igl::avg_edge_length(V,F));
+
+ faces = F;
+ igl::adjacency_list(F, vertex_to_vertices);
+ igl::vertex_triangle_adjacency(V, F, vertex_to_faces, vertex_to_faces_index);
+ igl::per_face_normals(V, F, face_normals);
+ igl::per_vertex_normals(V, F, face_normals, vertex_normals);
+}
+
+IGL_INLINE void CurvatureCalculator::fitQuadric(const Eigen::Vector3d& v, const std::vector<Eigen::Vector3d>& ref, const std::vector<int>& vv, Quadric *q)
+{
+ std::vector<Eigen::Vector3d> points;
+ points.reserve (vv.size());
+
+ for (unsigned int i = 0; i < vv.size(); ++i) {
+
+ Eigen::Vector3d cp = vertices.row(vv[i]);
+
+ // vtang non e` il v tangente!!!
+ Eigen::Vector3d vTang = cp - v;
+
+ double x = vTang.dot(ref[0]);
+ double y = vTang.dot(ref[1]);
+ double z = vTang.dot(ref[2]);
+ points.push_back(Eigen::Vector3d (x,y,z));
+ }
+ if (points.size() < 5)
+ {
+ std::cerr << "ASSERT FAILED! fit function requires at least 5 points: Only " << points.size() << " were given." << std::endl;
+ *q = Quadric(0,0,0,0,0);
+ }
+ else
+ {
+ *q = Quadric::fit (points);
+ }
+}
+
+IGL_INLINE void CurvatureCalculator::finalEigenStuff(int i, const std::vector<Eigen::Vector3d>& ref, Quadric& q)
+{
+
+ const double a = q.a();
+ const double b = q.b();
+ const double c = q.c();
+ const double d = q.d();
+ const double e = q.e();
+
+// if (fabs(a) < 10e-8 || fabs(b) < 10e-8)
+// {
+// std::cout << "Degenerate quadric: " << i << std::endl;
+// }
+
+ double E = 1.0 + d*d;
+ double F = d*e;
+ double G = 1.0 + e*e;
+
+ Eigen::Vector3d n = Eigen::Vector3d(-d,-e,1.0).normalized();
+
+ double L = 2.0 * a * n[2];
+ double M = b * n[2];
+ double N = 2 * c * n[2];
+
+
+ // ----------------- Eigen stuff
+ Eigen::Matrix2d m;
+ m << L*G - M*F, M*E-L*F, M*E-L*F, N*E-M*F;
+ m = m / (E*G-F*F);
+ Eigen::SelfAdjointEigenSolver<Eigen::Matrix2d> eig(m);
+
+ Eigen::Vector2d c_val = eig.eigenvalues();
+ Eigen::Matrix2d c_vec = eig.eigenvectors();
+
+ // std::cerr << "c_val:" << c_val << std::endl;
+ // std::cerr << "c_vec:" << c_vec << std::endl;
+
+ // std::cerr << "c_vec:" << c_vec(0) << " " << c_vec(1) << std::endl;
+
+ c_val = -c_val;
+
+ Eigen::Vector3d v1, v2;
+ v1[0] = c_vec(0);
+ v1[1] = c_vec(1);
+ v1[2] = 0; //d * v1[0] + e * v1[1];
+
+ v2[0] = c_vec(2);
+ v2[1] = c_vec(3);
+ v2[2] = 0; //d * v2[0] + e * v2[1];
+
+
+ // v1 = v1.normalized();
+ // v2 = v2.normalized();
+
+ Eigen::Vector3d v1global = ref[0] * v1[0] + ref[1] * v1[1] + ref[2] * v1[2];
+ Eigen::Vector3d v2global = ref[0] * v2[0] + ref[1] * v2[1] + ref[2] * v2[2];
+
+ v1global.normalize();
+ v2global.normalize();
+
+ v1global *= c_val(0);
+ v2global *= c_val(1);
+
+ if (c_val[0] > c_val[1])
+ {
+ curv[i]=std::vector<double>(2);
+ curv[i][0]=c_val(1);
+ curv[i][1]=c_val(0);
+ curvDir[i]=std::vector<Eigen::Vector3d>(2);
+ curvDir[i][0]=v2global;
+ curvDir[i][1]=v1global;
+ }
+ else
+ {
+ curv[i]=std::vector<double>(2);
+ curv[i][0]=c_val(0);
+ curv[i][1]=c_val(1);
+ curvDir[i]=std::vector<Eigen::Vector3d>(2);
+ curvDir[i][0]=v1global;
+ curvDir[i][1]=v2global;
+ }
+ // ---- end Eigen stuff
+}
+
+IGL_INLINE void CurvatureCalculator::getKRing(const int start, const double r, std::vector<int>&vv)
+{
+ int bufsize=vertices.rows();
+ vv.reserve(bufsize);
+ std::list<std::pair<int,int> > queue;
+ bool* visited = (bool*)calloc(bufsize,sizeof(bool));
+ queue.push_back(std::pair<int,int>(start,0));
+ visited[start]=true;
+ while (!queue.empty())
+ {
+ int toVisit=queue.front().first;
+ int distance=queue.front().second;
+ queue.pop_front();
+ vv.push_back(toVisit);
+ if (distance<(int)r)
+ {
+ for (unsigned int i=0; i<vertex_to_vertices[toVisit].size(); ++i)
+ {
+ int neighbor=vertex_to_vertices[toVisit][i];
+ if (!visited[neighbor])
+ {
+ queue.push_back(std::pair<int,int> (neighbor,distance+1));
+ visited[neighbor]=true;
+ }
+ }
+ }
+ }
+ free(visited);
+ return;
+}
+
+
+IGL_INLINE void CurvatureCalculator::getSphere(const int start, const double r, std::vector<int> &vv, int min)
+{
+ int bufsize=vertices.rows();
+ vv.reserve(bufsize);
+ std::list<int>* queue= new std::list<int>();
+ bool* visited = (bool*)calloc(bufsize,sizeof(bool));
+ queue->push_back(start);
+ visited[start]=true;
+ Eigen::Vector3d me=vertices.row(start);
+ std::priority_queue<std::pair<int, double>, std::vector<std::pair<int, double> >, comparer >* extra_candidates= new std::priority_queue<std::pair<int, double>, std::vector<std::pair<int, double> >, comparer >();
+ while (!queue->empty())
+ {
+ int toVisit=queue->front();
+ queue->pop_front();
+ vv.push_back(toVisit);
+ for (unsigned int i=0; i<vertex_to_vertices[toVisit].size(); ++i)
+ {
+ int neighbor=vertex_to_vertices[toVisit][i];
+ if (!visited[neighbor])
+ {
+ Eigen::Vector3d neigh=vertices.row(neighbor);
+ double distance=(me-neigh).norm();
+ if (distance<r)
+ queue->push_back(neighbor);
+ else if ((int)vv.size()<min)
+ extra_candidates->push(std::pair<int,double>(neighbor,distance));
+ visited[neighbor]=true;
+ }
+ }
+ }
+ while (!extra_candidates->empty() && (int)vv.size()<min)
+ {
+ std::pair<int, double> cand=extra_candidates->top();
+ extra_candidates->pop();
+ vv.push_back(cand.first);
+ for (unsigned int i=0; i<vertex_to_vertices[cand.first].size(); ++i)
+ {
+ int neighbor=vertex_to_vertices[cand.first][i];
+ if (!visited[neighbor])
+ {
+ Eigen::Vector3d neigh=vertices.row(neighbor);
+ double distance=(me-neigh).norm();
+ extra_candidates->push(std::pair<int,double>(neighbor,distance));
+ visited[neighbor]=true;
+ }
+ }
+ }
+ free(extra_candidates);
+ free(queue);
+ free(visited);
+}
+
+IGL_INLINE Eigen::Vector3d CurvatureCalculator::project(const Eigen::Vector3d& v, const Eigen::Vector3d& vp, const Eigen::Vector3d& ppn)
+{
+ return (vp - (ppn * ((vp - v).dot(ppn))));
+}
+
+IGL_INLINE void CurvatureCalculator::computeReferenceFrame(int i, const Eigen::Vector3d& normal, std::vector<Eigen::Vector3d>& ref )
+{
+
+ Eigen::Vector3d longest_v=Eigen::Vector3d(vertices.row(vertex_to_vertices[i][0]));
+
+ longest_v=(project(vertices.row(i),longest_v,normal)-Eigen::Vector3d(vertices.row(i))).normalized();
+
+ /* L'ultimo asse si ottiene come prodotto vettoriale tra i due
+ * calcolati */
+ Eigen::Vector3d y_axis=(normal.cross(longest_v)).normalized();
+ ref[0]=longest_v;
+ ref[1]=y_axis;
+ ref[2]=normal;
+}
+
+IGL_INLINE void CurvatureCalculator::getAverageNormal(int j, const std::vector<int>& vv, Eigen::Vector3d& normal)
+{
+ normal=(vertex_normals.row(j)).normalized();
+ if (localMode)
+ return;
+
+ for (unsigned int i=0; i<vv.size(); ++i)
+ {
+ normal+=vertex_normals.row(vv[i]).normalized();
+ }
+ normal.normalize();
+}
+
+IGL_INLINE void CurvatureCalculator::getProjPlane(int j, const std::vector<int>& vv, Eigen::Vector3d& ppn)
+{
+ int nr;
+ double a, b, c;
+ double nx, ny, nz;
+ double abcq;
+
+ a = b = c = 0;
+
+ if (localMode)
+ {
+ for (unsigned int i=0; i<vertex_to_faces.at(j).size(); ++i)
+ {
+ Eigen::Vector3d faceNormal=face_normals.row(vertex_to_faces.at(j).at(i));
+ a += faceNormal[0];
+ b += faceNormal[1];
+ c += faceNormal[2];
+ }
+ }
+ else
+ {
+ for (unsigned int i=0; i<vv.size(); ++i)
+ {
+ a+= vertex_normals.row(vv[i])[0];
+ b+= vertex_normals.row(vv[i])[1];
+ c+= vertex_normals.row(vv[i])[2];
+ }
+ }
+ nr = rotateForward (&a, &b, &c);
+ abcq = a*a + b*b + c*c;
+ nx = sqrt (a*a / abcq);
+ ny = sqrt (b*b / abcq);
+ nz = sqrt (1 - nx*nx - ny*ny);
+ rotateBackward (nr, &a, &b, &c);
+ rotateBackward (nr, &nx, &ny, &nz);
+
+ ppn = chooseMax (Eigen::Vector3d(nx, ny, nz), Eigen::Vector3d (a, b, c), a * b);
+ ppn.normalize();
+}
+
+
+IGL_INLINE double CurvatureCalculator::getAverageEdge()
+{
+ double sum = 0;
+ int count = 0;
+
+ for (int i = 0; i<faces.rows(); ++i)
+ {
+ for (short unsigned j=0; j<3; ++j)
+ {
+ Eigen::Vector3d p1=vertices.row(faces.row(i)[j]);
+ Eigen::Vector3d p2=vertices.row(faces.row(i)[(j+1)%3]);
+
+ double l = (p1-p2).norm();
+
+ sum+=l;
+ ++count;
+ }
+ }
+
+ return (sum/(double)count);
+}
+
+
+IGL_INLINE void CurvatureCalculator::applyProjOnPlane(const Eigen::Vector3d& ppn, const std::vector<int>& vin, std::vector<int> &vout)
+{
+ for (std::vector<int>::const_iterator vpi = vin.begin(); vpi != vin.end(); ++vpi)
+ if (vertex_normals.row(*vpi) * ppn > 0.0)
+ vout.push_back(*vpi);
+}
+
+IGL_INLINE void CurvatureCalculator::applyMontecarlo(const std::vector<int>& vin, std::vector<int> *vout)
+{
+ if (montecarloN >= vin.size ())
+ {
+ *vout = vin;
+ return;
+ }
+
+ float p = ((float) montecarloN) / (float) vin.size();
+ for (std::vector<int>::const_iterator vpi = vin.begin(); vpi != vin.end(); ++vpi)
+ {
+ float r;
+ if ((r = ((float)rand () / RAND_MAX)) < p)
+ {
+ vout->push_back(*vpi);
+ }
+ }
+}
+
+IGL_INLINE void CurvatureCalculator::computeCurvature()
+{
+ //CHECK che esista la mesh
+ const size_t vertices_count=vertices.rows();
+
+ if (vertices_count ==0)
+ return;
+
+ curvDir=std::vector< std::vector<Eigen::Vector3d> >(vertices_count);
+ curv=std::vector<std::vector<double> >(vertices_count);
+
+
+
+ scaledRadius=getAverageEdge()*sphereRadius;
+
+ std::vector<int> vv;
+ std::vector<int> vvtmp;
+ Eigen::Vector3d normal;
+
+ //double time_spent;
+ //double searchtime=0, ref_time=0, fit_time=0, final_time=0;
+
+ for (size_t i=0; i<vertices_count; ++i)
+ {
+ vv.clear();
+ vvtmp.clear();
+ Eigen::Vector3d me=vertices.row(i);
+ switch (st)
+ {
+ case SPHERE_SEARCH:
+ getSphere(i,scaledRadius,vv,6);
+ break;
+ case K_RING_SEARCH:
+ getKRing(i,kRing,vv);
+ break;
+ default:
+ fprintf(stderr,"Error: search type not recognized");
+ return;
+ }
+
+ if (vv.size()<6)
+ {
+ std::cerr << "Could not compute curvature of radius " << scaledRadius << std::endl;
+ return;
+ }
+
+
+ if (projectionPlaneCheck)
+ {
+ vvtmp.reserve (vv.size ());
+ applyProjOnPlane (vertex_normals.row(i), vv, vvtmp);
+ if (vvtmp.size() >= 6 && vvtmp.size()<vv.size())
+ vv = vvtmp;
+ }
+
+
+ switch (nt)
+ {
+ case AVERAGE:
+ getAverageNormal(i,vv,normal);
+ break;
+ case PROJ_PLANE:
+ getProjPlane(i,vv,normal);
+ break;
+ default:
+ fprintf(stderr,"Error: normal type not recognized");
+ return;
+ }
+ if (vv.size()<6)
+ {
+ std::cerr << "Could not compute curvature of radius " << scaledRadius << std::endl;
+ return;
+ }
+ if (montecarlo)
+ {
+ if(montecarloN<6)
+ break;
+ vvtmp.reserve(vv.size());
+ applyMontecarlo(vv,&vvtmp);
+ vv=vvtmp;
+ }
+
+ if (vv.size()<6)
+ return;
+ std::vector<Eigen::Vector3d> ref(3);
+ computeReferenceFrame(i,normal,ref);
+
+ Quadric q;
+ fitQuadric (me, ref, vv, &q);
+ finalEigenStuff(i,ref,q);
+ }
+
+ lastRadius=sphereRadius;
+ curvatureComputed=true;
+}
+
+IGL_INLINE void CurvatureCalculator::printCurvature(const std::string& outpath)
+{
+ using namespace std;
+ if (!curvatureComputed)
+ return;
+
+ std::ofstream of;
+ of.open(outpath.c_str());
+
+ if (!of)
+ {
+ fprintf(stderr, "Error: could not open output file %s\n", outpath.c_str());
+ return;
+ }
+
+ int vertices_count=vertices.rows();
+ of << vertices_count << endl;
+ for (int i=0; i<vertices_count; ++i)
+ {
+ of << curv[i][0] << " " << curv[i][1] << " " << curvDir[i][0][0] << " " << curvDir[i][0][1] << " " << curvDir[i][0][2] << " " <<
+ curvDir[i][1][0] << " " << curvDir[i][1][1] << " " << curvDir[i][1][2] << endl;
+ }
+
+ of.close();
+
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedPD1,
+ typename DerivedPD2,
+ typename DerivedPV1,
+ typename DerivedPV2>
+IGL_INLINE void igl::principal_curvature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedPD1>& PD1,
+ Eigen::PlainObjectBase<DerivedPD2>& PD2,
+ Eigen::PlainObjectBase<DerivedPV1>& PV1,
+ Eigen::PlainObjectBase<DerivedPV2>& PV2,
+ unsigned radius,
+ bool useKring)
+{
+ if (radius < 2)
+ {
+ radius = 2;
+ std::cout << "WARNING: igl::principal_curvature needs a radius >= 2, fixing it to 2." << std::endl;
+ }
+
+ // Preallocate memory
+ PD1.resize(V.rows(),3);
+ PD2.resize(V.rows(),3);
+
+ // Preallocate memory
+ PV1.resize(V.rows(),1);
+ PV2.resize(V.rows(),1);
+
+ // Precomputation
+ CurvatureCalculator cc;
+ cc.init(V.template cast<double>(),F.template cast<int>());
+ cc.sphereRadius = radius;
+
+ if (useKring)
+ {
+ cc.kRing = radius;
+ cc.st = K_RING_SEARCH;
+ }
+
+ // Compute
+ cc.computeCurvature();
+
+ // Copy it back
+ for (unsigned i=0; i<V.rows(); ++i)
+ {
+ PD1.row(i) << cc.curvDir[i][0][0], cc.curvDir[i][0][1], cc.curvDir[i][0][2];
+ PD2.row(i) << cc.curvDir[i][1][0], cc.curvDir[i][1][1], cc.curvDir[i][1][2];
+ PD1.row(i).normalize();
+ PD2.row(i).normalize();
+
+ if (std::isnan(PD1(i,0)) || std::isnan(PD1(i,1)) || std::isnan(PD1(i,2)) || std::isnan(PD2(i,0)) || std::isnan(PD2(i,1)) || std::isnan(PD2(i,2)))
+ {
+ PD1.row(i) << 0,0,0;
+ PD2.row(i) << 0,0,0;
+ }
+
+ PV1(i) = cc.curv[i][0];
+ PV2(i) = cc.curv[i][1];
+
+ if (PD1.row(i) * PD2.row(i).transpose() > 10e-6)
+ {
+ std::cerr << "PRINCIPAL_CURVATURE: Something is wrong with vertex: " << i << std::endl;
+ PD1.row(i) *= 0;
+ PD2.row(i) *= 0;
+ }
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::principal_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, unsigned int, bool);
+template void igl::principal_curvature<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, unsigned int, bool);
+template void igl::principal_curvature<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, unsigned int, bool);
+#endif
diff --git a/xs/src/igl/principal_curvature.h b/xs/src/igl/principal_curvature.h
new file mode 100644
index 000000000..958e58418
--- /dev/null
+++ b/xs/src/igl/principal_curvature.h
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PRINCIPAL_CURVATURE_H
+#define IGL_PRINCIPAL_CURVATURE_H
+
+
+#include <Eigen/Geometry>
+#include <Eigen/Dense>
+
+#include "igl_inline.h"
+//#include <igl/cotmatrix.h>
+//#include <igl/writeOFF.h>
+
+
+
+namespace igl
+{
+
+ // Compute the principal curvature directions and magnitude of the given triangle mesh
+ // DerivedV derived from vertex positions matrix type: i.e. MatrixXd
+ // DerivedF derived from face indices matrix type: i.e. MatrixXi
+ // Inputs:
+ // V eigen matrix #V by 3
+ // F #F by 3 list of mesh faces (must be triangles)
+ // radius controls the size of the neighbourhood used, 1 = average edge length
+ //
+ // Outputs:
+ // PD1 #V by 3 maximal curvature direction for each vertex.
+ // PD2 #V by 3 minimal curvature direction for each vertex.
+ // PV1 #V by 1 maximal curvature value for each vertex.
+ // PV2 #V by 1 minimal curvature value for each vertex.
+ //
+ // See also: average_onto_faces, average_onto_vertices
+ //
+ // This function has been developed by: Nikolas De Giorgis, Luigi Rocca and Enrico Puppo.
+ // The algorithm is based on:
+ // Efficient Multi-scale Curvature and Crease Estimation
+ // Daniele Panozzo, Enrico Puppo, Luigi Rocca
+ // GraVisMa, 2010
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedPD1,
+ typename DerivedPD2,
+ typename DerivedPV1,
+ typename DerivedPV2>
+IGL_INLINE void principal_curvature(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedPD1>& PD1,
+ Eigen::PlainObjectBase<DerivedPD2>& PD2,
+ Eigen::PlainObjectBase<DerivedPV1>& PV1,
+ Eigen::PlainObjectBase<DerivedPV2>& PV2,
+ unsigned radius = 5,
+ bool useKring = true);
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "principal_curvature.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/print_ijv.cpp b/xs/src/igl/print_ijv.cpp
new file mode 100644
index 000000000..38b1dd22a
--- /dev/null
+++ b/xs/src/igl/print_ijv.cpp
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "print_ijv.h"
+
+#include "find.h"
+#include <iostream>
+
+template <typename T>
+IGL_INLINE void igl::print_ijv(
+ const Eigen::SparseMatrix<T>& X,
+ const int offset)
+{
+ Eigen::Matrix<int,Eigen::Dynamic,1> I;
+ Eigen::Matrix<int,Eigen::Dynamic,1> J;
+ Eigen::Matrix<T,Eigen::Dynamic,1> V;
+ igl::find(X,I,J,V);
+ // Concatenate I,J,V
+ Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> IJV(I.size(),3);
+ IJV.col(0) = I.cast<T>();
+ IJV.col(1) = J.cast<T>();
+ IJV.col(2) = V;
+ // Offset
+ if(offset != 0)
+ {
+ IJV.col(0).array() += offset;
+ IJV.col(1).array() += offset;
+ }
+ std::cout<<IJV;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::print_ijv<double>(Eigen::SparseMatrix<double, 0, int> const&, int);
+#endif
diff --git a/xs/src/igl/print_ijv.h b/xs/src/igl/print_ijv.h
new file mode 100644
index 000000000..e45c1a76c
--- /dev/null
+++ b/xs/src/igl/print_ijv.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PRINT_IJV_H
+#define IGL_PRINT_IJV_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Prints a 3 column matrix representing [I,J,V] = find(X). That is, each
+ // row is the row index, column index and value for each non zero entry. Each
+ // row is printed on a new line
+ //
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Input:
+ // X m by n matrix whose entries are to be sorted
+ // offset optional offset for I and J indices {0}
+ template <typename T>
+ IGL_INLINE void print_ijv(
+ const Eigen::SparseMatrix<T>& X,
+ const int offset=0);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "print_ijv.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/print_vector.cpp b/xs/src/igl/print_vector.cpp
new file mode 100644
index 000000000..b47753216
--- /dev/null
+++ b/xs/src/igl/print_vector.cpp
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "print_vector.h"
+#include <iostream>
+#include <vector>
+
+
+template <typename T>
+IGL_INLINE void igl::print_vector( std::vector<T>& v)
+{
+ using namespace std;
+ for (int i=0; i<v.size(); ++i)
+ std::cerr << v[i] << " ";
+ std::cerr << std::endl;
+}
+
+template <typename T>
+IGL_INLINE void igl::print_vector( std::vector< std::vector<T> >& v)
+{
+ using namespace std;
+ for (int i=0; i<v.size(); ++i)
+ {
+ std::cerr << i << ": ";
+ for (int j=0; j<v[i].size(); ++j)
+ std::cerr << v[i][j] << " ";
+ std::cerr << std::endl;
+ }
+}
+
+
+template <typename T>
+IGL_INLINE void igl::print_vector( std::vector< std::vector< std::vector<T> > >& v)
+{
+ using namespace std;
+ for (int m=0; m<v.size(); ++m)
+ {
+ std::cerr << "Matrix " << m << std::endl;
+
+ for (int i=0; i<v[m].size(); ++i)
+ {
+ std::cerr << i << ": ";
+ for (int j=0; j<v[m][i].size(); ++j)
+ std::cerr << v[m][i][j] << " ";
+ std::cerr << std::endl;
+ }
+
+ std::cerr << "---- end " << m << std::endl;
+
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/print_vector.h b/xs/src/igl/print_vector.h
new file mode 100644
index 000000000..ab2dd018c
--- /dev/null
+++ b/xs/src/igl/print_vector.h
@@ -0,0 +1,29 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PRINT_VECTOR_H
+#define IGL_PRINT_VECTOR_H
+#include "igl_inline.h"
+
+#include <vector>
+namespace igl
+{
+ // Not clear what these are supposed to be doing. Currently they print
+ // vectors to standard error...
+ template <typename T>
+ IGL_INLINE void print_vector( std::vector<T>& v);
+ template <typename T>
+ IGL_INLINE void print_vector( std::vector< std::vector<T> >& v);
+ template <typename T>
+ IGL_INLINE void print_vector(std::vector< std::vector< std::vector<T> > >& v);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "print_vector.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/procrustes.cpp b/xs/src/igl/procrustes.cpp
new file mode 100644
index 000000000..659eea340
--- /dev/null
+++ b/xs/src/igl/procrustes.cpp
@@ -0,0 +1,140 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "procrustes.h"
+#include "polar_svd.h"
+#include "polar_dec.h"
+
+template <
+ typename DerivedX,
+ typename DerivedY,
+ typename Scalar,
+ typename DerivedR,
+ typename DerivedT>
+IGL_INLINE void igl::procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ bool includeScaling,
+ bool includeReflections,
+ Scalar& scale,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedT>& t)
+{
+ using namespace Eigen;
+ assert (X.rows() == Y.rows() && "Same number of points");
+ assert(X.cols() == Y.cols() && "Points have same dimensions");
+
+ // Center data
+ const VectorXd Xmean = X.colwise().mean();
+ const VectorXd Ymean = Y.colwise().mean();
+ MatrixXd XC = X.rowwise() - Xmean.transpose();
+ MatrixXd YC = Y.rowwise() - Ymean.transpose();
+
+ // Scale
+ scale = 1.;
+ if (includeScaling)
+ {
+ double scaleX = XC.norm() / XC.rows();
+ double scaleY = YC.norm() / YC.rows();
+ scale = scaleY/scaleX;
+ XC *= scale;
+ assert (std::abs(XC.norm() / XC.rows() - scaleY) < 1e-8);
+ }
+
+ // Rotation
+ MatrixXd S = XC.transpose() * YC;
+ MatrixXd T;
+ if (includeReflections)
+ {
+ polar_dec(S,R,T);
+ }else
+ {
+ polar_svd(S,R,T);
+ }
+// R.transposeInPlace();
+
+ // Translation
+ t = Ymean - scale*R.transpose()*Xmean;
+}
+
+
+template <
+ typename DerivedX,
+ typename DerivedY,
+ typename Scalar,
+ int DIM,
+ int TType>
+IGL_INLINE void igl::procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ bool includeScaling,
+ bool includeReflections,
+ Eigen::Transform<Scalar,DIM,TType>& T)
+{
+ using namespace Eigen;
+ double scale;
+ MatrixXd R;
+ VectorXd t;
+ procrustes(X,Y,includeScaling,includeReflections,scale,R,t);
+
+ // Combine
+ T = Translation<Scalar,DIM>(t) * R * Scaling(scale);
+}
+
+template <
+ typename DerivedX,
+ typename DerivedY,
+ typename DerivedR,
+ typename DerivedT>
+IGL_INLINE void igl::procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ bool includeScaling,
+ bool includeReflections,
+ Eigen::PlainObjectBase<DerivedR>& S,
+ Eigen::PlainObjectBase<DerivedT>& t)
+{
+ double scale;
+ procrustes(X,Y,includeScaling,includeReflections,scale,S,t);
+ S *= scale;
+}
+
+template <
+ typename DerivedX,
+ typename DerivedY,
+ typename DerivedR,
+ typename DerivedT>
+IGL_INLINE void igl::procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedT>& t)
+{
+ procrustes(X,Y,false,false,R,t);
+}
+
+template <
+ typename DerivedX,
+ typename DerivedY,
+ typename Scalar,
+ typename DerivedT>
+IGL_INLINE void igl::procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::Rotation2D<Scalar>& R,
+ Eigen::PlainObjectBase<DerivedT>& t)
+{
+ using namespace Eigen;
+ assert (X.cols() == 2 && Y.cols() == 2 && "Points must have dimension 2");
+ Matrix2d Rmat;
+ procrustes(X,Y,false,false,Rmat,t);
+ R.fromRotationMatrix(Rmat);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::procrustes<Eigen::Matrix<double, 3, 2, 0, 3, 2>, Eigen::Matrix<double, 3, 2, 0, 3, 2>, double, Eigen::Matrix<double, 2, 2, 0, 2, 2>, Eigen::Matrix<double, 2, 1, 0, 2, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 2, 0, 3, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 2, 0, 3, 2> > const&, bool, bool, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 2, 0, 2, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 2, 1, 0, 2, 1> >&);
+#endif
diff --git a/xs/src/igl/procrustes.h b/xs/src/igl/procrustes.h
new file mode 100644
index 000000000..5ce00db49
--- /dev/null
+++ b/xs/src/igl/procrustes.h
@@ -0,0 +1,137 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Stefan Brugger <stefanbrugger@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PROCRUSTES_H
+#define IGL_PROCRUSTES_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Geometry>
+
+namespace igl
+{
+ // Solve Procrustes problem in d dimensions. Given two point sets X,Y in R^d
+ // find best scale s, orthogonal R and translation t s.t. |s*X*R + t - Y|^2
+ // is minimized.
+ //
+ // Templates:
+ // DerivedV point type
+ // Scalar scalar type
+ // DerivedR type of R
+ // DerivedT type of t
+ // Inputs:
+ // X #V by DIM first list of points
+ // Y #V by DIM second list of points
+ // includeScaling if scaling should be allowed
+ // includeReflections if R is allowed to be a reflection
+ // Outputs:
+ // scale scaling
+ // R orthogonal matrix
+ // t translation
+ //
+ // Example:
+ // MatrixXd X, Y; (containing 3d points as rows)
+ // double scale;
+ // MatrixXd R;
+ // VectorXd t;
+ // igl::procrustes(X,Y,true,false,scale,R,t);
+ // R *= scale;
+ // MatrixXd Xprime = (X * R).rowwise() + t.transpose();
+ //
+ template <
+ typename DerivedX,
+ typename DerivedY,
+ typename Scalar,
+ typename DerivedR,
+ typename DerivedT>
+ IGL_INLINE void procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ bool includeScaling,
+ bool includeReflections,
+ Scalar& scale,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedT>& t);
+ // Same as above but returns Eigen transformation object.
+ //
+ // Templates:
+ // DerivedV point type
+ // Scalar scalar type
+ // DIM point dimension
+ // TType type of transformation
+ // (Isometry,Affine,AffineCompact,Projective)
+ // Inputs:
+ // X #V by DIM first list of points
+ // Y #V by DIM second list of points
+ // includeScaling if scaling should be allowed
+ // includeReflections if R is allowed to be a reflection
+ // Outputs:
+ // T transformation that minimizes error
+ //
+ // Example:
+ // MatrixXd X, Y; (containing 3d points as rows)
+ // AffineCompact3d T;
+ // igl::procrustes(X,Y,true,false,T);
+ // MatrixXd Xprime = (X * T.linear()).rowwise() + T.translation().transpose();
+ template <
+ typename DerivedX,
+ typename DerivedY,
+ typename Scalar,
+ int DIM,
+ int TType>
+ IGL_INLINE void procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ bool includeScaling,
+ bool includeReflections,
+ Eigen::Transform<Scalar,DIM,TType>& T);
+
+
+ // Convenient wrapper that returns S=scale*R instead of scale and R separately
+ template <
+ typename DerivedX,
+ typename DerivedY,
+ typename DerivedR,
+ typename DerivedT>
+ IGL_INLINE void procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ bool includeScaling,
+ bool includeReflections,
+ Eigen::PlainObjectBase<DerivedR>& S,
+ Eigen::PlainObjectBase<DerivedT>& t);
+
+ // Convenient wrapper for rigid case (no scaling, no reflections)
+ template <
+ typename DerivedX,
+ typename DerivedY,
+ typename DerivedR,
+ typename DerivedT>
+ IGL_INLINE void procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedR>& R,
+ Eigen::PlainObjectBase<DerivedT>& t);
+
+ // Convenient wrapper for 2D case.
+ template <
+ typename DerivedX,
+ typename DerivedY,
+ typename Scalar,
+ typename DerivedT>
+ IGL_INLINE void procrustes(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ const Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::Rotation2D<Scalar>& R,
+ Eigen::PlainObjectBase<DerivedT>& t);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+ #include "procrustes.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/project.cpp b/xs/src/igl/project.cpp
new file mode 100644
index 000000000..e57004f3c
--- /dev/null
+++ b/xs/src/igl/project.cpp
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "project.h"
+
+template <typename Scalar>
+Eigen::Matrix<Scalar,3,1> igl::project(
+ const Eigen::Matrix<Scalar,3,1>& obj,
+ const Eigen::Matrix<Scalar,4,4>& model,
+ const Eigen::Matrix<Scalar,4,4>& proj,
+ const Eigen::Matrix<Scalar,4,1>& viewport)
+{
+ Eigen::Matrix<Scalar,4,1> tmp;
+ tmp << obj,1;
+
+ tmp = model * tmp;
+
+ tmp = proj * tmp;
+
+ tmp = tmp.array() / tmp(3);
+ tmp = tmp.array() * 0.5f + 0.5f;
+ tmp(0) = tmp(0) * viewport(2) + viewport(0);
+ tmp(1) = tmp(1) * viewport(3) + viewport(1);
+
+ return tmp.head(3);
+}
+
+template <typename DerivedV, typename DerivedM, typename DerivedN, typename DerivedO, typename DerivedP>
+IGL_INLINE void igl::project(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedM>& model,
+ const Eigen::MatrixBase<DerivedN>& proj,
+ const Eigen::MatrixBase<DerivedO>& viewport,
+ Eigen::PlainObjectBase<DerivedP> & P)
+{
+ typedef typename DerivedP::Scalar PScalar;
+ Eigen::Matrix<PScalar,DerivedV::RowsAtCompileTime,4> HV(V.rows(),4);
+ HV.leftCols(3) = V.template cast<PScalar>();
+ HV.col(3).setConstant(1);
+ HV = (HV*model.template cast<PScalar>().transpose()*
+ proj.template cast<PScalar>().transpose()).eval();
+ HV = (HV.array().colwise()/HV.col(3).array()).eval();
+ HV = (HV.array() * 0.5 + 0.5).eval();
+ HV.col(0) = (HV.array().col(0) * viewport(2) + viewport(0)).eval();
+ HV.col(1) = (HV.array().col(1) * viewport(3) + viewport(1)).eval();
+ P = HV.leftCols(3);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template Eigen::Matrix<double, 3, 1, 0, 3, 1> igl::project<double>(Eigen::Matrix<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 4, 4, 0, 4, 4> const&, Eigen::Matrix<double, 4, 4, 0, 4, 4> const&, Eigen::Matrix<double, 4, 1, 0, 4, 1> const&);
+template Eigen::Matrix<float, 3, 1, 0, 3, 1> igl::project<float>(Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&);
+template void igl::project<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<float, -1, -1, 0, -1, -1>>(const Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>>&, const Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4>>&, const Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4>>&, const Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1>>&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1>>&);
+template void igl::project<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<double, 4, 1, 0, 4, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>>(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&, const Eigen::MatrixBase<Eigen::Matrix<double, 4, 4, 0, 4, 4>>&, const Eigen::MatrixBase<Eigen::Matrix<double, 4, 4, 0, 4, 4>>&, const Eigen::MatrixBase<Eigen::Matrix<double, 4, 1, 0, 4, 1>>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1>>&);
+#endif
diff --git a/xs/src/igl/project.h b/xs/src/igl/project.h
new file mode 100644
index 000000000..e2ee27a15
--- /dev/null
+++ b/xs/src/igl/project.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PROJECT_H
+#define IGL_PROJECT_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Eigen reimplementation of gluProject
+ // Inputs:
+ // obj* 3D objects' x, y, and z coordinates respectively
+ // model model matrix
+ // proj projection matrix
+ // viewport viewport vector
+ // Returns:
+ // screen space x, y, and z coordinates respectively
+ template <typename Scalar>
+ IGL_INLINE Eigen::Matrix<Scalar,3,1> project(
+ const Eigen::Matrix<Scalar,3,1>& obj,
+ const Eigen::Matrix<Scalar,4,4>& model,
+ const Eigen::Matrix<Scalar,4,4>& proj,
+ const Eigen::Matrix<Scalar,4,1>& viewport);
+ // Inputs:
+ // V #V by 3 list of object points
+ // model model matrix
+ // proj projection matrix
+ // viewport viewport vector
+ // Outputs:
+ // P #V by 3 list of screen space points
+ template <typename DerivedV, typename DerivedM, typename DerivedN, typename DerivedO, typename DerivedP>
+ IGL_INLINE void project(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedM>& model,
+ const Eigen::MatrixBase<DerivedN>& proj,
+ const Eigen::MatrixBase<DerivedO>& viewport,
+ Eigen::PlainObjectBase<DerivedP> & P);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "project.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/project_isometrically_to_plane.cpp b/xs/src/igl/project_isometrically_to_plane.cpp
new file mode 100644
index 000000000..537629caa
--- /dev/null
+++ b/xs/src/igl/project_isometrically_to_plane.cpp
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "project_isometrically_to_plane.h"
+#include "edge_lengths.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedU,
+ typename DerivedUF,
+ typename Scalar>
+IGL_INLINE void igl::project_isometrically_to_plane(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedUF> & UF,
+ Eigen::SparseMatrix<Scalar>& I)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(F.cols() == 3 && "F should contain triangles");
+ typedef DerivedV MatrixX;
+ MatrixX l;
+ edge_lengths(V,F,l);
+ // Number of faces
+ const int m = F.rows();
+
+ // First corner at origin
+ U = DerivedU::Zero(m*3,2);
+ // Second corner along x-axis
+ U.block(m,0,m,1) = l.col(2);
+ // Third corner rotated onto plane
+ U.block(m*2,0,m,1) =
+ (-l.col(0).array().square() +
+ l.col(1).array().square() +
+ l.col(2).array().square())/(2.*l.col(2).array());
+ U.block(m*2,1,m,1) =
+ (l.col(1).array().square()-U.block(m*2,0,m,1).array().square()).sqrt();
+
+ typedef Triplet<Scalar> IJV;
+ vector<IJV > ijv;
+ ijv.reserve(3*m);
+ UF.resize(m,3);
+ for(int f = 0;f<m;f++)
+ {
+ for(int c = 0;c<3;c++)
+ {
+ UF(f,c) = c*m+f;
+ ijv.push_back(IJV(F(f,c),c*m+f,1));
+ }
+ }
+ I.resize(V.rows(),m*3);
+ I.setFromTriplets(ijv.begin(),ijv.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::project_isometrically_to_plane<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/project_isometrically_to_plane.h b/xs/src/igl/project_isometrically_to_plane.h
new file mode 100644
index 000000000..388f6c307
--- /dev/null
+++ b/xs/src/igl/project_isometrically_to_plane.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PROJECT_ISOMETRICALLY_TO_PLANE_H
+#define IGL_PROJECT_ISOMETRICALLY_TO_PLANE_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Project each triangle to the plane
+ //
+ // [U,UF,I] = project_isometrically_to_plane(V,F)
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of mesh indices
+ // Outputs:
+ // U #F*3 by 2 list of triangle positions
+ // UF #F by 3 list of mesh indices into U
+ // I #V by #F such that I(i,j) = 1 implies U(j,:) corresponds to V(i,:)
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedU,
+ typename DerivedUF,
+ typename Scalar>
+ IGL_INLINE void project_isometrically_to_plane(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedUF> & UF,
+ Eigen::SparseMatrix<Scalar>& I);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "project_isometrically_to_plane.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/project_to_line.cpp b/xs/src/igl/project_to_line.cpp
new file mode 100644
index 000000000..a7f3a690e
--- /dev/null
+++ b/xs/src/igl/project_to_line.cpp
@@ -0,0 +1,139 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "project_to_line.h"
+#include <cassert>
+#include <Eigen/Core>
+
+template <
+ typename DerivedP,
+ typename DerivedS,
+ typename DerivedD,
+ typename Derivedt,
+ typename DerivedsqrD>
+IGL_INLINE void igl::project_to_line(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const Eigen::MatrixBase<DerivedD> & D,
+ Eigen::PlainObjectBase<Derivedt> & t,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD)
+{
+ // http://mathworld.wolfram.com/Point-LineDistance3-Dimensional.html
+
+ // number of dimensions
+#ifndef NDEBUG
+ int dim = P.cols();
+ assert(dim == S.size());
+ assert(dim == D.size());
+#endif
+ // number of points
+ int np = P.rows();
+ // vector from source to destination
+ DerivedD DmS = D-S;
+ double v_sqrlen = (double)(DmS.squaredNorm());
+ assert(v_sqrlen != 0);
+ // resize output
+ t.resize(np,1);
+ sqrD.resize(np,1);
+ // loop over points
+#pragma omp parallel for if (np>10000)
+ for(int i = 0;i<np;i++)
+ {
+ const typename DerivedP::ConstRowXpr Pi = P.row(i);
+ // vector from point i to source
+ const DerivedD SmPi = S-Pi;
+ t(i) = -(DmS.array()*SmPi.array()).sum() / v_sqrlen;
+ // P projected onto line
+ const DerivedD projP = (1-t(i))*S + t(i)*D;
+ sqrD(i) = (Pi-projP).squaredNorm();
+ }
+}
+
+template <typename Scalar>
+IGL_INLINE void igl::project_to_line(
+ const Scalar px,
+ const Scalar py,
+ const Scalar pz,
+ const Scalar sx,
+ const Scalar sy,
+ const Scalar sz,
+ const Scalar dx,
+ const Scalar dy,
+ const Scalar dz,
+ Scalar & projpx,
+ Scalar & projpy,
+ Scalar & projpz,
+ Scalar & t,
+ Scalar & sqrd)
+{
+ // vector from source to destination
+ Scalar dms[3];
+ dms[0] = dx-sx;
+ dms[1] = dy-sy;
+ dms[2] = dz-sz;
+ Scalar v_sqrlen = dms[0]*dms[0] + dms[1]*dms[1] + dms[2]*dms[2];
+ // line should have some length
+ assert(v_sqrlen != 0);
+ // vector from point to source
+ Scalar smp[3];
+ smp[0] = sx-px;
+ smp[1] = sy-py;
+ smp[2] = sz-pz;
+ t = -(dms[0]*smp[0]+dms[1]*smp[1]+dms[2]*smp[2])/v_sqrlen;
+ // P projectred onto line
+ projpx = (1.0-t)*sx + t*dx;
+ projpy = (1.0-t)*sy + t*dy;
+ projpz = (1.0-t)*sz + t*dz;
+ // vector from projected point to p
+ Scalar pmprojp[3];
+ pmprojp[0] = px-projpx;
+ pmprojp[1] = py-projpy;
+ pmprojp[2] = pz-projpz;
+ sqrd = pmprojp[0]*pmprojp[0] + pmprojp[1]*pmprojp[1] + pmprojp[2]*pmprojp[2];
+}
+
+template <typename Scalar>
+IGL_INLINE void igl::project_to_line(
+ const Scalar px,
+ const Scalar py,
+ const Scalar pz,
+ const Scalar sx,
+ const Scalar sy,
+ const Scalar sz,
+ const Scalar dx,
+ const Scalar dy,
+ const Scalar dz,
+ Scalar & t,
+ Scalar & sqrd)
+{
+ Scalar projpx;
+ Scalar projpy;
+ Scalar projpz;
+ return igl::project_to_line(
+ px, py, pz, sx, sy, sz, dx, dy, dz,
+ projpx, projpy, projpz, t, sqrd);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::project_to_line<Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, -1, -1, false>, Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, -1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, -1, -1, false>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 2, 0, -1, 2> const, -1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line<Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+template void igl::project_to_line<double>(double, double, double, double, double, double, double, double, double, double&, double&);
+template void igl::project_to_line<double>(double, double, double, double, double, double, double, double, double, double&, double&,double&,double&, double&);
+template void igl::project_to_line<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+template void igl::project_to_line<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/project_to_line.h b/xs/src/igl/project_to_line.h
new file mode 100644
index 000000000..d11399a76
--- /dev/null
+++ b/xs/src/igl/project_to_line.h
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PROJECT_TO_LINE_H
+#define IGL_PROJECT_TO_LINE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // PROJECT_TO_LINE project points onto vectors, that is find the parameter
+ // t for a point p such that proj_p = (y-x).*t, additionally compute the
+ // squared distance from p to the line of the vector, such that
+ // |p - proj_p|² = sqr_d
+ //
+ // [T,sqrD] = project_to_line(P,S,D)
+ //
+ // Inputs:
+ // P #P by dim list of points to be projected
+ // S size dim start position of line vector
+ // D size dim destination position of line vector
+ // Outputs:
+ // T #P by 1 list of parameters
+ // sqrD #P by 1 list of squared distances
+ //
+ //
+ template <
+ typename DerivedP,
+ typename DerivedS,
+ typename DerivedD,
+ typename Derivedt,
+ typename DerivedsqrD>
+ IGL_INLINE void project_to_line(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const Eigen::MatrixBase<DerivedD> & D,
+ Eigen::PlainObjectBase<Derivedt> & t,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD);
+
+ // Same as above but for a single query point
+ template <typename Scalar>
+ IGL_INLINE void project_to_line(
+ const Scalar px,
+ const Scalar py,
+ const Scalar pz,
+ const Scalar sx,
+ const Scalar sy,
+ const Scalar sz,
+ const Scalar dx,
+ const Scalar dy,
+ const Scalar dz,
+ Scalar & projpx,
+ Scalar & projpy,
+ Scalar & projpz,
+ Scalar & t,
+ Scalar & sqrd);
+
+ // Same as above but for a single query point
+ template <typename Scalar>
+ IGL_INLINE void project_to_line(
+ const Scalar px,
+ const Scalar py,
+ const Scalar pz,
+ const Scalar sx,
+ const Scalar sy,
+ const Scalar sz,
+ const Scalar dx,
+ const Scalar dy,
+ const Scalar dz,
+ Scalar & t,
+ Scalar & sqrd);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "project_to_line.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/project_to_line_segment.cpp b/xs/src/igl/project_to_line_segment.cpp
new file mode 100644
index 000000000..71866fa33
--- /dev/null
+++ b/xs/src/igl/project_to_line_segment.cpp
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "project_to_line_segment.h"
+#include "project_to_line.h"
+#include <Eigen/Core>
+
+template <
+ typename DerivedP,
+ typename DerivedS,
+ typename DerivedD,
+ typename Derivedt,
+ typename DerivedsqrD>
+IGL_INLINE void igl::project_to_line_segment(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const Eigen::MatrixBase<DerivedD> & D,
+ Eigen::PlainObjectBase<Derivedt> & t,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD)
+{
+ project_to_line(P,S,D,t,sqrD);
+ const int np = P.rows();
+ // loop over points and fix those that projected beyond endpoints
+#pragma omp parallel for if (np>10000)
+ for(int p = 0;p<np;p++)
+ {
+ const DerivedP Pp = P.row(p);
+ if(t(p)<0)
+ {
+ sqrD(p) = (Pp-S).squaredNorm();
+ t(p) = 0;
+ }else if(t(p)>1)
+ {
+ sqrD(p) = (Pp-D).squaredNorm();
+ t(p) = 1;
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::project_to_line_segment<Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line_segment<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line_segment<Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::project_to_line_segment<Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+template void igl::project_to_line_segment<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 1, 0, 1, 1>, Eigen::Matrix<double, 1, 1, 0, 1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+#endif
diff --git a/xs/src/igl/project_to_line_segment.h b/xs/src/igl/project_to_line_segment.h
new file mode 100644
index 000000000..2fe33f2d4
--- /dev/null
+++ b/xs/src/igl/project_to_line_segment.h
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PROJECT_TO_LINE_SEGMENT_H
+#define IGL_PROJECT_TO_LINE_SEGMENT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // PROJECT_TO_LINE_SEGMENT project points onto vectors, that is find the parameter
+ // t for a point p such that proj_p = (y-x).*t, additionally compute the
+ // squared distance from p to the line of the vector, such that
+ // |p - proj_p|² = sqr_d
+ //
+ // [T,sqrD] = project_to_line_segment(P,S,D)
+ //
+ // Inputs:
+ // P #P by dim list of points to be projected
+ // S size dim start position of line vector
+ // D size dim destination position of line vector
+ // Outputs:
+ // T #P by 1 list of parameters
+ // sqrD #P by 1 list of squared distances
+ //
+ //
+ template <
+ typename DerivedP,
+ typename DerivedS,
+ typename DerivedD,
+ typename Derivedt,
+ typename DerivedsqrD>
+ IGL_INLINE void project_to_line_segment(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const Eigen::MatrixBase<DerivedD> & D,
+ Eigen::PlainObjectBase<Derivedt> & t,
+ Eigen::PlainObjectBase<DerivedsqrD> & sqrD);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "project_to_line_segment.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/pseudonormal_test.cpp b/xs/src/igl/pseudonormal_test.cpp
new file mode 100644
index 000000000..b56fdf7ba
--- /dev/null
+++ b/xs/src/igl/pseudonormal_test.cpp
@@ -0,0 +1,224 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "pseudonormal_test.h"
+#include "barycentric_coordinates.h"
+#include "doublearea.h"
+#include "project_to_line_segment.h"
+#include <cassert>
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename Derivedq,
+ typename Derivedc,
+ typename Scalar,
+ typename Derivedn>
+IGL_INLINE void igl::pseudonormal_test(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const Eigen::MatrixBase<Derivedq> & q,
+ const int f,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Scalar & s,
+ Eigen::PlainObjectBase<Derivedn> & n)
+{
+ using namespace Eigen;
+ const auto & qc = q-c;
+ typedef Eigen::Matrix<Scalar,1,3> RowVector3S;
+ RowVector3S b;
+ // Using barycentric coorindates to determine whether close to a vertex/edge
+ // seems prone to error when dealing with nearly degenerate triangles: Even
+ // the barycenter (1/3,1/3,1/3) can be made arbitrarily close to an
+ // edge/vertex
+ //
+ const RowVector3S A = V.row(F(f,0));
+ const RowVector3S B = V.row(F(f,1));
+ const RowVector3S C = V.row(F(f,2));
+
+ const double area = [&A,&B,&C]()
+ {
+ Matrix<double,1,1> area;
+ doublearea(A,B,C,area);
+ return area(0);
+ }();
+ // These were chosen arbitrarily. In a floating point scenario, I'm not sure
+ // the best way to determine if c is on a vertex/edge or in the middle of the
+ // face: specifically, I'm worrying about degenerate triangles where
+ // barycentric coordinates are error-prone.
+ const double MIN_DOUBLE_AREA = 1e-4;
+ const double epsilon = 1e-12;
+ if(area>MIN_DOUBLE_AREA)
+ {
+ barycentric_coordinates( c,A,B,C,b);
+ // Determine which normal to use
+ const int type = (b.array()<=epsilon).template cast<int>().sum();
+ switch(type)
+ {
+ case 2:
+ // Find vertex
+ for(int x = 0;x<3;x++)
+ {
+ if(b(x)>epsilon)
+ {
+ n = VN.row(F(f,x));
+ break;
+ }
+ }
+ break;
+ case 1:
+ // Find edge
+ for(int x = 0;x<3;x++)
+ {
+ if(b(x)<=epsilon)
+ {
+ n = EN.row(EMAP(F.rows()*x+f));
+ break;
+ }
+ }
+ break;
+ default:
+ assert(false && "all barycentric coords zero.");
+ case 0:
+ n = FN.row(f);
+ break;
+ }
+ }else
+ {
+ // Check each vertex
+ bool found = false;
+ for(int v = 0;v<3 && !found;v++)
+ {
+ if( (c-V.row(F(f,v))).norm() < epsilon)
+ {
+ found = true;
+ n = VN.row(F(f,v));
+ }
+ }
+ // Check each edge
+ for(int e = 0;e<3 && !found;e++)
+ {
+ const RowVector3S s = V.row(F(f,(e+1)%3));
+ const RowVector3S d = V.row(F(f,(e+2)%3));
+ Matrix<double,1,1> sqr_d_j_x(1,1);
+ Matrix<double,1,1> t(1,1);
+ project_to_line_segment(c,s,d,t,sqr_d_j_x);
+ if(sqrt(sqr_d_j_x(0)) < epsilon)
+ {
+ n = EN.row(EMAP(F.rows()*e+f));
+ found = true;
+ }
+ }
+ // Finally just use face
+ if(!found)
+ {
+ n = FN.row(f);
+ }
+ }
+ s = (qc.dot(n) >= 0 ? 1. : -1.);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedEN,
+ typename DerivedVN,
+ typename Derivedq,
+ typename Derivedc,
+ typename Scalar,
+ typename Derivedn>
+IGL_INLINE void igl::pseudonormal_test(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & E,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<Derivedq> & q,
+ const int e,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Scalar & s,
+ Eigen::PlainObjectBase<Derivedn> & n)
+{
+ using namespace Eigen;
+ const auto & qc = q-c;
+ const double len = (V.row(E(e,1))-V.row(E(e,0))).norm();
+ // barycentric coordinates
+ // this .head() nonsense is for "ridiculus" templates instantiations that AABB
+ // needs to compile
+ Eigen::Matrix<Scalar,1,2>
+ b((c-V.row(E(e,1))).norm()/len,(c-V.row(E(e,0))).norm()/len);
+ //b((c-V.row(E(e,1)).head(c.size())).norm()/len,(c-V.row(E(e,0)).head(c.size())).norm()/len);
+ // Determine which normal to use
+ const double epsilon = 1e-12;
+ const int type = (b.array()<=epsilon).template cast<int>().sum();
+ switch(type)
+ {
+ case 1:
+ // Find vertex
+ for(int x = 0;x<2;x++)
+ {
+ if(b(x)>epsilon)
+ {
+ n = VN.row(E(e,x)).head(2);
+ break;
+ }
+ }
+ break;
+ default:
+ assert(false && "all barycentric coords zero.");
+ case 0:
+ n = EN.row(e).head(2);
+ break;
+ }
+ s = (qc.dot(n) >= 0 ? 1. : -1.);
+}
+
+// This is a bullshit template because AABB annoyingly needs templates for bad
+// combinations of 3D V with DIM=2 AABB
+//
+// _Define_ as a no-op rather than monkeying around with the proper code above
+namespace igl
+{
+ template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&){assert(false);};
+ template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&){assert(false);};
+ template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&){assert(false);};
+ template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&){assert(false);};
+ template <> IGL_INLINE void pseudonormal_test(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&) {assert(false);};
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::pseudonormal_test<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+template void igl::pseudonormal_test<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, -1, 1, 1, -1>, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::pseudonormal_test<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, 1, 2, 1, 1, 2>, Eigen::Matrix<float, 1, -1, 1, 1, -1>, float, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&);
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
+// generated by autoexplicit.sh
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, -1, 1, 1, -1>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, -1, 1, 1, -1>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
+// generated by autoexplicit.sh
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 1, -1, false> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+//template void igl::pseudonormal_test<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, 1, 2, 1, 1, 2>, Eigen::Matrix<float, 1, 2, 1, 1, 2>, float, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> >&);
+template void igl::pseudonormal_test<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, Eigen::Matrix<float, 1, 3, 1, 1, 3>, float, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&, float&, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::pseudonormal_test<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, Eigen::Matrix<double, 1, 2, 1, 1, 2>, double, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&, double&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> >&);
+#endif
diff --git a/xs/src/igl/pseudonormal_test.h b/xs/src/igl/pseudonormal_test.h
new file mode 100644
index 000000000..fc07946fb
--- /dev/null
+++ b/xs/src/igl/pseudonormal_test.h
@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_PSEUDONORMAL_TEST_H
+#define IGL_PSEUDONORMAL_TEST_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Given a mesh (V,F), a query point q, and a point on (V,F) c, determine
+ // whether q is inside (V,F) --> s=-1 or outside (V,F) s=1, based on the
+ // sign of the dot product between (q-c) and n, where n is the normal _at c_,
+ // carefully chosen according to [Bærentzen & Aanæs 2005]
+ //
+ // Inputs:
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // FN #F by 3 list of triangle normals
+ // VN #V by 3 list of vertex normals (ANGLE WEIGHTING)
+ // EN #E by 3 list of edge normals (UNIFORM WEIGHTING)
+ // EMAP #F*3 mapping edges in F to E
+ // q Query point
+ // f index into F to face to which c belongs
+ // c Point on (V,F)
+ // Outputs:
+ // s sign
+ // n normal
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename Derivedq,
+ typename Derivedc,
+ typename Scalar,
+ typename Derivedn>
+ IGL_INLINE void pseudonormal_test(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const Eigen::MatrixBase<Derivedq> & q,
+ const int f,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Scalar & s,
+ Eigen::PlainObjectBase<Derivedn> & n);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedEN,
+ typename DerivedVN,
+ typename Derivedq,
+ typename Derivedc,
+ typename Scalar,
+ typename Derivedn>
+ IGL_INLINE void pseudonormal_test(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & E,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<Derivedq> & q,
+ const int e,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Scalar & s,
+ Eigen::PlainObjectBase<Derivedn> & n);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "pseudonormal_test.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/pso.cpp b/xs/src/igl/pso.cpp
new file mode 100644
index 000000000..bf24a3a8c
--- /dev/null
+++ b/xs/src/igl/pso.cpp
@@ -0,0 +1,174 @@
+#include "pso.h"
+#include <cassert>
+#include <Eigen/StdVector>
+#include <vector>
+#include <iostream>
+
+template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB>
+IGL_INLINE Scalar igl::pso(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const int max_iters,
+ const int population,
+ DerivedX & X)
+{
+ const Eigen::Array<bool,Eigen::Dynamic,1> P =
+ Eigen::Array<bool,Eigen::Dynamic,1>::Zero(LB.size(),1);
+ return igl::pso(f,LB,UB,P,max_iters,population,X);
+}
+
+template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB,
+ typename DerivedP>
+IGL_INLINE Scalar igl::pso(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const Eigen::DenseBase<DerivedP> & P,
+ const int max_iters,
+ const int population,
+ DerivedX & X)
+{
+ const int dim = LB.size();
+ assert(UB.size() == dim && "UB should match LB size");
+ assert(P.size() == dim && "P should match LB size");
+ typedef std::vector<DerivedX,Eigen::aligned_allocator<DerivedX> > VectorList;
+ VectorList position(population);
+ VectorList best_position(population);
+ VectorList velocity(population);
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1> best_f(population);
+ // https://en.wikipedia.org/wiki/Particle_swarm_optimization#Algorithm
+ //
+ // g → X
+ // p_i → best[i]
+ // v_i → velocity[i]
+ // x_i → position[i]
+ Scalar min_f = std::numeric_limits<Scalar>::max();
+ for(int p=0;p<population;p++)
+ {
+ {
+ const DerivedX R = DerivedX::Random(dim).array()*0.5+0.5;
+ position[p] = LB.array() + R.array()*(UB-LB).array();
+ }
+ best_f[p] = f(position[p]);
+ best_position[p] = position[p];
+ if(best_f[p] < min_f)
+ {
+ min_f = best_f[p];
+ X = best_position[p];
+ }
+ {
+ const DerivedX R = DerivedX::Random(dim);
+ velocity[p] = (UB-LB).array() * R.array();
+ }
+ }
+
+ int iter = 0;
+ Scalar omega = 0.98;
+ Scalar phi_p = 0.01;
+ Scalar phi_g = 0.01;
+ while(true)
+ {
+ //if(iter % 10 == 0)
+ //{
+ // std::cout<<iter<<":"<<std::endl;
+ // for(int p=0;p<population;p++)
+ // {
+ // std::cout<<" "<<best_f[p]<<", "<<best_position[p]<<std::endl;
+ // }
+ // std::cout<<std::endl;
+ //}
+
+ for(int p=0;p<population;p++)
+ {
+ const DerivedX R_p = DerivedX::Random(dim).array()*0.5+0.5;
+ const DerivedX R_g = DerivedX::Random(dim).array()*0.5+0.5;
+ velocity[p] =
+ omega * velocity[p].array() +
+ phi_p * R_p.array() *(best_position[p] - position[p]).array() +
+ phi_g * R_g.array() *( X - position[p]).array();
+ position[p] += velocity[p];
+ // Clamp to bounds
+ for(int d = 0;d<dim;d++)
+ {
+//#define IGL_PSO_REFLECTION
+#ifdef IGL_PSO_REFLECTION
+ assert(!P(d));
+ // Reflect velocities if exceeding bounds
+ if(position[p](d) < LB(d))
+ {
+ position[p](d) = LB(d);
+ if(velocity[p](d) < 0.0) velocity[p](d) *= -1.0;
+ }
+ if(position[p](d) > UB(d))
+ {
+ position[p](d) = UB(d);
+ if(velocity[p](d) > 0.0) velocity[p](d) *= -1.0;
+ }
+#else
+//#warning "trying no bounds on periodic"
+// // TODO: I'm not sure this is the right thing to do/enough. The
+// // velocities could be weird. Suppose the current "best" value is ε and
+// // the value is -ε and the "periodic bounds" [0,2π]. Moding will send
+// // the value to 2π-ε but the "velocity" term will now be huge pointing
+// // all the way from 2π-ε to ε.
+// //
+// // Q: Would it be enough to try (all combinations) of ±(UB-LB) before
+// // computing velocities to "best"s? In the example above, instead of
+// //
+// // v += best - p = ε - (2π-ε) = -2π+2ε
+// //
+// // you'd use
+// //
+// // v += / argmin |b - p| \ - p = (ε+2π)-(2π-ε) = 2ε
+// // | |
+// // \ b∈{best, best+2π, best-2π} /
+// //
+// // Though, for multivariate b,p,v this would seem to explode
+// // combinatorially.
+// //
+// // Maybe periodic things just shouldn't be bounded and we hope that the
+// // forces toward the current minima "regularize" them away from insane
+// // values.
+// if(P(d))
+// {
+// position[p](d) = std::fmod(position[p](d)-LB(d),UB(d)-LB(d))+LB(d);
+// }else
+// {
+// position[p](d) = std::max(LB(d),std::min(UB(d),position[p](d)));
+// }
+ position[p](d) = std::max(LB(d),std::min(UB(d),position[p](d)));
+#endif
+ }
+ const Scalar fp = f(position[p]);
+ if(fp<best_f[p])
+ {
+ best_f[p] = fp;
+ best_position[p] = position[p];
+ if(best_f[p] < min_f)
+ {
+ min_f = best_f[p];
+ X = best_position[p];
+ }
+ }
+ }
+ iter++;
+ if(iter>=max_iters)
+ {
+ break;
+ }
+ }
+ return min_f;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template float igl::pso<float, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1> >(std::function<float (Eigen::Matrix<float, 1, -1, 1, 1, -1>&)>, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, int, int, Eigen::Matrix<float, 1, -1, 1, 1, -1>&);
+#endif
diff --git a/xs/src/igl/pso.h b/xs/src/igl/pso.h
new file mode 100644
index 000000000..d2a2ccdff
--- /dev/null
+++ b/xs/src/igl/pso.h
@@ -0,0 +1,59 @@
+#ifndef IGL_PSO_H
+#define IGL_PSO_H
+#include <igl/igl_inline.h>
+#include <Eigen/Core>
+#include <functional>
+
+namespace igl
+{
+ // Solve the problem:
+ //
+ // minimize f(x)
+ // subject to lb ≤ x ≤ ub
+ //
+ // by particle swarm optimization (PSO).
+ //
+ // Inputs:
+ // f function that evaluates the objective for a given "particle" location
+ // LB #X vector of lower bounds
+ // UB #X vector of upper bounds
+ // max_iters maximum number of iterations
+ // population number of particles in swarm
+ // Outputs:
+ // X best particle seen so far
+ // Returns objective corresponding to best particle seen so far
+ template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB>
+ IGL_INLINE Scalar pso(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const int max_iters,
+ const int population,
+ DerivedX & X);
+ // Inputs:
+ // P whether each DOF is periodic
+ template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB,
+ typename DerivedP>
+ IGL_INLINE Scalar pso(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const Eigen::DenseBase<DerivedP> & P,
+ const int max_iters,
+ const int population,
+ DerivedX & X);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "pso.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/qslim.cpp b/xs/src/igl/qslim.cpp
new file mode 100644
index 000000000..e76db5f0b
--- /dev/null
+++ b/xs/src/igl/qslim.cpp
@@ -0,0 +1,120 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "qslim.h"
+
+#include "collapse_edge.h"
+#include "connect_boundary_to_infinity.h"
+#include "decimate.h"
+#include "edge_flaps.h"
+#include "is_edge_manifold.h"
+#include "max_faces_stopping_condition.h"
+#include "per_vertex_point_to_plane_quadrics.h"
+#include "qslim_optimal_collapse_edge_callbacks.h"
+#include "quadric_binary_plus_operator.h"
+#include "remove_unreferenced.h"
+#include "slice.h"
+#include "slice_mask.h"
+
+IGL_INLINE bool igl::qslim(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I)
+{
+ using namespace igl;
+
+ // Original number of faces
+ const int orig_m = F.rows();
+ // Tracking number of faces
+ int m = F.rows();
+ typedef Eigen::MatrixXd DerivedV;
+ typedef Eigen::MatrixXi DerivedF;
+ DerivedV VO;
+ DerivedF FO;
+ igl::connect_boundary_to_infinity(V,F,VO,FO);
+ // decimate will not work correctly on non-edge-manifold meshes. By extension
+ // this includes meshes with non-manifold vertices on the boundary since these
+ // will create a non-manifold edge when connected to infinity.
+ if(!is_edge_manifold(FO))
+ {
+ return false;
+ }
+ Eigen::VectorXi EMAP;
+ Eigen::MatrixXi E,EF,EI;
+ edge_flaps(FO,E,EMAP,EF,EI);
+ // Quadrics per vertex
+ typedef std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> Quadric;
+ std::vector<Quadric> quadrics;
+ per_vertex_point_to_plane_quadrics(VO,FO,EMAP,EF,EI,quadrics);
+ // State variables keeping track of edge we just collapsed
+ int v1 = -1;
+ int v2 = -1;
+ // Callbacks for computing and updating metric
+ std::function<void(
+ const int e,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> cost_and_placement;
+ std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> pre_collapse;
+ std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> post_collapse;
+ qslim_optimal_collapse_edge_callbacks(
+ E,quadrics,v1,v2, cost_and_placement, pre_collapse,post_collapse);
+ // Call to greedy decimator
+ bool ret = decimate(
+ VO, FO,
+ cost_and_placement,
+ max_faces_stopping_condition(m,orig_m,max_m),
+ pre_collapse,
+ post_collapse,
+ E, EMAP, EF, EI,
+ U, G, J, I);
+ // Remove phony boundary faces and clean up
+ const Eigen::Array<bool,Eigen::Dynamic,1> keep = (J.array()<orig_m);
+ igl::slice_mask(Eigen::MatrixXi(G),keep,1,G);
+ igl::slice_mask(Eigen::VectorXi(J),keep,1,J);
+ Eigen::VectorXi _1,I2;
+ igl::remove_unreferenced(Eigen::MatrixXd(U),Eigen::MatrixXi(G),U,G,_1,I2);
+ igl::slice(Eigen::VectorXi(I),I2,1,I);
+
+ return ret;
+}
diff --git a/xs/src/igl/qslim.h b/xs/src/igl/qslim.h
new file mode 100644
index 000000000..c1cd9bd44
--- /dev/null
+++ b/xs/src/igl/qslim.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QSLIM_H
+#define IGL_QSLIM_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+
+ // Decimate (simplify) a triangle mesh in nD according to the paper
+ // "Simplifying Surfaces with Color and Texture using Quadric Error Metrics"
+ // by [Garland and Heckbert, 1987] (technically a followup to qslim). The
+ // mesh can have open boundaries but should be edge-manifold.
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions. Assumes that vertices w
+ // F #F by 3 list of triangle indices into V
+ // max_m desired number of output faces
+ // Outputs:
+ // U #U by dim list of output vertex posistions (can be same ref as V)
+ // G #G by 3 list of output face indices into U (can be same ref as G)
+ // J #G list of indices into F of birth face
+ // I #U list of indices into V of birth vertices
+ IGL_INLINE bool qslim(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const size_t max_m,
+ Eigen::MatrixXd & U,
+ Eigen::MatrixXi & G,
+ Eigen::VectorXi & J,
+ Eigen::VectorXi & I);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "qslim.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/qslim_optimal_collapse_edge_callbacks.cpp b/xs/src/igl/qslim_optimal_collapse_edge_callbacks.cpp
new file mode 100644
index 000000000..ff3fbd045
--- /dev/null
+++ b/xs/src/igl/qslim_optimal_collapse_edge_callbacks.cpp
@@ -0,0 +1,130 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "qslim_optimal_collapse_edge_callbacks.h"
+#include "quadric_binary_plus_operator.h"
+#include <Eigen/LU>
+
+IGL_INLINE void igl::qslim_optimal_collapse_edge_callbacks(
+ Eigen::MatrixXi & E,
+ std::vector<std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> > &
+ quadrics,
+ int & v1,
+ int & v2,
+ std::function<void(
+ const int e,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse)
+{
+ typedef std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> Quadric;
+ cost_and_placement = [&quadrics,&v1,&v2](
+ const int e,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & /*F*/,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & /*EMAP*/,
+ const Eigen::MatrixXi & /*EF*/,
+ const Eigen::MatrixXi & /*EI*/,
+ double & cost,
+ Eigen::RowVectorXd & p)
+ {
+ // Combined quadric
+ Quadric quadric_p;
+ quadric_p = quadrics[E(e,0)] + quadrics[E(e,1)];
+ // Quadric: p'Ap + 2b'p + c
+ // optimal point: Ap = -b, or rather because we have row vectors: pA=-b
+ const auto & A = std::get<0>(quadric_p);
+ const auto & b = std::get<1>(quadric_p);
+ const auto & c = std::get<2>(quadric_p);
+ p = -b*A.inverse();
+ cost = p.dot(p*A) + 2*p.dot(b) + c;
+ // Force infs and nans to infinity
+ if(std::isinf(cost) || cost!=cost)
+ {
+ cost = std::numeric_limits<double>::infinity();
+ // Prevent NaNs. Actually NaNs might be useful for debugging.
+ p.setConstant(0);
+ }
+ };
+ // Remember endpoints
+ pre_collapse = [&v1,&v2](
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int e)->bool
+ {
+ v1 = E(e,0);
+ v2 = E(e,1);
+ return true;
+ };
+ // update quadric
+ post_collapse = [&v1,&v2,&quadrics](
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool collapsed
+ )->void
+ {
+ if(collapsed)
+ {
+ quadrics[v1<v2?v1:v2] = quadrics[v1] + quadrics[v2];
+ }
+ };
+}
+
diff --git a/xs/src/igl/qslim_optimal_collapse_edge_callbacks.h b/xs/src/igl/qslim_optimal_collapse_edge_callbacks.h
new file mode 100644
index 000000000..2625eadf5
--- /dev/null
+++ b/xs/src/igl/qslim_optimal_collapse_edge_callbacks.h
@@ -0,0 +1,81 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QSLIM_OPTIMAL_COLLAPSE_EDGE_CALLBACKS_H
+#define IGL_QSLIM_OPTIMAL_COLLAPSE_EDGE_CALLBACKS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <functional>
+#include <vector>
+#include <tuple>
+#include <set>
+namespace igl
+{
+
+ // Prepare callbacks for decimating edges using the qslim optimal placement
+ // metric.
+ //
+ // Inputs:
+ // E #E by 2 list of working edges
+ // quadrics reference to list of working per vertex quadrics
+ // v1 working variable to maintain end point of collapsed edge
+ // v2 working variable to maintain end point of collapsed edge
+ // Outputs
+ // cost_and_placement callback for evaluating cost of edge collapse and
+ // determining placement of vertex (see collapse_edge)
+ // pre_collapse callback before edge collapse (see collapse_edge)
+ // post_collapse callback after edge collapse (see collapse_edge)
+ IGL_INLINE void qslim_optimal_collapse_edge_callbacks(
+ Eigen::MatrixXi & E,
+ std::vector<std::tuple<Eigen::MatrixXd,Eigen::RowVectorXd,double> > &
+ quadrics,
+ int & v1,
+ int & v2,
+ std::function<void(
+ const int e,
+ const Eigen::MatrixXd &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::VectorXi &,
+ const Eigen::MatrixXi &,
+ const Eigen::MatrixXi &,
+ double &,
+ Eigen::RowVectorXd &)> & cost_and_placement,
+ std::function<bool(
+ const Eigen::MatrixXd & ,/*V*/
+ const Eigen::MatrixXi & ,/*F*/
+ const Eigen::MatrixXi & ,/*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & ,/*EF*/
+ const Eigen::MatrixXi & ,/*EI*/
+ const std::set<std::pair<double,int> > & ,/*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &,/*Qit*/
+ const Eigen::MatrixXd & ,/*C*/
+ const int /*e*/
+ )> & pre_collapse,
+ std::function<void(
+ const Eigen::MatrixXd & , /*V*/
+ const Eigen::MatrixXi & , /*F*/
+ const Eigen::MatrixXi & , /*E*/
+ const Eigen::VectorXi & ,/*EMAP*/
+ const Eigen::MatrixXi & , /*EF*/
+ const Eigen::MatrixXi & , /*EI*/
+ const std::set<std::pair<double,int> > & , /*Q*/
+ const std::vector<std::set<std::pair<double,int> >::iterator > &, /*Qit*/
+ const Eigen::MatrixXd & , /*C*/
+ const int , /*e*/
+ const int , /*e1*/
+ const int , /*e2*/
+ const int , /*f1*/
+ const int , /*f2*/
+ const bool /*collapsed*/
+ )> & post_collapse);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "qslim_optimal_collapse_edge_callbacks.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/quad_planarity.cpp b/xs/src/igl/quad_planarity.cpp
new file mode 100644
index 000000000..2e0e4773e
--- /dev/null
+++ b/xs/src/igl/quad_planarity.cpp
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "quad_planarity.h"
+#include <Eigen/Geometry>
+
+template <typename DerivedV, typename DerivedF, typename DerivedP>
+IGL_INLINE void igl::quad_planarity(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedP> & P)
+{
+ int nf = F.rows();
+ P.setZero(nf,1);
+ for (int i =0; i<nf; ++i)
+ {
+ const Eigen::Matrix<typename DerivedV::Scalar,1,3> &v1 = V.row(F(i,0));
+ const Eigen::Matrix<typename DerivedV::Scalar,1,3> &v2 = V.row(F(i,1));
+ const Eigen::Matrix<typename DerivedV::Scalar,1,3> &v3 = V.row(F(i,2));
+ const Eigen::Matrix<typename DerivedV::Scalar,1,3> &v4 = V.row(F(i,3));
+ Eigen::Matrix<typename DerivedV::Scalar,1,3> diagCross=(v3-v1).cross(v4-v2);
+ typename DerivedV::Scalar denom =
+ diagCross.norm()*(((v3-v1).norm()+(v4-v2).norm())/2);
+ if (fabs(denom)<1e-8)
+ //degenerate quad is still planar
+ P[i] = 0;
+ else
+ P[i] = (diagCross.dot(v2-v1)/denom);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::quad_planarity<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/quad_planarity.h b/xs/src/igl/quad_planarity.h
new file mode 100644
index 000000000..0d78b4e35
--- /dev/null
+++ b/xs/src/igl/quad_planarity.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QUAD_PLANARITY_H
+#define IGL_QUAD_PLANARITY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute planarity of the faces of a quad mesh
+ // Inputs:
+ // V #V by 3 eigen Matrix of mesh vertex 3D positions
+ // F #F by 4 eigen Matrix of face (quad) indices
+ // Output:
+ // P #F by 1 eigen Matrix of mesh face (quad) planarities
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedP>
+ IGL_INLINE void quad_planarity(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedP> & P);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quad_planarity.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/quadric_binary_plus_operator.cpp b/xs/src/igl/quadric_binary_plus_operator.cpp
new file mode 100644
index 000000000..eb3fd695e
--- /dev/null
+++ b/xs/src/igl/quadric_binary_plus_operator.cpp
@@ -0,0 +1,24 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "quadric_binary_plus_operator.h"
+
+IGL_INLINE std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double>
+ igl::operator+(
+ const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & a,
+ const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & b)
+{
+ std::tuple<
+ Eigen::MatrixXd,
+ Eigen::RowVectorXd,
+ double> c;
+ std::get<0>(c) = (std::get<0>(a) + std::get<0>(b)).eval();
+ std::get<1>(c) = (std::get<1>(a) + std::get<1>(b)).eval();
+ std::get<2>(c) = (std::get<2>(a) + std::get<2>(b));
+ return c;
+}
+
diff --git a/xs/src/igl/quadric_binary_plus_operator.h b/xs/src/igl/quadric_binary_plus_operator.h
new file mode 100644
index 000000000..3c6b845d8
--- /dev/null
+++ b/xs/src/igl/quadric_binary_plus_operator.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QUADRIC_BINARY_PLUS_OPERATOR_H
+#define IGL_QUADRIC_BINARY_PLUS_OPERATOR_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <tuple>
+
+namespace igl
+{
+ // A binary addition operator for Quadric tuples compatible with qslim,
+ // computing c = a+b
+ //
+ // Inputs:
+ // a QSlim quadric
+ // b QSlim quadric
+ // Output
+ // c QSlim quadric
+ //
+ IGL_INLINE std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double>
+ operator+(
+ const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & a,
+ const std::tuple< Eigen::MatrixXd, Eigen::RowVectorXd, double> & b);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quadric_binary_plus_operator.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/quat_conjugate.cpp b/xs/src/igl/quat_conjugate.cpp
new file mode 100644
index 000000000..5856ea72d
--- /dev/null
+++ b/xs/src/igl/quat_conjugate.cpp
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "quat_conjugate.h"
+
+template <typename Q_type>
+IGL_INLINE void igl::quat_conjugate(
+ const Q_type *q1,
+ Q_type *out)
+{
+ out[0] = -q1[0];
+ out[1] = -q1[1];
+ out[2] = -q1[2];
+ out[3] = q1[3];
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::quat_conjugate<double>(double const*, double*);
+// generated by autoexplicit.sh
+template void igl::quat_conjugate<float>(float const*, float*);
+#endif
diff --git a/xs/src/igl/quat_conjugate.h b/xs/src/igl/quat_conjugate.h
new file mode 100644
index 000000000..32ccb3b5b
--- /dev/null
+++ b/xs/src/igl/quat_conjugate.h
@@ -0,0 +1,32 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QUAT_CONJUGATE_H
+#define IGL_QUAT_CONJUGATE_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Compute conjugate of given quaternion
+ // http://en.wikipedia.org/wiki/Quaternion#Conjugation.2C_the_norm.2C_and_reciprocal
+ // 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:
+ // q1 input quaternion
+ // Outputs:
+ // out result of conjugation, allowed to be same as input
+ template <typename Q_type>
+ IGL_INLINE void quat_conjugate(
+ const Q_type *q1,
+ Q_type *out);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quat_conjugate.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/quat_mult.cpp b/xs/src/igl/quat_mult.cpp
new file mode 100644
index 000000000..beb7baba5
--- /dev/null
+++ b/xs/src/igl/quat_mult.cpp
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "quat_mult.h"
+
+#include <cassert>
+// http://www.antisphere.com/Wiki/tools:anttweakbar
+template <typename Q_type>
+IGL_INLINE void igl::quat_mult(
+ const Q_type *q1,
+ const Q_type *q2,
+ Q_type *out)
+{
+ // output can't be either of the inputs
+ assert(q1 != out);
+ assert(q2 != out);
+
+ out[0] = q1[3]*q2[0] + q1[0]*q2[3] + q1[1]*q2[2] - q1[2]*q2[1];
+ out[1] = q1[3]*q2[1] + q1[1]*q2[3] + q1[2]*q2[0] - q1[0]*q2[2];
+ out[2] = q1[3]*q2[2] + q1[2]*q2[3] + q1[0]*q2[1] - q1[1]*q2[0];
+ out[3] = q1[3]*q2[3] - (q1[0]*q2[0] + q1[1]*q2[1] + q1[2]*q2[2]);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::quat_mult<double>(double const*, double const*, double*);
+// generated by autoexplicit.sh
+template void igl::quat_mult<float>(float const*, float const*, float*);
+#endif
diff --git a/xs/src/igl/quat_mult.h b/xs/src/igl/quat_mult.h
new file mode 100644
index 000000000..4a7ba654f
--- /dev/null
+++ b/xs/src/igl/quat_mult.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QUAT_MULT_H
+#define IGL_QUAT_MULT_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Computes out = q1 * q2 with quaternion multiplication
+ // 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:
+ // q1 left quaternion
+ // q2 right quaternion
+ // Outputs:
+ // out result of multiplication
+ template <typename Q_type>
+ IGL_INLINE void quat_mult(
+ const Q_type *q1,
+ const Q_type *q2,
+ Q_type *out);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quat_mult.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/quat_to_axis_angle.cpp b/xs/src/igl/quat_to_axis_angle.cpp
new file mode 100644
index 000000000..1aa59fad6
--- /dev/null
+++ b/xs/src/igl/quat_to_axis_angle.cpp
@@ -0,0 +1,75 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "quat_to_axis_angle.h"
+#include "EPS.h"
+#include "PI.h"
+#include <cmath>
+#include <cstdio>
+//
+// http://www.antisphere.com/Wiki/tools:anttweakbar
+template <typename Q_type>
+IGL_INLINE void igl::quat_to_axis_angle(
+ const Q_type *q,
+ Q_type *axis,
+ Q_type & angle)
+{
+ if( fabs(q[3])>(1.0 + igl::EPS<Q_type>()) )
+ {
+ //axis[0] = axis[1] = axis[2] = 0; // no, keep the previous value
+ angle = 0;
+ }
+ else
+ {
+ double a;
+ if( q[3]>=1.0f )
+ a = 0; // and keep V
+ else if( q[3]<=-1.0f )
+ a = PI; // and keep V
+ else if( fabs(q[0]*q[0]+q[1]*q[1]+q[2]*q[2]+q[3]*q[3])<igl::EPS_SQ<Q_type>())
+ {
+ a = 0;
+ }else
+ {
+ a = acos(q[3]);
+ if( a*angle<0 ) // Preserve the sign of angle
+ a = -a;
+ double f = 1.0f / sin(a);
+ axis[0] = q[0] * f;
+ axis[1] = q[1] * f;
+ axis[2] = q[2] * f;
+ }
+ angle = 2.0*a;
+ }
+
+ // if( angle>FLOAT_PI )
+ // angle -= 2.0f*FLOAT_PI;
+ // else if( angle<-FLOAT_PI )
+ // angle += 2.0f*FLOAT_PI;
+ //angle = RadToDeg(angle);
+
+ if( fabs(angle)<igl::EPS<Q_type>()&& fabs(axis[0]*axis[0]+axis[1]*axis[1]+axis[2]*axis[2])<igl::EPS_SQ<Q_type>())
+ {
+ axis[0] = 1.0e-7; // all components cannot be null
+ }
+}
+
+template <typename Q_type>
+IGL_INLINE void igl::quat_to_axis_angle_deg(
+ const Q_type *q,
+ Q_type *axis,
+ Q_type & angle)
+{
+ igl::quat_to_axis_angle(q,axis,angle);
+ angle = angle*(180.0/PI);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::quat_to_axis_angle<float>(float const*, float*, float&);
+template void igl::quat_to_axis_angle_deg<float>(float const*, float*, float&);
+#endif
diff --git a/xs/src/igl/quat_to_axis_angle.h b/xs/src/igl/quat_to_axis_angle.h
new file mode 100644
index 000000000..77ea10e5c
--- /dev/null
+++ b/xs/src/igl/quat_to_axis_angle.h
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QUAT_TO_AXIS_ANGLE_H
+#define IGL_QUAT_TO_AXIS_ANGLE_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Convert quat representation of a rotation to axis angle
+ // 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:
+ // q quaternion
+ // Outputs:
+ // axis 3d vector
+ // angle scalar in radians
+ template <typename Q_type>
+ IGL_INLINE void quat_to_axis_angle(
+ const Q_type *q,
+ Q_type *axis,
+ Q_type & angle);
+ // Wrapper with angle in degrees
+ template <typename Q_type>
+ IGL_INLINE void quat_to_axis_angle_deg(
+ const Q_type *q,
+ Q_type *axis,
+ Q_type & angle);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quat_to_axis_angle.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/quat_to_mat.cpp b/xs/src/igl/quat_to_mat.cpp
new file mode 100644
index 000000000..22ec07b94
--- /dev/null
+++ b/xs/src/igl/quat_to_mat.cpp
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "quat_to_mat.h"
+
+template <typename Q_type>
+IGL_INLINE void igl::quat_to_mat(const Q_type * quat, Q_type * mat)
+{
+ Q_type yy2 = 2.0f * quat[1] * quat[1];
+ Q_type xy2 = 2.0f * quat[0] * quat[1];
+ Q_type xz2 = 2.0f * quat[0] * quat[2];
+ Q_type yz2 = 2.0f * quat[1] * quat[2];
+ Q_type zz2 = 2.0f * quat[2] * quat[2];
+ Q_type wz2 = 2.0f * quat[3] * quat[2];
+ Q_type wy2 = 2.0f * quat[3] * quat[1];
+ Q_type wx2 = 2.0f * quat[3] * quat[0];
+ Q_type xx2 = 2.0f * quat[0] * quat[0];
+ mat[0*4+0] = - yy2 - zz2 + 1.0f;
+ mat[0*4+1] = xy2 + wz2;
+ mat[0*4+2] = xz2 - wy2;
+ mat[0*4+3] = 0;
+ mat[1*4+0] = xy2 - wz2;
+ mat[1*4+1] = - xx2 - zz2 + 1.0f;
+ mat[1*4+2] = yz2 + wx2;
+ mat[1*4+3] = 0;
+ mat[2*4+0] = xz2 + wy2;
+ mat[2*4+1] = yz2 - wx2;
+ mat[2*4+2] = - xx2 - yy2 + 1.0f;
+ mat[2*4+3] = 0;
+ mat[3*4+0] = mat[3*4+1] = mat[3*4+2] = 0;
+ mat[3*4+3] = 1;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::quat_to_mat<double>(double const*, double*);
+// generated by autoexplicit.sh
+template void igl::quat_to_mat<float>(float const*, float*);
+#endif
diff --git a/xs/src/igl/quat_to_mat.h b/xs/src/igl/quat_to_mat.h
new file mode 100644
index 000000000..4291b291e
--- /dev/null
+++ b/xs/src/igl/quat_to_mat.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QUAT_TO_MAT_H
+#define IGL_QUAT_TO_MAT_H
+#include "igl_inline.h"
+// Name history:
+// quat2mat until 16 Sept 2011
+namespace igl
+{
+ // Convert a quaternion to a 4x4 matrix
+ // 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
+ // Input:
+ // quat pointer to four elements of quaternion (x,y,z,w)
+ // Output:
+ // mat pointer to 16 elements of matrix
+ template <typename Q_type>
+ IGL_INLINE void quat_to_mat(const Q_type * quat, Q_type * mat);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quat_to_mat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/quats_to_column.cpp b/xs/src/igl/quats_to_column.cpp
new file mode 100644
index 000000000..a4a88a666
--- /dev/null
+++ b/xs/src/igl/quats_to_column.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "quats_to_column.h"
+
+IGL_INLINE void igl::quats_to_column(
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > vQ,
+ Eigen::VectorXd & Q)
+{
+ Q.resize(vQ.size()*4);
+ for(int q = 0;q<(int)vQ.size();q++)
+ {
+ auto & xyzw = vQ[q].coeffs();
+ for(int c = 0;c<4;c++)
+ {
+ Q(q*4+c) = xyzw(c);
+ }
+ }
+}
+
+IGL_INLINE Eigen::VectorXd igl::quats_to_column(
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > vQ)
+{
+ Eigen::VectorXd Q;
+ quats_to_column(vQ,Q);
+ return Q;
+}
diff --git a/xs/src/igl/quats_to_column.h b/xs/src/igl/quats_to_column.h
new file mode 100644
index 000000000..4a7795ae1
--- /dev/null
+++ b/xs/src/igl/quats_to_column.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_QUATS_TO_COLUMN_H
+#define IGL_QUATS_TO_COLUMN_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <Eigen/StdVector>
+#include <vector>
+namespace igl
+{
+ // "Columnize" a list of quaternions (q1x,q1y,q1z,q1w,q2x,q2y,q2z,q2w,...)
+ //
+ // Inputs:
+ // vQ n-long list of quaternions
+ // Outputs:
+ // Q n*4-long list of coefficients
+ IGL_INLINE void quats_to_column(
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > vQ,
+ Eigen::VectorXd & Q);
+ IGL_INLINE Eigen::VectorXd quats_to_column(
+ const std::vector<
+ Eigen::Quaterniond,Eigen::aligned_allocator<Eigen::Quaterniond> > vQ);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "quats_to_column.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/ramer_douglas_peucker.cpp b/xs/src/igl/ramer_douglas_peucker.cpp
new file mode 100644
index 000000000..0dd1a40a3
--- /dev/null
+++ b/xs/src/igl/ramer_douglas_peucker.cpp
@@ -0,0 +1,150 @@
+#include "ramer_douglas_peucker.h"
+
+#include "LinSpaced.h"
+#include "find.h"
+#include "cumsum.h"
+#include "histc.h"
+#include "slice.h"
+#include "project_to_line.h"
+#include "EPS.h"
+#include "slice_mask.h"
+
+template <typename DerivedP, typename DerivedS, typename DerivedJ>
+IGL_INLINE void igl::ramer_douglas_peucker(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const typename DerivedP::Scalar tol,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ typedef typename DerivedP::Scalar Scalar;
+ // number of vertices
+ const int n = P.rows();
+ // Trivial base case
+ if(n <= 1)
+ {
+ J = DerivedJ::Zero(n);
+ S = P;
+ return;
+ }
+ // number of dimensions
+ const int m = P.cols();
+ Eigen::Array<bool,Eigen::Dynamic,1> I =
+ Eigen::Array<bool,Eigen::Dynamic,1>::Constant(n,1,true);
+ const auto stol = tol*tol;
+ std::function<void(const int,const int)> simplify;
+ simplify = [&I,&P,&stol,&simplify](const int ixs, const int ixe)->void
+ {
+ assert(ixe>ixs);
+ Scalar sdmax = 0;
+ typename Eigen::Matrix<Scalar,Eigen::Dynamic,1>::Index ixc = -1;
+ if((ixe-ixs)>1)
+ {
+ Scalar sdes = (P.row(ixe)-P.row(ixs)).squaredNorm();
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1> sD;
+ const auto & Pblock = P.block(ixs+1,0,((ixe+1)-ixs)-2,P.cols());
+ if(sdes<=EPS<Scalar>())
+ {
+ sD = (Pblock.rowwise()-P.row(ixs)).rowwise().squaredNorm();
+ }else
+ {
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1> T;
+ project_to_line(Pblock,P.row(ixs).eval(),P.row(ixe).eval(),T,sD);
+ }
+ sdmax = sD.maxCoeff(&ixc);
+ // Index full P
+ ixc = ixc+(ixs+1);
+ }
+ if(sdmax <= stol)
+ {
+ if(ixs != ixe-1)
+ {
+ I.block(ixs+1,0,((ixe+1)-ixs)-2,1).setConstant(false);
+ }
+ }else
+ {
+ simplify(ixs,ixc);
+ simplify(ixc,ixe);
+ }
+ };
+ simplify(0,n-1);
+ slice_mask(P,I,1,S);
+ find(I,J);
+}
+
+template <
+ typename DerivedP,
+ typename DerivedS,
+ typename DerivedJ,
+ typename DerivedQ>
+IGL_INLINE void igl::ramer_douglas_peucker(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const typename DerivedP::Scalar tol,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedQ> & Q)
+{
+ typedef typename DerivedP::Scalar Scalar;
+ ramer_douglas_peucker(P,tol,S,J);
+ const int n = P.rows();
+ assert(n>=2 && "Curve should be at least 2 points");
+ typedef Eigen::Matrix<Scalar,Eigen::Dynamic,1> VectorXS;
+ // distance traveled along high-res curve
+ VectorXS L(n);
+ L(0) = 0;
+ L.block(1,0,n-1,1) = (P.bottomRows(n-1)-P.topRows(n-1)).rowwise().norm();
+ // Give extra on end
+ VectorXS T;
+ cumsum(L,1,T);
+ T.conservativeResize(T.size()+1);
+ T(T.size()-1) = T(T.size()-2);
+ // index of coarse point before each fine vertex
+ Eigen::VectorXi B;
+ {
+ Eigen::VectorXi N;
+ histc(igl::LinSpaced<Eigen::VectorXi >(n,0,n-1),J,N,B);
+ }
+ // Add extra point at end
+ J.conservativeResize(J.size()+1);
+ J(J.size()-1) = J(J.size()-2);
+ Eigen::VectorXi s,d;
+ // Find index in original list of "start" vertices
+ slice(J,B,s);
+ // Find index in original list of "destination" vertices
+ slice(J,(B.array()+1).eval(),d);
+ // Parameter between start and destination is linear in arc-length
+ VectorXS Ts,Td;
+ slice(T,s,Ts);
+ slice(T,d,Td);
+ T = ((T.head(T.size()-1)-Ts).array()/(Td-Ts).array()).eval();
+ for(int t =0;t<T.size();t++)
+ {
+ if(!std::isfinite(T(t)) || T(t)!=T(t))
+ {
+ T(t) = 0;
+ }
+ }
+ DerivedS SB;
+ slice(S,B,1,SB);
+ Eigen::VectorXi MB = B.array()+1;
+ for(int b = 0;b<MB.size();b++)
+ {
+ if(MB(b) >= S.rows())
+ {
+ MB(b) = S.rows()-1;
+ }
+ }
+ DerivedS SMB;
+ slice(S,MB,1,SMB);
+ Q = SB.array() + ((SMB.array()-SB.array()).colwise()*T.array());
+
+ // Remove extra point at end
+ J.conservativeResize(J.size()-1);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::ramer_douglas_peucker<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::ramer_douglas_peucker<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::Matrix<double, -1, 2, 0, -1, 2>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+#endif
diff --git a/xs/src/igl/ramer_douglas_peucker.h b/xs/src/igl/ramer_douglas_peucker.h
new file mode 100644
index 000000000..dcfe47e85
--- /dev/null
+++ b/xs/src/igl/ramer_douglas_peucker.h
@@ -0,0 +1,49 @@
+#ifndef IGL_RAMER_DOUGLAS_PEUCKER_H
+#define IGL_RAMER_DOUGLAS_PEUCKER_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Ramer-Douglas-Peucker piecewise-linear curve simplification.
+ //
+ // Inputs:
+ // P #P by dim ordered list of vertices along the curve
+ // tol tolerance (maximal euclidean distance allowed between the new line
+ // and a vertex)
+ // Outputs:
+ // S #S by dim ordered list of points along the curve
+ // J #S list of indices into P so that S = P(J,:)
+ template <typename DerivedP, typename DerivedS, typename DerivedJ>
+ IGL_INLINE void ramer_douglas_peucker(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const typename DerivedP::Scalar tol,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ // Run (Ramer-)Duglass-Peucker curve simplification but keep track of where
+ // every point on the original curve maps to on the simplified curve.
+ //
+ // Inputs:
+ // P #P by dim list of points, (use P([1:end 1],:) for loops)
+ // tol DP tolerance
+ // Outputs:
+ // S #S by dim list of points along simplified curve
+ // J #S indices into P of simplified points
+ // Q #P by dim list of points mapping along simplified curve
+ //
+ template <
+ typename DerivedP,
+ typename DerivedS,
+ typename DerivedJ,
+ typename DerivedQ>
+ IGL_INLINE void ramer_douglas_peucker(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const typename DerivedP::Scalar tol,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::PlainObjectBase<DerivedQ> & Q);
+
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "ramer_douglas_peucker.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/random_dir.cpp b/xs/src/igl/random_dir.cpp
new file mode 100644
index 000000000..f30783418
--- /dev/null
+++ b/xs/src/igl/random_dir.cpp
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "random_dir.h"
+#include <igl/PI.h>
+#include <cmath>
+
+IGL_INLINE Eigen::Vector3d igl::random_dir()
+{
+ using namespace Eigen;
+ double z = (double)rand() / (double)RAND_MAX*2.0 - 1.0;
+ double t = (double)rand() / (double)RAND_MAX*2.0*PI;
+ // http://www.altdevblogaday.com/2012/05/03/generating-uniformly-distributed-points-on-sphere/
+ double r = sqrt(1.0-z*z);
+ double x = r * cos(t);
+ double y = r * sin(t);
+ return Vector3d(x,y,z);
+}
+
+IGL_INLINE Eigen::MatrixXd igl::random_dir_stratified(const int n)
+{
+ using namespace Eigen;
+ using namespace std;
+ const double m = std::floor(sqrt(double(n)));
+ MatrixXd N(n,3);
+ int row = 0;
+ for(int i = 0;i<m;i++)
+ {
+ const double x = double(i)*1./m;
+ for(int j = 0;j<m;j++)
+ {
+ const double y = double(j)*1./m;
+ double z = (x+(1./m)*(double)rand() / (double)RAND_MAX)*2.0 - 1.0;
+ double t = (y+(1./m)*(double)rand() / (double)RAND_MAX)*2.0*PI;
+ double r = sqrt(1.0-z*z);
+ N(row,0) = r * cos(t);
+ N(row,1) = r * sin(t);
+ N(row,2) = z;
+ row++;
+ }
+ }
+ // Finish off with uniform random directions
+ for(;row<n;row++)
+ {
+ N.row(row) = random_dir();
+ }
+ return N;
+}
diff --git a/xs/src/igl/random_dir.h b/xs/src/igl/random_dir.h
new file mode 100644
index 000000000..78027db05
--- /dev/null
+++ b/xs/src/igl/random_dir.h
@@ -0,0 +1,31 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RANDOM_DIR_H
+#define IGL_RANDOM_DIR_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Generate a uniformly random unit direction in 3D, return as vector
+ IGL_INLINE Eigen::Vector3d random_dir();
+ // Generate n stratified uniformly random unit directions in 3d, return as rows
+ // of an n by 3 matrix
+ //
+ // Inputs:
+ // n number of directions
+ // Return n by 3 matrix of random directions
+ IGL_INLINE Eigen::MatrixXd random_dir_stratified(const int n);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "random_dir.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/random_points_on_mesh.cpp b/xs/src/igl/random_points_on_mesh.cpp
new file mode 100644
index 000000000..b28135ad1
--- /dev/null
+++ b/xs/src/igl/random_points_on_mesh.cpp
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "random_points_on_mesh.h"
+#include "doublearea.h"
+#include "cumsum.h"
+#include "histc.h"
+#include <iostream>
+#include <cassert>
+
+template <typename DerivedV, typename DerivedF, typename DerivedB, typename DerivedFI>
+IGL_INLINE void igl::random_points_on_mesh(
+ const int n,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::PlainObjectBase<DerivedB > & B,
+ Eigen::PlainObjectBase<DerivedFI > & FI)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef typename DerivedV::Scalar Scalar;
+ typedef Matrix<Scalar,Dynamic,1> VectorXs;
+ VectorXs A;
+ doublearea(V,F,A);
+ A /= A.array().sum();
+ // Should be traingle mesh. Although Turk's method 1 generalizes...
+ assert(F.cols() == 3);
+ VectorXs C;
+ VectorXs A0(A.size()+1);
+ A0(0) = 0;
+ A0.bottomRightCorner(A.size(),1) = A;
+ // Even faster would be to use the "Alias Table Method"
+ cumsum(A0,1,C);
+ const VectorXs R = (VectorXs::Random(n,1).array() + 1.)/2.;
+ assert(R.minCoeff() >= 0);
+ assert(R.maxCoeff() <= 1);
+ histc(R,C,FI);
+ const VectorXs S = (VectorXs::Random(n,1).array() + 1.)/2.;
+ const VectorXs T = (VectorXs::Random(n,1).array() + 1.)/2.;
+ B.resize(n,3);
+ B.col(0) = 1.-T.array().sqrt();
+ B.col(1) = (1.-S.array()) * T.array().sqrt();
+ B.col(2) = S.array() * T.array().sqrt();
+}
+
+template <typename DerivedV, typename DerivedF, typename ScalarB, typename DerivedFI>
+IGL_INLINE void igl::random_points_on_mesh(
+ const int n,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::SparseMatrix<ScalarB > & B,
+ Eigen::PlainObjectBase<DerivedFI > & FI)
+{
+ using namespace Eigen;
+ using namespace std;
+ Matrix<ScalarB,Dynamic,3> BC;
+ random_points_on_mesh(n,V,F,BC,FI);
+ vector<Triplet<ScalarB> > BIJV;
+ BIJV.reserve(n*3);
+ for(int s = 0;s<n;s++)
+ {
+ for(int c = 0;c<3;c++)
+ {
+ assert(FI(s) < F.rows());
+ assert(FI(s) >= 0);
+ const int v = F(FI(s),c);
+ BIJV.push_back(Triplet<ScalarB>(s,v,BC(s,c)));
+ }
+ }
+ B.resize(n,V.rows());
+ B.reserve(n*3);
+ B.setFromTriplets(BIJV.begin(),BIJV.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::random_points_on_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::random_points_on_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/random_points_on_mesh.h b/xs/src/igl/random_points_on_mesh.h
new file mode 100644
index 000000000..7cde24f3c
--- /dev/null
+++ b/xs/src/igl/random_points_on_mesh.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RANDOM_POINTS_ON_MESH_H
+#define IGL_RANDOM_POINTS_ON_MESH_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // RANDOM_POINTS_ON_MESH Randomly sample a mesh (V,F) n times.
+ //
+ // Inputs:
+ // n number of samples
+ // V #V by dim list of mesh vertex positions
+ // F #F by 3 list of mesh triangle indices
+ // Outputs:
+ // B n by 3 list of barycentric coordinates, ith row are coordinates of
+ // ith sampled point in face FI(i)
+ // FI n list of indices into F
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedB, typename DerivedFI>
+ IGL_INLINE void random_points_on_mesh(
+ const int n,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::PlainObjectBase<DerivedB > & B,
+ Eigen::PlainObjectBase<DerivedFI > & FI);
+ // Outputs:
+ // B n by #V sparse matrix so that B*V produces a list of sample points
+ template <typename DerivedV, typename DerivedF, typename ScalarB, typename DerivedFI>
+ IGL_INLINE void random_points_on_mesh(
+ const int n,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ const Eigen::PlainObjectBase<DerivedF > & F,
+ Eigen::SparseMatrix<ScalarB > & B,
+ Eigen::PlainObjectBase<DerivedFI > & FI);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "random_points_on_mesh.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/random_quaternion.cpp b/xs/src/igl/random_quaternion.cpp
new file mode 100644
index 000000000..2d042e33f
--- /dev/null
+++ b/xs/src/igl/random_quaternion.cpp
@@ -0,0 +1,84 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "random_quaternion.h"
+#include "PI.h"
+
+template <typename Scalar>
+IGL_INLINE Eigen::Quaternion<Scalar> igl::random_quaternion()
+{
+ const auto & unit_rand = []()->Scalar
+ {
+ return ((Scalar)rand() / (Scalar)RAND_MAX);
+ };
+#ifdef false
+ // http://mathproofs.blogspot.com/2005/05/uniformly-distributed-random-unit.html
+ const Scalar t0 = 2.*igl::PI*unit_rand();
+ const Scalar t1 = acos(1.-2.*unit_rand());
+ const Scalar t2 = 0.5*(igl::PI*unit_rand() + acos(unit_rand()));
+ return Eigen::Quaternion<Scalar>(
+ 1.*sin(t0)*sin(t1)*sin(t2),
+ 1.*cos(t0)*sin(t1)*sin(t2),
+ 1.*cos(t1)*sin(t2),
+ 1.*cos(t2));
+#elif false
+ // "Uniform Random Rotations" [Shoemake 1992] method 1
+ const auto & uurand = [&unit_rand]()->Scalar
+ {
+ return unit_rand()*2.-1.;
+ };
+ Scalar x = uurand();
+ Scalar y = uurand();
+ Scalar z = uurand();
+ Scalar w = uurand();
+ const auto & hype = [&uurand](Scalar & x, Scalar & y)->Scalar
+ {
+ Scalar s1;
+ while((s1 = x*x + y*y) > 1.0)
+ {
+ x = uurand();
+ y = uurand();
+ }
+ return s1;
+ };
+ Scalar s1 = hype(x,y);
+ Scalar s2 = hype(z,w);
+ Scalar num1 = -2.*log(s1);
+ Scalar num2 = -2.*log(s2);
+ Scalar r = num1 + num2;
+ Scalar root1 = sqrt((num1/s1)/r);
+ Scalar root2 = sqrt((num2/s2)/r);
+ return Eigen::Quaternion<Scalar>(
+ x*root1,
+ y*root1,
+ z*root2,
+ w*root2);
+#else
+ // Shoemake method 2
+ const Scalar x0 = unit_rand();
+ const Scalar x1 = unit_rand();
+ const Scalar x2 = unit_rand();
+ const Scalar r1 = sqrt(1.0 - x0);
+ const Scalar r2 = sqrt(x0);
+ const Scalar t1 = 2.*igl::PI*x1;
+ const Scalar t2 = 2.*igl::PI*x2;
+ const Scalar c1 = cos(t1);
+ const Scalar s1 = sin(t1);
+ const Scalar c2 = cos(t2);
+ const Scalar s2 = sin(t2);
+ return Eigen::Quaternion<Scalar>(
+ s1*r1,
+ c1*r1,
+ s2*r2,
+ c2*r2);
+#endif
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template Eigen::Quaternion<double, 0> igl::random_quaternion<double>();
+#endif
diff --git a/xs/src/igl/random_quaternion.h b/xs/src/igl/random_quaternion.h
new file mode 100644
index 000000000..dfa36022b
--- /dev/null
+++ b/xs/src/igl/random_quaternion.h
@@ -0,0 +1,21 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RANDOM_QUATERNION_H
+#define IGL_RANDOM_QUATERNION_H
+#include "igl_inline.h"
+#include <Eigen/Geometry>
+namespace igl
+{
+ // Return a random quaternion via uniform sampling of the 4-sphere
+ template <typename Scalar>
+ IGL_INLINE Eigen::Quaternion<Scalar> random_quaternion();
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "random_quaternion.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/random_search.cpp b/xs/src/igl/random_search.cpp
new file mode 100644
index 000000000..d248d73e6
--- /dev/null
+++ b/xs/src/igl/random_search.cpp
@@ -0,0 +1,36 @@
+#include "random_search.h"
+#include <iostream>
+#include <cassert>
+
+template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB>
+IGL_INLINE Scalar igl::random_search(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const int iters,
+ DerivedX & X)
+{
+ Scalar min_f = std::numeric_limits<Scalar>::max();
+ const int dim = LB.size();
+ assert(UB.size() == dim && "UB should match LB size");
+ for(int iter = 0;iter<iters;iter++)
+ {
+ const DerivedX R = DerivedX::Random(dim).array()*0.5+0.5;
+ DerivedX Xr = LB.array() + R.array()*(UB-LB).array();
+ const Scalar fr = f(Xr);
+ if(fr<min_f)
+ {
+ min_f = fr;
+ X = Xr;
+ }
+ }
+ return min_f;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template float igl::random_search<float, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1>, Eigen::Matrix<float, 1, -1, 1, 1, -1> >(std::function<float (Eigen::Matrix<float, 1, -1, 1, 1, -1>&)>, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, -1, 1, 1, -1> > const&, int, Eigen::Matrix<float, 1, -1, 1, 1, -1>&);
+#endif
diff --git a/xs/src/igl/random_search.h b/xs/src/igl/random_search.h
new file mode 100644
index 000000000..8573e88cf
--- /dev/null
+++ b/xs/src/igl/random_search.h
@@ -0,0 +1,42 @@
+#ifndef IGL_RANDOM_SEARCH_H
+#define IGL_RANDOM_SEARCH_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <functional>
+namespace igl
+{
+ // Solve the problem:
+ //
+ // minimize f(x)
+ // subject to lb ≤ x ≤ ub
+ //
+ // by uniform random search.
+ //
+ // Inputs:
+ // f function to minimize
+ // LB #X vector of finite lower bounds
+ // UB #X vector of finite upper bounds
+ // iters number of iterations
+ // Outputs:
+ // X #X optimal parameter vector
+ // Returns f(X)
+ //
+ template <
+ typename Scalar,
+ typename DerivedX,
+ typename DerivedLB,
+ typename DerivedUB>
+ IGL_INLINE Scalar random_search(
+ const std::function< Scalar (DerivedX &) > f,
+ const Eigen::MatrixBase<DerivedLB> & LB,
+ const Eigen::MatrixBase<DerivedUB> & UB,
+ const int iters,
+ DerivedX & X);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "random_search.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/randperm.cpp b/xs/src/igl/randperm.cpp
new file mode 100644
index 000000000..d32af1760
--- /dev/null
+++ b/xs/src/igl/randperm.cpp
@@ -0,0 +1,27 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "randperm.h"
+#include "colon.h"
+#include <algorithm>
+
+template <typename DerivedI>
+IGL_INLINE void igl::randperm(
+ const int n,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ Eigen::VectorXi II;
+ igl::colon(0,1,n-1,II);
+ I = II;
+ std::random_shuffle(I.data(),I.data()+n);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::randperm<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::randperm<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/randperm.h b/xs/src/igl/randperm.h
new file mode 100644
index 000000000..0ba067141
--- /dev/null
+++ b/xs/src/igl/randperm.h
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RANDPERM_H
+#define IGL_RANDPERM_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Like matlab's randperm(n) but minus 1
+ //
+ // Inputs:
+ // n number of elements
+ // Outputs:
+ // I n list of rand permutation of 0:n-1
+ template <typename DerivedI>
+ IGL_INLINE void randperm(
+ const int n,
+ Eigen::PlainObjectBase<DerivedI> & I);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "randperm.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/ray_box_intersect.cpp b/xs/src/igl/ray_box_intersect.cpp
new file mode 100644
index 000000000..8c6346d86
--- /dev/null
+++ b/xs/src/igl/ray_box_intersect.cpp
@@ -0,0 +1,149 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ray_box_intersect.h"
+#include <vector>
+
+template <
+ typename Derivedsource,
+ typename Deriveddir,
+ typename Scalar>
+IGL_INLINE bool igl::ray_box_intersect(
+ const Eigen::MatrixBase<Derivedsource> & origin,
+ const Eigen::MatrixBase<Deriveddir> & dir,
+ const Eigen::AlignedBox<Scalar,3> & box,
+ const Scalar & t0,
+ const Scalar & t1,
+ Scalar & tmin,
+ Scalar & tmax)
+{
+#ifdef false
+ // https://github.com/RMonica/basic_next_best_view/blob/master/src/RayTracer.cpp
+ const auto & intersectRayBox = [](
+ const Eigen::Vector3f& rayo,
+ const Eigen::Vector3f& rayd,
+ const Eigen::Vector3f& bmin,
+ const Eigen::Vector3f& bmax,
+ float & tnear,
+ float & tfar
+ )->bool
+ {
+ Eigen::Vector3f bnear;
+ Eigen::Vector3f bfar;
+ // Checks for intersection testing on each direction coordinate
+ // Computes
+ float t1, t2;
+ tnear = -1e+6f, tfar = 1e+6f; //, tCube;
+ bool intersectFlag = true;
+ for (int i = 0; i < 3; ++i) {
+ // std::cout << "coordinate " << i << ": bmin " << bmin(i) << ", bmax " << bmax(i) << std::endl;
+ assert(bmin(i) <= bmax(i));
+ if (::fabs(rayd(i)) < 1e-6) { // Ray parallel to axis i-th
+ if (rayo(i) < bmin(i) || rayo(i) > bmax(i)) {
+ intersectFlag = false;
+ }
+ }
+ else {
+ // Finds the nearest and the farthest vertices of the box from the ray origin
+ if (::fabs(bmin(i) - rayo(i)) < ::fabs(bmax(i) - rayo(i))) {
+ bnear(i) = bmin(i);
+ bfar(i) = bmax(i);
+ }
+ else {
+ bnear(i) = bmax(i);
+ bfar(i) = bmin(i);
+ }
+ // std::cout << " bnear " << bnear(i) << ", bfar " << bfar(i) << std::endl;
+ // Finds the distance parameters t1 and t2 of the two ray-box intersections:
+ // t1 must be the closest to the ray origin rayo.
+ t1 = (bnear(i) - rayo(i)) / rayd(i);
+ t2 = (bfar(i) - rayo(i)) / rayd(i);
+ if (t1 > t2) {
+ std::swap(t1,t2);
+ }
+ // The two intersection values are used to saturate tnear and tfar
+ if (t1 > tnear) {
+ tnear = t1;
+ }
+ if (t2 < tfar) {
+ tfar = t2;
+ }
+ // std::cout << " t1 " << t1 << ", t2 " << t2 << ", tnear " << tnear << ", tfar " << tfar
+ // << " tnear > tfar? " << (tnear > tfar) << ", tfar < 0? " << (tfar < 0) << std::endl;
+ if(tnear > tfar) {
+ intersectFlag = false;
+ }
+ if(tfar < 0) {
+ intersectFlag = false;
+ }
+ }
+ }
+ // Checks whether intersection occurs or not
+ return intersectFlag;
+ };
+ float tmin_f, tmax_f;
+ bool ret = intersectRayBox(
+ origin. template cast<float>(),
+ dir. template cast<float>(),
+ box.min().template cast<float>(),
+ box.max().template cast<float>(),
+ tmin_f,
+ tmax_f);
+ tmin = tmin_f;
+ tmax = tmax_f;
+ return ret;
+#else
+ using namespace Eigen;
+ // This should be precomputed and provided as input
+ typedef Matrix<Scalar,1,3> RowVector3S;
+ const RowVector3S inv_dir( 1./dir(0),1./dir(1),1./dir(2));
+ const std::vector<bool> sign = { inv_dir(0)<0, inv_dir(1)<0, inv_dir(2)<0};
+ // http://people.csail.mit.edu/amy/papers/box-jgt.pdf
+ // "An Efficient and Robust Ray–Box Intersection Algorithm"
+ Scalar tymin, tymax, tzmin, tzmax;
+ std::vector<RowVector3S> bounds = {box.min(),box.max()};
+ tmin = ( bounds[sign[0]](0) - origin(0)) * inv_dir(0);
+ tmax = ( bounds[1-sign[0]](0) - origin(0)) * inv_dir(0);
+ tymin = (bounds[sign[1]](1) - origin(1)) * inv_dir(1);
+ tymax = (bounds[1-sign[1]](1) - origin(1)) * inv_dir(1);
+ if ( (tmin > tymax) || (tymin > tmax) )
+ {
+ return false;
+ }
+ if (tymin > tmin)
+ {
+ tmin = tymin;
+ }
+ if (tymax < tmax)
+ {
+ tmax = tymax;
+ }
+ tzmin = (bounds[sign[2]](2) - origin(2)) * inv_dir(2);
+ tzmax = (bounds[1-sign[2]](2) - origin(2)) * inv_dir(2);
+ if ( (tmin > tzmax) || (tzmin > tmax) )
+ {
+ return false;
+ }
+ if (tzmin > tmin)
+ {
+ tmin = tzmin;
+ }
+ if (tzmax < tmax)
+ {
+ tmax = tzmax;
+ }
+ if(!( (tmin < t1) && (tmax > t0) ))
+ {
+ return false;
+ }
+ return true;
+#endif
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::ray_box_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double>(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::AlignedBox<double, 3> const&, double const&, double const&, double&, double&);
+#endif \ No newline at end of file
diff --git a/xs/src/igl/ray_box_intersect.h b/xs/src/igl/ray_box_intersect.h
new file mode 100644
index 000000000..6b6e14aaa
--- /dev/null
+++ b/xs/src/igl/ray_box_intersect.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RAY_BOX_INTERSECT_H
+#define IGL_RAY_BOX_INTERSECT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+namespace igl
+{
+ // Determine whether a ray origin+t*dir and box intersect within the ray's parameterized
+ // range (t0,t1)
+ //
+ // Inputs:
+ // source 3-vector origin of ray
+ // dir 3-vector direction of ray
+ // box axis aligned box
+ // t0 hit only if hit.t less than t0
+ // t1 hit only if hit.t greater than t1
+ // Outputs:
+ // tmin minimum of interval of overlap within [t0,t1]
+ // tmax maximum of interval of overlap within [t0,t1]
+ // Returns true if hit
+ template <
+ typename Derivedsource,
+ typename Deriveddir,
+ typename Scalar>
+ IGL_INLINE bool ray_box_intersect(
+ const Eigen::MatrixBase<Derivedsource> & source,
+ const Eigen::MatrixBase<Deriveddir> & dir,
+ const Eigen::AlignedBox<Scalar,3> & box,
+ const Scalar & t0,
+ const Scalar & t1,
+ Scalar & tmin,
+ Scalar & tmax);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "ray_box_intersect.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/ray_mesh_intersect.cpp b/xs/src/igl/ray_mesh_intersect.cpp
new file mode 100644
index 000000000..512a35c46
--- /dev/null
+++ b/xs/src/igl/ray_mesh_intersect.cpp
@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ray_mesh_intersect.h"
+
+extern "C"
+{
+#include "raytri.c"
+}
+
+template <
+ typename Derivedsource,
+ typename Deriveddir,
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE bool igl::ray_mesh_intersect(
+ const Eigen::MatrixBase<Derivedsource> & s,
+ const Eigen::MatrixBase<Deriveddir> & dir,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<igl::Hit> & hits)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Should be but can't be const
+ Vector3d s_d = s.template cast<double>();
+ Vector3d dir_d = dir.template cast<double>();
+ hits.clear();
+ // loop over all triangles
+ for(int f = 0;f<F.rows();f++)
+ {
+ // Should be but can't be const
+ RowVector3d v0 = V.row(F(f,0)).template cast<double>();
+ RowVector3d v1 = V.row(F(f,1)).template cast<double>();
+ RowVector3d v2 = V.row(F(f,2)).template cast<double>();
+ // shoot ray, record hit
+ double t,u,v;
+ if(intersect_triangle1(
+ s_d.data(), dir_d.data(), v0.data(), v1.data(), v2.data(), &t, &u, &v) &&
+ t>0)
+ {
+ hits.push_back({(int)f,(int)-1,(float)u,(float)v,(float)t});
+ }
+ }
+ // Sort hits based on distance
+ std::sort(
+ hits.begin(),
+ hits.end(),
+ [](const Hit & a, const Hit & b)->bool{ return a.t < b.t;});
+ return hits.size() > 0;
+}
+
+template <
+ typename Derivedsource,
+ typename Deriveddir,
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE bool igl::ray_mesh_intersect(
+ const Eigen::MatrixBase<Derivedsource> & source,
+ const Eigen::MatrixBase<Deriveddir> & dir,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ igl::Hit & hit)
+{
+ std::vector<igl::Hit> hits;
+ ray_mesh_intersect(source,dir,V,F,hits);
+ if(hits.size() > 0)
+ {
+ hit = hits.front();
+ return true;
+ }else
+ {
+ return false;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::ray_mesh_intersect<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+template bool igl::ray_mesh_intersect<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::Hit&);
+template bool igl::ray_mesh_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<int, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, igl::Hit&);
+#endif
diff --git a/xs/src/igl/ray_mesh_intersect.h b/xs/src/igl/ray_mesh_intersect.h
new file mode 100644
index 000000000..e081bf3bb
--- /dev/null
+++ b/xs/src/igl/ray_mesh_intersect.h
@@ -0,0 +1,56 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RAY_MESH_INTERSECT_H
+#define IGL_RAY_MESH_INTERSECT_H
+#include "igl_inline.h"
+#include "Hit.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ // Shoot a ray against a mesh (V,F) and collect all hits.
+ //
+ // Inputs:
+ // source 3-vector origin of ray
+ // dir 3-vector direction of ray
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of mesh face indices into V
+ // Outputs:
+ // hits **sorted** list of hits
+ // Returns true if there were any hits (hits.size() > 0)
+ //
+ template <
+ typename Derivedsource,
+ typename Deriveddir,
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE bool ray_mesh_intersect(
+ const Eigen::MatrixBase<Derivedsource> & source,
+ const Eigen::MatrixBase<Deriveddir> & dir,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<igl::Hit> & hits);
+ // Outputs:
+ // hit first hit, set only if it exists
+ // Returns true if there was a hit
+ template <
+ typename Derivedsource,
+ typename Deriveddir,
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE bool ray_mesh_intersect(
+ const Eigen::MatrixBase<Derivedsource> & source,
+ const Eigen::MatrixBase<Deriveddir> & dir,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ igl::Hit & hit);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "ray_mesh_intersect.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/ray_sphere_intersect.cpp b/xs/src/igl/ray_sphere_intersect.cpp
new file mode 100644
index 000000000..8a05c2a12
--- /dev/null
+++ b/xs/src/igl/ray_sphere_intersect.cpp
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "ray_sphere_intersect.h"
+
+template <
+ typename Derivedo,
+ typename Derivedd,
+ typename Derivedc,
+ typename r_type,
+ typename t_type>
+IGL_INLINE int igl::ray_sphere_intersect(
+ const Eigen::PlainObjectBase<Derivedo> & ao,
+ const Eigen::PlainObjectBase<Derivedd> & d,
+ const Eigen::PlainObjectBase<Derivedc> & ac,
+ r_type r,
+ t_type & t0,
+ t_type & t1)
+{
+ Eigen::Vector3d o = ao-ac;
+ // http://wiki.cgsociety.org/index.php/Ray_Sphere_Intersection
+ //Compute A, B and C coefficients
+ double a = d.dot(d);
+ double b = 2 * d.dot(o);
+ double c = o.dot(o) - (r * r);
+
+ //Find discriminant
+ double disc = b * b - 4 * a * c;
+
+ // if discriminant is negative there are no real roots, so return
+ // false as ray misses sphere
+ if (disc < 0)
+ {
+ return 0;
+ }
+
+ // compute q as described above
+ double distSqrt = sqrt(disc);
+ double q;
+ if (b < 0)
+ {
+ q = (-b - distSqrt)/2.0;
+ } else
+ {
+ q = (-b + distSqrt)/2.0;
+ }
+
+ // compute t0 and t1
+ t0 = q / a;
+ double _t1 = c/q;
+ if(_t1 == t0)
+ {
+ return 1;
+ }
+ t1 = _t1;
+ // make sure t0 is smaller than t1
+ if (t0 > t1)
+ {
+ // if t0 is bigger than t1 swap them around
+ double temp = t0;
+ t0 = t1;
+ t1 = temp;
+ }
+ return 2;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template int igl::ray_sphere_intersect<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, 3, 1, 0, 3, 1>, double, double>(Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&, double, double&, double&);
+#endif
diff --git a/xs/src/igl/ray_sphere_intersect.h b/xs/src/igl/ray_sphere_intersect.h
new file mode 100644
index 000000000..b4dfea379
--- /dev/null
+++ b/xs/src/igl/ray_sphere_intersect.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RAY_SPHERE_INTERSECT_H
+#define IGL_RAY_SPHERE_INTERSECT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Compute the intersection between a ray from O in direction D and a sphere
+ // centered at C with radius r
+ //
+ // Inputs:
+ // o origin of ray
+ // d direction of ray
+ // c center of sphere
+ // r radius of sphere
+ // Outputs:
+ // t0 parameterization of first hit (set only if exists) so that hit
+ // position = o + t0*d
+ // t1 parameterization of second hit (set only if exists)
+ //
+ // Returns the number of hits
+ template <
+ typename Derivedo,
+ typename Derivedd,
+ typename Derivedc,
+ typename r_type,
+ typename t_type>
+ IGL_INLINE int ray_sphere_intersect(
+ const Eigen::PlainObjectBase<Derivedo> & o,
+ const Eigen::PlainObjectBase<Derivedd> & d,
+ const Eigen::PlainObjectBase<Derivedc> & c,
+ r_type r,
+ t_type & t0,
+ t_type & t1);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "ray_sphere_intersect.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/raytri.c b/xs/src/igl/raytri.c
new file mode 100644
index 000000000..b5e7f7b1f
--- /dev/null
+++ b/xs/src/igl/raytri.c
@@ -0,0 +1,267 @@
+/* Ray-Triangle Intersection Test Routines */
+/* Different optimizations of my and Ben Trumbore's */
+/* code from journals of graphics tools (JGT) */
+/* http://www.acm.org/jgt/ */
+/* by Tomas Moller, May 2000 */
+
+
+// Alec: this file is listed as "Public Domain"
+// http://fileadmin.cs.lth.se/cs/Personal/Tomas_Akenine-Moller/code/
+
+// Alec: I've added an include guard, made all functions inline and added
+// IGL_RAY_TRI_ to #define macros
+#ifndef IGL_RAY_TRI_C
+#define IGL_RAY_TRI_C
+
+#include <math.h>
+
+#define IGL_RAY_TRI_EPSILON 0.000001
+#define IGL_RAY_TRI_CROSS(dest,v1,v2) \
+ dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
+ dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
+ dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
+#define IGL_RAY_TRI_DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
+#define IGL_RAY_TRI_SUB(dest,v1,v2) \
+ dest[0]=v1[0]-v2[0]; \
+ dest[1]=v1[1]-v2[1]; \
+ dest[2]=v1[2]-v2[2];
+
+/* the original jgt code */
+inline int intersect_triangle(double orig[3], double dir[3],
+ double vert0[3], double vert1[3], double vert2[3],
+ double *t, double *u, double *v)
+{
+ double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
+ double det,inv_det;
+
+ /* find vectors for two edges sharing vert0 */
+ IGL_RAY_TRI_SUB(edge1, vert1, vert0);
+ IGL_RAY_TRI_SUB(edge2, vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ IGL_RAY_TRI_CROSS(pvec, dir, edge2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ det = IGL_RAY_TRI_DOT(edge1, pvec);
+
+ if (det > -IGL_RAY_TRI_EPSILON && det < IGL_RAY_TRI_EPSILON)
+ return 0;
+ inv_det = 1.0 / det;
+
+ /* calculate distance from vert0 to ray origin */
+ IGL_RAY_TRI_SUB(tvec, orig, vert0);
+
+ /* calculate U parameter and test bounds */
+ *u = IGL_RAY_TRI_DOT(tvec, pvec) * inv_det;
+ if (*u < 0.0 || *u > 1.0)
+ return 0;
+
+ /* prepare to test V parameter */
+ IGL_RAY_TRI_CROSS(qvec, tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ *v = IGL_RAY_TRI_DOT(dir, qvec) * inv_det;
+ if (*v < 0.0 || *u + *v > 1.0)
+ return 0;
+
+ /* calculate t, ray intersects triangle */
+ *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det;
+
+ return 1;
+}
+
+
+/* code rewritten to do tests on the sign of the determinant */
+/* the division is at the end in the code */
+inline int intersect_triangle1(double orig[3], double dir[3],
+ double vert0[3], double vert1[3], double vert2[3],
+ double *t, double *u, double *v)
+{
+ double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
+ double det,inv_det;
+
+ /* find vectors for two edges sharing vert0 */
+ IGL_RAY_TRI_SUB(edge1, vert1, vert0);
+ IGL_RAY_TRI_SUB(edge2, vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ IGL_RAY_TRI_CROSS(pvec, dir, edge2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ det = IGL_RAY_TRI_DOT(edge1, pvec);
+
+ if (det > IGL_RAY_TRI_EPSILON)
+ {
+ /* calculate distance from vert0 to ray origin */
+ IGL_RAY_TRI_SUB(tvec, orig, vert0);
+
+ /* calculate U parameter and test bounds */
+ *u = IGL_RAY_TRI_DOT(tvec, pvec);
+ if (*u < 0.0 || *u > det)
+ return 0;
+
+ /* prepare to test V parameter */
+ IGL_RAY_TRI_CROSS(qvec, tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ *v = IGL_RAY_TRI_DOT(dir, qvec);
+ if (*v < 0.0 || *u + *v > det)
+ return 0;
+
+ }
+ else if(det < -IGL_RAY_TRI_EPSILON)
+ {
+ /* calculate distance from vert0 to ray origin */
+ IGL_RAY_TRI_SUB(tvec, orig, vert0);
+
+ /* calculate U parameter and test bounds */
+ *u = IGL_RAY_TRI_DOT(tvec, pvec);
+/* printf("*u=%f\n",(float)*u); */
+/* printf("det=%f\n",det); */
+ if (*u > 0.0 || *u < det)
+ return 0;
+
+ /* prepare to test V parameter */
+ IGL_RAY_TRI_CROSS(qvec, tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ *v = IGL_RAY_TRI_DOT(dir, qvec) ;
+ if (*v > 0.0 || *u + *v < det)
+ return 0;
+ }
+ else return 0; /* ray is parallel to the plane of the triangle */
+
+
+ inv_det = 1.0 / det;
+
+ /* calculate t, ray intersects triangle */
+ *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det;
+ (*u) *= inv_det;
+ (*v) *= inv_det;
+
+ return 1;
+}
+
+/* code rewritten to do tests on the sign of the determinant */
+/* the division is before the test of the sign of the det */
+inline int intersect_triangle2(double orig[3], double dir[3],
+ double vert0[3], double vert1[3], double vert2[3],
+ double *t, double *u, double *v)
+{
+ double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
+ double det,inv_det;
+
+ /* find vectors for two edges sharing vert0 */
+ IGL_RAY_TRI_SUB(edge1, vert1, vert0);
+ IGL_RAY_TRI_SUB(edge2, vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ IGL_RAY_TRI_CROSS(pvec, dir, edge2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ det = IGL_RAY_TRI_DOT(edge1, pvec);
+
+ /* calculate distance from vert0 to ray origin */
+ IGL_RAY_TRI_SUB(tvec, orig, vert0);
+ inv_det = 1.0 / det;
+
+ if (det > IGL_RAY_TRI_EPSILON)
+ {
+ /* calculate U parameter and test bounds */
+ *u = IGL_RAY_TRI_DOT(tvec, pvec);
+ if (*u < 0.0 || *u > det)
+ return 0;
+
+ /* prepare to test V parameter */
+ IGL_RAY_TRI_CROSS(qvec, tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ *v = IGL_RAY_TRI_DOT(dir, qvec);
+ if (*v < 0.0 || *u + *v > det)
+ return 0;
+
+ }
+ else if(det < -IGL_RAY_TRI_EPSILON)
+ {
+ /* calculate U parameter and test bounds */
+ *u = IGL_RAY_TRI_DOT(tvec, pvec);
+ if (*u > 0.0 || *u < det)
+ return 0;
+
+ /* prepare to test V parameter */
+ IGL_RAY_TRI_CROSS(qvec, tvec, edge1);
+
+ /* calculate V parameter and test bounds */
+ *v = IGL_RAY_TRI_DOT(dir, qvec) ;
+ if (*v > 0.0 || *u + *v < det)
+ return 0;
+ }
+ else return 0; /* ray is parallel to the plane of the triangle */
+
+ /* calculate t, ray intersects triangle */
+ *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det;
+ (*u) *= inv_det;
+ (*v) *= inv_det;
+
+ return 1;
+}
+
+/* code rewritten to do tests on the sign of the determinant */
+/* the division is before the test of the sign of the det */
+/* and one IGL_RAY_TRI_CROSS has been moved out from the if-else if-else */
+inline int intersect_triangle3(double orig[3], double dir[3],
+ double vert0[3], double vert1[3], double vert2[3],
+ double *t, double *u, double *v)
+{
+ double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3];
+ double det,inv_det;
+
+ /* find vectors for two edges sharing vert0 */
+ IGL_RAY_TRI_SUB(edge1, vert1, vert0);
+ IGL_RAY_TRI_SUB(edge2, vert2, vert0);
+
+ /* begin calculating determinant - also used to calculate U parameter */
+ IGL_RAY_TRI_CROSS(pvec, dir, edge2);
+
+ /* if determinant is near zero, ray lies in plane of triangle */
+ det = IGL_RAY_TRI_DOT(edge1, pvec);
+
+ /* calculate distance from vert0 to ray origin */
+ IGL_RAY_TRI_SUB(tvec, orig, vert0);
+ inv_det = 1.0 / det;
+
+ IGL_RAY_TRI_CROSS(qvec, tvec, edge1);
+
+ if (det > IGL_RAY_TRI_EPSILON)
+ {
+ *u = IGL_RAY_TRI_DOT(tvec, pvec);
+ if (*u < 0.0 || *u > det)
+ return 0;
+
+ /* calculate V parameter and test bounds */
+ *v = IGL_RAY_TRI_DOT(dir, qvec);
+ if (*v < 0.0 || *u + *v > det)
+ return 0;
+
+ }
+ else if(det < -IGL_RAY_TRI_EPSILON)
+ {
+ /* calculate U parameter and test bounds */
+ *u = IGL_RAY_TRI_DOT(tvec, pvec);
+ if (*u > 0.0 || *u < det)
+ return 0;
+
+ /* calculate V parameter and test bounds */
+ *v = IGL_RAY_TRI_DOT(dir, qvec) ;
+ if (*v > 0.0 || *u + *v < det)
+ return 0;
+ }
+ else return 0; /* ray is parallel to the plane of the triangle */
+
+ *t = IGL_RAY_TRI_DOT(edge2, qvec) * inv_det;
+ (*u) *= inv_det;
+ (*v) *= inv_det;
+
+ return 1;
+}
+#endif
diff --git a/xs/src/igl/readBF.cpp b/xs/src/igl/readBF.cpp
new file mode 100644
index 000000000..03099ea7e
--- /dev/null
+++ b/xs/src/igl/readBF.cpp
@@ -0,0 +1,114 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readBF.h"
+#include "list_to_matrix.h"
+#include <vector>
+#include <cstdio>
+#include <fstream>
+#include <cassert>
+#include <functional>
+template <
+ typename DerivedWI,
+ typename DerivedP,
+ typename DerivedO>
+IGL_INLINE bool igl::readBF(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedWI> & WI,
+ Eigen::PlainObjectBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedO> & O)
+{
+ using namespace std;
+ ifstream is(filename);
+ if(!is.is_open())
+ {
+ return false;
+ }
+ string line;
+ std::vector<typename DerivedWI::Scalar> vWI;
+ std::vector<typename DerivedP::Scalar> vP;
+ std::vector<std::vector<typename DerivedO::Scalar> > vO;
+ while(getline(is, line))
+ {
+ int wi,p;
+ double cx,cy,cz;
+ if(sscanf(line.c_str(), "%d %d %lg %lg %lg",&wi,&p,&cx,&cy,&cz) != 5)
+ {
+ return false;
+ }
+ vWI.push_back(wi);
+ vP.push_back(p);
+ vO.push_back({cx,cy,cz});
+ }
+ list_to_matrix(vWI,WI);
+ list_to_matrix(vP,P);
+ list_to_matrix(vO,O);
+ return true;
+}
+
+template <
+ typename DerivedWI,
+ typename DerivedbfP,
+ typename DerivedO,
+ typename DerivedC,
+ typename DerivedBE,
+ typename DerivedP>
+IGL_INLINE bool igl::readBF(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedWI> & WI,
+ Eigen::PlainObjectBase<DerivedbfP> & bfP,
+ Eigen::PlainObjectBase<DerivedO> & offsets,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedBE> & BE,
+ Eigen::PlainObjectBase<DerivedP> & P)
+{
+ using namespace Eigen;
+ using namespace std;
+ if(!readBF(filename,WI,bfP,offsets))
+ {
+ return false;
+ }
+
+ C.resize(WI.rows(),3);
+ vector<bool> computed(C.rows(),false);
+ // better not be cycles in bfP
+ std::function<Eigen::RowVector3d(const int)> locate_tip;
+ locate_tip =
+ [&offsets,&computed,&bfP,&locate_tip,&C](const int w)->Eigen::RowVector3d
+ {
+ if(w<0) return Eigen::RowVector3d(0,0,0);
+ if(computed[w]) return C.row(w);
+ computed[w] = true;
+ return C.row(w) = locate_tip(bfP(w)) + offsets.row(w);
+ };
+ int num_roots = (bfP.array() == -1).count();
+ BE.resize(WI.rows()-num_roots,2);
+ P.resize(BE.rows());
+ for(int c = 0;c<C.rows();c++)
+ {
+ locate_tip(c);
+ assert(c>=0);
+ // weight associated with this bone
+ const int wi = WI(c);
+ if(wi >= 0)
+ {
+ // index into C
+ const int p = bfP(c);
+ assert(p >= 0 && "No weights for roots allowed");
+ // index into BE
+ const int pwi = WI(p);
+ P(wi) = pwi;
+ BE(wi,0) = p;
+ BE(wi,1) = c;
+ }
+ }
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::readBF<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/readBF.h b/xs/src/igl/readBF.h
new file mode 100644
index 000000000..a2b010c85
--- /dev/null
+++ b/xs/src/igl/readBF.h
@@ -0,0 +1,67 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READBF_H
+#define IGL_READBF_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+namespace igl
+{
+ // Read a bones forest from a file, returns a list of bone roots
+ // Input:
+ // file_name path to .bf bones tree file
+ // Output:
+ // WI #B list of unique weight indices
+ // P #B list of parent indices into B, -1 for roots
+ // O #B by 3 list of tip offset vectors from parent (or position for roots)
+ // Returns true on success, false on errors
+ template <
+ typename DerivedWI,
+ typename DerivedP,
+ typename DerivedO>
+ IGL_INLINE bool readBF(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedWI> & WI,
+ Eigen::PlainObjectBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedO> & O);
+ // Read bone forest into pure bone-skeleton format, expects only bones (no
+ // point handles), and that a root in the .bf <---> no weight attachment.
+ //
+ // Input:
+ // file_name path to .bf bones tree file
+ // Output:
+ // WI #B list of unique weight indices
+ // P #B list of parent indices into B, -1 for roots
+ // O #B by 3 list of tip offset vectors from parent (or position for roots)
+ // C #C by 3 list of absolute joint locations
+ // BE #BE by 3 list of bone indices into C, in order of weight index
+ // P #BE list of parent bone indices into BE, -1 means root bone
+ // Returns true on success, false on errors
+ //
+ // See also: readTGF, bone_parents, forward_kinematics
+ template <
+ typename DerivedWI,
+ typename DerivedbfP,
+ typename DerivedO,
+ typename DerivedC,
+ typename DerivedBE,
+ typename DerivedP>
+ IGL_INLINE bool readBF(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedWI> & WI,
+ Eigen::PlainObjectBase<DerivedbfP> & bfP,
+ Eigen::PlainObjectBase<DerivedO> & O,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedBE> & BE,
+ Eigen::PlainObjectBase<DerivedP> & P);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readBF.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/readCSV.cpp b/xs/src/igl/readCSV.cpp
new file mode 100644
index 000000000..eb00b1fe4
--- /dev/null
+++ b/xs/src/igl/readCSV.cpp
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readCSV.h"
+
+#include <sstream>
+#include <string>
+#include <fstream>
+#include <iostream>
+
+#include <vector>
+
+template <typename Scalar>
+IGL_INLINE bool igl::readCSV(
+ const std::string str,
+ Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>& M)
+{
+ using namespace std;
+
+ std::vector<std::vector<Scalar> > Mt;
+
+ std::ifstream infile(str.c_str());
+ std::string line;
+ while (std::getline(infile, line))
+ {
+ std::istringstream iss(line);
+ vector<Scalar> temp;
+ Scalar a;
+ while (iss >> a)
+ temp.push_back(a);
+
+ if (temp.size() != 0) // skip empty lines
+ Mt.push_back(temp);
+ }
+
+ if (Mt.size() != 0)
+ {
+ // Verify that it is indeed a matrix
+ for (unsigned i = 0; i<Mt.size(); ++i)
+ {
+ if (Mt[i].size() != Mt[0].size())
+ {
+ infile.close();
+ return false;
+ }
+ }
+
+ M.resize(Mt.size(),Mt[0].size());
+ for (unsigned i = 0; i<Mt.size(); ++i)
+ for (unsigned j = 0; j<Mt[i].size(); ++j)
+ M(i,j) = Mt[i][j];
+
+// cerr << "TRUE!" << endl;
+ return true;
+ }
+
+ infile.close();
+ return false;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+#endif
diff --git a/xs/src/igl/readCSV.h b/xs/src/igl/readCSV.h
new file mode 100644
index 000000000..480aad129
--- /dev/null
+++ b/xs/src/igl/readCSV.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READ_CSV_H
+#define IGL_READ_CSV_H
+
+#include "igl/igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+#include <vector>
+
+namespace igl
+{
+ // read a matrix from a csv file into a Eigen matrix
+ // Templates:
+ // Scalar type for the matrix
+ // Inputs:
+ // str path to .csv file
+ // Outputs:
+ // M eigen matrix
+ template <typename Scalar>
+ IGL_INLINE bool readCSV(
+ const std::string str,
+ Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic>& M);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readCSV.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/readDMAT.cpp b/xs/src/igl/readDMAT.cpp
new file mode 100644
index 000000000..1ae9fdd65
--- /dev/null
+++ b/xs/src/igl/readDMAT.cpp
@@ -0,0 +1,229 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readDMAT.h"
+
+#include "verbose.h"
+#include <cstdio>
+#include <iostream>
+#include <cassert>
+
+// Static helper method reads the first to elements in the given file
+// Inputs:
+// fp file pointer of .dmat file that was just opened
+// Outputs:
+// num_rows number of rows
+// num_cols number of columns
+// Returns
+// 0 success
+// 1 did not find header
+// 2 bad num_cols
+// 3 bad num_rows
+// 4 bad line ending
+static inline int readDMAT_read_header(FILE * fp, int & num_rows, int & num_cols)
+{
+ // first line contains number of rows and number of columns
+ int res = fscanf(fp,"%d %d",&num_cols,&num_rows);
+ if(res != 2)
+ {
+ return 1;
+ }
+ // check that number of columns and rows are sane
+ if(num_cols < 0)
+ {
+ fprintf(stderr,"IOError: readDMAT() number of columns %d < 0\n",num_cols);
+ return 2;
+ }
+ if(num_rows < 0)
+ {
+ fprintf(stderr,"IOError: readDMAT() number of rows %d < 0\n",num_rows);
+ return 3;
+ }
+ // finish reading header
+ char lf;
+
+ if(fread(&lf, sizeof(char), 1, fp)!=1 || !(lf == '\n' || lf == '\r'))
+ {
+ fprintf(stderr,"IOError: bad line ending in header\n");
+ return 4;
+ }
+
+ return 0;
+}
+
+#ifndef IGL_NO_EIGEN
+template <typename DerivedW>
+IGL_INLINE bool igl::readDMAT(const std::string file_name,
+ Eigen::PlainObjectBase<DerivedW> & W)
+{
+ FILE * fp = fopen(file_name.c_str(),"rb");
+ if(fp == NULL)
+ {
+ fprintf(stderr,"IOError: readDMAT() could not open %s...\n",file_name.c_str());
+ return false;
+ }
+ int num_rows,num_cols;
+ int head_success = readDMAT_read_header(fp,num_rows,num_cols);
+ if(head_success != 0)
+ {
+ if(head_success == 1)
+ {
+ fprintf(stderr,
+ "IOError: readDMAT() first row should be [num cols] [num rows]...\n");
+ }
+ fclose(fp);
+ return false;
+ }
+
+ // Resize output to fit matrix, only if non-empty since this will trigger an
+ // error on fixed size matrices before reaching binary data.
+ bool empty = num_rows == 0 || num_cols == 0;
+ if(!empty)
+ {
+ W.resize(num_rows,num_cols);
+ }
+
+ // Loop over columns slowly
+ for(int j = 0;j < num_cols;j++)
+ {
+ // loop over rows (down columns) quickly
+ for(int i = 0;i < num_rows;i++)
+ {
+ double d;
+ if(fscanf(fp," %lg",&d) != 1)
+ {
+ fclose(fp);
+ fprintf(
+ stderr,
+ "IOError: readDMAT() bad format after reading %d entries\n",
+ j*num_rows + i);
+ return false;
+ }
+ W(i,j) = d;
+ }
+ }
+
+ // Try to read header for binary part
+ head_success = readDMAT_read_header(fp,num_rows,num_cols);
+ if(head_success == 0)
+ {
+ assert(W.size() == 0);
+ // Resize for output
+ W.resize(num_rows,num_cols);
+ double * Wraw = new double[num_rows*num_cols];
+ fread(Wraw, sizeof(double), num_cols*num_rows, fp);
+ // Loop over columns slowly
+ for(int j = 0;j < num_cols;j++)
+ {
+ // loop over rows (down columns) quickly
+ for(int i = 0;i < num_rows;i++)
+ {
+ W(i,j) = Wraw[j*num_rows+i];
+ }
+ }
+ }else
+ {
+ // we skipped resizing before in case there was binary data
+ if(empty)
+ {
+ // This could trigger an error if using fixed size matrices.
+ W.resize(num_rows,num_cols);
+ }
+ }
+
+ fclose(fp);
+ return true;
+}
+#endif
+
+template <typename Scalar>
+IGL_INLINE bool igl::readDMAT(
+ const std::string file_name,
+ std::vector<std::vector<Scalar> > & W)
+{
+ FILE * fp = fopen(file_name.c_str(),"r");
+ if(fp == NULL)
+ {
+ fprintf(stderr,"IOError: readDMAT() could not open %s...\n",file_name.c_str());
+ return false;
+ }
+ int num_rows,num_cols;
+ bool head_success = readDMAT_read_header(fp,num_rows,num_cols);
+ if(head_success != 0)
+ {
+ if(head_success == 1)
+ {
+ fprintf(stderr,
+ "IOError: readDMAT() first row should be [num cols] [num rows]...\n");
+ }
+ fclose(fp);
+ return false;
+ }
+
+ // Resize for output
+ W.resize(num_rows,typename std::vector<Scalar>(num_cols));
+
+ // Loop over columns slowly
+ for(int j = 0;j < num_cols;j++)
+ {
+ // loop over rows (down columns) quickly
+ for(int i = 0;i < num_rows;i++)
+ {
+ double d;
+ if(fscanf(fp," %lg",&d) != 1)
+ {
+ fclose(fp);
+ fprintf(
+ stderr,
+ "IOError: readDMAT() bad format after reading %d entries\n",
+ j*num_rows + i);
+ return false;
+ }
+ W[i][j] = (Scalar)d;
+ }
+ }
+
+ // Try to read header for binary part
+ head_success = readDMAT_read_header(fp,num_rows,num_cols);
+ if(head_success == 0)
+ {
+ assert(W.size() == 0);
+ // Resize for output
+ W.resize(num_rows,typename std::vector<Scalar>(num_cols));
+ double * Wraw = new double[num_rows*num_cols];
+ fread(Wraw, sizeof(double), num_cols*num_rows, fp);
+ // Loop over columns slowly
+ for(int j = 0;j < num_cols;j++)
+ {
+ // loop over rows (down columns) quickly
+ for(int i = 0;i < num_rows;i++)
+ {
+ W[i][j] = Wraw[j*num_rows+i];
+ }
+ }
+ }
+
+ fclose(fp);
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readDMAT<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::readDMAT<double>(std::string, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&);
+template bool igl::readDMAT<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::readDMAT<Eigen::Matrix<double, 4, 1, 0, 4, 1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 1, 0, 4, 1> >&);
+template bool igl::readDMAT<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template bool igl::readDMAT<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template bool igl::readDMAT<Eigen::Matrix<int, -1, 2, 0, -1, 2> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template bool igl::readDMAT<Eigen::Matrix<double, -1, -1, 1, -1, -1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+template bool igl::readDMAT<Eigen::Matrix<int, -1, -1, 1, -1, -1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 1, -1, -1> >&);
+template bool igl::readDMAT<Eigen::Matrix<float, 1, 3, 1, 1, 3> >( std::string, Eigen::PlainObjectBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> >&);
+template bool igl::readDMAT<Eigen::Matrix<double, 1, 1, 0, 1, 1> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 1, 0, 1, 1> >&);
+#endif
+
diff --git a/xs/src/igl/readDMAT.h b/xs/src/igl/readDMAT.h
new file mode 100644
index 000000000..e09c492c1
--- /dev/null
+++ b/xs/src/igl/readDMAT.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READDMAT_H
+#define IGL_READDMAT_H
+#include "igl_inline.h"
+// .dmat is a simple ascii matrix file type, defined as follows. The first line
+// is always:
+// <#columns> <#rows>
+// Then the coefficients of the matrix are given separated by whitespace with
+// columns running fastest.
+//
+// Example:
+// The matrix m = [1 2 3; 4 5 6];
+// corresponds to a .dmat file containing:
+// 3 2
+// 1 4 2 5 3 6
+#include <string>
+#include <vector>
+#ifndef IGL_NO_EIGEN
+# include <Eigen/Core>
+#endif
+namespace igl
+{
+ // Read a matrix from an ascii dmat file
+ //
+ // Inputs:
+ // file_name path to .dmat file
+ // Outputs:
+ // W eigen matrix containing read-in coefficients
+ // Returns true on success, false on error
+ //
+#ifndef IGL_NO_EIGEN
+ template <typename DerivedW>
+ IGL_INLINE bool readDMAT(const std::string file_name,
+ Eigen::PlainObjectBase<DerivedW> & W);
+#endif
+ // Wrapper for vector of vectors
+ template <typename Scalar>
+ IGL_INLINE bool readDMAT(
+ const std::string file_name,
+ std::vector<std::vector<Scalar> > & W);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readDMAT.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/readMESH.cpp b/xs/src/igl/readMESH.cpp
new file mode 100644
index 000000000..bc912e11b
--- /dev/null
+++ b/xs/src/igl/readMESH.cpp
@@ -0,0 +1,506 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readMESH.h"
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readMESH(
+ const std::string mesh_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & T,
+ std::vector<std::vector<Index > > & F)
+{
+ using namespace std;
+ FILE * mesh_file = fopen(mesh_file_name.c_str(),"r");
+ if(NULL==mesh_file)
+ {
+ fprintf(stderr,"IOError: %s could not be opened...",mesh_file_name.c_str());
+ return false;
+ }
+ return igl::readMESH(mesh_file,V,T,F);
+}
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readMESH(
+ FILE * mesh_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & T,
+ std::vector<std::vector<Index > > & F)
+{
+ using namespace std;
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+ char line[LINE_MAX];
+ bool still_comments;
+ V.clear();
+ T.clear();
+ F.clear();
+
+ // eat comments at beginning of file
+ still_comments= true;
+ while(still_comments)
+ {
+ if(fgets(line,LINE_MAX,mesh_file) == NULL)
+ {
+ fprintf(stderr, "Error: couldn't find start of .mesh file");
+ fclose(mesh_file);
+ return false;
+ }
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+ char str[LINE_MAX];
+ sscanf(line," %s",str);
+ // check that first word is MeshVersionFormatted
+ if(0!=strcmp(str,"MeshVersionFormatted"))
+ {
+ fprintf(stderr,
+ "Error: first word should be MeshVersionFormatted not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+
+ int one = -1;
+ if(2 != sscanf(line,"%s %d",str,&one))
+ {
+ // 1 appears on next line?
+ fscanf(mesh_file," %d",&one);
+ }
+ if(one != 1)
+ {
+ fprintf(stderr,"Error: second word should be 1 not %d\n",one);
+ fclose(mesh_file);
+ return false;
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that third word is Dimension
+ if(0!=strcmp(str,"Dimension"))
+ {
+ fprintf(stderr,"Error: third word should be Dimension not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+ int three = -1;
+ if(2 != sscanf(line,"%s %d",str,&three))
+ {
+ // 1 appears on next line?
+ fscanf(mesh_file," %d",&three);
+ }
+ if(three != 3)
+ {
+ fprintf(stderr,"Error: only Dimension 3 supported not %d\n",three);
+ fclose(mesh_file);
+ return false;
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that fifth word is Vertices
+ if(0!=strcmp(str,"Vertices"))
+ {
+ fprintf(stderr,"Error: fifth word should be Vertices not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+
+ //fgets(line,LINE_MAX,mesh_file);
+
+ int number_of_vertices;
+ if(1 != fscanf(mesh_file," %d",&number_of_vertices) || number_of_vertices > 1000000000)
+ {
+ fprintf(stderr,"Error: expecting number of vertices less than 10^9...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ // allocate space for vertices
+ V.resize(number_of_vertices,vector<Scalar>(3,0));
+ int extra;
+ for(int i = 0;i<number_of_vertices;i++)
+ {
+ double x,y,z;
+ if(4 != fscanf(mesh_file," %lg %lg %lg %d",&x,&y,&z,&extra))
+ {
+ fprintf(stderr,"Error: expecting vertex position...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ V[i][0] = x;
+ V[i][1] = y;
+ V[i][2] = z;
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that sixth word is Triangles
+ if(0!=strcmp(str,"Triangles"))
+ {
+ fprintf(stderr,"Error: sixth word should be Triangles not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+ int number_of_triangles;
+ if(1 != fscanf(mesh_file," %d",&number_of_triangles))
+ {
+ fprintf(stderr,"Error: expecting number of triangles...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ // allocate space for triangles
+ F.resize(number_of_triangles,vector<Index>(3));
+ // triangle indices
+ int tri[3];
+ for(int i = 0;i<number_of_triangles;i++)
+ {
+ if(4 != fscanf(mesh_file," %d %d %d %d",&tri[0],&tri[1],&tri[2],&extra))
+ {
+ printf("Error: expecting triangle indices...\n");
+ return false;
+ }
+ for(int j = 0;j<3;j++)
+ {
+ F[i][j] = tri[j]-1;
+ }
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that sixth word is Triangles
+ if(0!=strcmp(str,"Tetrahedra"))
+ {
+ fprintf(stderr,"Error: seventh word should be Tetrahedra not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+ int number_of_tetrahedra;
+ if(1 != fscanf(mesh_file," %d",&number_of_tetrahedra))
+ {
+ fprintf(stderr,"Error: expecting number of tetrahedra...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ // allocate space for tetrahedra
+ T.resize(number_of_tetrahedra,vector<Index>(4));
+ // tet indices
+ int a,b,c,d;
+ for(int i = 0;i<number_of_tetrahedra;i++)
+ {
+ if(5 != fscanf(mesh_file," %d %d %d %d %d",&a,&b,&c,&d,&extra))
+ {
+ fprintf(stderr,"Error: expecting tetrahedra indices...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ T[i][0] = a-1;
+ T[i][1] = b-1;
+ T[i][2] = c-1;
+ T[i][3] = d-1;
+ }
+ fclose(mesh_file);
+ return true;
+}
+
+#include <Eigen/Core>
+#include "list_to_matrix.h"
+
+
+template <typename DerivedV, typename DerivedF, typename DerivedT>
+IGL_INLINE bool igl::readMESH(
+ const std::string mesh_file_name,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ using namespace std;
+ FILE * mesh_file = fopen(mesh_file_name.c_str(),"r");
+ if(NULL==mesh_file)
+ {
+ fprintf(stderr,"IOError: %s could not be opened...",mesh_file_name.c_str());
+ return false;
+ }
+ return readMESH(mesh_file,V,T,F);
+}
+
+template <typename DerivedV, typename DerivedF, typename DerivedT>
+IGL_INLINE bool igl::readMESH(
+ FILE * mesh_file,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ using namespace std;
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+ char line[LINE_MAX];
+ bool still_comments;
+
+ // eat comments at beginning of file
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ char str[LINE_MAX];
+ sscanf(line," %s",str);
+ // check that first word is MeshVersionFormatted
+ if(0!=strcmp(str,"MeshVersionFormatted"))
+ {
+ fprintf(stderr,
+ "Error: first word should be MeshVersionFormatted not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+ int one = -1;
+ if(2 != sscanf(line,"%s %d",str,&one))
+ {
+ // 1 appears on next line?
+ fscanf(mesh_file," %d",&one);
+ }
+ if(one != 1)
+ {
+ fprintf(stderr,"Error: second word should be 1 not %d\n",one);
+ fclose(mesh_file);
+ return false;
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that third word is Dimension
+ if(0!=strcmp(str,"Dimension"))
+ {
+ fprintf(stderr,"Error: third word should be Dimension not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+ int three = -1;
+ if(2 != sscanf(line,"%s %d",str,&three))
+ {
+ // 1 appears on next line?
+ fscanf(mesh_file," %d",&three);
+ }
+ if(three != 3)
+ {
+ fprintf(stderr,"Error: only Dimension 3 supported not %d\n",three);
+ fclose(mesh_file);
+ return false;
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that fifth word is Vertices
+ if(0!=strcmp(str,"Vertices"))
+ {
+ fprintf(stderr,"Error: fifth word should be Vertices not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+
+ //fgets(line,LINE_MAX,mesh_file);
+
+ int number_of_vertices;
+ if(1 != fscanf(mesh_file," %d",&number_of_vertices) || number_of_vertices > 1000000000)
+ {
+ fprintf(stderr,"Error: expecting number of vertices less than 10^9...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ // allocate space for vertices
+ V.resize(number_of_vertices,3);
+ int extra;
+ for(int i = 0;i<number_of_vertices;i++)
+ {
+ double x,y,z;
+ if(4 != fscanf(mesh_file," %lg %lg %lg %d",&x,&y,&z,&extra))
+ {
+ fprintf(stderr,"Error: expecting vertex position...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ V(i,0) = x;
+ V(i,1) = y;
+ V(i,2) = z;
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that sixth word is Triangles
+ if(0!=strcmp(str,"Triangles"))
+ {
+ fprintf(stderr,"Error: sixth word should be Triangles not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+ int number_of_triangles;
+ if(1 != fscanf(mesh_file," %d",&number_of_triangles))
+ {
+ fprintf(stderr,"Error: expecting number of triangles...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ // allocate space for triangles
+ F.resize(number_of_triangles,3);
+ // triangle indices
+ int tri[3];
+ for(int i = 0;i<number_of_triangles;i++)
+ {
+ if(4 != fscanf(mesh_file," %d %d %d %d",&tri[0],&tri[1],&tri[2],&extra))
+ {
+ printf("Error: expecting triangle indices...\n");
+ return false;
+ }
+ for(int j = 0;j<3;j++)
+ {
+ F(i,j) = tri[j]-1;
+ }
+ }
+
+ // eat comments
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,mesh_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ sscanf(line," %s",str);
+ // check that sixth word is Triangles
+ if(0!=strcmp(str,"Tetrahedra"))
+ {
+ fprintf(stderr,"Error: seventh word should be Tetrahedra not %s\n",str);
+ fclose(mesh_file);
+ return false;
+ }
+ int number_of_tetrahedra;
+ if(1 != fscanf(mesh_file," %d",&number_of_tetrahedra))
+ {
+ fprintf(stderr,"Error: expecting number of tetrahedra...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ // allocate space for tetrahedra
+ T.resize(number_of_tetrahedra,4);
+ // tet indices
+ int a,b,c,d;
+ for(int i = 0;i<number_of_tetrahedra;i++)
+ {
+ if(5 != fscanf(mesh_file," %d %d %d %d %d",&a,&b,&c,&d,&extra))
+ {
+ fprintf(stderr,"Error: expecting tetrahedra indices...\n");
+ fclose(mesh_file);
+ return false;
+ }
+ T(i,0) = a-1;
+ T(i,1) = b-1;
+ T(i,2) = c-1;
+ T(i,3) = d-1;
+ }
+ fclose(mesh_file);
+ return true;
+}
+//{
+// std::vector<std::vector<double> > vV,vT,vF;
+// bool success = igl::readMESH(mesh_file_name,vV,vT,vF);
+// if(!success)
+// {
+// // readMESH already printed error message to std err
+// return false;
+// }
+// bool V_rect = igl::list_to_matrix(vV,V);
+// if(!V_rect)
+// {
+// // igl::list_to_matrix(vV,V) already printed error message to std err
+// return false;
+// }
+// bool T_rect = igl::list_to_matrix(vT,T);
+// if(!T_rect)
+// {
+// // igl::list_to_matrix(vT,T) already printed error message to std err
+// return false;
+// }
+// bool F_rect = igl::list_to_matrix(vF,F);
+// if(!F_rect)
+// {
+// // igl::list_to_matrix(vF,F) already printed error message to std err
+// return false;
+// }
+// assert(V.cols() == 3);
+// assert(T.cols() == 4);
+// assert(F.cols() == 3);
+// return true;
+//}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readMESH<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template bool igl::readMESH<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(FILE*, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template bool igl::readMESH<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readMESH<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template bool igl::readMESH<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template bool igl::readMESH<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::readMESH<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::readMESH<double, int>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template bool igl::readMESH<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/readMESH.h b/xs/src/igl/readMESH.h
new file mode 100644
index 000000000..b9b763035
--- /dev/null
+++ b/xs/src/igl/readMESH.h
@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READMESH_H
+#define IGL_READMESH_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <string>
+#include <vector>
+#include <cstdio>
+
+namespace igl
+{
+ // load a tetrahedral volume mesh from a .mesh file
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Input:
+ // mesh_file_name path of .mesh file
+ // Outputs:
+ // V double matrix of vertex positions #V by 3
+ // T #T list of tet indices into vertex positions
+ // F #F list of face indices into vertex positions
+ //
+ // Known bugs: Holes and regions are not supported
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readMESH(
+ const std::string mesh_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & T,
+ std::vector<std::vector<Index > > & F);
+ // Inputs:
+ // mesh_file pointer to already opened .mesh file
+ // Outputs:
+ // mesh_file closed file
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readMESH(
+ FILE * mesh_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & T,
+ std::vector<std::vector<Index > > & F);
+
+ // Input:
+ // mesh_file_name path of .mesh file
+ // Outputs:
+ // V eigen double matrix #V by 3
+ // T eigen int matrix #T by 4
+ // F eigen int matrix #F by 3
+ template <typename DerivedV, typename DerivedF, typename DerivedT>
+ IGL_INLINE bool readMESH(
+ const std::string mesh_file_name,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ // Inputs:
+ // mesh_file pointer to already opened .mesh file
+ // Outputs:
+ // mesh_file closed file
+ template <typename DerivedV, typename DerivedF, typename DerivedT>
+ IGL_INLINE bool readMESH(
+ FILE * mesh_file,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedT>& T,
+ Eigen::PlainObjectBase<DerivedF>& F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readMESH.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/readMSH.cpp b/xs/src/igl/readMSH.cpp
new file mode 100644
index 000000000..2335fd1cc
--- /dev/null
+++ b/xs/src/igl/readMSH.cpp
@@ -0,0 +1,500 @@
+
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#include "readMSH.h"
+#include <iostream>
+#include <sstream>
+#include <fstream>
+#include <vector>
+#include <map>
+
+template <
+ typename DerivedV,
+ typename DerivedT>
+IGL_INLINE bool igl::readMSH(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedT> & T)
+{
+ // https://github.com/Yixin-Hu/TetWild/blob/master/pymesh/MshSaver.cpp
+ // Original copyright: /* This file is part of PyMesh. Copyright (c) 2015 by Qingnan Zhou */
+ typedef typename DerivedV::Scalar Float;
+ typedef Eigen::Matrix<Float,Eigen::Dynamic,1> VectorF;
+ typedef Eigen::Matrix<int,Eigen::Dynamic,1> VectorI;
+ typedef std::map<std::string, VectorF> FieldMap;
+ typedef std::vector<std::string> FieldNames;
+ VectorF m_nodes;
+ VectorI m_elements;
+ FieldMap m_node_fields;
+ FieldMap m_element_fields;
+
+ bool m_binary;
+ size_t m_data_size;
+ size_t m_nodes_per_element;
+ size_t m_element_type;
+ std::ifstream fin(filename.c_str(), std::ios::in | std::ios::binary);
+ if (!fin.is_open())
+ {
+ std::stringstream err_msg;
+ err_msg << "failed to open file \"" << filename << "\"";
+ return false;
+ }
+ // Parse header
+ std::string buf;
+ double version;
+ int type;
+ fin >> buf;
+ const auto invalid_format = []()->bool
+ {
+ assert(false && "Invalid format");
+ return false;
+ };
+ const auto not_implemented = []()->bool
+ {
+ assert(false && "Not implemented");
+ return false;
+ };
+ if (buf != "$MeshFormat") { return invalid_format(); }
+
+ fin >> version >> type >> m_data_size;
+ m_binary = (type == 1);
+
+ // Some sanity check.
+ if (m_data_size != 8) {
+ std::cerr << "Error: data size must be 8 bytes." << std::endl;
+ return not_implemented();
+ }
+ if (sizeof(int) != 4) {
+ std::cerr << "Error: code must be compiled with int size 4 bytes." << std::endl;
+ return not_implemented();
+ }
+ const auto eat_white_space = [](std::ifstream& fin)
+ {
+ char next = fin.peek();
+ while (next == '\n' || next == ' ' || next == '\t' || next == '\r')
+ {
+ fin.get();
+ next = fin.peek();
+ }
+ };
+
+ // Read in extra info from binary header.
+ if (m_binary) {
+ int one;
+ eat_white_space(fin);
+ fin.read(reinterpret_cast<char*>(&one), sizeof(int));
+ if (one != 1) {
+ std::cerr << "Warning: binary msh file " << filename
+ << " is saved with different endianness than this machine."
+ << std::endl;
+ return not_implemented();
+ }
+ }
+
+ fin >> buf;
+ if (buf != "$EndMeshFormat") { return not_implemented(); }
+
+ const auto num_nodes_per_elem_type = [](int elem_type)->int
+ {
+ size_t nodes_per_element = 0;
+ switch (elem_type) {
+ case 2:
+ nodes_per_element = 3; // Triangle
+ break;
+ case 3:
+ nodes_per_element = 4; // Quad
+ break;
+ case 4:
+ nodes_per_element = 4; // Tet
+ break;
+ case 5:
+ nodes_per_element = 8; // hexahedron
+ break;
+ default:
+ assert(false && "not implemented");
+ nodes_per_element = -1;
+ break;
+ }
+ return nodes_per_element;
+ };
+
+ const auto parse_nodes = [&](std::ifstream& fin)
+ {
+ size_t num_nodes;
+ fin >> num_nodes;
+ m_nodes.resize(num_nodes*3);
+
+ if (m_binary) {
+ size_t num_bytes = (4+3*m_data_size) * num_nodes;
+ char* data = new char[num_bytes];
+ eat_white_space(fin);
+ fin.read(data, num_bytes);
+
+ for (size_t i=0; i<num_nodes; i++) {
+ int node_idx = *reinterpret_cast<int*> (&data[i*(4+3*m_data_size)]) - 1;
+ m_nodes[node_idx*3] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4]);
+ m_nodes[node_idx*3+1] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + m_data_size]);
+ m_nodes[node_idx*3+2] = *reinterpret_cast<Float*>(&data[i*(4+3*m_data_size) + 4 + 2*m_data_size]);
+ }
+
+ delete [] data;
+ } else {
+ int node_idx;
+ for (size_t i=0; i<num_nodes; i++) {
+ fin >> node_idx;
+ node_idx -= 1;
+ fin >> m_nodes[node_idx*3]
+ >> m_nodes[node_idx*3+1]
+ >> m_nodes[node_idx*3+2];
+ }
+ }
+ };
+
+ const auto parse_elements = [&](std::ifstream& fin)
+ {
+ size_t num_elements;
+ fin >> num_elements;
+
+ // Tmp storage of elements;
+ std::vector<int> triangle_element_idx;
+ std::vector<int> triangle_elements;
+ std::vector<int> quad_element_idx;
+ std::vector<int> quad_elements;
+ std::vector<int> tet_element_idx;
+ std::vector<int> tet_elements;
+ std::vector<int> hex_element_idx;
+ std::vector<int> hex_elements;
+
+ auto get_element_storage = [&](int elem_type) -> std::vector<int>* {
+ switch (elem_type) {
+ default:
+ assert(false && "Unsupported element type encountered");
+ case 2:
+ return &triangle_elements;
+ case 3:
+ return &quad_elements;
+ case 4:
+ return &tet_elements;
+ case 5:
+ return &hex_elements;
+ };
+ };
+
+ auto get_element_idx_storage = [&](int elem_type) -> std::vector<int>* {
+ switch (elem_type) {
+ default:
+ assert(false && "Unsupported element type encountered");
+ case 2:
+ return &triangle_element_idx;
+ case 3:
+ return &quad_element_idx;
+ case 4:
+ return &tet_element_idx;
+ case 5:
+ return &hex_element_idx;
+ };
+ };
+
+ size_t nodes_per_element;
+ int glob_elem_type = -1;
+
+
+ if (m_binary)
+ {
+ eat_white_space(fin);
+ int elem_read = 0;
+ while (elem_read < num_elements) {
+ // Parse element header.
+ int elem_type, num_elems, num_tags;
+ fin.read((char*)&elem_type, sizeof(int));
+ fin.read((char*)&num_elems, sizeof(int));
+ fin.read((char*)&num_tags, sizeof(int));
+ nodes_per_element = num_nodes_per_elem_type(elem_type);
+ std::vector<int>& elements = *get_element_storage(elem_type);
+ std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
+
+ for (size_t i=0; i<num_elems; i++) {
+ int elem_idx;
+ fin.read((char*)&elem_idx, sizeof(int));
+ elem_idx -= 1;
+ element_idx.push_back(elem_idx);
+
+ // Eat up tags.
+ for (size_t j=0; j<num_tags; j++) {
+ int tag;
+ fin.read((char*)&tag, sizeof(int));
+ }
+
+ // Element values.
+ for (size_t j=0; j<nodes_per_element; j++) {
+ int idx;
+ fin.read((char*)&idx, sizeof(int));
+ elements.push_back(idx-1);
+ }
+ }
+
+ elem_read += num_elems;
+ }
+ } else
+ {
+ for (size_t i=0; i<num_elements; i++) {
+ // Parse per element header
+ int elem_num, elem_type, num_tags;
+ fin >> elem_num >> elem_type >> num_tags;
+ for (size_t j=0; j<num_tags; j++) {
+ int tag;
+ fin >> tag;
+ }
+ nodes_per_element = num_nodes_per_elem_type(elem_type);
+ std::vector<int>& elements = *get_element_storage(elem_type);
+ std::vector<int>& element_idx = *get_element_idx_storage(elem_type);
+
+ elem_num -= 1;
+ element_idx.push_back(elem_num);
+
+ // Parse node idx.
+ for (size_t j=0; j<nodes_per_element; j++) {
+ int idx;
+ fin >> idx;
+ elements.push_back(idx-1); // msh index starts from 1.
+ }
+ }
+ }
+
+ auto copy_to_array = [&](
+ const std::vector<int>& elements,
+ const int nodes_per_element) {
+ const size_t num_elements = elements.size() / nodes_per_element;
+ if (elements.size() % nodes_per_element != 0) {
+ assert(false && "parsing element failed");
+ return;
+ }
+ m_elements.resize(elements.size());
+ std::copy(elements.begin(), elements.end(), m_elements.data());
+ m_nodes_per_element = nodes_per_element;
+ };
+
+ if (!tet_elements.empty()) {
+ copy_to_array(tet_elements, 4);
+ m_element_type = 4;
+ } else if (!hex_elements.empty()) {
+ copy_to_array(hex_elements, 8);
+ m_element_type = 5;
+ } else if (!triangle_elements.empty()) {
+ copy_to_array(triangle_elements, 3);
+ m_element_type = 2;
+ } else if (!quad_elements.empty()) {
+ copy_to_array(quad_elements, 4);
+ m_element_type = 3;
+ } else {
+ // 0 elements, use triangle by default.
+ m_element_type = 2;
+ }
+ };
+ const auto parse_element_field = [&](std::ifstream& fin)
+ {
+ size_t num_string_tags;
+ size_t num_real_tags;
+ size_t num_int_tags;
+
+ fin >> num_string_tags;
+ std::string* str_tags = new std::string[num_string_tags];
+ for (size_t i=0; i<num_string_tags; i++) {
+ eat_white_space(fin);
+ if (fin.peek() == '\"') {
+ // Handle field name between quoates.
+ char buf[128];
+ fin.get(); // remove the quote at the beginning.
+ fin.getline(buf, 128, '\"');
+ str_tags[i] = std::string(buf);
+ } else {
+ fin >> str_tags[i];
+ }
+ }
+
+ fin >> num_real_tags;
+ Float* real_tags = new Float[num_real_tags];
+ for (size_t i=0; i<num_real_tags; i++)
+ fin >> real_tags[i];
+
+ fin >> num_int_tags;
+ int* int_tags = new int[num_int_tags];
+ for (size_t i=0; i<num_int_tags; i++)
+ fin >> int_tags[i];
+
+ if (num_string_tags <= 0 || num_int_tags <= 2) { assert(false && "invalid format"); return; }
+ std::string fieldname = str_tags[0];
+ int num_components = int_tags[1];
+ int num_entries = int_tags[2];
+ VectorF field(num_entries * num_components);
+
+ delete [] str_tags;
+ delete [] real_tags;
+ delete [] int_tags;
+
+ if (m_binary) {
+ size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
+ char* data = new char[num_bytes];
+ eat_white_space(fin);
+ fin.read(data, num_bytes);
+ for (size_t i=0; i<num_entries; i++) {
+ int elem_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
+ elem_idx -= 1;
+ size_t base_idx = i*(4+num_components*m_data_size) + 4;
+ for (size_t j=0; j<num_components; j++) {
+ field[elem_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
+ }
+ }
+ delete [] data;
+ } else {
+ int elem_idx;
+ for (size_t i=0; i<num_entries; i++) {
+ fin >> elem_idx;
+ elem_idx -= 1;
+ for (size_t j=0; j<num_components; j++) {
+ fin >> field[elem_idx * num_components + j];
+ }
+ }
+ }
+
+ m_element_fields[fieldname] = field;
+ };
+
+ const auto parse_node_field = [&](std::ifstream& fin)
+ {
+ size_t num_string_tags;
+ size_t num_real_tags;
+ size_t num_int_tags;
+
+ fin >> num_string_tags;
+ std::string* str_tags = new std::string[num_string_tags];
+ for (size_t i=0; i<num_string_tags; i++) {
+ eat_white_space(fin);
+ if (fin.peek() == '\"') {
+ // Handle field name between quoates.
+ char buf[128];
+ fin.get(); // remove the quote at the beginning.
+ fin.getline(buf, 128, '\"');
+ str_tags[i] = std::string(buf);
+ } else {
+ fin >> str_tags[i];
+ }
+ }
+
+ fin >> num_real_tags;
+ Float* real_tags = new Float[num_real_tags];
+ for (size_t i=0; i<num_real_tags; i++)
+ fin >> real_tags[i];
+
+ fin >> num_int_tags;
+ int* int_tags = new int[num_int_tags];
+ for (size_t i=0; i<num_int_tags; i++)
+ fin >> int_tags[i];
+
+ if (num_string_tags <= 0 || num_int_tags <= 2) { assert(false && "invalid format"); return; }
+ std::string fieldname = str_tags[0];
+ int num_components = int_tags[1];
+ int num_entries = int_tags[2];
+ VectorF field(num_entries * num_components);
+
+ delete [] str_tags;
+ delete [] real_tags;
+ delete [] int_tags;
+
+ if (m_binary) {
+ size_t num_bytes = (num_components * m_data_size + 4) * num_entries;
+ char* data = new char[num_bytes];
+ eat_white_space(fin);
+ fin.read(data, num_bytes);
+ for (size_t i=0; i<num_entries; i++) {
+ int node_idx = *reinterpret_cast<int*>(&data[i*(4+num_components*m_data_size)]);
+ node_idx -= 1;
+ size_t base_idx = i*(4+num_components*m_data_size) + 4;
+ for (size_t j=0; j<num_components; j++) {
+ field[node_idx * num_components + j] = *reinterpret_cast<Float*>(&data[base_idx+j*m_data_size]);
+ }
+ }
+ delete [] data;
+ } else {
+ int node_idx;
+ for (size_t i=0; i<num_entries; i++) {
+ fin >> node_idx;
+ node_idx -= 1;
+ for (size_t j=0; j<num_components; j++) {
+ fin >> field[node_idx * num_components + j];
+ }
+ }
+ }
+
+ m_node_fields[fieldname] = field;
+ };
+ const auto parse_unknown_field = [](std::ifstream& fin,
+ const std::string& fieldname)
+ {
+ std::cerr << "Warning: \"" << fieldname << "\" not supported yet. Ignored." << std::endl;
+ std::string endmark = fieldname.substr(0,1) + "End"
+ + fieldname.substr(1,fieldname.size()-1);
+
+ std::string buf("");
+ while (buf != endmark && !fin.eof()) {
+ fin >> buf;
+ }
+ };
+
+
+ while (!fin.eof()) {
+ buf.clear();
+ fin >> buf;
+ if (buf == "$Nodes") {
+ parse_nodes(fin);
+ fin >> buf;
+ if (buf != "$EndNodes") { return invalid_format(); }
+ } else if (buf == "$Elements") {
+ parse_elements(fin);
+ fin >> buf;
+ if (buf != "$EndElements") { return invalid_format(); }
+ } else if (buf == "$NodeData") {
+ parse_node_field(fin);
+ fin >> buf;
+ if (buf != "$EndNodeData") { return invalid_format(); }
+ } else if (buf == "$ElementData") {
+ parse_element_field(fin);
+ fin >> buf;
+ if (buf != "$EndElementData") { return invalid_format(); }
+ } else if (fin.eof()) {
+ break;
+ } else {
+ parse_unknown_field(fin, buf);
+ }
+ }
+ fin.close();
+ V.resize(m_nodes.rows()/3,3);
+ for (int i = 0; i < m_nodes.rows() / 3; i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ V(i,j) = m_nodes(i * 3 + j);
+ }
+ }
+ int ss = num_nodes_per_elem_type(m_element_type);
+ T.resize(m_elements.rows()/ss,ss);
+ for (int i = 0; i < m_elements.rows() / ss; i++)
+ {
+ for (int j = 0; j < ss; j++)
+ {
+ T(i, j) = m_elements(i * ss + j);
+ }
+ }
+ return true;
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/readMSH.h b/xs/src/igl/readMSH.h
new file mode 100644
index 000000000..1463411d8
--- /dev/null
+++ b/xs/src/igl/readMSH.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READMSH_H
+#define IGL_READMSH_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <string>
+
+namespace igl
+{
+ // Read a mesh (e.g., tet mesh) from a gmsh .msh file
+ //
+ // Inputs:
+ // filename path to .msh file
+ // Outputs:
+ // V #V by 3 list of 3D mesh vertex positions
+ // T #T by ss list of 3D ss-element indices into V (e.g., ss=4 for tets)
+ // Returns true on success
+ template <
+ typename DerivedV,
+ typename DerivedT>
+ IGL_INLINE bool readMSH(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedT> & T);
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readMSH.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/readNODE.cpp b/xs/src/igl/readNODE.cpp
new file mode 100644
index 000000000..cb775e599
--- /dev/null
+++ b/xs/src/igl/readNODE.cpp
@@ -0,0 +1,161 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readNODE.h"
+#include "matrix_to_list.h"
+#include <stdio.h>
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readNODE(
+ const std::string node_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & I)
+{
+ // TODO: should be templated
+ Eigen::MatrixXd mV;
+ Eigen::MatrixXi mI;
+ if(igl::readNODE(node_file_name,mV,mI))
+ {
+ matrix_to_list(mV,V);
+ matrix_to_list(mI,I);
+ return true;
+ }else
+ {
+ return false;
+ }
+}
+
+template <typename DerivedV, typename DerivedI>
+IGL_INLINE bool igl::readNODE(
+ const std::string node_file_name,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedI>& I)
+{
+ using namespace std;
+ FILE * node_file = fopen(node_file_name.c_str(),"r");
+ if(NULL==node_file)
+ {
+ fprintf(stderr,"readNODE: IOError: %s could not be opened...\n",
+ node_file_name.c_str());
+ return false;
+ }
+#ifndef LINE_MAX
+# define LINE_MAX 2048
+#endif
+ char line[LINE_MAX];
+ bool still_comments;
+
+ // eat comments at beginning of file
+ still_comments= true;
+ while(still_comments)
+ {
+ fgets(line,LINE_MAX,node_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+
+ // Read header
+ // n number of points
+ // dim dimension
+ // num_attr number of attributes
+ // num_bm number of boundary markers
+ int n,dim,num_attr,num_bm;
+ int head_count = sscanf(line,"%d %d %d %d", &n, &dim, &num_attr, &num_bm);
+ if(head_count!=4)
+ {
+ fprintf(stderr,"readNODE: Error: incorrect header in %s...\n",
+ node_file_name.c_str());
+ fclose(node_file);
+ return false;
+ }
+ if(num_attr)
+ {
+ fprintf(stderr,"readNODE: Error: %d attributes found in %s. "
+ "Attributes are not supported...\n",
+ num_attr,
+ node_file_name.c_str());
+ fclose(node_file);
+ return false;
+ }
+ // Just quietly ignore boundary markers
+ //if(num_bm)
+ //{
+ // fprintf(stderr,"readNODE: Warning: %d boundary markers found in %s. "
+ // "Boundary markers are ignored...\n",
+ // num_bm,
+ // node_file_name.c_str());
+ //}
+
+ // resize output
+ V.resize(n,dim);
+ I.resize(n,1);
+
+ int line_no = 0;
+ int p = 0;
+ while (fgets(line, LINE_MAX, node_file) != NULL)
+ {
+ line_no++;
+ // Skip comments and blank lines
+ if(line[0] == '#' || line[0] == '\n')
+ {
+ continue;
+ }
+ char * l = line;
+ int offset;
+
+ if(sscanf(l,"%d%n",&I(p),&offset) != 1)
+ {
+ fprintf(stderr,"readNODE Error: bad index (%d) in %s...\n",
+ line_no,
+ node_file_name.c_str());
+ fclose(node_file);
+ return false;
+ }
+ // adjust offset
+ l += offset;
+
+ // Read coordinates
+ for(int d = 0;d<dim;d++)
+ {
+ if(sscanf(l,"%lf%n",&V(p,d),&offset) != 1)
+ {
+ fprintf(stderr,"readNODE Error: bad coordinates (%d) in %s...\n",
+ line_no,
+ node_file_name.c_str());
+ fclose(node_file);
+ return false;
+ }
+ // adjust offset
+ l += offset;
+ }
+ // Read boundary markers
+ for(int b = 0;b<num_bm;b++)
+ {
+ int dummy;
+ if(sscanf(l,"%d%n",&dummy,&offset) != 1)
+ {
+ fprintf(stderr,"readNODE Error: bad boundary markers (%d) in %s...\n",
+ line_no,
+ node_file_name.c_str());
+ fclose(node_file);
+ return false;
+ }
+ // adjust offset
+ l += offset;
+ }
+ p++;
+ }
+
+ assert(p == V.rows());
+
+ fclose(node_file);
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::readNODE<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/readNODE.h b/xs/src/igl/readNODE.h
new file mode 100644
index 000000000..a4bdb4774
--- /dev/null
+++ b/xs/src/igl/readNODE.h
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READNODE_H
+#define IGL_READNODE_H
+#include "igl_inline.h"
+
+#include <string>
+#include <vector>
+#include <Eigen/Core>
+
+namespace igl
+{
+ // load a list of points from a .node file
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Input:
+ // node_file_name path of .node file
+ // Outputs:
+ // V double matrix of vertex positions #V by dim
+ // I list of indices (first tells whether 0 or 1 indexed)
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readNODE(
+ const std::string node_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & I);
+
+ // Input:
+ // node_file_name path of .node file
+ // Outputs:
+ // V eigen double matrix #V by dim
+ template <typename DerivedV, typename DerivedI>
+ IGL_INLINE bool readNODE(
+ const std::string node_file_name,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedI>& I);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readNODE.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/readOBJ.cpp b/xs/src/igl/readOBJ.cpp
new file mode 100644
index 000000000..42173fc84
--- /dev/null
+++ b/xs/src/igl/readOBJ.cpp
@@ -0,0 +1,366 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readOBJ.h"
+
+#include "list_to_matrix.h"
+#include "max_size.h"
+#include "min_size.h"
+
+#include <iostream>
+#include <cstdio>
+#include <fstream>
+#include <sstream>
+#include <iterator>
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readOBJ(
+ const std::string obj_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Scalar > > & TC,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Index > > & FTC,
+ std::vector<std::vector<Index > > & FN)
+{
+ // Open file, and check for error
+ FILE * obj_file = fopen(obj_file_name.c_str(),"r");
+ if(NULL==obj_file)
+ {
+ fprintf(stderr,"IOError: %s could not be opened...\n",
+ obj_file_name.c_str());
+ return false;
+ }
+ return igl::readOBJ(obj_file,V,TC,N,F,FTC,FN);
+}
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readOBJ(
+ FILE * obj_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Scalar > > & TC,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Index > > & FTC,
+ std::vector<std::vector<Index > > & FN)
+{
+ // File open was successful so clear outputs
+ V.clear();
+ TC.clear();
+ N.clear();
+ F.clear();
+ FTC.clear();
+ FN.clear();
+
+ // variables and constants to assist parsing the .obj file
+ // Constant strings to compare against
+ std::string v("v");
+ std::string vn("vn");
+ std::string vt("vt");
+ std::string f("f");
+ std::string tic_tac_toe("#");
+#ifndef IGL_LINE_MAX
+# define IGL_LINE_MAX 2048
+#endif
+
+ char line[IGL_LINE_MAX];
+ int line_no = 1;
+ while (fgets(line, IGL_LINE_MAX, obj_file) != NULL)
+ {
+ char type[IGL_LINE_MAX];
+ // Read first word containing type
+ if(sscanf(line, "%s",type) == 1)
+ {
+ // Get pointer to rest of line right after type
+ char * l = &line[strlen(type)];
+ if(type == v)
+ {
+ std::istringstream ls(&line[1]);
+ std::vector<Scalar > vertex{ std::istream_iterator<Scalar >(ls), std::istream_iterator<Scalar >() };
+
+ if (vertex.size() < 3)
+ {
+ fprintf(stderr,
+ "Error: readOBJ() vertex on line %d should have at least 3 coordinates",
+ line_no);
+ fclose(obj_file);
+ return false;
+ }
+
+ V.push_back(vertex);
+ }else if(type == vn)
+ {
+ double x[3];
+ int count =
+ sscanf(l,"%lf %lf %lf\n",&x[0],&x[1],&x[2]);
+ if(count != 3)
+ {
+ fprintf(stderr,
+ "Error: readOBJ() normal on line %d should have 3 coordinates",
+ line_no);
+ fclose(obj_file);
+ return false;
+ }
+ std::vector<Scalar > normal(count);
+ for(int i = 0;i<count;i++)
+ {
+ normal[i] = x[i];
+ }
+ N.push_back(normal);
+ }else if(type == vt)
+ {
+ double x[3];
+ int count =
+ sscanf(l,"%lf %lf %lf\n",&x[0],&x[1],&x[2]);
+ if(count != 2 && count != 3)
+ {
+ fprintf(stderr,
+ "Error: readOBJ() texture coords on line %d should have 2 "
+ "or 3 coordinates (%d)",
+ line_no,count);
+ fclose(obj_file);
+ return false;
+ }
+ std::vector<Scalar > tex(count);
+ for(int i = 0;i<count;i++)
+ {
+ tex[i] = x[i];
+ }
+ TC.push_back(tex);
+ }else if(type == f)
+ {
+ const auto & shift = [&V](const int i)->int
+ {
+ return i<0 ? i+V.size() : i-1;
+ };
+ const auto & shift_t = [&TC](const int i)->int
+ {
+ return i<0 ? i+TC.size() : i-1;
+ };
+ const auto & shift_n = [&N](const int i)->int
+ {
+ return i<0 ? i+N.size() : i-1;
+ };
+ std::vector<Index > f;
+ std::vector<Index > ftc;
+ std::vector<Index > fn;
+ // Read each "word" after type
+ char word[IGL_LINE_MAX];
+ int offset;
+ while(sscanf(l,"%s%n",word,&offset) == 1)
+ {
+ // adjust offset
+ l += offset;
+ // Process word
+ long int i,it,in;
+ if(sscanf(word,"%ld/%ld/%ld",&i,&it,&in) == 3)
+ {
+ f.push_back(shift(i));
+ ftc.push_back(shift_t(it));
+ fn.push_back(shift_n(in));
+ }else if(sscanf(word,"%ld/%ld",&i,&it) == 2)
+ {
+ f.push_back(shift(i));
+ ftc.push_back(shift_t(it));
+ }else if(sscanf(word,"%ld//%ld",&i,&in) == 2)
+ {
+ f.push_back(shift(i));
+ fn.push_back(shift_n(in));
+ }else if(sscanf(word,"%ld",&i) == 1)
+ {
+ f.push_back(shift(i));
+ }else
+ {
+ fprintf(stderr,
+ "Error: readOBJ() face on line %d has invalid element format\n",
+ line_no);
+ fclose(obj_file);
+ return false;
+ }
+ }
+ if(
+ (f.size()>0 && fn.size() == 0 && ftc.size() == 0) ||
+ (f.size()>0 && fn.size() == f.size() && ftc.size() == 0) ||
+ (f.size()>0 && fn.size() == 0 && ftc.size() == f.size()) ||
+ (f.size()>0 && fn.size() == f.size() && ftc.size() == f.size()))
+ {
+ // No matter what add each type to lists so that lists are the
+ // correct lengths
+ F.push_back(f);
+ FTC.push_back(ftc);
+ FN.push_back(fn);
+ }else
+ {
+ fprintf(stderr,
+ "Error: readOBJ() face on line %d has invalid format\n", line_no);
+ fclose(obj_file);
+ return false;
+ }
+ }else if(strlen(type) >= 1 && (type[0] == '#' ||
+ type[0] == 'g' ||
+ type[0] == 's' ||
+ strcmp("usemtl",type)==0 ||
+ strcmp("mtllib",type)==0))
+ {
+ //ignore comments or other shit
+ }else
+ {
+ //ignore any other lines
+ fprintf(stderr,
+ "Warning: readOBJ() ignored non-comment line %d:\n %s",
+ line_no,
+ line);
+ }
+ }else
+ {
+ // ignore empty line
+ }
+ line_no++;
+ }
+ fclose(obj_file);
+
+ assert(F.size() == FN.size());
+ assert(F.size() == FTC.size());
+
+ return true;
+}
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readOBJ(
+ const std::string obj_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F)
+{
+ std::vector<std::vector<Scalar > > TC,N;
+ std::vector<std::vector<Index > > FTC,FN;
+ return readOBJ(obj_file_name,V,TC,N,F,FTC,FN);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedTC,
+ typename DerivedCN,
+ typename DerivedF,
+ typename DerivedFTC,
+ typename DerivedFN>
+IGL_INLINE bool igl::readOBJ(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedTC>& TC,
+ Eigen::PlainObjectBase<DerivedCN>& CN,
+ Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedFTC>& FTC,
+ Eigen::PlainObjectBase<DerivedFN>& FN)
+{
+ std::vector<std::vector<double> > vV,vTC,vN;
+ std::vector<std::vector<int> > vF,vFTC,vFN;
+ bool success = igl::readOBJ(str,vV,vTC,vN,vF,vFTC,vFN);
+ if(!success)
+ {
+ // readOBJ(str,vV,vTC,vN,vF,vFTC,vFN) should have already printed an error
+ // message to stderr
+ return false;
+ }
+ bool V_rect = igl::list_to_matrix(vV,V);
+ const char * format = "Failed to cast %s to matrix: min (%d) != max (%d)\n";
+ if(!V_rect)
+ {
+ printf(format,"V",igl::min_size(vV),igl::max_size(vV));
+ return false;
+ }
+ bool F_rect = igl::list_to_matrix(vF,F);
+ if(!F_rect)
+ {
+ printf(format,"F",igl::min_size(vF),igl::max_size(vF));
+ return false;
+ }
+ if(!vN.empty())
+ {
+ bool VN_rect = igl::list_to_matrix(vN,CN);
+ if(!VN_rect)
+ {
+ printf(format,"CN",igl::min_size(vN),igl::max_size(vN));
+ return false;
+ }
+ }
+
+ if(!vFN.empty() && !vFN[0].empty())
+ {
+ bool FN_rect = igl::list_to_matrix(vFN,FN);
+ if(!FN_rect)
+ {
+ printf(format,"FN",igl::min_size(vFN),igl::max_size(vFN));
+ return false;
+ }
+ }
+
+ if(!vTC.empty())
+ {
+
+ bool T_rect = igl::list_to_matrix(vTC,TC);
+ if(!T_rect)
+ {
+ printf(format,"TC",igl::min_size(vTC),igl::max_size(vTC));
+ return false;
+ }
+ }
+ if(!vFTC.empty()&& !vFTC[0].empty())
+ {
+
+ bool FTC_rect = igl::list_to_matrix(vFTC,FTC);
+ if(!FTC_rect)
+ {
+ printf(format,"FTC",igl::min_size(vFTC),igl::max_size(vFTC));
+ return false;
+ }
+ }
+ return true;
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::readOBJ(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ std::vector<std::vector<double> > vV,vTC,vN;
+ std::vector<std::vector<int> > vF,vFTC,vFN;
+ bool success = igl::readOBJ(str,vV,vTC,vN,vF,vFTC,vFN);
+ if(!success)
+ {
+ // readOBJ(str,vV,vTC,vN,vF,vFTC,vFN) should have already printed an error
+ // message to stderr
+ return false;
+ }
+ bool V_rect = igl::list_to_matrix(vV,V);
+ if(!V_rect)
+ {
+ // igl::list_to_matrix(vV,V) already printed error message to std err
+ return false;
+ }
+ bool F_rect = igl::list_to_matrix(vF,F);
+ if(!F_rect)
+ {
+ // igl::list_to_matrix(vF,F) already printed error message to std err
+ return false;
+ }
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readOBJ<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readOBJ<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readOBJ<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readOBJ<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readOBJ<double, int>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+#endif
diff --git a/xs/src/igl/readOBJ.h b/xs/src/igl/readOBJ.h
new file mode 100644
index 000000000..443b6fc8e
--- /dev/null
+++ b/xs/src/igl/readOBJ.h
@@ -0,0 +1,101 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READOBJ_H
+#define IGL_READOBJ_H
+#include "igl_inline.h"
+#include "deprecated.h"
+// History:
+// return type changed from void to bool Alec 18 Sept 2011
+// added pure vector of vectors version that has much more support Alec 31 Oct
+// 2011
+
+#ifndef IGL_NO_EIGEN
+# include <Eigen/Core>
+#endif
+#include <string>
+#include <vector>
+#include <cstdio>
+
+namespace igl
+{
+ // Read a mesh from an ascii obj file, filling in vertex positions, normals
+ // and texture coordinates. Mesh may have faces of any number of degree
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Inputs:
+ // str path to .obj file
+ // Outputs:
+ // V double matrix of vertex positions #V by 3
+ // TC double matrix of texture coordinats #TC by 2
+ // N double matrix of corner normals #N by 3
+ // F #F list of face indices into vertex positions
+ // FTC #F list of face indices into vertex texture coordinates
+ // FN #F list of face indices into vertex normals
+ // Returns true on success, false on errors
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readOBJ(
+ const std::string obj_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Scalar > > & TC,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Index > > & FTC,
+ std::vector<std::vector<Index > > & FN);
+ // Inputs:
+ // obj_file pointer to already opened .obj file
+ // Outputs:
+ // obj_file closed file
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readOBJ(
+ FILE * obj_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Scalar > > & TC,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Index > > & FTC,
+ std::vector<std::vector<Index > > & FN);
+ // Just V and F
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readOBJ(
+ const std::string obj_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F);
+ // Eigen Wrappers. These will return true only if the data is perfectly
+ // "rectangular": All faces are the same degree, all have the same number of
+ // textures/normals etc.
+ template <
+ typename DerivedV,
+ typename DerivedTC,
+ typename DerivedCN,
+ typename DerivedF,
+ typename DerivedFTC,
+ typename DerivedFN>
+ IGL_INLINE bool readOBJ(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedTC>& TC,
+ Eigen::PlainObjectBase<DerivedCN>& CN,
+ Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedFTC>& FTC,
+ Eigen::PlainObjectBase<DerivedFN>& FN);
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool readOBJ(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readOBJ.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/readOFF.cpp b/xs/src/igl/readOFF.cpp
new file mode 100644
index 000000000..11d7e0efc
--- /dev/null
+++ b/xs/src/igl/readOFF.cpp
@@ -0,0 +1,268 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readOFF.h"
+#include "list_to_matrix.h"
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readOFF(
+ const std::string off_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Scalar > > & C)
+{
+ using namespace std;
+ FILE * off_file = fopen(off_file_name.c_str(),"r");
+ if(NULL==off_file)
+ {
+ printf("IOError: %s could not be opened...\n",off_file_name.c_str());
+ return false;
+ }
+ return readOFF(off_file,V,F,N,C);
+}
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readOFF(
+ FILE * off_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Scalar > > & C)
+{
+ using namespace std;
+ V.clear();
+ F.clear();
+ N.clear();
+ C.clear();
+
+ // First line is always OFF
+ char header[1000];
+ const std::string OFF("OFF");
+ const std::string NOFF("NOFF");
+ const std::string COFF("COFF");
+ if(fscanf(off_file,"%s\n",header)!=1
+ || !(
+ string(header).compare(0, OFF.length(), OFF)==0 ||
+ string(header).compare(0, COFF.length(), COFF)==0 ||
+ string(header).compare(0,NOFF.length(),NOFF)==0))
+ {
+ printf("Error: readOFF() first line should be OFF or NOFF or COFF, not %s...",header);
+ fclose(off_file);
+ return false;
+ }
+ bool has_normals = string(header).compare(0,NOFF.length(),NOFF)==0;
+ bool has_vertexColors = string(header).compare(0,COFF.length(),COFF)==0;
+ // Second line is #vertices #faces #edges
+ int number_of_vertices;
+ int number_of_faces;
+ int number_of_edges;
+ char tic_tac_toe;
+ char line[1000];
+ bool still_comments = true;
+ while(still_comments)
+ {
+ fgets(line,1000,off_file);
+ still_comments = (line[0] == '#' || line[0] == '\n');
+ }
+ sscanf(line,"%d %d %d",&number_of_vertices,&number_of_faces,&number_of_edges);
+ V.resize(number_of_vertices);
+ if (has_normals)
+ N.resize(number_of_vertices);
+ if (has_vertexColors)
+ C.resize(number_of_vertices);
+ F.resize(number_of_faces);
+ //printf("%s %d %d %d\n",(has_normals ? "NOFF" : "OFF"),number_of_vertices,number_of_faces,number_of_edges);
+ // Read vertices
+ for(int i = 0;i<number_of_vertices;)
+ {
+ fgets(line, 1000, off_file);
+ double x,y,z,nx,ny,nz;
+ if(sscanf(line, "%lg %lg %lg %lg %lg %lg",&x,&y,&z,&nx,&ny,&nz)>= 3)
+ {
+ std::vector<Scalar > vertex;
+ vertex.resize(3);
+ vertex[0] = x;
+ vertex[1] = y;
+ vertex[2] = z;
+ V[i] = vertex;
+
+ if (has_normals)
+ {
+ std::vector<Scalar > normal;
+ normal.resize(3);
+ normal[0] = nx;
+ normal[1] = ny;
+ normal[2] = nz;
+ N[i] = normal;
+ }
+
+ if (has_vertexColors)
+ {
+ C[i].resize(3);
+ C[i][0] = nx / 255.0;
+ C[i][1] = ny / 255.0;
+ C[i][2] = nz / 255.0;
+ }
+ i++;
+ }else if(
+ fscanf(off_file,"%[#]",&tic_tac_toe)==1)
+ {
+ char comment[1000];
+ fscanf(off_file,"%[^\n]",comment);
+ }else
+ {
+ printf("Error: bad line (%d)\n",i);
+ if(feof(off_file))
+ {
+ fclose(off_file);
+ return false;
+ }
+ }
+ }
+ // Read faces
+ for(int i = 0;i<number_of_faces;)
+ {
+ std::vector<Index > face;
+ int valence;
+ if(fscanf(off_file,"%d",&valence)==1)
+ {
+ face.resize(valence);
+ for(int j = 0;j<valence;j++)
+ {
+ int index;
+ if(j<valence-1)
+ {
+ fscanf(off_file,"%d",&index);
+ }else{
+ fscanf(off_file,"%d%*[^\n]",&index);
+ }
+
+ face[j] = index;
+ }
+ F[i] = face;
+ i++;
+ }else if(
+ fscanf(off_file,"%[#]",&tic_tac_toe)==1)
+ {
+ char comment[1000];
+ fscanf(off_file,"%[^\n]",comment);
+ }else
+ {
+ printf("Error: bad line\n");
+ fclose(off_file);
+ return false;
+ }
+ }
+ fclose(off_file);
+ return true;
+}
+
+
+#ifndef IGL_NO_EIGEN
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::readOFF(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ std::vector<std::vector<double> > vV;
+ std::vector<std::vector<double> > vN;
+ std::vector<std::vector<int> > vF;
+ std::vector<std::vector<double> > vC;
+ bool success = igl::readOFF(str,vV,vF,vN,vC);
+ if(!success)
+ {
+ // readOFF(str,vV,vF,vN,vC) should have already printed an error
+ // message to stderr
+ return false;
+ }
+ bool V_rect = igl::list_to_matrix(vV,V);
+ if(!V_rect)
+ {
+ // igl::list_to_matrix(vV,V) already printed error message to std err
+ return false;
+ }
+ bool F_rect = igl::list_to_matrix(vF,F);
+ if(!F_rect)
+ {
+ // igl::list_to_matrix(vF,F) already printed error message to std err
+ return false;
+ }
+ return true;
+}
+
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::readOFF(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedV>& N)
+{
+ std::vector<std::vector<double> > vV;
+ std::vector<std::vector<double> > vN;
+ std::vector<std::vector<int> > vF;
+ std::vector<std::vector<double> > vC;
+ bool success = igl::readOFF(str,vV,vF,vN,vC);
+ if(!success)
+ {
+ // readOFF(str,vV,vF,vC) should have already printed an error
+ // message to stderr
+ return false;
+ }
+ bool V_rect = igl::list_to_matrix(vV,V);
+ if(!V_rect)
+ {
+ // igl::list_to_matrix(vV,V) already printed error message to std err
+ return false;
+ }
+ bool F_rect = igl::list_to_matrix(vF,F);
+ if(!F_rect)
+ {
+ // igl::list_to_matrix(vF,F) already printed error message to std err
+ return false;
+ }
+
+ if (vN.size())
+ {
+ bool N_rect = igl::list_to_matrix(vN,N);
+ if(!N_rect)
+ {
+ // igl::list_to_matrix(vN,N) already printed error message to std err
+ return false;
+ }
+ }
+
+ //Warning: RGB colors will be returned in the N matrix
+ if (vC.size())
+ {
+ bool C_rect = igl::list_to_matrix(vC,N);
+ if(!C_rect)
+ {
+ // igl::list_to_matrix(vC,N) already printed error message to std err
+ return false;
+ }
+ }
+
+ return true;
+}
+#endif
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readOFF<double, int>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&);
+// generated by autoexplicit.sh
+template bool igl::readOFF<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readOFF<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::readOFF<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >&);
+template bool igl::readOFF<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template bool igl::readOFF<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/readOFF.h b/xs/src/igl/readOFF.h
new file mode 100644
index 000000000..3d8c41fa5
--- /dev/null
+++ b/xs/src/igl/readOFF.h
@@ -0,0 +1,86 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READOFF_H
+#define IGL_READOFF_H
+#include "igl_inline.h"
+// History:
+// return type changed from void to bool Alec 18 Sept 2011
+
+#ifndef IGL_NO_EIGEN
+# include <Eigen/Core>
+#endif
+#include <string>
+#include <vector>
+#include <cstdio>
+
+namespace igl
+{
+
+ // Read a mesh from an ascii OFF file, filling in vertex positions, normals
+ // and texture coordinates. Mesh may have faces of any number of degree
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Inputs:
+ // str path to .obj file
+ // Outputs:
+ // V double matrix of vertex positions #V by 3
+ // F #F list of face indices into vertex positions
+ // N list of vertex normals #V by 3
+ // C list of rgb color values per vertex #V by 3
+ // Returns true on success, false on errors
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readOFF(
+ const std::string off_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Scalar > > & C);
+ // Inputs:
+ // off_file pointer to already opened .off file
+ // Outputs:
+ // off_file closed file
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readOFF(
+ FILE * off_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F,
+ std::vector<std::vector<Scalar > > & N,
+ std::vector<std::vector<Scalar > > & C);
+
+
+#ifndef IGL_NO_EIGEN
+ // read mesh from a ascii off file
+ // Inputs:
+ // str path to .off file
+ // Outputs:
+ // V eigen double matrix #V by 3
+ // F eigen int matrix #F by 3
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool readOFF(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F);
+
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool readOFF(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedV>& N);
+#endif
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readOFF.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/readPLY.cpp b/xs/src/igl/readPLY.cpp
new file mode 100644
index 000000000..515b3307a
--- /dev/null
+++ b/xs/src/igl/readPLY.cpp
@@ -0,0 +1,224 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readPLY.h"
+#include "list_to_matrix.h"
+#include "ply.h"
+#include <iostream>
+
+template <
+ typename Vtype,
+ typename Ftype,
+ typename Ntype,
+ typename UVtype>
+IGL_INLINE bool igl::readPLY(
+ const std::string filename,
+ std::vector<std::vector<Vtype> > & V,
+ std::vector<std::vector<Ftype> > & F,
+ std::vector<std::vector<Ntype> > & N,
+ std::vector<std::vector<UVtype> > & UV)
+{
+ using namespace std;
+ // Largely follows ply2iv.c
+ FILE * ply_file = fopen(filename.c_str(),"r");
+ if(ply_file == NULL)
+ {
+ return false;
+ }
+ return readPLY(ply_file,V,F,N,UV);
+}
+
+template <
+ typename Vtype,
+ typename Ftype,
+ typename Ntype,
+ typename UVtype>
+IGL_INLINE bool igl::readPLY(
+ FILE * ply_file,
+ std::vector<std::vector<Vtype> > & V,
+ std::vector<std::vector<Ftype> > & F,
+ std::vector<std::vector<Ntype> > & N,
+ std::vector<std::vector<UVtype> > & UV)
+{
+ using namespace std;
+ typedef struct Vertex {
+ double x,y,z; /* position */
+ double nx,ny,nz; /* surface normal */
+ double s,t; /* texture coordinates */
+ void *other_props; /* other properties */
+ } Vertex;
+
+ typedef struct Face {
+ unsigned char nverts; /* number of vertex indices in list */
+ int *verts; /* vertex index list */
+ void *other_props; /* other properties */
+ } Face;
+
+ igl::ply::PlyProperty vert_props[] = { /* list of property information for a vertex */
+ {"x", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,x), 0, 0, 0, 0},
+ {"y", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,y), 0, 0, 0, 0},
+ {"z", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,z), 0, 0, 0, 0},
+ {"nx", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nx), 0, 0, 0, 0},
+ {"ny", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,ny), 0, 0, 0, 0},
+ {"nz", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,nz), 0, 0, 0, 0},
+ {"s", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,s), 0, 0, 0, 0},
+ {"t", PLY_DOUBLE, PLY_DOUBLE, offsetof(Vertex,t), 0, 0, 0, 0},
+ };
+
+ igl::ply::PlyProperty face_props[] = { /* list of property information for a face */
+ {"vertex_indices", PLY_INT, PLY_INT, offsetof(Face,verts),
+ 1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
+ };
+
+ int nelems;
+ char ** elem_names;
+ igl::ply::PlyFile * in_ply = igl::ply::ply_read(ply_file,&nelems,&elem_names);
+ if(in_ply==NULL)
+ {
+ return false;
+ }
+
+ bool has_normals = false;
+ bool has_texture_coords = false;
+ igl::ply::PlyProperty **plist;
+ int nprops;
+ int elem_count;
+ plist = ply_get_element_description (in_ply,"vertex", &elem_count, &nprops);
+ int native_binary_type = igl::ply::get_native_binary_type2();
+ if (plist != NULL)
+ {
+ /* set up for getting vertex elements */
+ ply_get_property (in_ply,"vertex",&vert_props[0]);
+ ply_get_property (in_ply,"vertex",&vert_props[1]);
+ ply_get_property (in_ply,"vertex",&vert_props[2]);
+ for (int j = 0; j < nprops; j++)
+ {
+ igl::ply::PlyProperty * prop = plist[j];
+ if (igl::ply::equal_strings ("nx", prop->name)
+ || igl::ply::equal_strings ("ny", prop->name)
+ || igl::ply::equal_strings ("nz", prop->name))
+ {
+ ply_get_property (in_ply,"vertex",&vert_props[3]);
+ ply_get_property (in_ply,"vertex",&vert_props[4]);
+ ply_get_property (in_ply,"vertex",&vert_props[5]);
+ has_normals = true;
+ }
+ if (igl::ply::equal_strings ("s", prop->name) ||
+ igl::ply::equal_strings ("t", prop->name))
+ {
+ ply_get_property(in_ply,"vertex",&vert_props[6]);
+ ply_get_property(in_ply,"vertex",&vert_props[7]);
+ has_texture_coords = true;
+ }
+ }
+ // Is this call necessary?
+ ply_get_other_properties(in_ply,"vertex",
+ offsetof(Vertex,other_props));
+ V.resize(elem_count,std::vector<Vtype>(3));
+ if(has_normals)
+ {
+ N.resize(elem_count,std::vector<Ntype>(3));
+ }else
+ {
+ N.resize(0);
+ }
+ if(has_texture_coords)
+ {
+ UV.resize(elem_count,std::vector<UVtype>(2));
+ }else
+ {
+ UV.resize(0);
+ }
+
+ for(int j = 0;j<elem_count;j++)
+ {
+ Vertex v;
+ ply_get_element_setup(in_ply,"vertex",3,vert_props);
+ ply_get_element(in_ply,(void*)&v, &native_binary_type);
+ V[j][0] = v.x;
+ V[j][1] = v.y;
+ V[j][2] = v.z;
+ if(has_normals)
+ {
+ N[j][0] = v.nx;
+ N[j][1] = v.ny;
+ N[j][2] = v.nz;
+ }
+ if(has_texture_coords)
+ {
+ UV[j][0] = v.s;
+ UV[j][1] = v.t;
+ }
+ }
+ }
+ plist = ply_get_element_description (in_ply,"face", &elem_count, &nprops);
+ if (plist != NULL)
+ {
+ F.resize(elem_count);
+ ply_get_property(in_ply,"face",&face_props[0]);
+ for (int j = 0; j < elem_count; j++)
+ {
+ Face f;
+ ply_get_element(in_ply, (void *) &f, &native_binary_type);
+ for(size_t c = 0;c<f.nverts;c++)
+ {
+ F[j].push_back(f.verts[c]);
+ }
+ }
+ }
+ ply_close(in_ply);
+ return true;
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedUV>
+IGL_INLINE bool igl::readPLY(
+ const std::string filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedUV> & UV)
+{
+ std::vector<std::vector<typename DerivedV::Scalar> > vV;
+ std::vector<std::vector<typename DerivedF::Scalar> > vF;
+ std::vector<std::vector<typename DerivedN::Scalar> > vN;
+ std::vector<std::vector<typename DerivedUV::Scalar> > vUV;
+ if(!readPLY(filename,vV,vF,vN,vUV))
+ {
+ return false;
+ }
+ return
+ list_to_matrix(vV,V) &&
+ list_to_matrix(vF,F) &&
+ list_to_matrix(vN,N) &&
+ list_to_matrix(vUV,UV);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE bool igl::readPLY(
+ const std::string filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F)
+{
+ Eigen::MatrixXd N,UV;
+ return readPLY(filename,V,F,N,UV);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::readPLY<double, int, double, double>(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&);
+
+template bool igl::readPLY<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &);
+
+template bool igl::readPLY<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>, Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, Eigen::PlainObjectBase<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic> > &, Eigen::PlainObjectBase<Eigen::Matrix<int, Eigen::Dynamic, Eigen::Dynamic> > &);
+template bool igl::readPLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/readPLY.h b/xs/src/igl/readPLY.h
new file mode 100644
index 000000000..bcb69eee2
--- /dev/null
+++ b/xs/src/igl/readPLY.h
@@ -0,0 +1,77 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READPLY_H
+#define IGL_READPLY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+#include <vector>
+#include <cstdio>
+
+namespace igl
+{
+ // Read a mesh from a .ply file.
+ //
+ // Inputs:
+ // filename path to .ply file
+ // Outputs:
+ // V #V by 3 list of vertex positions
+ // F #F list of lists of triangle indices
+ // N #V by 3 list of vertex normals
+ // UV #V by 2 list of vertex texture coordinates
+ // Returns true iff success
+ template <
+ typename Vtype,
+ typename Ftype,
+ typename Ntype,
+ typename UVtype>
+ IGL_INLINE bool readPLY(
+ const std::string filename,
+ std::vector<std::vector<Vtype> > & V,
+ std::vector<std::vector<Ftype> > & F,
+ std::vector<std::vector<Ntype> > & N,
+ std::vector<std::vector<UVtype> > & UV);
+ template <
+ typename Vtype,
+ typename Ftype,
+ typename Ntype,
+ typename UVtype>
+ // Inputs:
+ // ply_file pointer to already opened .ply file
+ // Outputs:
+ // ply_file closed file
+ IGL_INLINE bool readPLY(
+ FILE * ply_file,
+ std::vector<std::vector<Vtype> > & V,
+ std::vector<std::vector<Ftype> > & F,
+ std::vector<std::vector<Ntype> > & N,
+ std::vector<std::vector<UVtype> > & UV);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedUV>
+ IGL_INLINE bool readPLY(
+ const std::string filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedN> & N,
+ Eigen::PlainObjectBase<DerivedUV> & UV);
+ template <
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE bool readPLY(
+ const std::string filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "readPLY.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/readSTL.cpp b/xs/src/igl/readSTL.cpp
new file mode 100644
index 000000000..fcdeddcdd
--- /dev/null
+++ b/xs/src/igl/readSTL.cpp
@@ -0,0 +1,290 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readSTL.h"
+#include "list_to_matrix.h"
+
+#include <iostream>
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE bool igl::readSTL(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ using namespace std;
+ vector<vector<typename DerivedV::Scalar> > vV;
+ vector<vector<typename DerivedN::Scalar> > vN;
+ vector<vector<typename DerivedF::Scalar> > vF;
+ if(!readSTL(filename,vV,vF,vN))
+ {
+ return false;
+ }
+
+ if(!list_to_matrix(vV,V))
+ {
+ return false;
+ }
+
+ if(!list_to_matrix(vF,F))
+ {
+ return false;
+ }
+
+ if(!list_to_matrix(vN,N))
+ {
+ return false;
+ }
+ return true;
+}
+
+template <typename TypeV, typename TypeF, typename TypeN>
+IGL_INLINE bool igl::readSTL(
+ const std::string & filename,
+ std::vector<std::vector<TypeV> > & V,
+ std::vector<std::vector<TypeF> > & F,
+ std::vector<std::vector<TypeN> > & N)
+{
+ using namespace std;
+ // Should test for ascii
+
+ // Open file, and check for error
+ FILE * stl_file = fopen(filename.c_str(),"rb");
+ if(NULL==stl_file)
+ {
+ fprintf(stderr,"IOError: %s could not be opened...\n",
+ filename.c_str());
+ return false;
+ }
+ return readSTL(stl_file,V,F,N);
+}
+
+template <typename TypeV, typename TypeF, typename TypeN>
+IGL_INLINE bool igl::readSTL(
+ FILE * stl_file,
+ std::vector<std::vector<TypeV> > & V,
+ std::vector<std::vector<TypeF> > & F,
+ std::vector<std::vector<TypeN> > & N)
+{
+ using namespace std;
+ //stl_file = freopen(NULL,"rb",stl_file);
+ if(NULL==stl_file)
+ {
+ fprintf(stderr,"IOError: stl file could not be reopened as binary (1) ...\n");
+ return false;
+ }
+
+ V.clear();
+ F.clear();
+ N.clear();
+
+
+ // Specifically 80 character header
+ char header[80];
+ char solid[80];
+ bool is_ascii = true;
+ if(fread(header,1,80,stl_file) != 80)
+ {
+ cerr<<"IOError: too short (1)."<<endl;
+ goto close_false;
+ }
+ sscanf(header,"%s",solid);
+ if(string("solid") != solid)
+ {
+ // definitely **not** ascii
+ is_ascii = false;
+ }else
+ {
+ // might still be binary
+ char buf[4];
+ if(fread(buf,1,4,stl_file) != 4)
+ {
+ cerr<<"IOError: too short (3)."<<endl;
+ goto close_false;
+ }
+ size_t num_faces = *reinterpret_cast<unsigned int*>(buf);
+ fseek(stl_file,0,SEEK_END);
+ int file_size = ftell(stl_file);
+ if(file_size == 80 + 4 + (4*12 + 2) * num_faces)
+ {
+ is_ascii = false;
+ }else
+ {
+ is_ascii = true;
+ }
+ }
+
+ if(is_ascii)
+ {
+ // Rewind to end of header
+ //stl_file = fopen(filename.c_str(),"r");
+ //stl_file = freopen(NULL,"r",stl_file);
+ fseek(stl_file, 0, SEEK_SET);
+ if(NULL==stl_file)
+ {
+ fprintf(stderr,"IOError: stl file could not be reopened as ascii ...\n");
+ return false;
+ }
+ // Read 80 header
+ // Eat file name
+#ifndef IGL_LINE_MAX
+# define IGL_LINE_MAX 2048
+#endif
+ char name[IGL_LINE_MAX];
+ if(NULL==fgets(name,IGL_LINE_MAX,stl_file))
+ {
+ cerr<<"IOError: ascii too short (2)."<<endl;
+ goto close_false;
+ }
+ // ascii
+ while(true)
+ {
+ int ret;
+ char facet[IGL_LINE_MAX],normal[IGL_LINE_MAX];
+ vector<TypeN > n(3);
+ double nd[3];
+ ret = fscanf(stl_file,"%s %s %lg %lg %lg",facet,normal,nd,nd+1,nd+2);
+ if(string("endsolid") == facet)
+ {
+ break;
+ }
+ if(ret != 5 ||
+ !(string("facet") == facet ||
+ string("faced") == facet) ||
+ string("normal") != normal)
+ {
+ cout<<"facet: "<<facet<<endl;
+ cout<<"normal: "<<normal<<endl;
+ cerr<<"IOError: bad format (1)."<<endl;
+ goto close_false;
+ }
+ // copy casts to Type
+ n[0] = nd[0]; n[1] = nd[1]; n[2] = nd[2];
+ N.push_back(n);
+ char outer[IGL_LINE_MAX], loop[IGL_LINE_MAX];
+ ret = fscanf(stl_file,"%s %s",outer,loop);
+ if(ret != 2 || string("outer") != outer || string("loop") != loop)
+ {
+ cerr<<"IOError: bad format (2)."<<endl;
+ goto close_false;
+ }
+ vector<TypeF> f;
+ while(true)
+ {
+ char word[IGL_LINE_MAX];
+ int ret = fscanf(stl_file,"%s",word);
+ if(ret == 1 && string("endloop") == word)
+ {
+ break;
+ }else if(ret == 1 && string("vertex") == word)
+ {
+ vector<TypeV> v(3);
+ double vd[3];
+ int ret = fscanf(stl_file,"%lg %lg %lg",vd,vd+1,vd+2);
+ if(ret != 3)
+ {
+ cerr<<"IOError: bad format (3)."<<endl;
+ goto close_false;
+ }
+ f.push_back(V.size());
+ // copy casts to Type
+ v[0] = vd[0]; v[1] = vd[1]; v[2] = vd[2];
+ V.push_back(v);
+ }else
+ {
+ cerr<<"IOError: bad format (4)."<<endl;
+ goto close_false;
+ }
+ }
+ F.push_back(f);
+ char endfacet[IGL_LINE_MAX];
+ ret = fscanf(stl_file,"%s",endfacet);
+ if(ret != 1 || string("endfacet") != endfacet)
+ {
+ cerr<<"IOError: bad format (5)."<<endl;
+ goto close_false;
+ }
+ }
+ // read endfacet
+ goto close_true;
+ }else
+ {
+ // Binary
+ //stl_file = freopen(NULL,"rb",stl_file);
+ fseek(stl_file, 0, SEEK_SET);
+ // Read 80 header
+ char header[80];
+ if(fread(header,sizeof(char),80,stl_file)!=80)
+ {
+ cerr<<"IOError: bad format (6)."<<endl;
+ goto close_false;
+ }
+ // Read number of triangles
+ unsigned int num_tri;
+ if(fread(&num_tri,sizeof(unsigned int),1,stl_file)!=1)
+ {
+ cerr<<"IOError: bad format (7)."<<endl;
+ goto close_false;
+ }
+ V.resize(num_tri*3,vector<TypeV >(3,0));
+ N.resize(num_tri,vector<TypeN >(3,0));
+ F.resize(num_tri,vector<TypeF >(3,0));
+ for(int t = 0;t<(int)num_tri;t++)
+ {
+ // Read normal
+ float n[3];
+ if(fread(n,sizeof(float),3,stl_file)!=3)
+ {
+ cerr<<"IOError: bad format (8)."<<endl;
+ goto close_false;
+ }
+ // Read each vertex
+ for(int c = 0;c<3;c++)
+ {
+ F[t][c] = 3*t+c;
+ N[t][c] = n[c];
+ float v[3];
+ if(fread(v,sizeof(float),3,stl_file)!=3)
+ {
+ cerr<<"IOError: bad format (9)."<<endl;
+ goto close_false;
+ }
+ V[3*t+c][0] = v[0];
+ V[3*t+c][1] = v[1];
+ V[3*t+c][2] = v[2];
+ }
+ // Read attribute size
+ unsigned short att_count;
+ if(fread(&att_count,sizeof(unsigned short),1,stl_file)!=1)
+ {
+ cerr<<"IOError: bad format (10)."<<endl;
+ goto close_false;
+ }
+ }
+ goto close_true;
+ }
+close_false:
+ fclose(stl_file);
+ return false;
+close_true:
+ fclose(stl_file);
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template bool igl::readSTL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template bool igl::readSTL<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+template bool igl::readSTL<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/readSTL.h b/xs/src/igl/readSTL.h
new file mode 100644
index 000000000..ca1f7c9e5
--- /dev/null
+++ b/xs/src/igl/readSTL.h
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READSTL_H
+#define IGL_READSTL_H
+#include "igl_inline.h"
+
+#ifndef IGL_NO_EIGEN
+# include <Eigen/Core>
+#endif
+#include <string>
+#include <cstdio>
+#include <vector>
+
+namespace igl
+{
+ // Read a mesh from an ascii/binary stl file.
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Inputs:
+ // filename path to .stl file
+ // Outputs:
+ // V double matrix of vertex positions #V*3 by 3
+ // F index matrix of triangle indices #F by 3
+ // N double matrix of surface normals #F by 3
+ // Returns true on success, false on errors
+ //
+ // Example:
+ // bool success = readSTL(filename,temp_V,F,N);
+ // remove_duplicate_vertices(temp_V,0,V,SVI,SVJ);
+ // for_each(F.data(),F.data()+F.size(),[&SVJ](int & f){f=SVJ(f);});
+ // writeOBJ("Downloads/cat.obj",V,F);
+ template <typename DerivedV, typename DerivedF, typename DerivedN>
+ IGL_INLINE bool readSTL(
+ const std::string & filename,
+ Eigen::PlainObjectBase<DerivedV> & V,
+ Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Inputs:
+ // stl_file pointer to already opened .stl file
+ // Outputs:
+ // stl_file closed file
+ template <typename TypeV, typename TypeF, typename TypeN>
+ IGL_INLINE bool readSTL(
+ FILE * stl_file,
+ std::vector<std::vector<TypeV> > & V,
+ std::vector<std::vector<TypeF> > & F,
+ std::vector<std::vector<TypeN> > & N);
+ template <typename TypeV, typename TypeF, typename TypeN>
+ IGL_INLINE bool readSTL(
+ const std::string & filename,
+ std::vector<std::vector<TypeV> > & V,
+ std::vector<std::vector<TypeF> > & F,
+ std::vector<std::vector<TypeN> > & N);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readSTL.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/readTGF.cpp b/xs/src/igl/readTGF.cpp
new file mode 100644
index 000000000..814395b30
--- /dev/null
+++ b/xs/src/igl/readTGF.cpp
@@ -0,0 +1,200 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readTGF.h"
+
+#include <cstdio>
+
+IGL_INLINE bool igl::readTGF(
+ const std::string tgf_filename,
+ std::vector<std::vector<double> > & C,
+ std::vector<std::vector<int> > & E,
+ std::vector<int> & P,
+ std::vector<std::vector<int> > & BE,
+ std::vector<std::vector<int> > & CE,
+ std::vector<std::vector<int> > & PE)
+{
+ using namespace std;
+ // clear output
+ C.clear();
+ E.clear();
+ P.clear();
+ BE.clear();
+ CE.clear();
+ PE.clear();
+
+ FILE * tgf_file = fopen(tgf_filename.c_str(),"r");
+ if(NULL==tgf_file)
+ {
+ printf("IOError: %s could not be opened\n",tgf_filename.c_str());
+ return false;
+ }
+
+ bool reading_vertices = true;
+ bool reading_edges = true;
+ const int MAX_LINE_LENGTH = 500;
+ char line[MAX_LINE_LENGTH];
+ // read until seeing end of file
+ while(fgets(line,MAX_LINE_LENGTH,tgf_file)!=NULL)
+ {
+ // comment signifies end of vertices, next line is start of edges
+ if(line[0] == '#')
+ {
+ if(reading_vertices)
+ {
+ reading_vertices = false;
+ reading_edges = true;
+ }else if(reading_edges)
+ {
+ reading_edges = false;
+ }
+ // process vertex line
+ }else if(reading_vertices)
+ {
+ int index;
+ vector<double> position(3);
+ int count =
+ sscanf(line,"%d %lg %lg %lg",
+ &index,
+ &position[0],
+ &position[1],
+ &position[2]);
+ if(count != 4)
+ {
+ fprintf(stderr,"Error: readTGF.h: bad format in vertex line\n");
+ fclose(tgf_file);
+ return false;
+ }
+ // index is ignored since vertices must already be in order
+ C.push_back(position);
+ }else if(reading_edges)
+ {
+ vector<int> edge(2);
+ int is_BE = 0;
+ int is_PE = 0;
+ int is_CE = 0;
+ int count = sscanf(line,"%d %d %d %d %d\n",
+ &edge[0],
+ &edge[1],
+ &is_BE,
+ &is_PE,
+ &is_CE);
+ if(count<2)
+ {
+ fprintf(stderr,"Error: readTGF.h: bad format in edge line\n");
+ fclose(tgf_file);
+ return false;
+ }
+ // .tgf is one indexed
+ edge[0]--;
+ edge[1]--;
+ E.push_back(edge);
+ if(is_BE == 1)
+ {
+ BE.push_back(edge);
+ }
+ if(is_PE == 1)
+ {
+ // PE should index P
+ fprintf(stderr,
+ "Warning: readTGF.h found pseudo edges but does not support "
+ "them\n");
+ }
+ if(is_CE == 1)
+ {
+ // CE should index P
+ fprintf(stderr,
+ "Warning: readTGF.h found cage edges but does not support them\n");
+ }
+ }else
+ {
+ // ignore faces
+ }
+ }
+ fclose(tgf_file);
+ // Construct P, indices not in BE
+ for(int i = 0;i<(int)C.size();i++)
+ {
+ bool in_edge = false;
+ for(int j = 0;j<(int)BE.size();j++)
+ {
+ if(i == BE[j][0] || i == BE[j][1])
+ {
+ in_edge = true;
+ break;
+ }
+ }
+ if(!in_edge)
+ {
+ P.push_back(i);
+ }
+ }
+ return true;
+}
+
+#ifndef IGL_NO_EIGEN
+#include "list_to_matrix.h"
+
+IGL_INLINE bool igl::readTGF(
+ const std::string tgf_filename,
+ Eigen::MatrixXd & C,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & P,
+ Eigen::MatrixXi & BE,
+ Eigen::MatrixXi & CE,
+ Eigen::MatrixXi & PE)
+{
+ std::vector<std::vector<double> > vC;
+ std::vector<std::vector<int> > vE;
+ std::vector<int> vP;
+ std::vector<std::vector<int> > vBE;
+ std::vector<std::vector<int> > vCE;
+ std::vector<std::vector<int> > vPE;
+ bool success = readTGF(tgf_filename,vC,vE,vP,vBE,vCE,vPE);
+ if(!success)
+ {
+ return false;
+ }
+
+ if(!list_to_matrix(vC,C))
+ {
+ return false;
+ }
+ if(!list_to_matrix(vE,E))
+ {
+ return false;
+ }
+ if(!list_to_matrix(vP,P))
+ {
+ return false;
+ }
+ if(!list_to_matrix(vBE,BE))
+ {
+ return false;
+ }
+ if(!list_to_matrix(vCE,CE))
+ {
+ return false;
+ }
+ if(!list_to_matrix(vPE,PE))
+ {
+ return false;
+ }
+
+ return true;
+}
+
+IGL_INLINE bool igl::readTGF(
+ const std::string tgf_filename,
+ Eigen::MatrixXd & C,
+ Eigen::MatrixXi & E)
+{
+ Eigen::VectorXi P;
+ Eigen::MatrixXi BE,CE,PE;
+ return readTGF(tgf_filename,C,E,P,BE,CE,PE);
+}
+#endif
diff --git a/xs/src/igl/readTGF.h b/xs/src/igl/readTGF.h
new file mode 100644
index 000000000..68c5ddef8
--- /dev/null
+++ b/xs/src/igl/readTGF.h
@@ -0,0 +1,66 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READTGF_H
+#define IGL_READTGF_H
+#include "igl_inline.h"
+
+#include <vector>
+#include <string>
+#ifndef IGL_NO_EIGEN
+#include <Eigen/Dense>
+#endif
+
+namespace igl
+{
+ // READTGF
+ //
+ // [V,E,P,BE,CE,PE] = readTGF(filename)
+ //
+ // Read a graph from a .tgf file
+ //
+ // Input:
+ // filename .tgf file name
+ // Output:
+ // V # vertices by 3 list of vertex positions
+ // E # edges by 2 list of edge indices
+ // P # point-handles list of point handle indices
+ // BE # bone-edges by 2 list of bone-edge indices
+ // CE # cage-edges by 2 list of cage-edge indices
+ // PE # pseudo-edges by 2 list of pseudo-edge indices
+ //
+ // Assumes that graph vertices are 3 dimensional
+ IGL_INLINE bool readTGF(
+ const std::string tgf_filename,
+ std::vector<std::vector<double> > & C,
+ std::vector<std::vector<int> > & E,
+ std::vector<int> & P,
+ std::vector<std::vector<int> > & BE,
+ std::vector<std::vector<int> > & CE,
+ std::vector<std::vector<int> > & PE);
+
+ #ifndef IGL_NO_EIGEN
+ IGL_INLINE bool readTGF(
+ const std::string tgf_filename,
+ Eigen::MatrixXd & C,
+ Eigen::MatrixXi & E,
+ Eigen::VectorXi & P,
+ Eigen::MatrixXi & BE,
+ Eigen::MatrixXi & CE,
+ Eigen::MatrixXi & PE);
+ IGL_INLINE bool readTGF(
+ const std::string tgf_filename,
+ Eigen::MatrixXd & C,
+ Eigen::MatrixXi & E);
+ #endif
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readTGF.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/readWRL.cpp b/xs/src/igl/readWRL.cpp
new file mode 100644
index 000000000..ce6de3e73
--- /dev/null
+++ b/xs/src/igl/readWRL.cpp
@@ -0,0 +1,121 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "readWRL.h"
+#include <iostream>
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readWRL(
+ const std::string wrl_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F)
+{
+ using namespace std;
+ FILE * wrl_file = fopen(wrl_file_name.c_str(),"r");
+ if(NULL==wrl_file)
+ {
+ printf("IOError: %s could not be opened...",wrl_file_name.c_str());
+ return false;
+ }
+ return readWRL(wrl_file,V,F);
+}
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::readWRL(
+ FILE * wrl_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F)
+{
+ using namespace std;
+
+ char line[1000];
+ // Read lines until seeing "point ["
+ // treat other lines in file as "comments"
+ bool still_comments = true;
+ string needle("point [");
+ string haystack;
+ while(still_comments)
+ {
+ if(fgets(line,1000,wrl_file) == NULL)
+ {
+ std::cerr<<"readWRL, reached EOF without finding \"point [\""<<std::endl;
+ fclose(wrl_file);
+ return false;
+ }
+ haystack = string(line);
+ still_comments = string::npos == haystack.find(needle);
+ }
+
+ // read points in sets of 3
+ int floats_read = 3;
+ double x,y,z;
+ while(floats_read == 3)
+ {
+ floats_read = fscanf(wrl_file," %lf %lf %lf,",&x,&y,&z);
+ if(floats_read == 3)
+ {
+ vector<Scalar > point;
+ point.resize(3);
+ point[0] = x;
+ point[1] = y;
+ point[2] = z;
+ V.push_back(point);
+ //printf("(%g, %g, %g)\n",x,y,z);
+ }else if(floats_read != 0)
+ {
+ printf("ERROR: unrecognized format...\n");
+ return false;
+ }
+ }
+ // Read lines until seeing "coordIndex ["
+ // treat other lines in file as "comments"
+ still_comments = true;
+ needle = string("coordIndex [");
+ while(still_comments)
+ {
+ fgets(line,1000,wrl_file);
+ haystack = string(line);
+ still_comments = string::npos == haystack.find(needle);
+ }
+ // read F
+ int ints_read = 1;
+ while(ints_read > 0)
+ {
+ // read new face indices (until hit -1)
+ vector<Index > face;
+ while(true)
+ {
+ // indices are 0-indexed
+ int i;
+ ints_read = fscanf(wrl_file," %d,",&i);
+ if(ints_read > 0)
+ {
+ if(i>=0)
+ {
+ face.push_back(i);
+ }else
+ {
+ F.push_back(face);
+ break;
+ }
+ }else
+ {
+ break;
+ }
+ }
+ }
+
+
+
+ fclose(wrl_file);
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::readWRL<double, int>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+#endif
diff --git a/xs/src/igl/readWRL.h b/xs/src/igl/readWRL.h
new file mode 100644
index 000000000..45c1fa048
--- /dev/null
+++ b/xs/src/igl/readWRL.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READWRL_H
+#define IGL_READWRL_H
+#include "igl_inline.h"
+
+#include <string>
+#include <vector>
+#include <cstdio>
+
+namespace igl
+{
+ // Read a mesh from an ascii wrl file, filling in vertex positions and face
+ // indices of the first model. Mesh may have faces of any number of degree
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Inputs:
+ // str path to .wrl file
+ // Outputs:
+ // V double matrix of vertex positions #V by 3
+ // F #F list of face indices into vertex positions
+ // Returns true on success, false on errors
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readWRL(
+ const std::string wrl_file_name,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F);
+ // Inputs:
+ // wrl_file pointer to already opened .wrl file
+ // Outputs:
+ // wrl_file closed file
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool readWRL(
+ FILE * wrl_file,
+ std::vector<std::vector<Scalar > > & V,
+ std::vector<std::vector<Index > > & F);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "readWRL.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/read_triangle_mesh.cpp b/xs/src/igl/read_triangle_mesh.cpp
new file mode 100644
index 000000000..b6e52539f
--- /dev/null
+++ b/xs/src/igl/read_triangle_mesh.cpp
@@ -0,0 +1,183 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "read_triangle_mesh.h"
+
+#include "list_to_matrix.h"
+#include "readMESH.h"
+#include "readOBJ.h"
+#include "readOFF.h"
+#include "readSTL.h"
+#include "readPLY.h"
+#include "readWRL.h"
+#include "pathinfo.h"
+#include "boundary_facets.h"
+#include "polygon_mesh_to_triangle_mesh.h"
+
+#include <algorithm>
+#include <iostream>
+
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::read_triangle_mesh(
+ const std::string str,
+ std::vector<std::vector<Scalar> > & V,
+ std::vector<std::vector<Index> > & F)
+{
+ using namespace std;
+ // dirname, basename, extension and filename
+ string d,b,e,f;
+ pathinfo(str,d,b,e,f);
+ // Convert extension to lower case
+ std::transform(e.begin(), e.end(), e.begin(), ::tolower);
+ vector<vector<Scalar> > TC, N, C;
+ vector<vector<Index> > FTC, FN;
+ if(e == "obj")
+ {
+ // Annoyingly obj can store 4 coordinates, truncate to xyz for this generic
+ // read_triangle_mesh
+ bool success = readOBJ(str,V,TC,N,F,FTC,FN);
+ for(auto & v : V)
+ {
+ v.resize(std::min(v.size(),(size_t)3));
+ }
+ return success;
+ }else if(e == "off")
+ {
+ return readOFF(str,V,F,N,C);
+ }
+ cerr<<"Error: "<<__FUNCTION__<<": "<<
+ str<<" is not a recognized mesh file format."<<endl;
+ return false;
+}
+
+
+#ifndef IGL_NO_EIGN
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::read_triangle_mesh(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ std::string _1,_2,_3,_4;
+ return read_triangle_mesh(str,V,F,_1,_2,_3,_4);
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::read_triangle_mesh(
+ const std::string filename,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F,
+ std::string & dir,
+ std::string & base,
+ std::string & ext,
+ std::string & name)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // dirname, basename, extension and filename
+ pathinfo(filename,dir,base,ext,name);
+ // Convert extension to lower case
+ transform(ext.begin(), ext.end(), ext.begin(), ::tolower);
+ FILE * fp = fopen(filename.c_str(),"rb");
+ return read_triangle_mesh(ext,fp,V,F);
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::read_triangle_mesh(
+ const std::string & ext,
+ FILE * fp,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ using namespace std;
+ using namespace Eigen;
+ vector<vector<double > > vV,vN,vTC,vC;
+ vector<vector<int > > vF,vFTC,vFN;
+ if(ext == "mesh")
+ {
+ // Convert extension to lower case
+ MatrixXi T;
+ if(!readMESH(fp,V,T,F))
+ {
+ return 1;
+ }
+ //if(F.size() > T.size() || F.size() == 0)
+ {
+ boundary_facets(T,F);
+ }
+ }else if(ext == "obj")
+ {
+ if(!readOBJ(fp,vV,vTC,vN,vF,vFTC,vFN))
+ {
+ return false;
+ }
+ // Annoyingly obj can store 4 coordinates, truncate to xyz for this generic
+ // read_triangle_mesh
+ for(auto & v : vV)
+ {
+ v.resize(std::min(v.size(),(size_t)3));
+ }
+ }else if(ext == "off")
+ {
+ if(!readOFF(fp,vV,vF,vN,vC))
+ {
+ return false;
+ }
+ }else if(ext == "ply")
+ {
+ if(!readPLY(fp,vV,vF,vN,vTC))
+ {
+ return false;
+ }
+ }else if(ext == "stl")
+ {
+ if(!readSTL(fp,vV,vF,vN))
+ {
+ return false;
+ }
+ }else if(ext == "wrl")
+ {
+ if(!readWRL(fp,vV,vF))
+ {
+ return false;
+ }
+ }else
+ {
+ cerr<<"Error: unknown extension: "<<ext<<endl;
+ return false;
+ }
+ if(vV.size() > 0)
+ {
+ if(!list_to_matrix(vV,V))
+ {
+ return false;
+ }
+ polygon_mesh_to_triangle_mesh(vF,F);
+ }
+ return true;
+}
+
+#endif
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::read_triangle_mesh<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template bool igl::read_triangle_mesh<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::read_triangle_mesh<double, int>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::string, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template bool igl::read_triangle_mesh<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> >&);
+template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&);
+template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template bool igl::read_triangle_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >&);
+#endif
diff --git a/xs/src/igl/read_triangle_mesh.h b/xs/src/igl/read_triangle_mesh.h
new file mode 100644
index 000000000..26b84c5f1
--- /dev/null
+++ b/xs/src/igl/read_triangle_mesh.h
@@ -0,0 +1,80 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_READ_TRIANGLE_MESH_H
+#define IGL_READ_TRIANGLE_MESH_H
+#include "igl_inline.h"
+
+#ifndef IGL_NO_EIGEN
+# include <Eigen/Core>
+#endif
+#include <string>
+#include <cstdio>
+#include <vector>
+// History:
+// renamed read -> read_triangle_mesh Daniele 24 June 2014
+// return type changed from void to bool Alec 18 Sept 2011
+
+namespace igl
+{
+ // read mesh from an ascii file with automatic detection of file format.
+ // supported: obj, off, stl, wrl, ply, mesh)
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Inputs:
+ // str path to file
+ // Outputs:
+ // V eigen double matrix #V by 3
+ // F eigen int matrix #F by 3
+ // Returns true iff success
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool read_triangle_mesh(
+ const std::string str,
+ std::vector<std::vector<Scalar> > & V,
+ std::vector<std::vector<Index> > & F);
+#ifndef IGL_NO_EIGEN
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool read_triangle_mesh(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F);
+ // Outputs:
+ // dir directory path (see pathinfo.h)
+ // base base name (see pathinfo.h)
+ // ext extension (see pathinfo.h)
+ // name filename (see pathinfo.h)
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool read_triangle_mesh(
+ const std::string str,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F,
+ std::string & dir,
+ std::string & base,
+ std::string & ext,
+ std::string & name);
+ // Inputs:
+ // ext file extension
+ // fp pointer to already opened .ext file
+ // Outputs:
+ // fp closed file
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool read_triangle_mesh(
+ const std::string & ext,
+ FILE * fp,
+ Eigen::PlainObjectBase<DerivedV>& V,
+ Eigen::PlainObjectBase<DerivedF>& F);
+#endif
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "read_triangle_mesh.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/redux.h b/xs/src/igl/redux.h
new file mode 100644
index 000000000..38ce9395a
--- /dev/null
+++ b/xs/src/igl/redux.h
@@ -0,0 +1,70 @@
+#ifndef IGL_REDUX_H
+#define IGL_REDUX_H
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // REDUX Perform reductions on the rows or columns of a SparseMatrix. This is
+ // _similar_ to DenseBase::redux, but different in two important ways:
+ // 1. (unstored) Zeros are **not** "visited", however if the first element
+ // in the column/row does not appear in the first row/column then the
+ // reduction is assumed to start with zero. In this way, "any", "all",
+ // "count"(non-zeros) work as expected. This means it is **not** possible
+ // to use this to count (implicit) zeros.
+ // 2. This redux is more powerful in the sense that A and B may have
+ // different types. This makes it possible to count the number of
+ // non-zeros in a SparseMatrix<bool> A into a VectorXi B.
+ //
+ // Inputs:
+ // A m by n sparse matrix
+ // dim dimension along which to sum (1 or 2)
+ // func function handle with the prototype `X(Y a, I i, J j, Z b)` where a
+ // is the running value, b is A(i,j)
+ // Output:
+ // S n-long sparse vector (if dim == 1)
+ // or
+ // S m-long sparse vector (if dim == 2)
+ template <typename AType, typename Func, typename DerivedB>
+ inline void redux(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ const Func & func,
+ Eigen::PlainObjectBase<DerivedB> & B);
+}
+
+// Implementation
+
+#include "redux.h"
+#include "for_each.h"
+
+template <typename AType, typename Func, typename DerivedB>
+inline void igl::redux(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ const Func & func,
+ Eigen::PlainObjectBase<DerivedB> & B)
+{
+ assert((dim == 1 || dim == 2) && "dim must be 2 or 1");
+ // Get size of input
+ int m = A.rows();
+ int n = A.cols();
+ // resize output
+ B = DerivedB::Zero(dim==1?n:m);
+ const auto func_wrap = [&func,&B,&dim](const int i, const int j, const int v)
+ {
+ if(dim == 1)
+ {
+ B(j) = i == 0? v : func(B(j),v);
+ }else
+ {
+ B(i) = j == 0? v : func(B(i),v);
+ }
+ };
+ for_each(A,func_wrap);
+}
+
+
+//#ifndef IGL_STATIC_LIBRARY
+//# include "redux.cpp"
+//#endif
+#endif
diff --git a/xs/src/igl/remesh_along_isoline.cpp b/xs/src/igl/remesh_along_isoline.cpp
new file mode 100644
index 000000000..7164ba8e5
--- /dev/null
+++ b/xs/src/igl/remesh_along_isoline.cpp
@@ -0,0 +1,160 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "remesh_along_isoline.h"
+#include "list_to_matrix.h"
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedU,
+ typename DerivedG,
+ typename DerivedJ,
+ typename BCtype,
+ typename DerivedSU,
+ typename DerivedL>
+ IGL_INLINE void igl::remesh_along_isoline(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const typename DerivedS::Scalar val,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedSU> & SU,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::SparseMatrix<BCtype> & BC,
+ Eigen::PlainObjectBase<DerivedL> & L)
+{
+ igl::remesh_along_isoline(V.rows(),F,S,val,G,SU,J,BC,L);
+ U = BC * V;
+}
+
+template <
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedG,
+ typename DerivedJ,
+ typename BCtype,
+ typename DerivedSU,
+ typename DerivedL>
+ IGL_INLINE void igl::remesh_along_isoline(
+ const int num_vertices,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const typename DerivedS::Scalar val,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedSU> & SU,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::SparseMatrix<BCtype> & BC,
+ Eigen::PlainObjectBase<DerivedL> & L)
+{
+ // Lazy implementation using vectors
+
+ //assert(val.size() == 1);
+ const int isoval_i = 0;
+ //auto isoval = val(isoval_i);
+ auto isoval = val;
+ std::vector<std::vector<typename DerivedG::Scalar> > vG;
+ std::vector<typename DerivedJ::Scalar> vJ;
+ std::vector<typename DerivedL::Scalar> vL;
+ std::vector<Eigen::Triplet<BCtype> > vBC;
+ int Ucount = 0;
+ for(int i = 0;i<num_vertices;i++)
+ {
+ vBC.emplace_back(Ucount,i,1.0);
+ Ucount++;
+ }
+
+ // Loop over each face
+ for(int f = 0;f<F.rows();f++)
+ {
+ bool Psign[2];
+ int P[2];
+ int count = 0;
+ for(int p = 0;p<3;p++)
+ {
+ const bool psign = S(F(f,p)) > isoval;
+ // Find crossings
+ const int n = (p+1)%3;
+ const bool nsign = S(F(f,n)) > isoval;
+ if(psign != nsign)
+ {
+ P[count] = p;
+ Psign[count] = psign;
+ // record crossing
+ count++;
+ }
+ }
+
+ assert(count == 0 || count == 2);
+ switch(count)
+ {
+ case 0:
+ {
+ // Easy case
+ std::vector<typename DerivedG::Scalar> row = {F(f,0),F(f,1),F(f,2)};
+ vG.push_back(row);
+ vJ.push_back(f);
+ vL.push_back( S(F(f,0))>isoval ? isoval_i+1 : isoval_i );
+ break;
+ }
+ case 2:
+ {
+ // Cut case
+ // flip so that P[1] is the one-off vertex
+ if(P[0] == 0 && P[1] == 2)
+ {
+ std::swap(P[0],P[1]);
+ std::swap(Psign[0],Psign[1]);
+ }
+ assert(Psign[0] != Psign[1]);
+ // Create two new vertices
+ for(int i = 0;i<2;i++)
+ {
+ const double bci = (isoval - S(F(f,(P[i]+1)%3)))/
+ (S(F(f,P[i]))-S(F(f,(P[i]+1)%3)));
+ vBC.emplace_back(Ucount,F(f,P[i]),bci);
+ vBC.emplace_back(Ucount,F(f,(P[i]+1)%3),1.0-bci);
+ Ucount++;
+ }
+ const int v0 = F(f,P[0]);
+ const int v01 = Ucount-2;
+ assert(((P[0]+1)%3) == P[1]);
+ const int v1 = F(f,P[1]);
+ const int v12 = Ucount-1;
+ const int v2 = F(f,(P[1]+1)%3);
+ // v0
+ // | \
+ // | \
+ // | \
+ // v01 \
+ // | \
+ // | \
+ // | \
+ // v1--v12---v2
+ typedef std::vector<typename DerivedG::Scalar> Row;
+ {Row row = {v01,v1,v12}; vG.push_back(row);vJ.push_back(f);vL.push_back(Psign[0]?isoval_i:isoval_i+1);}
+ {Row row = {v12,v2,v01}; vG.push_back(row);vJ.push_back(f);vL.push_back(Psign[1]?isoval_i:isoval_i+1);}
+ {Row row = {v2,v0,v01}; vG.push_back(row) ;vJ.push_back(f);vL.push_back(Psign[1]?isoval_i:isoval_i+1);}
+ break;
+ }
+ default: assert(false);
+ }
+ }
+ igl::list_to_matrix(vG,G);
+ igl::list_to_matrix(vJ,J);
+ igl::list_to_matrix(vL,L);
+ BC.resize(Ucount,num_vertices);
+ BC.setFromTriplets(vBC.begin(),vBC.end());
+ SU = BC * S;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::remesh_along_isoline<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<double, -1, 1, 0, -1, 1>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/remesh_along_isoline.h b/xs/src/igl/remesh_along_isoline.h
new file mode 100644
index 000000000..9a7c553b2
--- /dev/null
+++ b/xs/src/igl/remesh_along_isoline.h
@@ -0,0 +1,81 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REMESH_ALONG_ISOLINE_H
+#define IGL_REMESH_ALONG_ISOLINE_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Given a triangle mesh and a scalar field, remesh so that a given isovalue
+ // of the scalar field follows (new) edges of the output mesh. Effectively
+ // running "marching triangles" on mesh, but not in any coherent order. The
+ // output mesh should be as manifold as the input.
+ //
+ // Inputs:
+ // V #V by dim list of mesh vertex positions
+ // F #F by 3 list of mesh triangle indices into V
+ // S #V by 1 list of scalar field
+ // val value of S to remesh along
+ // Outputs:
+ // U #U by dim list of mesh vertex positions #U>=#V
+ // G #G by 3 list of mesh triangle indices into U, #G>=#F
+ // SU #U list of scalar field values over new mesh
+ // J #G list of indices into G revealing birth triangles
+ // BC #U by #V sparse matrix of barycentric coordinates so that U = BC*V
+ // L #G list of bools whether scalar field in triangle below or above val
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedU,
+ typename DerivedG,
+ typename DerivedJ,
+ typename BCtype,
+ typename DerivedSU,
+ typename DerivedL>
+ IGL_INLINE void remesh_along_isoline(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const typename DerivedS::Scalar val,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedSU> & SU,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::SparseMatrix<BCtype> & BC,
+ Eigen::PlainObjectBase<DerivedL> & L);
+ // Input:
+ // n number of vertices (#V)
+ template <
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedG,
+ typename DerivedJ,
+ typename BCtype,
+ typename DerivedSU,
+ typename DerivedL>
+ IGL_INLINE void remesh_along_isoline(
+ const int n,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedS> & S,
+ const typename DerivedS::Scalar val,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedSU> & SU,
+ Eigen::PlainObjectBase<DerivedJ> & J,
+ Eigen::SparseMatrix<BCtype> & BC,
+ Eigen::PlainObjectBase<DerivedL> & L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "remesh_along_isoline.h"
+#endif
+
+#endif
diff --git a/xs/src/igl/remove_duplicate_vertices.cpp b/xs/src/igl/remove_duplicate_vertices.cpp
new file mode 100644
index 000000000..815ee51f8
--- /dev/null
+++ b/xs/src/igl/remove_duplicate_vertices.cpp
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "remove_duplicate_vertices.h"
+#include "round.h"
+#include "unique_rows.h"
+#include "colon.h"
+#include "slice.h"
+#include <functional>
+
+template <
+ typename DerivedV,
+ typename DerivedSV,
+ typename DerivedSVI,
+ typename DerivedSVJ>
+IGL_INLINE void igl::remove_duplicate_vertices(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const double epsilon,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSVI>& SVI,
+ Eigen::PlainObjectBase<DerivedSVJ>& SVJ)
+{
+ if(epsilon > 0)
+ {
+ DerivedV rV,rSV;
+ round((V/(10.0*epsilon)).eval(),rV);
+ unique_rows(rV,rSV,SVI,SVJ);
+ slice(V,SVI,colon<int>(0,V.cols()-1),SV);
+ }else
+ {
+ unique_rows(V,SV,SVI,SVJ);
+ }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedSV,
+ typename DerivedSVI,
+ typename DerivedSVJ,
+ typename DerivedSF>
+IGL_INLINE void igl::remove_duplicate_vertices(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const double epsilon,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSVI>& SVI,
+ Eigen::PlainObjectBase<DerivedSVJ>& SVJ,
+ Eigen::PlainObjectBase<DerivedSF>& SF)
+{
+ using namespace Eigen;
+ using namespace std;
+ remove_duplicate_vertices(V,epsilon,SV,SVI,SVJ);
+ SF.resizeLike(F);
+ for(int f = 0;f<F.rows();f++)
+ {
+ for(int c = 0;c<F.cols();c++)
+ {
+ SF(f,c) = SVJ(F(f,c));
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::remove_duplicate_vertices<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::remove_duplicate_vertices<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::remove_duplicate_vertices<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::remove_duplicate_vertices<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::remove_duplicate_vertices<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::remove_duplicate_vertices<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::remove_duplicate_vertices<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::remove_duplicate_vertices<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::remove_duplicate_vertices<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/remove_duplicate_vertices.h b/xs/src/igl/remove_duplicate_vertices.h
new file mode 100644
index 000000000..9276ba729
--- /dev/null
+++ b/xs/src/igl/remove_duplicate_vertices.h
@@ -0,0 +1,65 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REMOVE_DUPLICATE_VERTICES_H
+#define IGL_REMOVE_DUPLICATE_VERTICES_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // REMOVE_DUPLICATE_VERTICES Remove duplicate vertices upto a uniqueness
+ // tolerance (epsilon)
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // epsilon uniqueness tolerance (significant digit), can probably think of
+ // this as a tolerance on L1 distance
+ // Outputs:
+ // SV #SV by dim new list of vertex positions
+ // SVI #V by 1 list of indices so SV = V(SVI,:)
+ // SVJ #SV by 1 list of indices so V = SV(SVJ,:)
+ //
+ // Example:
+ // % Mesh in (V,F)
+ // [SV,SVI,SVJ] = remove_duplicate_vertices(V,1e-7);
+ // % remap faces
+ // SF = SVJ(F);
+ //
+ template <
+ typename DerivedV,
+ typename DerivedSV,
+ typename DerivedSVI,
+ typename DerivedSVJ>
+ IGL_INLINE void remove_duplicate_vertices(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const double epsilon,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSVI>& SVI,
+ Eigen::PlainObjectBase<DerivedSVJ>& SVJ);
+ // Wrapper that also remaps given faces (F) --> (SF) so that SF index SV
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedSV,
+ typename DerivedSVI,
+ typename DerivedSVJ,
+ typename DerivedSF>
+ IGL_INLINE void remove_duplicate_vertices(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const double epsilon,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSVI>& SVI,
+ Eigen::PlainObjectBase<DerivedSVJ>& SVJ,
+ Eigen::PlainObjectBase<DerivedSF>& SF);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "remove_duplicate_vertices.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/remove_duplicates.cpp b/xs/src/igl/remove_duplicates.cpp
new file mode 100644
index 000000000..3e97a39e1
--- /dev/null
+++ b/xs/src/igl/remove_duplicates.cpp
@@ -0,0 +1,88 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "remove_duplicates.h"
+#include <vector>
+
+//template <typename T, typename S>
+//IGL_INLINE void igl::remove_duplicates(
+// const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
+// const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &F,
+// Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &NV,
+// Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &NF,
+// Eigen::Matrix<S, Eigen::Dynamic, 1> &I,
+// const double epsilon)
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE void igl::remove_duplicates(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedV> &NV,
+ Eigen::PlainObjectBase<DerivedF> &NF,
+ Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 1> &I,
+ const double epsilon)
+{
+ using namespace std;
+ //// build collapse map
+ int n = V.rows();
+
+ I = Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 1>(n);
+ I[0] = 0;
+
+ bool *VISITED = new bool[n];
+ for (int i =0; i <n; ++i)
+ VISITED[i] = false;
+
+ NV.resize(n,V.cols());
+ int count = 0;
+ Eigen::VectorXd d(n);
+ for (int i =0; i <n; ++i)
+ {
+ if(!VISITED[i])
+ {
+ NV.row(count) = V.row(i);
+ I[i] = count;
+ VISITED[i] = true;
+ for (int j = i+1; j <n; ++j)
+ {
+ if((V.row(j) - V.row(i)).norm() < epsilon)
+ {
+ VISITED[j] = true;
+ I[j] = count;
+ }
+ }
+ count ++;
+ }
+ }
+
+ NV.conservativeResize ( count , Eigen::NoChange );
+
+ count = 0;
+ std::vector<typename DerivedF::Scalar> face;
+ NF.resizeLike(F);
+ for (int i =0; i <F.rows(); ++i)
+ {
+ face.clear();
+ for (int j = 0; j< F.cols(); ++j)
+ if(std::find(face.begin(), face.end(), I[F(i,j)]) == face.end())
+ face.push_back(I[F(i,j)]);
+ if (face.size() == size_t(F.cols()))
+ {
+ for (unsigned j = 0; j< F.cols(); ++j)
+ NF(count,j) = face[j];
+ count ++;
+ }
+ }
+ NF.conservativeResize ( count , Eigen::NoChange );
+
+ delete [] VISITED;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::remove_duplicates<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::Matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, -1, 1, 0, -1, 1>&, double);
+template void igl::remove_duplicates<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::Matrix<Eigen::Matrix<int, -1, 3, 1, -1, 3>::Scalar, -1, 1, 0, -1, 1>&, double);
+#endif
diff --git a/xs/src/igl/remove_duplicates.h b/xs/src/igl/remove_duplicates.h
new file mode 100644
index 000000000..0e1249ce9
--- /dev/null
+++ b/xs/src/igl/remove_duplicates.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REMOVE_DUPLICATES_H
+#define IGL_REMOVE_DUPLICATES_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+namespace igl
+{
+ // [ NV, NF ] = remove_duplicates( V,F,epsilon )
+ // Merge the duplicate vertices from V, fixing the topology accordingly
+ //
+ // Input:
+ // V,F: mesh description
+ // epsilon: minimal distance to consider two vertices identical
+ //
+ // Output:
+ // NV, NF: new mesh without duplicate vertices
+
+// template <typename T, typename S>
+// IGL_INLINE void remove_duplicates(
+// const Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &V,
+// const Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &F,
+// Eigen::Matrix<T, Eigen::Dynamic, Eigen::Dynamic> &NV,
+// Eigen::Matrix<S, Eigen::Dynamic, Eigen::Dynamic> &NF,
+// Eigen::Matrix<S, Eigen::Dynamic, 1> &I,
+// const double epsilon = 2.2204e-15);
+
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE void remove_duplicates(
+ const Eigen::PlainObjectBase<DerivedV> &V,
+ const Eigen::PlainObjectBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedV> &NV,
+ Eigen::PlainObjectBase<DerivedF> &NF,
+ Eigen::Matrix<typename DerivedF::Scalar, Eigen::Dynamic, 1> &I,
+ const double epsilon = 2.2204e-15);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "remove_duplicates.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/remove_unreferenced.cpp b/xs/src/igl/remove_unreferenced.cpp
new file mode 100644
index 000000000..3ee8260aa
--- /dev/null
+++ b/xs/src/igl/remove_unreferenced.cpp
@@ -0,0 +1,122 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "remove_unreferenced.h"
+#include "slice.h"
+#include <algorithm>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF,
+ typename DerivedI>
+IGL_INLINE void igl::remove_unreferenced(
+ const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedNV> &NV,
+ Eigen::PlainObjectBase<DerivedNF> &NF,
+ Eigen::PlainObjectBase<DerivedI> &I)
+{
+ Eigen::Matrix<typename DerivedI::Scalar,Eigen::Dynamic,1> J;
+ remove_unreferenced(V,F,NV,NF,I,J);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF,
+ typename DerivedI,
+ typename DerivedJ>
+IGL_INLINE void igl::remove_unreferenced(
+ const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedNV> &NV,
+ Eigen::PlainObjectBase<DerivedNF> &NF,
+ Eigen::PlainObjectBase<DerivedI> &I,
+ Eigen::PlainObjectBase<DerivedJ> &J)
+{
+ using namespace std;
+ const size_t n = V.rows();
+ remove_unreferenced(n,F,I,J);
+ NF = F;
+ std::for_each(NF.data(),NF.data()+NF.size(),
+ [&I](typename DerivedNF::Scalar & a){a=I(a);});
+ slice(V,J,1,NV);
+}
+
+template <
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedJ>
+IGL_INLINE void igl::remove_unreferenced(
+ const size_t n,
+ const Eigen::MatrixBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedI> &I,
+ Eigen::PlainObjectBase<DerivedJ> &J)
+{
+ // Mark referenced vertices
+ typedef Eigen::Matrix<bool,Eigen::Dynamic,1> MatrixXb;
+ MatrixXb mark = MatrixXb::Zero(n,1);
+ for(int i=0; i<F.rows(); ++i)
+ {
+ for(int j=0; j<F.cols(); ++j)
+ {
+ if (F(i,j) != -1)
+ {
+ mark(F(i,j)) = 1;
+ }
+ }
+ }
+
+ // Sum the occupied cells
+ int newsize = mark.count();
+
+ I.resize(n,1);
+ J.resize(newsize,1);
+
+ // Do a pass on the marked vector and remove the unreferenced vertices
+ int count = 0;
+ for(int i=0;i<mark.rows();++i)
+ {
+ if (mark(i) == 1)
+ {
+ I(i) = count;
+ J(count) = i;
+ count++;
+ }
+ else
+ {
+ I(i) = -1;
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::remove_unreferenced<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+// generated by autoexplicit.sh
+template void igl::remove_unreferenced<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+//template void igl::remove_unreferenced<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(unsigned long, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::remove_unreferenced<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/remove_unreferenced.h b/xs/src/igl/remove_unreferenced.h
new file mode 100644
index 000000000..2284190ab
--- /dev/null
+++ b/xs/src/igl/remove_unreferenced.h
@@ -0,0 +1,82 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+// remove_unreferenced.h
+// Preview3D
+//
+// Created by Daniele Panozzo on 17/11/11.
+
+#ifndef IGL_REMOVE_UNREFERENCED_H
+#define IGL_REMOVE_UNREFERENCED_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+namespace igl
+{
+ // Remove unreferenced vertices from V, updating F accordingly
+ //
+ // Input:
+ // V #V by dim list of mesh vertex positions
+ // F #F by ss list of simplices (Values of -1 are quitely skipped)
+ // Outputs:
+ // NV #NV by dim list of mesh vertex positions
+ // NF #NF by ss list of simplices
+ // IM #V by 1 list of indices such that: NF = IM(F) and NT = IM(T)
+ // and V(find(IM<=size(NV,1)),:) = NV
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF,
+ typename DerivedI>
+ IGL_INLINE void remove_unreferenced(
+ const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedNV> &NV,
+ Eigen::PlainObjectBase<DerivedNF> &NF,
+ Eigen::PlainObjectBase<DerivedI> &I);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF,
+ typename DerivedI,
+ typename DerivedJ>
+ IGL_INLINE void remove_unreferenced(
+ const Eigen::MatrixBase<DerivedV> &V,
+ const Eigen::MatrixBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedNV> &NV,
+ Eigen::PlainObjectBase<DerivedNF> &NF,
+ Eigen::PlainObjectBase<DerivedI> &I,
+ Eigen::PlainObjectBase<DerivedJ> &J);
+ // Inputs:
+ // n number of vertices (possibly greater than F.maxCoeff()+1)
+ // F #F by ss list of simplices
+ // Outputs:
+ // IM #V by 1 list of indices such that: NF = IM(F) and NT = IM(T)
+ // and V(find(IM<=size(NV,1)),:) = NV
+ // J #RV by 1 list, such that RV = V(J,:)
+ //
+ template <
+ typename DerivedF,
+ typename DerivedI,
+ typename DerivedJ>
+ IGL_INLINE void remove_unreferenced(
+ const size_t n,
+ const Eigen::MatrixBase<DerivedF> &F,
+ Eigen::PlainObjectBase<DerivedI> &I,
+ Eigen::PlainObjectBase<DerivedJ> &J);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "remove_unreferenced.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/reorder.cpp b/xs/src/igl/reorder.cpp
new file mode 100644
index 000000000..ee74b2096
--- /dev/null
+++ b/xs/src/igl/reorder.cpp
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "reorder.h"
+#include "SortableRow.h"
+#ifndef IGL_NO_EIGEN
+#include <Eigen/Core>
+#endif
+
+// This implementation is O(n), but also uses O(n) extra memory
+template< class T >
+IGL_INLINE void igl::reorder(
+ const std::vector<T> & unordered,
+ std::vector<size_t> const & index_map,
+ std::vector<T> & ordered)
+{
+ // copy for the reorder according to index_map, because unsorted may also be
+ // sorted
+ std::vector<T> copy = unordered;
+ ordered.resize(index_map.size());
+ for(int i = 0; i<(int)index_map.size();i++)
+ {
+ ordered[i] = copy[index_map[i]];
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::reorder<float>(std::vector<float, std::allocator<float> > const&, std::vector<unsigned long, std::allocator<unsigned long> > const&, std::vector<float, std::allocator<float> >&);
+template void igl::reorder<double>(std::vector<double, std::allocator<double> > const&, std::vector<size_t, std::allocator<size_t> > const&, std::vector<double, std::allocator<double> >&);
+template void igl::reorder<int>(std::vector<int, std::allocator<int> > const&, std::vector<size_t, std::allocator<size_t> > const&, std::vector<int, std::allocator<int> >&);
+# ifndef IGL_NO_EIGEN
+ template void igl::reorder<igl::SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> > >(std::vector<igl::SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> >, std::allocator<igl::SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> > > > const&, std::vector<size_t, std::allocator<size_t> > const&, std::vector<igl::SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> >, std::allocator<igl::SortableRow<Eigen::Matrix<int, -1, 1, 0, -1, 1> > > >&);
+ template void igl::reorder<igl::SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> > >(std::vector<igl::SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> >, std::allocator<igl::SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> > > > const&, std::vector<size_t, std::allocator<size_t> > const&, std::vector<igl::SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> >, std::allocator<igl::SortableRow<Eigen::Matrix<double, -1, 1, 0, -1, 1> > > >&);
+# endif
+template void igl::reorder<long>(std::vector<long, std::allocator<long> > const&, std::vector<size_t, std::allocator<size_t> > const&, std::vector<long, std::allocator<long> >&);
+#ifdef WIN32
+template void igl::reorder<float>(class std::vector<float,class std::allocator<float> > const &,class std::vector<unsigned __int64,class std::allocator<unsigned __int64> > const &,class std::vector<float,class std::allocator<float> > &);
+#endif
+#endif
diff --git a/xs/src/igl/reorder.h b/xs/src/igl/reorder.h
new file mode 100644
index 000000000..50f7d7b0f
--- /dev/null
+++ b/xs/src/igl/reorder.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REORDER_H
+#define IGL_REORDER_H
+#include "igl_inline.h"
+#include <vector>
+// For size_t
+#include <stddef.h>
+#include <cstdlib>
+
+namespace igl
+{
+ // Act like matlab's Y = X(I) for std vectors
+ // where I contains a vector of indices so that after,
+ // Y[j] = X[I[j]] for index j
+ // this implies that Y.size() == I.size()
+ // X and Y are allowed to be the same reference
+ template< class T >
+ IGL_INLINE void reorder(
+ const std::vector<T> & unordered,
+ std::vector<size_t> const & index_map,
+ std::vector<T> & ordered);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "reorder.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/repdiag.cpp b/xs/src/igl/repdiag.cpp
new file mode 100644
index 000000000..283ae1e75
--- /dev/null
+++ b/xs/src/igl/repdiag.cpp
@@ -0,0 +1,97 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "repdiag.h"
+#include <vector>
+
+template <typename T>
+IGL_INLINE void igl::repdiag(
+ const Eigen::SparseMatrix<T>& A,
+ const int d,
+ Eigen::SparseMatrix<T>& B)
+{
+ using namespace std;
+ using namespace Eigen;
+ int m = A.rows();
+ int n = A.cols();
+#if false
+ vector<Triplet<T> > IJV;
+ IJV.reserve(A.nonZeros()*d);
+ // Loop outer level
+ for (int k=0; k<A.outerSize(); ++k)
+ {
+ // loop inner level
+ for (typename Eigen::SparseMatrix<T>::InnerIterator it(A,k); it; ++it)
+ {
+ for(int i = 0;i<d;i++)
+ {
+ IJV.push_back(Triplet<T>(i*m+it.row(),i*n+it.col(),it.value()));
+ }
+ }
+ }
+ B.resize(m*d,n*d);
+ B.setFromTriplets(IJV.begin(),IJV.end());
+#else
+ // This will not work for RowMajor
+ B.resize(m*d,n*d);
+ Eigen::VectorXi per_col = Eigen::VectorXi::Zero(n*d);
+ for (int k=0; k<A.outerSize(); ++k)
+ {
+ for (typename Eigen::SparseMatrix<T>::InnerIterator it(A,k); it; ++it)
+ {
+ for(int r = 0;r<d;r++) per_col(n*r + k)++;
+ }
+ }
+ B.reserve(per_col);
+ for(int r = 0;r<d;r++)
+ {
+ const int mr = m*r;
+ const int nr = n*r;
+ for (int k=0; k<A.outerSize(); ++k)
+ {
+ for (typename Eigen::SparseMatrix<T>::InnerIterator it(A,k); it; ++it)
+ {
+ B.insert(it.row()+mr,k+nr) = it.value();
+ }
+ }
+ }
+ B.makeCompressed();
+#endif
+}
+
+template <typename T>
+IGL_INLINE void igl::repdiag(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
+ const int d,
+ Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B)
+{
+ int m = A.rows();
+ int n = A.cols();
+ B.resize(m*d,n*d);
+ B.array() *= 0;
+ for(int i = 0;i<d;i++)
+ {
+ B.block(i*m,i*n,m,n) = A;
+ }
+}
+
+// Wrapper with B as output
+template <class Mat>
+IGL_INLINE Mat igl::repdiag(const Mat & A, const int d)
+{
+ Mat B;
+ repdiag(A,d,B);
+ return B;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::repdiag<double>(Eigen::SparseMatrix<double, 0, int> const&, int, Eigen::SparseMatrix<double, 0, int>&);
+// generated by autoexplicit.sh
+template Eigen::SparseMatrix<double, 0, int> igl::repdiag<Eigen::SparseMatrix<double, 0, int> >(Eigen::SparseMatrix<double, 0, int> const&, int);
+#endif
diff --git a/xs/src/igl/repdiag.h b/xs/src/igl/repdiag.h
new file mode 100644
index 000000000..779443374
--- /dev/null
+++ b/xs/src/igl/repdiag.h
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REPDIAG_H
+#define IGL_REPDIAG_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // REPDIAG repeat a matrix along the diagonal a certain number of times, so
+ // that if A is a m by n matrix and we want to repeat along the diagonal d
+ // times, we get a m*d by n*d matrix B such that:
+ // B( (k*m+1):(k*m+1+m-1), (k*n+1):(k*n+1+n-1)) = A
+ // for k from 0 to d-1
+ //
+ // Inputs:
+ // A m by n matrix we are repeating along the diagonal. May be dense or
+ // sparse
+ // d number of times to repeat A along the diagonal
+ // Outputs:
+ // B m*d by n*d matrix with A repeated d times along the diagonal,
+ // will be dense or sparse to match A
+ //
+
+ // Sparse version
+ template <typename T>
+ IGL_INLINE void repdiag(
+ const Eigen::SparseMatrix<T>& A,
+ const int d,
+ Eigen::SparseMatrix<T>& B);
+ // Dense version
+ template <typename T>
+ IGL_INLINE void repdiag(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
+ const int d,
+ Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B);
+ // Wrapper with B as output
+ template <class Mat>
+ IGL_INLINE Mat repdiag(const Mat & A, const int d);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "repdiag.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/repmat.cpp b/xs/src/igl/repmat.cpp
new file mode 100644
index 000000000..f79840444
--- /dev/null
+++ b/xs/src/igl/repmat.cpp
@@ -0,0 +1,67 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "repmat.h"
+
+template <typename DerivedA, typename DerivedB>
+IGL_INLINE void igl::repmat(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const int r,
+ const int c,
+ Eigen::PlainObjectBase<DerivedB> & B)
+{
+ assert(r>0);
+ assert(c>0);
+ // Make room for output
+ B.resize(r*A.rows(),c*A.cols());
+
+ // copy tiled blocks
+ for(int i = 0;i<r;i++)
+ {
+ for(int j = 0;j<c;j++)
+ {
+ B.block(i*A.rows(),j*A.cols(),A.rows(),A.cols()) = A;
+ }
+ }
+}
+
+template <typename T>
+IGL_INLINE void igl::repmat(
+ const Eigen::SparseMatrix<T> & A,
+ const int r,
+ const int c,
+ Eigen::SparseMatrix<T> & B)
+{
+ assert(r>0);
+ assert(c>0);
+ B.resize(r*A.rows(),c*A.cols());
+ B.reserve(r*c*A.nonZeros());
+ for(int i = 0;i<r;i++)
+ {
+ for(int j = 0;j<c;j++)
+ {
+ // Loop outer level
+ for (int k=0; k<A.outerSize(); ++k)
+ {
+ // loop inner level
+ for (typename Eigen::SparseMatrix<T>::InnerIterator it(A,k); it; ++it)
+ {
+ B.insert(i*A.rows()+it.row(),j*A.cols() + it.col()) = it.value();
+ }
+ }
+ }
+ }
+ B.finalize();
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::repmat<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::repmat<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::repmat<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/repmat.h b/xs/src/igl/repmat.h
new file mode 100644
index 000000000..1509875aa
--- /dev/null
+++ b/xs/src/igl/repmat.h
@@ -0,0 +1,53 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_REPMAT_H
+#define IGL_REPMAT_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // At least for Dense matrices this is replaced by `replicate` e.g., dst = src.replicate(n,m);
+ // http://forum.kde.org/viewtopic.php?f=74&t=90876#p173517
+
+ // Ideally this is a super overloaded function that behaves just like
+ // matlab's repmat
+
+ // Replicate and tile a matrix
+ //
+ // Templates:
+ // T should be a eigen matrix primitive type like int or double
+ // Inputs:
+ // A m by n input matrix
+ // r number of row-direction copies
+ // c number of col-direction copies
+ // Outputs:
+ // B r*m by c*n output matrix
+ //
+ template <typename DerivedA,typename DerivedB>
+ IGL_INLINE void repmat(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const int r,
+ const int c,
+ Eigen::PlainObjectBase<DerivedB> & B);
+ template <typename T>
+ IGL_INLINE void repmat(
+ const Eigen::SparseMatrix<T> & A,
+ const int r,
+ const int c,
+ Eigen::SparseMatrix<T> & B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "repmat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/resolve_duplicated_faces.cpp b/xs/src/igl/resolve_duplicated_faces.cpp
new file mode 100644
index 000000000..3b26b8ecc
--- /dev/null
+++ b/xs/src/igl/resolve_duplicated_faces.cpp
@@ -0,0 +1,96 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+
+#include "resolve_duplicated_faces.h"
+
+#include "slice.h"
+#include "unique_simplices.h"
+
+template<
+ typename DerivedF1,
+ typename DerivedF2,
+ typename DerivedJ >
+IGL_INLINE void igl::resolve_duplicated_faces(
+ const Eigen::PlainObjectBase<DerivedF1>& F1,
+ Eigen::PlainObjectBase<DerivedF2>& F2,
+ Eigen::PlainObjectBase<DerivedJ>& J) {
+
+ //typedef typename DerivedF1::Scalar Index;
+ Eigen::VectorXi IA,IC;
+ DerivedF1 uF;
+ igl::unique_simplices(F1,uF,IA,IC);
+
+ const size_t num_faces = F1.rows();
+ const size_t num_unique_faces = uF.rows();
+ assert((size_t) IA.rows() == num_unique_faces);
+ // faces on top of each unique face
+ std::vector<std::vector<int> > uF2F(num_unique_faces);
+ // signed counts
+ Eigen::VectorXi counts = Eigen::VectorXi::Zero(num_unique_faces);
+ Eigen::VectorXi ucounts = Eigen::VectorXi::Zero(num_unique_faces);
+ // loop over all faces
+ for (size_t i=0; i<num_faces; i++) {
+ const size_t ui = IC(i);
+ const bool consistent =
+ (F1(i,0) == uF(ui, 0) && F1(i,1) == uF(ui, 1) && F1(i,2) == uF(ui, 2)) ||
+ (F1(i,0) == uF(ui, 1) && F1(i,1) == uF(ui, 2) && F1(i,2) == uF(ui, 0)) ||
+ (F1(i,0) == uF(ui, 2) && F1(i,1) == uF(ui, 0) && F1(i,2) == uF(ui, 1));
+ uF2F[ui].push_back(int(i+1) * (consistent?1:-1));
+ counts(ui) += consistent ? 1:-1;
+ ucounts(ui)++;
+ }
+
+ std::vector<size_t> kept_faces;
+ for (size_t i=0; i<num_unique_faces; i++) {
+ if (ucounts[i] == 1) {
+ kept_faces.push_back(abs(uF2F[i][0])-1);
+ continue;
+ }
+ if (counts[i] == 1) {
+ bool found = false;
+ for (auto fid : uF2F[i]) {
+ if (fid > 0) {
+ kept_faces.push_back(abs(fid)-1);
+ found = true;
+ break;
+ }
+ }
+ assert(found);
+ } else if (counts[i] == -1) {
+ bool found = false;
+ for (auto fid : uF2F[i]) {
+ if (fid < 0) {
+ kept_faces.push_back(abs(fid)-1);
+ found = true;
+ break;
+ }
+ }
+ assert(found);
+ } else {
+ assert(counts[i] == 0);
+ }
+ }
+
+ const size_t num_kept = kept_faces.size();
+ J.resize(num_kept, 1);
+ std::copy(kept_faces.begin(), kept_faces.end(), J.data());
+ igl::slice(F1, J, 1, F2);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::resolve_duplicated_faces<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::resolve_duplicated_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::resolve_duplicated_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::resolve_duplicated_faces<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#ifdef WIN32
+template void igl::resolve_duplicated_faces<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/resolve_duplicated_faces.h b/xs/src/igl/resolve_duplicated_faces.h
new file mode 100644
index 000000000..03ea3d6e6
--- /dev/null
+++ b/xs/src/igl/resolve_duplicated_faces.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Qingnan Zhou <qnzhou@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//
+#ifndef IGL_COPYLEFT_RESOLVE_DUPLICATED_FACES
+#define IGL_COPYLEFT_RESOLVE_DUPLICATED_FACES
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl {
+
+ // Resolve duplicated faces according to the following rules per unique face:
+ //
+ // 1. If the number of positively oriented faces equals the number of
+ // negatively oriented faces, remove all duplicated faces at this triangle.
+ // 2. If the number of positively oriented faces equals the number of
+ // negatively oriented faces plus 1, keeps one of the positively oriented
+ // face.
+ // 3. If the number of positively oriented faces equals the number of
+ // negatively oriented faces minus 1, keeps one of the negatively oriented
+ // face.
+ // 4. If the number of postively oriented faces differ with the number of
+ // negativley oriented faces by more than 1, the mesh is not orientable.
+ // An exception will be thrown.
+ //
+ // Inputs:
+ // F1 #F1 by 3 array of input faces.
+ //
+ // Outputs:
+ // F2 #F2 by 3 array of output faces without duplicated faces.
+ // J #F2 list of indices into F1.
+ template<
+ typename DerivedF1,
+ typename DerivedF2,
+ typename DerivedJ >
+ IGL_INLINE void resolve_duplicated_faces(
+ const Eigen::PlainObjectBase<DerivedF1>& F1,
+ Eigen::PlainObjectBase<DerivedF2>& F2,
+ Eigen::PlainObjectBase<DerivedJ>& J);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "resolve_duplicated_faces.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/rgb_to_hsv.cpp b/xs/src/igl/rgb_to_hsv.cpp
new file mode 100644
index 000000000..fbf32bfec
--- /dev/null
+++ b/xs/src/igl/rgb_to_hsv.cpp
@@ -0,0 +1,102 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "rgb_to_hsv.h"
+
+template <typename R,typename H>
+IGL_INLINE void igl::rgb_to_hsv(const R * rgb, H * hsv)
+{
+ // http://en.literateprograms.org/RGB_to_HSV_color_space_conversion_%28C%29
+ R rgb_max = 0.0;
+ R rgb_min = 1.0;
+ rgb_max = (rgb[0]>rgb_max?rgb[0]:rgb_max);
+ rgb_max = (rgb[1]>rgb_max?rgb[1]:rgb_max);
+ rgb_max = (rgb[2]>rgb_max?rgb[2]:rgb_max);
+ rgb_min = (rgb[0]<rgb_min?rgb[0]:rgb_min);
+ rgb_min = (rgb[1]<rgb_min?rgb[1]:rgb_min);
+ rgb_min = (rgb[2]<rgb_min?rgb[2]:rgb_min);
+ //hsv[2] = rgb_max;
+ hsv[2] = rgb_max;
+ if(hsv[2] == 0)
+ {
+ hsv[0]=hsv[1]=0;
+ return;
+ }
+ // normalize
+ R rgb_n[3];
+ rgb_n[0] = rgb[0]/hsv[2];
+ rgb_n[1] = rgb[1]/hsv[2];
+ rgb_n[2] = rgb[2]/hsv[2];
+ // Recomput max min?
+ rgb_max = 0;
+ rgb_max = (rgb_n[0]>rgb_max?rgb_n[0]:rgb_max);
+ rgb_max = (rgb_n[1]>rgb_max?rgb_n[1]:rgb_max);
+ rgb_max = (rgb_n[2]>rgb_max?rgb_n[2]:rgb_max);
+ rgb_min = 1;
+ rgb_min = (rgb_n[0]<rgb_min?rgb_n[0]:rgb_min);
+ rgb_min = (rgb_n[1]<rgb_min?rgb_n[1]:rgb_min);
+ rgb_min = (rgb_n[2]<rgb_min?rgb_n[2]:rgb_min);
+ hsv[1] = rgb_max - rgb_min;
+ if(hsv[1] == 0)
+ {
+ hsv[0] = 0;
+ return;
+ }
+ rgb_n[0] = (rgb_n[0] - rgb_min)/(rgb_max - rgb_min);
+ rgb_n[1] = (rgb_n[1] - rgb_min)/(rgb_max - rgb_min);
+ rgb_n[2] = (rgb_n[2] - rgb_min)/(rgb_max - rgb_min);
+ // Recomput max min?
+ rgb_max = 0;
+ rgb_max = (rgb_n[0]>rgb_max?rgb_n[0]:rgb_max);
+ rgb_max = (rgb_n[1]>rgb_max?rgb_n[1]:rgb_max);
+ rgb_max = (rgb_n[2]>rgb_max?rgb_n[2]:rgb_max);
+ rgb_min = 1;
+ rgb_min = (rgb_n[0]<rgb_min?rgb_n[0]:rgb_min);
+ rgb_min = (rgb_n[1]<rgb_min?rgb_n[1]:rgb_min);
+ rgb_min = (rgb_n[2]<rgb_min?rgb_n[2]:rgb_min);
+ if (rgb_max == rgb_n[0]) {
+ hsv[0] = 0.0 + 60.0*(rgb_n[1] - rgb_n[2]);
+ if (hsv[0] < 0.0) {
+ hsv[0] += 360.0;
+ }
+ } else if (rgb_max == rgb_n[1]) {
+ hsv[0] = 120.0 + 60.0*(rgb_n[2] - rgb_n[0]);
+ } else /* rgb_max == rgb_n[2] */ {
+ hsv[0] = 240.0 + 60.0*(rgb_n[0] - rgb_n[1]);
+ }
+}
+
+
+template <typename DerivedR,typename DerivedH>
+IGL_INLINE void igl::rgb_to_hsv(
+ const Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedH> & H)
+{
+ assert(R.cols() == 3);
+ H.resizeLike(R);
+ for(typename DerivedR::Index r = 0;r<R.rows();r++)
+ {
+ typename DerivedR::Scalar rgb[3];
+ rgb[0] = R(r,0);
+ rgb[1] = R(r,1);
+ rgb[2] = R(r,2);
+ typename DerivedH::Scalar hsv[] = {0,0,0};
+ rgb_to_hsv(rgb,hsv);
+ H(r,0) = hsv[0];
+ H(r,1) = hsv[1];
+ H(r,2) = hsv[2];
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::rgb_to_hsv<float, double>(float const*, double*);
+template void igl::rgb_to_hsv<double, double>(double const*, double*);
+template void igl::rgb_to_hsv<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::rgb_to_hsv<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+template void igl::rgb_to_hsv<Eigen::Matrix<float, 64, 3, 1, 64, 3>, Eigen::Matrix<float, 64, 3, 1, 64, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 64, 3, 1, 64, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 64, 3, 1, 64, 3> >&);
+#endif
diff --git a/xs/src/igl/rgb_to_hsv.h b/xs/src/igl/rgb_to_hsv.h
new file mode 100644
index 000000000..ed695ad60
--- /dev/null
+++ b/xs/src/igl/rgb_to_hsv.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_RGB_TO_HSV_H
+#define IGL_RGB_TO_HSV_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Convert RGB to HSV
+ //
+ // Inputs:
+ // r red value ([0,1])
+ // g green value ([0,1])
+ // b blue value ([0,1])
+ // Outputs:
+ // h hue value (degrees: [0,360])
+ // s saturation value ([0,1])
+ // v value value ([0,1])
+ template <typename R,typename H>
+ IGL_INLINE void rgb_to_hsv(const R * rgb, H * hsv);
+ template <typename DerivedR,typename DerivedH>
+ IGL_INLINE void rgb_to_hsv(
+ const Eigen::PlainObjectBase<DerivedR> & R,
+ Eigen::PlainObjectBase<DerivedH> & H);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "rgb_to_hsv.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/rotate_by_quat.cpp b/xs/src/igl/rotate_by_quat.cpp
new file mode 100644
index 000000000..b77c812ea
--- /dev/null
+++ b/xs/src/igl/rotate_by_quat.cpp
@@ -0,0 +1,55 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "rotate_by_quat.h"
+
+#include "quat_conjugate.h"
+#include "quat_mult.h"
+#include "normalize_quat.h"
+#include <cassert>
+
+template <typename Q_type>
+IGL_INLINE void igl::rotate_by_quat(
+ const Q_type *v,
+ const Q_type *q,
+ Q_type *out)
+{
+ // Quaternion form of v, copy data in v, (as a result out can be same pointer
+ // as v)
+ Q_type quat_v[4] = {v[0],v[1],v[2],0};
+
+ // normalize input
+ Q_type normalized_q[4];
+
+#ifndef NDEBUG
+ bool normalized =
+#endif
+ igl::normalize_quat<Q_type>(q,normalized_q);
+#ifndef NDEBUG
+ assert(normalized);
+#endif
+
+ // Conjugate of q
+ Q_type q_conj[4];
+ igl::quat_conjugate<Q_type>(normalized_q,q_conj);
+
+ // Rotate of vector v by quaternion q is:
+ // q*v*conj(q)
+ // Compute q*v
+ Q_type q_mult_quat_v[4];
+ igl::quat_mult<Q_type>(normalized_q,quat_v,q_mult_quat_v);
+ // Compute (q*v) * conj(q)
+ igl::quat_mult<Q_type>(q_mult_quat_v,q_conj,out);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::rotate_by_quat<double>(double const*, double const*, double*);
+// generated by autoexplicit.sh
+template void igl::rotate_by_quat<float>(float const*, float const*, float*);
+#endif
diff --git a/xs/src/igl/rotate_by_quat.h b/xs/src/igl/rotate_by_quat.h
new file mode 100644
index 000000000..b45204839
--- /dev/null
+++ b/xs/src/igl/rotate_by_quat.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ROTATE_BY_QUAT_H
+#define IGL_ROTATE_BY_QUAT_H
+#include "igl_inline.h"
+
+namespace igl
+{
+ // Compute rotation of a given vector/point by 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:
+ // v input 3d point/vector
+ // q input quaternion
+ // Outputs:
+ // out result of rotation, allowed to be same as v
+ template <typename Q_type>
+ IGL_INLINE void rotate_by_quat(
+ const Q_type *v,
+ const Q_type *q,
+ Q_type *out);
+};
+
+#ifndef IGL_STATIC_LIBRARY
+# include "rotate_by_quat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/rotate_vectors.cpp b/xs/src/igl/rotate_vectors.cpp
new file mode 100644
index 000000000..b236d79e6
--- /dev/null
+++ b/xs/src/igl/rotate_vectors.cpp
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "rotate_vectors.h"
+IGL_INLINE Eigen::MatrixXd igl::rotate_vectors(
+ const Eigen::MatrixXd& V,
+ const Eigen::VectorXd& A,
+ const Eigen::MatrixXd& B1,
+ const Eigen::MatrixXd& B2)
+{
+ Eigen::MatrixXd RV(V.rows(),V.cols());
+
+ for (unsigned i=0; i<V.rows();++i)
+ {
+ double norm = V.row(i).norm();
+
+ // project onto the tangent plane and convert to angle
+ double a = atan2(B2.row(i).dot(V.row(i)),B1.row(i).dot(V.row(i)));
+
+ // rotate
+ a += (A.size() == 1) ? A(0) : A(i);
+
+ // move it back to global coordinates
+ RV.row(i) = norm*cos(a) * B1.row(i) + norm*sin(a) * B2.row(i);
+ }
+
+ return RV;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/rotate_vectors.h b/xs/src/igl/rotate_vectors.h
new file mode 100644
index 000000000..a1b64bcca
--- /dev/null
+++ b/xs/src/igl/rotate_vectors.h
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_ROTATE_VECTORS_H
+#define IGL_ROTATE_VECTORS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Rotate the vectors V by A radiants on the tangent plane spanned by B1 and
+ // B2
+ //
+ // Inputs:
+ // V #V by 3 eigen Matrix of vectors
+ // A #V eigen vector of rotation angles or a single angle to be applied
+ // to all vectors
+ // B1 #V by 3 eigen Matrix of base vector 1
+ // B2 #V by 3 eigen Matrix of base vector 2
+ //
+ // Output:
+ // Returns the rotated vectors
+ //
+ IGL_INLINE Eigen::MatrixXd rotate_vectors(
+ const Eigen::MatrixXd& V,
+ const Eigen::VectorXd& A,
+ const Eigen::MatrixXd& B1,
+ const Eigen::MatrixXd& B2);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "rotate_vectors.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/rotation_matrix_from_directions.cpp b/xs/src/igl/rotation_matrix_from_directions.cpp
new file mode 100644
index 000000000..4ecc1a5d9
--- /dev/null
+++ b/xs/src/igl/rotation_matrix_from_directions.cpp
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>, Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "rotation_matrix_from_directions.h"
+#include <Eigen/Geometry>
+#include <iostream>
+
+template <typename Scalar>
+IGL_INLINE Eigen::Matrix<Scalar, 3, 3> igl::rotation_matrix_from_directions(
+ const Eigen::Matrix<Scalar, 3, 1> v0,
+ const Eigen::Matrix<Scalar, 3, 1> v1)
+{
+ Eigen::Matrix<Scalar, 3, 3> rotM;
+ const double epsilon=1e-8;
+ Scalar dot=v0.normalized().dot(v1.normalized());
+ ///control if there is no rotation
+ if ((v0-v1).norm()<epsilon)
+ {
+ rotM = Eigen::Matrix<Scalar, 3, 3>::Identity();
+ return rotM;
+ }
+ if ((v0+v1).norm()<epsilon)
+ {
+ rotM = -Eigen::Matrix<Scalar, 3, 3>::Identity();
+ rotM(0,0) = 1.;
+ std::cerr<<"igl::rotation_matrix_from_directions: rotating around x axis by 180o"<<std::endl;
+ return rotM;
+ }
+ ///find the axis of rotation
+ Eigen::Matrix<Scalar, 3, 1> axis;
+ axis=v0.cross(v1);
+ axis.normalize();
+
+ ///construct rotation matrix
+ Scalar u=axis(0);
+ Scalar v=axis(1);
+ Scalar w=axis(2);
+ Scalar phi=acos(dot);
+ Scalar rcos = cos(phi);
+ Scalar rsin = sin(phi);
+
+ rotM(0,0) = rcos + u*u*(1-rcos);
+ rotM(1,0) = w * rsin + v*u*(1-rcos);
+ rotM(2,0) = -v * rsin + w*u*(1-rcos);
+ rotM(0,1) = -w * rsin + u*v*(1-rcos);
+ rotM(1,1) = rcos + v*v*(1-rcos);
+ rotM(2,1) = u * rsin + w*v*(1-rcos);
+ rotM(0,2) = v * rsin + u*w*(1-rcos);
+ rotM(1,2) = -u * rsin + v*w*(1-rcos);
+ rotM(2,2) = rcos + w*w*(1-rcos);
+
+ return rotM;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template Eigen::Matrix<double, 3, 3, 0, 3, 3> igl::rotation_matrix_from_directions<double>(const Eigen::Matrix<double, 3, 1, 0, 3, 1>, const Eigen::Matrix<double, 3, 1, 0, 3, 1>);
+#endif
diff --git a/xs/src/igl/rotation_matrix_from_directions.h b/xs/src/igl/rotation_matrix_from_directions.h
new file mode 100644
index 000000000..ca1397272
--- /dev/null
+++ b/xs/src/igl/rotation_matrix_from_directions.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson, Daniele Panozzo, Olga Diamanti
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ROTATION_MATRIX_FROM_DIRECTIONS_H
+#define IGL_ROTATION_MATRIX_FROM_DIRECTIONS_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Given 2 vectors centered on origin calculate the rotation matrix from
+ // first to the second
+ //
+ // Inputs:
+ // v0 3D column vector
+ // v1 3D column vector
+ // Output:
+ // 3 by 3 rotation matrix that takes v0 to v1
+ //
+ template <typename Scalar>
+ IGL_INLINE Eigen::Matrix<Scalar, 3, 3> rotation_matrix_from_directions(
+ const Eigen::Matrix<Scalar, 3, 1> v0,
+ const Eigen::Matrix<Scalar, 3, 1> v1);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "rotation_matrix_from_directions.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/round.cpp b/xs/src/igl/round.cpp
new file mode 100644
index 000000000..acde47316
--- /dev/null
+++ b/xs/src/igl/round.cpp
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "round.h"
+#include <cmath>
+
+
+// http://stackoverflow.com/a/485549
+template <typename DerivedX >
+IGL_INLINE DerivedX igl::round(const DerivedX r)
+{
+ return (r > 0.0) ? std::floor(r + 0.5) : std::ceil(r - 0.5);
+}
+
+template < typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::round(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedY>& Y)
+{
+ Y.resizeLike(X);
+ // loop over rows
+ for(int i = 0;i<X.rows();i++)
+ {
+ // loop over cols
+ for(int j = 0;j<X.cols();j++)
+ {
+ Y(i,j) = igl::round(X(i,j));
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::round<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::round<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::round<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::round<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+template void igl::round<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::round<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+template void igl::round<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/round.h b/xs/src/igl/round.h
new file mode 100644
index 000000000..cdaac731b
--- /dev/null
+++ b/xs/src/igl/round.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ROUND_H
+#define IGL_ROUND_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Round a scalar value
+ //
+ // Inputs:
+ // x number
+ // Returns x rounded to integer
+ template <typename DerivedX>
+ DerivedX round(const DerivedX r);
+ // Round a given matrix to nearest integers
+ //
+ // Inputs:
+ // X m by n matrix of scalars
+ // Outputs:
+ // Y m by n matrix of rounded integers
+ template < typename DerivedX, typename DerivedY>
+ IGL_INLINE void round(
+ const Eigen::PlainObjectBase<DerivedX>& X,
+ Eigen::PlainObjectBase<DerivedY>& Y);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "round.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/rows_to_matrix.cpp b/xs/src/igl/rows_to_matrix.cpp
new file mode 100644
index 000000000..14c369e40
--- /dev/null
+++ b/xs/src/igl/rows_to_matrix.cpp
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "rows_to_matrix.h"
+
+#include <cassert>
+#include <cstdio>
+
+#include "max_size.h"
+#include "min_size.h"
+
+template <class Row, class Mat>
+IGL_INLINE bool igl::rows_to_matrix(const std::vector<Row> & V,Mat & M)
+{
+ // number of columns
+ int m = V.size();
+ if(m == 0)
+ {
+ fprintf(stderr,"Error: rows_to_matrix() list is empty()\n");
+ return false;
+ }
+ // number of rows
+ int n = igl::min_size(V);
+ if(n != igl::max_size(V))
+ {
+ fprintf(stderr,"Error: rows_to_matrix()"
+ " list elements are not all the same size\n");
+ return false;
+ }
+ assert(n != -1);
+ // Resize output
+ M.resize(m,n);
+
+ // Loop over rows
+ int i = 0;
+ typename std::vector<Row>::const_iterator iter = V.begin();
+ while(iter != V.end())
+ {
+ M.row(i) = V[i];
+ // increment index and iterator
+ i++;
+ iter++;
+ }
+
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/rows_to_matrix.h b/xs/src/igl/rows_to_matrix.h
new file mode 100644
index 000000000..8f62b5a2d
--- /dev/null
+++ b/xs/src/igl/rows_to_matrix.h
@@ -0,0 +1,34 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_ROWS_TO_MATRIX_H
+#define IGL_ROWS_TO_MATRIX_H
+#include "igl_inline.h"
+#include <vector>
+namespace igl
+{
+ // Convert a list (std::vector) of row vectors of the same length to a matrix
+ // Template:
+ // Row row vector type, must implement:
+ // .size()
+ // Mat Matrix type, must implement:
+ // .resize(m,n)
+ // .row(i) = Row
+ // Inputs:
+ // V a m-long list of vectors of size n
+ // Outputs:
+ // M an m by n matrix
+ // Returns true on success, false on errors
+ template <class Row, class Mat>
+ IGL_INLINE bool rows_to_matrix(const std::vector<Row> & V,Mat & M);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "rows_to_matrix.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/sample_edges.cpp b/xs/src/igl/sample_edges.cpp
new file mode 100644
index 000000000..a20df1426
--- /dev/null
+++ b/xs/src/igl/sample_edges.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sample_edges.h"
+
+IGL_INLINE void igl::sample_edges(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & E,
+ const int k,
+ Eigen::MatrixXd & S)
+{
+ using namespace Eigen;
+ // Resize output
+ S.resize(V.rows() + k * E.rows(),V.cols());
+ // Copy V at front of S
+ S.block(0,0,V.rows(),V.cols()) = V;
+
+ // loop over edges
+ for(int i = 0;i<E.rows();i++)
+ {
+ VectorXd tip = V.row(E(i,0));
+ VectorXd tail = V.row(E(i,1));
+ for(int s=0;s<k;s++)
+ {
+ double f = double(s+1)/double(k+1);
+ S.row(V.rows()+k*i+s) = f*tail + (1.0-f)*tip;
+ }
+ }
+}
diff --git a/xs/src/igl/sample_edges.h b/xs/src/igl/sample_edges.h
new file mode 100644
index 000000000..96822736f
--- /dev/null
+++ b/xs/src/igl/sample_edges.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SAMPLE_EDGES_H
+#define IGL_SAMPLE_EDGES_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Compute samples_per_edge extra points along each edge in E defined over
+ // vertices of V.
+ //
+ // Inputs:
+ // V vertices over which edges are defined, # vertices by dim
+ // E edge list, # edges by 2
+ // k number of extra samples to be computed along edge not
+ // including start and end points
+ // Output:
+ // S sampled vertices, size less than # edges * (2+k) by dim always begins
+ // with V so that E is also defined over S
+ IGL_INLINE void sample_edges(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & E,
+ const int k,
+ Eigen::MatrixXd & S);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "sample_edges.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/seam_edges.cpp b/xs/src/igl/seam_edges.cpp
new file mode 100644
index 000000000..8cbca143c
--- /dev/null
+++ b/xs/src/igl/seam_edges.cpp
@@ -0,0 +1,211 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Yotam Gingold <yotam@yotamgingold.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "seam_edges.h"
+#include <unordered_map>
+#include <unordered_set>
+#include <cassert>
+
+// Yotam has verified that this function produces the exact same output as
+// `find_seam_fast.py` for `cow_triangled.obj`.
+template <
+ typename DerivedV,
+ typename DerivedTC,
+ typename DerivedF,
+ typename DerivedFTC,
+ typename Derivedseams,
+ typename Derivedboundaries,
+ typename Derivedfoldovers>
+IGL_INLINE void igl::seam_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedTC>& TC,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedFTC>& FTC,
+ Eigen::PlainObjectBase<Derivedseams>& seams,
+ Eigen::PlainObjectBase<Derivedboundaries>& boundaries,
+ Eigen::PlainObjectBase<Derivedfoldovers>& foldovers)
+{
+ // Assume triangles.
+ assert( F.cols() == 3 );
+ assert( F.cols() == FTC.cols() );
+ assert( F.rows() == FTC.rows() );
+
+ // Assume 2D texture coordinates (foldovers tests).
+ assert( TC.cols() == 2 );
+ typedef Eigen::Matrix< typename DerivedTC::Scalar, 2, 1 > Vector2S;
+ // Computes the orientation of `c` relative to the line between `a` and `b`.
+ // Assumes 2D vector input.
+ // Based on: https://www.cs.cmu.edu/~quake/robust.html
+ const auto& Orientation = [](
+ const Vector2S& a,
+ const Vector2S& b,
+ const Vector2S& c ) -> typename DerivedTC::Scalar
+ {
+ const Vector2S row0 = a - c;
+ const Vector2S row1 = b - c;
+ return row0(0)*row1(1) - row1(0)*row0(1);
+ };
+
+ seams .setZero( 3*F.rows(), 4 );
+ boundaries.setZero( 3*F.rows(), 2 );
+ foldovers .setZero( 3*F.rows(), 4 );
+
+ int num_seams = 0;
+ int num_boundaries = 0;
+ int num_foldovers = 0;
+
+ // A map from a pair of vertex indices to the index (face and endpoints)
+ // into face_position_indices.
+ // The following should be true for every key, value pair:
+ // key == face_position_indices[ value ]
+ // This gives us a "reverse map" so that we can look up other face
+ // attributes based on position edges.
+ // The value are written in the format returned by numpy.where(),
+ // which stores multi-dimensional indices such as array[a0,b0], array[a1,b1]
+ // as ( (a0,a1), (b0,b1) ).
+
+ // We need to make a hash function for our directed edges.
+ // We'll use i*V.rows() + j.
+ typedef std::pair< typename DerivedF::Scalar, typename DerivedF::Scalar >
+ directed_edge;
+ const int numV = V.rows();
+ const int numF = F.rows();
+ const auto& edge_hasher =
+ [numV]( directed_edge const& e ) { return e.first*numV + e.second; };
+ // When we pass a hash function object, we also need to specify the number of
+ // buckets. The Euler characteristic says that the number of undirected edges
+ // is numV + numF -2*genus.
+ std::unordered_map<directed_edge,std::pair<int,int>,decltype(edge_hasher) >
+ directed_position_edge2face_position_index(2*( numV + numF ), edge_hasher);
+ for( int fi = 0; fi < F.rows(); ++fi )
+ {
+ for( int i = 0; i < 3; ++i )
+ {
+ const int j = ( i+1 ) % 3;
+ directed_position_edge2face_position_index[
+ std::make_pair( F(fi,i), F(fi,j) ) ] = std::make_pair( fi, i );
+ }
+ }
+
+ // First find all undirected position edges (collect a canonical orientation
+ // of the directed edges).
+ std::unordered_set< directed_edge, decltype( edge_hasher ) >
+ undirected_position_edges( numV + numF, edge_hasher );
+ for( const auto& el : directed_position_edge2face_position_index )
+ {
+ // The canonical orientation is the one where the smaller of
+ // the two vertex indices is first.
+ undirected_position_edges.insert( std::make_pair(
+ std::min( el.first.first, el.first.second ),
+ std::max( el.first.first, el.first.second ) ) );
+ }
+
+ // Now we will iterate over all position edges.
+ // Seam edges are the edges whose two opposite directed edges have different
+ // texcoord indices (or one doesn't exist at all in the case of a mesh
+ // boundary).
+ for( const auto& vp_edge : undirected_position_edges )
+ {
+ // We should only see canonical edges,
+ // where the first vertex index is smaller.
+ assert( vp_edge.first < vp_edge.second );
+
+ const auto vp_edge_reverse = std::make_pair(vp_edge.second, vp_edge.first);
+ // If it and its opposite exist as directed edges, check if their
+ // texture coordinate indices match.
+ if( directed_position_edge2face_position_index.count( vp_edge ) &&
+ directed_position_edge2face_position_index.count( vp_edge_reverse ) )
+ {
+ const auto forwards =
+ directed_position_edge2face_position_index[ vp_edge ];
+ const auto backwards =
+ directed_position_edge2face_position_index[ vp_edge_reverse ];
+
+ // NOTE: They should never be equal.
+ assert( forwards != backwards );
+
+ // If the texcoord indices match (are similarly flipped),
+ // this edge is not a seam. It could be a foldover.
+ if(
+ std::make_pair(
+ FTC( forwards.first, forwards.second ),
+ FTC( forwards.first, ( forwards.second+1 ) % 3 ) )
+ ==
+ std::make_pair(
+ FTC( backwards.first, ( backwards.second+1 ) % 3 ),
+ FTC( backwards.first, backwards.second ) ))
+ {
+ // Check for foldovers in UV space.
+ // Get the edge (a,b) and the two opposite vertices's texture
+ // coordinates.
+ const Vector2S a = TC.row( FTC( forwards.first, forwards.second ) );
+ const Vector2S b =
+ TC.row( FTC( forwards.first, (forwards.second+1) % 3 ) );
+ const Vector2S c_forwards =
+ TC.row( FTC( forwards .first, (forwards .second+2) % 3 ) );
+ const Vector2S c_backwards =
+ TC.row( FTC( backwards.first, (backwards.second+2) % 3 ) );
+ // If the opposite vertices' texture coordinates fall on the same side
+ // of the edge, we have a UV-space foldover.
+ const auto orientation_forwards = Orientation( a, b, c_forwards );
+ const auto orientation_backwards = Orientation( a, b, c_backwards );
+ if( ( orientation_forwards > 0 && orientation_backwards > 0 ) ||
+ ( orientation_forwards < 0 && orientation_backwards < 0 )
+ ) {
+ foldovers( num_foldovers, 0 ) = forwards.first;
+ foldovers( num_foldovers, 1 ) = forwards.second;
+ foldovers( num_foldovers, 2 ) = backwards.first;
+ foldovers( num_foldovers, 3 ) = backwards.second;
+ num_foldovers += 1;
+ }
+ }
+ // Otherwise, we have a non-matching seam edge.
+ else
+ {
+ seams( num_seams, 0 ) = forwards.first;
+ seams( num_seams, 1 ) = forwards.second;
+ seams( num_seams, 2 ) = backwards.first;
+ seams( num_seams, 3 ) = backwards.second;
+ num_seams += 1;
+ }
+ }
+ // Otherwise, the edge and its opposite aren't both in the directed edges.
+ // One of them should be.
+ else if( directed_position_edge2face_position_index.count( vp_edge ) )
+ {
+ const auto forwards = directed_position_edge2face_position_index[vp_edge];
+ boundaries( num_boundaries, 0 ) = forwards.first;
+ boundaries( num_boundaries, 1 ) = forwards.second;
+ num_boundaries += 1;
+ } else if(
+ directed_position_edge2face_position_index.count( vp_edge_reverse ) )
+ {
+ const auto backwards =
+ directed_position_edge2face_position_index[ vp_edge_reverse ];
+ boundaries( num_boundaries, 0 ) = backwards.first;
+ boundaries( num_boundaries, 1 ) = backwards.second;
+ num_boundaries += 1;
+ } else {
+ // This should never happen! One of these two must have been seen.
+ assert(
+ directed_position_edge2face_position_index.count( vp_edge ) ||
+ directed_position_edge2face_position_index.count( vp_edge_reverse )
+ );
+ }
+ }
+
+ seams .conservativeResize( num_seams, Eigen::NoChange_t() );
+ boundaries.conservativeResize( num_boundaries, Eigen::NoChange_t() );
+ foldovers .conservativeResize( num_foldovers, Eigen::NoChange_t() );
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::seam_edges<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/seam_edges.h b/xs/src/igl/seam_edges.h
new file mode 100644
index 000000000..15c82826c
--- /dev/null
+++ b/xs/src/igl/seam_edges.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Yotam Gingold <yotam@yotamgingold.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SEAM_EDGES_H
+#define IGL_SEAM_EDGES_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Finds all UV-space boundaries of a mesh.
+ //
+ // Inputs:
+ // V #V by dim list of positions of the input mesh.
+ // TC #TC by 2 list of 2D texture coordinates of the input mesh
+ // F #F by 3 list of triange indices into V representing a
+ // manifold-with-boundary triangle mesh
+ // FTC #F by 3 list of indices into TC for each corner
+ // Outputs:
+ // seams Edges where the forwards and backwards directions have different
+ // texture coordinates, as a #seams-by-4 matrix of indices. Each row is
+ // organized as [ forward_face_index, forward_face_vertex_index,
+ // backwards_face_index, backwards_face_vertex_index ] such that one side
+ // of the seam is the edge:
+ // F[ seams( i, 0 ), seams( i, 1 ) ], F[ seams( i, 0 ), (seams( i, 1 ) + 1) % 3 ]
+ // and the other side is the edge:
+ // F[ seams( i, 2 ), seams( i, 3 ) ], F[ seams( i, 2 ), (seams( i, 3 ) + 1) % 3 ]
+ // boundaries Edges with only one incident triangle, as a #boundaries-by-2
+ // matrix of indices. Each row is organized as
+ // [ face_index, face_vertex_index ]
+ // such that the edge is:
+ // F[ boundaries( i, 0 ), boundaries( i, 1 ) ], F[ boundaries( i, 0 ), (boundaries( i, 1 ) + 1) % 3 ]
+ // foldovers Edges where the two incident triangles fold over each other
+ // in UV-space, as a #foldovers-by-4 matrix of indices.
+ // Each row is organized as [ forward_face_index, forward_face_vertex_index,
+ // backwards_face_index, backwards_face_vertex_index ]
+ // such that one side of the foldover is the edge:
+ // F[ foldovers( i, 0 ), foldovers( i, 1 ) ], F[ foldovers( i, 0 ), (foldovers( i, 1 ) + 1) % 3 ]
+ // and the other side is the edge:
+ // F[ foldovers( i, 2 ), foldovers( i, 3 ) ], F[ foldovers( i, 2 ), (foldovers( i, 3 ) + 1) % 3 ]
+ template <
+ typename DerivedV,
+ typename DerivedTC,
+ typename DerivedF,
+ typename DerivedFTC,
+ typename Derivedseams,
+ typename Derivedboundaries,
+ typename Derivedfoldovers>
+ IGL_INLINE void seam_edges(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedTC>& TC,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedFTC>& FTC,
+ Eigen::PlainObjectBase<Derivedseams>& seams,
+ Eigen::PlainObjectBase<Derivedboundaries>& boundaries,
+ Eigen::PlainObjectBase<Derivedfoldovers>& foldovers);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "seam_edges.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/segment_segment_intersect.cpp b/xs/src/igl/segment_segment_intersect.cpp
new file mode 100644
index 000000000..8438c0496
--- /dev/null
+++ b/xs/src/igl/segment_segment_intersect.cpp
@@ -0,0 +1,67 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Francisca Gil Ureta <gilureta@cs.nyu.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "segment_segment_intersect.h"
+
+#include <Eigen/Geometry>
+
+template<typename DerivedSource, typename DerivedDir>
+IGL_INLINE bool igl::segments_intersect(
+ const Eigen::PlainObjectBase <DerivedSource> &p,
+ const Eigen::PlainObjectBase <DerivedDir> &r,
+ const Eigen::PlainObjectBase <DerivedSource> &q,
+ const Eigen::PlainObjectBase <DerivedDir> &s,
+ double &a_t,
+ double &a_u,
+ double eps
+)
+{
+ // http://stackoverflow.com/questions/563198/how-do-you-detect-where-two-line-segments-intersect
+ // Search intersection between two segments
+ // p + t*r : t \in [0,1]
+ // q + u*s : u \in [0,1]
+
+ // p + t * r = q + u * s // x s
+ // t(r x s) = (q - p) x s
+ // t = (q - p) x s / (r x s)
+
+ // (r x s) ~ 0 --> directions are parallel, they will never cross
+ Eigen::RowVector3d rxs = r.cross(s);
+ if (rxs.norm() <= eps)
+ return false;
+
+ int sign;
+
+ double u;
+ // u = (q − p) × r / (r × s)
+ Eigen::RowVector3d u1 = (q - p).cross(r);
+ sign = ((u1.dot(rxs)) > 0) ? 1 : -1;
+ u = u1.norm() / rxs.norm();
+ u = u * sign;
+
+ if ((u - 1.) > eps || u < -eps)
+ return false;
+
+ double t;
+ // t = (q - p) x s / (r x s)
+ Eigen::RowVector3d t1 = (q - p).cross(s);
+ sign = ((t1.dot(rxs)) > 0) ? 1 : -1;
+ t = t1.norm() / rxs.norm();
+ t = t * sign;
+
+ if (t < -eps || fabs(t) < eps)
+ return false;
+
+ a_t = t;
+ a_u = u;
+
+ return true;
+};
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::segments_intersect<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, double&, double&, double);
+#endif
diff --git a/xs/src/igl/segment_segment_intersect.h b/xs/src/igl/segment_segment_intersect.h
new file mode 100644
index 000000000..714629215
--- /dev/null
+++ b/xs/src/igl/segment_segment_intersect.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Francisca Gil Ureta <gilureta@cs.nyu.edu>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_SEGMENT_SEGMENT_INTERSECT_H
+#define IGL_SEGMENT_SEGMENT_INTERSECT_H
+
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+
+ // Determine whether two line segments A,B intersect
+ // A: p + t*r : t \in [0,1]
+ // B: q + u*s : u \in [0,1]
+ // Inputs:
+ // p 3-vector origin of segment A
+ // r 3-vector direction of segment A
+ // q 3-vector origin of segment B
+ // s 3-vector direction of segment B
+ // eps precision
+ // Outputs:
+ // t scalar point of intersection along segment A, t \in [0,1]
+ // u scalar point of intersection along segment B, u \in [0,1]
+ // Returns true if intersection
+ template<typename DerivedSource, typename DerivedDir>
+ IGL_INLINE bool segments_intersect(
+ const Eigen::PlainObjectBase <DerivedSource> &p,
+ const Eigen::PlainObjectBase <DerivedDir> &r,
+ const Eigen::PlainObjectBase <DerivedSource> &q,
+ const Eigen::PlainObjectBase <DerivedDir> &s,
+ double &t,
+ double &u,
+ double eps = 1e-6
+ );
+
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "segment_segment_intersect.cpp"
+#endif
+#endif //IGL_SEGMENT_SEGMENT_INTERSECT_H
diff --git a/xs/src/igl/serialize.h b/xs/src/igl/serialize.h
new file mode 100644
index 000000000..54967293b
--- /dev/null
+++ b/xs/src/igl/serialize.h
@@ -0,0 +1,1258 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SERIALIZE_H
+#define IGL_SERIALIZE_H
+
+// -----------------------------------------------------------------------------
+// Functions to save and load a serialization of fundamental c++ data types to
+// and from a binary file. STL containers, Eigen matrix types and nested data
+// structures are also supported. To serialize a user defined class implement
+// the interface Serializable or SerializableBase.
+//
+// See also: xml/serialize_xml.h
+// -----------------------------------------------------------------------------
+// TODOs:
+// * arbitrary pointer graph structures
+// -----------------------------------------------------------------------------
+
+// Known issues: This is not written in libigl-style so it isn't (easily)
+// "dualized" into the static library.
+//
+
+#include <type_traits>
+#include <iostream>
+#include <fstream>
+#include <cstdint>
+#include <numeric>
+#include <vector>
+#include <set>
+#include <map>
+#include <memory>
+#include <cstdint>
+#include <list>
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+#include "igl_inline.h"
+
+// non-intrusive serialization helper macros
+
+#define SERIALIZE_TYPE(Type,Params) \
+namespace igl { namespace serialization { \
+ void _serialization(bool s,Type& obj,std::vector<char>& buffer) {Params} \
+ template<> inline void serialize(const Type& obj,std::vector<char>& buffer) { \
+ _serialization(true,const_cast<Type&>(obj),buffer); \
+ } \
+ template<> inline void deserialize(Type& obj,const std::vector<char>& buffer) { \
+ _serialization(false,obj,const_cast<std::vector<char>&>(buffer)); \
+ } \
+}}
+
+#define SERIALIZE_TYPE_SOURCE(Type,Params) \
+namespace igl { namespace serialization { \
+ void _serialization(bool s,Type& obj,std::vector<char>& buffer) {Params} \
+ void _serialize(const Type& obj,std::vector<char>& buffer) { \
+ _serialization(true,const_cast<Type&>(obj),buffer); \
+ } \
+ void _deserialize(Type& obj,const std::vector<char>& buffer) { \
+ _serialization(false,obj,const_cast<std::vector<char>&>(buffer)); \
+ } \
+}}
+
+#define SERIALIZE_MEMBER(Object) igl::serializer(s,obj.Object,std::string(#Object),buffer);
+#define SERIALIZE_MEMBER_NAME(Object,Name) igl::serializer(s,obj.Object,std::string(Name),buffer);
+
+
+namespace igl
+{
+ struct IndexedPointerBase;
+
+ // Serializes the given object either to a file or to a provided buffer
+ // Templates:
+ // T type of the object to serialize
+ // Inputs:
+ // obj object to serialize
+ // objectName unique object name,used for the identification
+ // overwrite set to true to overwrite an existing file
+ // filename name of the file containing the serialization
+ // Outputs:
+ // buffer binary serialization
+ //
+ template <typename T>
+ inline bool serialize(const T& obj,const std::string& filename);
+ template <typename T>
+ inline bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite = false);
+ template <typename T>
+ inline bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer);
+ template <typename T>
+ inline bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer);
+
+ // Deserializes the given data from a file or buffer back to the provided object
+ //
+ // Templates:
+ // T type of the object to serialize
+ // Inputs:
+ // buffer binary serialization
+ // objectName unique object name, used for the identification
+ // filename name of the file containing the serialization
+ // Outputs:
+ // obj object to load back serialization to
+ //
+ template <typename T>
+ inline bool deserialize(T& obj,const std::string& filename);
+ template <typename T>
+ inline bool deserialize(T& obj,const std::string& objectName,const std::string& filename);
+ template <typename T>
+ inline bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer);
+
+ // Wrapper to expose both, the de- and serialization as one function
+ //
+ template <typename T>
+ inline bool serializer(bool serialize,T& obj,const std::string& filename);
+ template <typename T>
+ inline bool serializer(bool serialize,T& obj,const std::string& objectName,const std::string& filename,bool overwrite = false);
+ template <typename T>
+ inline bool serializer(bool serialize,T& obj,const std::string& objectName,std::vector<char>& buffer);
+
+ // User defined types have to either overload the function igl::serialization::serialize()
+ // and igl::serialization::deserialize() for their type (non-intrusive serialization):
+ //
+ // namespace igl { namespace serialization
+ // {
+ // template<>
+ // inline void serialize(const UserType& obj,std::vector<char>& buffer) {
+ // ::igl::serialize(obj.var,"var",buffer);
+ // }
+ //
+ // template<>
+ // inline void deserialize(UserType& obj,const std::vector<char>& buffer) {
+ // ::igl::deserialize(obj.var,"var",buffer);
+ // }
+ // }}
+ //
+ // or use this macro for convenience:
+ //
+ // SERIALIZE_TYPE(UserType,
+ // SERIALIZE_MEMBER(var)
+ // )
+ //
+ // or to derive from the class Serializable and add their the members
+ // in InitSerialization like the following:
+ //
+ // class UserType : public igl::Serializable {
+ //
+ // int var;
+ //
+ // void InitSerialization() {
+ // this->Add(var,"var");
+ // }
+ // };
+
+ // Base interface for user defined types
+ struct SerializableBase
+ {
+ virtual void Serialize(std::vector<char>& buffer) const = 0;
+ virtual void Deserialize(const std::vector<char>& buffer) = 0;
+ };
+
+ // Convenient interface for user defined types
+ class Serializable: public SerializableBase
+ {
+ private:
+
+ template <typename T>
+ struct SerializationObject : public SerializableBase
+ {
+ bool Binary;
+ std::string Name;
+ std::unique_ptr<T> Object;
+
+ void Serialize(std::vector<char>& buffer) const override {
+ igl::serialize(*Object,Name,buffer);
+ }
+
+ void Deserialize(const std::vector<char>& buffer) override {
+ igl::deserialize(*Object,Name,buffer);
+ }
+ };
+
+ mutable bool initialized;
+ mutable std::vector<SerializableBase*> objects;
+
+ public:
+
+ // You **MUST** Override this function to add your member variables which
+ // should be serialized
+ //
+ // http://stackoverflow.com/a/6634382/148668
+ virtual void InitSerialization() = 0;
+
+ // Following functions can be overridden to handle the specific events.
+ // Return false to prevent the de-/serialization of an object.
+ inline virtual bool PreSerialization() const;
+ inline virtual void PostSerialization() const;
+ inline virtual bool PreDeserialization();
+ inline virtual void PostDeserialization();
+
+ // Default implementation of SerializableBase interface
+ inline void Serialize(std::vector<char>& buffer) const override final;
+ inline void Deserialize(const std::vector<char>& buffer) override final;
+
+ // Default constructor, destructor, assignment and copy constructor
+ inline Serializable();
+ inline Serializable(const Serializable& obj);
+ inline ~Serializable();
+ inline Serializable& operator=(const Serializable& obj);
+
+ // Use this function to add your variables which should be serialized
+ template <typename T>
+ inline void Add(T& obj,std::string name,bool binary = false);
+ };
+
+ // structure for pointer handling
+ struct IndexedPointerBase
+ {
+ enum { BEGIN,END } Type;
+ size_t Index;
+ };
+ template<typename T>
+ struct IndexedPointer: public IndexedPointerBase
+ {
+ const T* Object;
+ };
+
+ // internal functions
+ namespace serialization
+ {
+ // compile time type checks
+ template <typename T>
+ struct is_stl_container { static const bool value = false; };
+ template <typename T1,typename T2>
+ struct is_stl_container<std::pair<T1,T2> > { static const bool value = true; };
+ template <typename T1,typename T2>
+ struct is_stl_container<std::vector<T1,T2> > { static const bool value = true; };
+ template <typename T>
+ struct is_stl_container<std::set<T> > { static const bool value = true; };
+ template <typename T1,typename T2>
+ struct is_stl_container<std::map<T1,T2> > { static const bool value = true; };
+ template <typename T>
+ struct is_stl_container<std::list<T> > { static const bool value = true; };
+
+ template <typename T>
+ struct is_eigen_type { static const bool value = false; };
+ template <typename T,int R,int C,int P,int MR,int MC>
+ struct is_eigen_type<Eigen::Matrix<T,R,C,P,MR,MC> > { static const bool value = true; };
+ template <typename T,int P,typename I>
+ struct is_eigen_type<Eigen::SparseMatrix<T,P,I> > { static const bool value = true; };
+
+ template <typename T>
+ struct is_smart_ptr { static const bool value = false; };
+ template <typename T>
+ struct is_smart_ptr<std::shared_ptr<T> > { static const bool value = true; };
+ template <typename T>
+ struct is_smart_ptr<std::unique_ptr<T> > { static const bool value = true; };
+ template <typename T>
+ struct is_smart_ptr<std::weak_ptr<T> > { static const bool value = true; };
+
+ template <typename T>
+ struct is_serializable {
+ static const bool value = std::is_fundamental<T>::value || std::is_same<std::string,T>::value || std::is_enum<T>::value || std::is_base_of<SerializableBase,T>::value
+ || is_stl_container<T>::value || is_eigen_type<T>::value || std::is_pointer<T>::value || serialization::is_smart_ptr<T>::value;
+ };
+
+ // non serializable types
+ template <typename T>
+ inline typename std::enable_if<!is_serializable<T>::value,size_t>::type getByteSize(const T& obj);
+ template <typename T>
+ inline typename std::enable_if<!is_serializable<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T>
+ inline typename std::enable_if<!is_serializable<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+ // fundamental types
+ template <typename T>
+ inline typename std::enable_if<std::is_fundamental<T>::value,size_t>::type getByteSize(const T& obj);
+ template <typename T>
+ inline typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T>
+ inline typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+ // std::string
+ inline size_t getByteSize(const std::string& obj);
+ inline void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ inline void deserialize(std::string& obj,std::vector<char>::const_iterator& iter);
+
+ // enum types
+ template <typename T>
+ inline typename std::enable_if<std::is_enum<T>::value,size_t>::type getByteSize(const T& obj);
+ template <typename T>
+ inline typename std::enable_if<std::is_enum<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T>
+ inline typename std::enable_if<std::is_enum<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+ // SerializableBase
+ template <typename T>
+ inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value,size_t>::type getByteSize(const T& obj);
+ template <typename T>
+ inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T>
+ inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+ // stl containers
+ // std::pair
+ template <typename T1,typename T2>
+ inline size_t getByteSize(const std::pair<T1,T2>& obj);
+ template <typename T1,typename T2>
+ inline void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T1,typename T2>
+ inline void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+
+ // std::vector
+ template <typename T1,typename T2>
+ inline size_t getByteSize(const std::vector<T1,T2>& obj);
+ template <typename T1,typename T2>
+ inline void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T1,typename T2>
+ inline void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+ template <typename T2>
+ inline void deserialize(std::vector<bool,T2>& obj,std::vector<char>::const_iterator& iter);
+
+ // std::set
+ template <typename T>
+ inline size_t getByteSize(const std::set<T>& obj);
+ template <typename T>
+ inline void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T>
+ inline void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter);
+
+ // std::map
+ template <typename T1,typename T2>
+ inline size_t getByteSize(const std::map<T1,T2>& obj);
+ template <typename T1,typename T2>
+ inline void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T1,typename T2>
+ inline void deserialize(std::map<T1,T2>& obj,std::vector<char>::const_iterator& iter);
+
+ // std::list
+ template <typename T>
+ inline size_t getByteSize(const std::list<T>& obj);
+ template <typename T>
+ inline void serialize(const std::list<T>& obj, std::vector<char>& buffer, std::vector<char>::iterator& iter);
+ template <typename T>
+ inline void deserialize(std::list<T>& obj, std::vector<char>::const_iterator& iter);
+
+ // Eigen types
+ template<typename T,int R,int C,int P,int MR,int MC>
+ inline size_t getByteSize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj);
+ template<typename T,int R,int C,int P,int MR,int MC>
+ inline void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template<typename T,int R,int C,int P,int MR,int MC>
+ inline void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter);
+
+ template<typename T,int P,typename I>
+ inline size_t getByteSize(const Eigen::SparseMatrix<T,P,I>& obj);
+ template<typename T,int P,typename I>
+ inline void serialize(const Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template<typename T,int P,typename I>
+ inline void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter);
+
+ template<typename T,int P>
+ inline size_t getByteSize(const Eigen::Quaternion<T,P>& obj);
+ template<typename T,int P>
+ inline void serialize(const Eigen::Quaternion<T,P>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template<typename T,int P>
+ inline void deserialize(Eigen::Quaternion<T,P>& obj,std::vector<char>::const_iterator& iter);
+
+ // raw pointers
+ template <typename T>
+ inline typename std::enable_if<std::is_pointer<T>::value,size_t>::type getByteSize(const T& obj);
+ template <typename T>
+ inline typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T>
+ inline typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter);
+
+ // std::shared_ptr and std::unique_ptr
+ template <typename T>
+ inline typename std::enable_if<serialization::is_smart_ptr<T>::value,size_t>::type getByteSize(const T& obj);
+ template <typename T>
+ inline typename std::enable_if<serialization::is_smart_ptr<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <template<typename> class T0, typename T1>
+ inline typename std::enable_if<serialization::is_smart_ptr<T0<T1> >::value>::type deserialize(T0<T1>& obj,std::vector<char>::const_iterator& iter);
+
+ // std::weak_ptr
+ template <typename T>
+ inline size_t getByteSize(const std::weak_ptr<T>& obj);
+ template <typename T>
+ inline void serialize(const std::weak_ptr<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter);
+ template <typename T>
+ inline void deserialize(std::weak_ptr<T>& obj,std::vector<char>::const_iterator& iter);
+
+ // functions to overload for non-intrusive serialization
+ template <typename T>
+ inline void serialize(const T& obj,std::vector<char>& buffer);
+ template <typename T>
+ inline void deserialize(T& obj,const std::vector<char>& buffer);
+
+ // helper functions
+ template <typename T>
+ inline void updateMemoryMap(T& obj,size_t size);
+ }
+}
+
+// Always include inlines for these functions
+
+// IMPLEMENTATION
+
+namespace igl
+{
+ template <typename T>
+ inline bool serialize(const T& obj,const std::string& filename)
+ {
+ return serialize(obj,"obj",filename,true);
+ }
+
+ template <typename T>
+ inline bool serialize(const T& obj,const std::string& objectName,const std::string& filename,bool overwrite)
+ {
+ bool success = false;
+
+ std::vector<char> buffer;
+
+ std::ios_base::openmode mode = std::ios::out | std::ios::binary;
+
+ if(overwrite)
+ mode |= std::ios::trunc;
+ else
+ mode |= std::ios::app;
+
+ std::ofstream file(filename.c_str(),mode);
+
+ if(file.is_open())
+ {
+ serialize(obj,objectName,buffer);
+
+ file.write(&buffer[0],buffer.size());
+
+ file.close();
+
+ success = true;
+ }
+ else
+ {
+ std::cerr << "serialization: file " << filename << " not found!" << std::endl;
+ }
+
+ return success;
+ }
+
+ template <typename T>
+ inline bool serialize(const T& obj,const std::string& objectName,std::vector<char>& buffer)
+ {
+ // serialize object data
+ size_t size = serialization::getByteSize(obj);
+ std::vector<char> tmp(size);
+ auto it = tmp.begin();
+ serialization::serialize(obj,tmp,it);
+
+ std::string objectType(typeid(obj).name());
+ size_t newObjectSize = tmp.size();
+ size_t newHeaderSize = serialization::getByteSize(objectName) + serialization::getByteSize(objectType) + sizeof(size_t);
+ size_t curSize = buffer.size();
+ size_t newSize = curSize + newHeaderSize + newObjectSize;
+
+ buffer.resize(newSize);
+
+ std::vector<char>::iterator iter = buffer.begin()+curSize;
+
+ // serialize object header (name/type/size)
+ serialization::serialize(objectName,buffer,iter);
+ serialization::serialize(objectType,buffer,iter);
+ serialization::serialize(newObjectSize,buffer,iter);
+
+ // copy serialized data to buffer
+ iter = std::copy(tmp.begin(),tmp.end(),iter);
+
+ return true;
+ }
+
+ template <typename T>
+ inline bool deserialize(T& obj,const std::string& filename)
+ {
+ return deserialize(obj,"obj",filename);
+ }
+
+ template <typename T>
+ inline bool deserialize(T& obj,const std::string& objectName,const std::string& filename)
+ {
+ bool success = false;
+
+ std::ifstream file(filename.c_str(),std::ios::binary);
+
+ if(file.is_open())
+ {
+ file.seekg(0,std::ios::end);
+ std::streamoff size = file.tellg();
+ file.seekg(0,std::ios::beg);
+
+ std::vector<char> buffer(size);
+ file.read(&buffer[0],size);
+
+ deserialize(obj,objectName,buffer);
+ file.close();
+
+ success = true;
+ }
+ else
+ {
+ std::cerr << "serialization: file " << filename << " not found!" << std::endl;
+ }
+
+ return success;
+ }
+
+ template <typename T>
+ inline bool deserialize(T& obj,const std::string& objectName,const std::vector<char>& buffer)
+ {
+ bool success = false;
+
+ // find suitable object header
+ auto objectIter = buffer.cend();
+ auto iter = buffer.cbegin();
+ while(iter != buffer.end())
+ {
+ std::string name;
+ std::string type;
+ size_t size;
+ serialization::deserialize(name,iter);
+ serialization::deserialize(type,iter);
+ serialization::deserialize(size,iter);
+
+ if(name == objectName && type == typeid(obj).name())
+ {
+ objectIter = iter;
+ //break; // find first suitable object header
+ }
+
+ iter+=size;
+ }
+
+ if(objectIter != buffer.end())
+ {
+ serialization::deserialize(obj,objectIter);
+ success = true;
+ }
+ else
+ {
+ obj = T();
+ }
+
+ return success;
+ }
+
+ // Wrapper function which combines both, de- and serialization
+ template <typename T>
+ inline bool serializer(bool s,T& obj,const std::string& filename)
+ {
+ return s ? serialize(obj,filename) : deserialize(obj,filename);
+ }
+
+ template <typename T>
+ inline bool serializer(bool s,T& obj,const std::string& objectName,const std::string& filename,bool overwrite)
+ {
+ return s ? serialize(obj,objectName,filename,overwrite) : deserialize(obj,objectName,filename);
+ }
+
+ template <typename T>
+ inline bool serializer(bool s,T& obj,const std::string& objectName,std::vector<char>& buffer)
+ {
+ return s ? serialize(obj,objectName,buffer) : deserialize(obj,objectName,buffer);
+ }
+
+ inline bool Serializable::PreSerialization() const
+ {
+ return true;
+ }
+
+ inline void Serializable::PostSerialization() const
+ {
+ }
+
+ inline bool Serializable::PreDeserialization()
+ {
+ return true;
+ }
+
+ inline void Serializable::PostDeserialization()
+ {
+ }
+
+ inline void Serializable::Serialize(std::vector<char>& buffer) const
+ {
+ if(this->PreSerialization())
+ {
+ if(initialized == false)
+ {
+ objects.clear();
+ (const_cast<Serializable*>(this))->InitSerialization();
+ initialized = true;
+ }
+
+ for(const auto& v : objects)
+ {
+ v->Serialize(buffer);
+ }
+
+ this->PostSerialization();
+ }
+ }
+
+ inline void Serializable::Deserialize(const std::vector<char>& buffer)
+ {
+ if(this->PreDeserialization())
+ {
+ if(initialized == false)
+ {
+ objects.clear();
+ (const_cast<Serializable*>(this))->InitSerialization();
+ initialized = true;
+ }
+
+ for(auto& v : objects)
+ {
+ v->Deserialize(buffer);
+ }
+
+ this->PostDeserialization();
+ }
+ }
+
+ inline Serializable::Serializable()
+ {
+ initialized = false;
+ }
+
+ inline Serializable::Serializable(const Serializable& obj)
+ {
+ initialized = false;
+ objects.clear();
+ }
+
+ inline Serializable::~Serializable()
+ {
+ initialized = false;
+ objects.clear();
+ }
+
+ inline Serializable& Serializable::operator=(const Serializable& obj)
+ {
+ if(this != &obj)
+ {
+ if(initialized)
+ {
+ initialized = false;
+ objects.clear();
+ }
+ }
+ return *this;
+ }
+
+ template <typename T>
+ inline void Serializable::Add(T& obj,const std::string name,bool binary)
+ {
+ auto object = new SerializationObject<T>();
+ object->Binary = binary;
+ object->Name = name;
+ object->Object = std::unique_ptr<T>(&obj);
+
+ objects.push_back(object);
+ }
+
+ namespace serialization
+ {
+ template <typename T>
+ inline typename std::enable_if<!is_serializable<T>::value,size_t>::type getByteSize(const T& obj)
+ {
+ return sizeof(std::vector<char>::size_type);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<!is_serializable<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ // data
+ std::vector<char> tmp;
+ serialize<>(obj,tmp);
+
+ // size
+ size_t size = buffer.size();
+ serialization::serialize(tmp.size(),buffer,iter);
+ size_t cur = iter - buffer.begin();
+
+ buffer.resize(size+tmp.size());
+ iter = buffer.begin()+cur;
+ iter = std::copy(tmp.begin(),tmp.end(),iter);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<!is_serializable<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+ {
+ std::vector<char>::size_type size;
+ serialization::deserialize<>(size,iter);
+
+ std::vector<char> tmp;
+ tmp.resize(size);
+ std::copy(iter,iter+size,tmp.begin());
+
+ deserialize<>(obj,tmp);
+ iter += size;
+ }
+
+ // fundamental types
+
+ template <typename T>
+ inline typename std::enable_if<std::is_fundamental<T>::value,size_t>::type getByteSize(const T& obj)
+ {
+ return sizeof(T);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ //serialization::updateMemoryMap(obj,sizeof(T));
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&obj);
+ iter = std::copy(ptr,ptr+sizeof(T),iter);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+ {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(&obj);
+ std::copy(iter,iter+sizeof(T),ptr);
+ iter += sizeof(T);
+ }
+
+ // std::string
+
+ inline size_t getByteSize(const std::string& obj)
+ {
+ return getByteSize(obj.length())+obj.length()*sizeof(uint8_t);
+ }
+
+ inline void serialize(const std::string& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.length(),buffer,iter);
+ for(const auto& cur : obj)
+ {
+ serialization::serialize(cur,buffer,iter);
+ }
+ }
+
+ inline void deserialize(std::string& obj,std::vector<char>::const_iterator& iter)
+ {
+ size_t size;
+ serialization::deserialize(size,iter);
+
+ std::string str(size,'\0');
+ for(size_t i=0; i<size; ++i)
+ {
+ serialization::deserialize(str.at(i),iter);
+ }
+
+ obj = str;
+ }
+
+ // enum types
+
+ template <typename T>
+ inline typename std::enable_if<std::is_enum<T>::value,size_t>::type getByteSize(const T& obj)
+ {
+ return sizeof(T);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_enum<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ const uint8_t* ptr = reinterpret_cast<const uint8_t*>(&obj);
+ iter = std::copy(ptr,ptr+sizeof(T),iter);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_enum<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+ {
+ uint8_t* ptr = reinterpret_cast<uint8_t*>(&obj);
+ std::copy(iter,iter+sizeof(T),ptr);
+ iter += sizeof(T);
+ }
+
+ // SerializableBase
+
+ template <typename T>
+ inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value,size_t>::type getByteSize(const T& obj)
+ {
+ return sizeof(std::vector<char>::size_type);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ // data
+ std::vector<char> tmp;
+ obj.Serialize(tmp);
+
+ // size
+ size_t size = buffer.size();
+ serialization::serialize(tmp.size(),buffer,iter);
+ size_t cur = iter - buffer.begin();
+
+ buffer.resize(size+tmp.size());
+ iter = buffer.begin()+cur;
+ iter = std::copy(tmp.begin(),tmp.end(),iter);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_base_of<SerializableBase,T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+ {
+ std::vector<char>::size_type size;
+ serialization::deserialize(size,iter);
+
+ std::vector<char> tmp;
+ tmp.resize(size);
+ std::copy(iter,iter+size,tmp.begin());
+
+ obj.Deserialize(tmp);
+ iter += size;
+ }
+
+ // STL containers
+
+ // std::pair
+
+ template <typename T1,typename T2>
+ inline size_t getByteSize(const std::pair<T1,T2>& obj)
+ {
+ return getByteSize(obj.first)+getByteSize(obj.second);
+ }
+
+ template <typename T1,typename T2>
+ inline void serialize(const std::pair<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.first,buffer,iter);
+ serialization::serialize(obj.second,buffer,iter);
+ }
+
+ template <typename T1,typename T2>
+ inline void deserialize(std::pair<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+ {
+ serialization::deserialize(obj.first,iter);
+ serialization::deserialize(obj.second,iter);
+ }
+
+ // std::vector
+
+ template <typename T1,typename T2>
+ inline size_t getByteSize(const std::vector<T1,T2>& obj)
+ {
+ return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const T1& cur) { return acc+getByteSize(cur); });
+ }
+
+ template <typename T1,typename T2>
+ inline void serialize(const std::vector<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ size_t size = obj.size();
+ serialization::serialize(size,buffer,iter);
+ for(const T1& cur : obj)
+ {
+ serialization::serialize(cur,buffer,iter);
+ }
+ }
+
+ template <typename T1,typename T2>
+ inline void deserialize(std::vector<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+ {
+ size_t size;
+ serialization::deserialize(size,iter);
+
+ obj.resize(size);
+ for(T1& v : obj)
+ {
+ serialization::deserialize(v,iter);
+ }
+ }
+
+ template <typename T2>
+ inline void deserialize(std::vector<bool,T2>& obj,std::vector<char>::const_iterator& iter)
+ {
+ size_t size;
+ serialization::deserialize(size,iter);
+
+ obj.resize(size);
+ for(int i=0;i<obj.size();i++)
+ {
+ bool val;
+ serialization::deserialize(val,iter);
+ obj[i] = val;
+ }
+ }
+
+ //std::set
+
+ template <typename T>
+ inline size_t getByteSize(const std::set<T>& obj)
+ {
+ return std::accumulate(obj.begin(),obj.end(),getByteSize(obj.size()),[](const size_t& acc,const T& cur) { return acc+getByteSize(cur); });
+ }
+
+ template <typename T>
+ inline void serialize(const std::set<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.size(),buffer,iter);
+ for(const T& cur : obj)
+ {
+ serialization::serialize(cur,buffer,iter);
+ }
+ }
+
+ template <typename T>
+ inline void deserialize(std::set<T>& obj,std::vector<char>::const_iterator& iter)
+ {
+ size_t size;
+ serialization::deserialize(size,iter);
+
+ obj.clear();
+ for(size_t i=0; i<size; ++i)
+ {
+ T val;
+ serialization::deserialize(val,iter);
+ obj.insert(val);
+ }
+ }
+
+ // std::map
+
+ template <typename T1,typename T2>
+ inline size_t getByteSize(const std::map<T1,T2>& obj)
+ {
+ return std::accumulate(obj.begin(),obj.end(),sizeof(size_t),[](const size_t& acc,const std::pair<T1,T2>& cur) { return acc+getByteSize(cur); });
+ }
+
+ template <typename T1,typename T2>
+ inline void serialize(const std::map<T1,T2>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.size(),buffer,iter);
+ for(const auto& cur : obj)
+ {
+ serialization::serialize(cur,buffer,iter);
+ }
+ }
+
+ template <typename T1,typename T2>
+ inline void deserialize(std::map<T1,T2>& obj,std::vector<char>::const_iterator& iter)
+ {
+ size_t size;
+ serialization::deserialize(size,iter);
+
+ obj.clear();
+ for(size_t i=0; i<size; ++i)
+ {
+ std::pair<T1,T2> pair;
+ serialization::deserialize(pair,iter);
+ obj.insert(pair);
+ }
+ }
+
+ //std::list
+
+ template <typename T>
+ inline size_t getByteSize(const std::list<T>& obj)
+ {
+ return std::accumulate(obj.begin(), obj.end(), getByteSize(obj.size()), [](const size_t& acc, const T& cur) { return acc + getByteSize(cur); });
+ }
+
+ template <typename T>
+ inline void serialize(const std::list<T>& obj, std::vector<char>& buffer, std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.size(), buffer, iter);
+ for (const T& cur : obj)
+ {
+ serialization::serialize(cur, buffer, iter);
+ }
+ }
+
+ template <typename T>
+ inline void deserialize(std::list<T>& obj, std::vector<char>::const_iterator& iter)
+ {
+ size_t size;
+ serialization::deserialize(size, iter);
+
+ obj.clear();
+ for (size_t i = 0; i < size; ++i)
+ {
+ T val;
+ serialization::deserialize(val, iter);
+ obj.emplace_back(val);
+ }
+ }
+
+
+ // Eigen types
+ template<typename T,int R,int C,int P,int MR,int MC>
+ inline size_t getByteSize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj)
+ {
+ // space for numbers of rows,cols and data
+ return 2*sizeof(typename Eigen::Matrix<T,R,C,P,MR,MC>::Index)+sizeof(T)*obj.rows()*obj.cols();
+ }
+
+ template<typename T,int R,int C,int P,int MR,int MC>
+ inline void serialize(const Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.rows(),buffer,iter);
+ serialization::serialize(obj.cols(),buffer,iter);
+ size_t size = sizeof(T)*obj.rows()*obj.cols();
+ auto ptr = reinterpret_cast<const uint8_t*>(obj.data());
+ iter = std::copy(ptr,ptr+size,iter);
+ }
+
+ template<typename T,int R,int C,int P,int MR,int MC>
+ inline void deserialize(Eigen::Matrix<T,R,C,P,MR,MC>& obj,std::vector<char>::const_iterator& iter)
+ {
+ typename Eigen::Matrix<T,R,C,P,MR,MC>::Index rows,cols;
+ serialization::deserialize(rows,iter);
+ serialization::deserialize(cols,iter);
+ size_t size = sizeof(T)*rows*cols;
+ obj.resize(rows,cols);
+ auto ptr = reinterpret_cast<uint8_t*>(obj.data());
+ std::copy(iter,iter+size,ptr);
+ iter+=size;
+ }
+
+ template<typename T,int P,typename I>
+ inline size_t getByteSize(const Eigen::SparseMatrix<T,P,I>& obj)
+ {
+ // space for numbers of rows,cols,nonZeros and tripplets with data (rowIdx,colIdx,value)
+ size_t size = sizeof(typename Eigen::SparseMatrix<T,P,I>::Index);
+ return 3*size+(sizeof(T)+2*size)*obj.nonZeros();
+ }
+
+ template<typename T,int P,typename I>
+ inline void serialize(const Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.rows(),buffer,iter);
+ serialization::serialize(obj.cols(),buffer,iter);
+ serialization::serialize(obj.nonZeros(),buffer,iter);
+
+ for(int k=0;k<obj.outerSize();++k)
+ {
+ for(typename Eigen::SparseMatrix<T,P,I>::InnerIterator it(obj,k);it;++it)
+ {
+ serialization::serialize(it.row(),buffer,iter);
+ serialization::serialize(it.col(),buffer,iter);
+ serialization::serialize(it.value(),buffer,iter);
+ }
+ }
+ }
+
+ template<typename T,int P,typename I>
+ inline void deserialize(Eigen::SparseMatrix<T,P,I>& obj,std::vector<char>::const_iterator& iter)
+ {
+ typename Eigen::SparseMatrix<T,P,I>::Index rows,cols,nonZeros;
+ serialization::deserialize(rows,iter);
+ serialization::deserialize(cols,iter);
+ serialization::deserialize(nonZeros,iter);
+
+ obj.resize(rows,cols);
+ obj.setZero();
+
+ std::vector<Eigen::Triplet<T,I> > triplets;
+ for(int i=0;i<nonZeros;i++)
+ {
+ typename Eigen::SparseMatrix<T,P,I>::Index rowId,colId;
+ serialization::deserialize(rowId,iter);
+ serialization::deserialize(colId,iter);
+ T value;
+ serialization::deserialize(value,iter);
+ triplets.push_back(Eigen::Triplet<T,I>(rowId,colId,value));
+ }
+ obj.setFromTriplets(triplets.begin(),triplets.end());
+ }
+
+ template<typename T,int P>
+ inline size_t getByteSize(const Eigen::Quaternion<T,P>& obj)
+ {
+ return sizeof(T)*4;
+ }
+
+ template<typename T,int P>
+ inline void serialize(const Eigen::Quaternion<T,P>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj.w(),buffer,iter);
+ serialization::serialize(obj.x(),buffer,iter);
+ serialization::serialize(obj.y(),buffer,iter);
+ serialization::serialize(obj.z(),buffer,iter);
+ }
+
+ template<typename T,int P>
+ inline void deserialize(Eigen::Quaternion<T,P>& obj,std::vector<char>::const_iterator& iter)
+ {
+ serialization::deserialize(obj.w(),iter);
+ serialization::deserialize(obj.x(),iter);
+ serialization::deserialize(obj.y(),iter);
+ serialization::deserialize(obj.z(),iter);
+ }
+
+ // pointers
+
+ template <typename T>
+ inline typename std::enable_if<std::is_pointer<T>::value,size_t>::type getByteSize(const T& obj)
+ {
+ size_t size = sizeof(bool);
+
+ if(obj)
+ size += getByteSize(*obj);
+
+ return size;
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialization::serialize(obj == nullptr,buffer,iter);
+
+ if(obj)
+ serialization::serialize(*obj,buffer,iter);
+ }
+
+ template <typename T>
+ inline typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,std::vector<char>::const_iterator& iter)
+ {
+ bool isNullPtr;
+ serialization::deserialize(isNullPtr,iter);
+
+ if(isNullPtr)
+ {
+ if(obj)
+ {
+ std::cout << "serialization: possible memory leak in serialization for '" << typeid(obj).name() << "'" << std::endl;
+ obj = nullptr;
+ }
+ }
+ else
+ {
+ if(obj)
+ {
+ std::cout << "serialization: possible memory corruption in deserialization for '" << typeid(obj).name() << "'" << std::endl;
+ }
+ else
+ {
+ obj = new typename std::remove_pointer<T>::type();
+ }
+ serialization::deserialize(*obj,iter);
+ }
+ }
+
+ // std::shared_ptr and std::unique_ptr
+
+ template <typename T>
+ inline typename std::enable_if<serialization::is_smart_ptr<T>::value,size_t>::type getByteSize(const T& obj)
+ {
+ return getByteSize(obj.get());
+ }
+
+ template <typename T>
+ inline typename std::enable_if<serialization::is_smart_ptr<T>::value>::type serialize(const T& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+ serialize(obj.get(),buffer,iter);
+ }
+
+ template <template<typename> class T0,typename T1>
+ inline typename std::enable_if<serialization::is_smart_ptr<T0<T1> >::value>::type deserialize(T0<T1>& obj,std::vector<char>::const_iterator& iter)
+ {
+ bool isNullPtr;
+ serialization::deserialize(isNullPtr,iter);
+
+ if(isNullPtr)
+ {
+ obj.reset();
+ }
+ else
+ {
+ obj = T0<T1>(new T1());
+ serialization::deserialize(*obj,iter);
+ }
+ }
+
+ // std::weak_ptr
+
+ template <typename T>
+ inline size_t getByteSize(const std::weak_ptr<T>& obj)
+ {
+ return sizeof(size_t);
+ }
+
+ template <typename T>
+ inline void serialize(const std::weak_ptr<T>& obj,std::vector<char>& buffer,std::vector<char>::iterator& iter)
+ {
+
+ }
+
+ template <typename T>
+ inline void deserialize(std::weak_ptr<T>& obj,std::vector<char>::const_iterator& iter)
+ {
+
+ }
+
+ // functions to overload for non-intrusive serialization
+ template <typename T>
+ inline void serialize(const T& obj,std::vector<char>& buffer)
+ {
+ std::cerr << typeid(obj).name() << " is not serializable: derive from igl::Serializable or spezialize the template function igl::serialization::serialize(const T& obj,std::vector<char>& buffer)" << std::endl;
+ }
+
+ template <typename T>
+ inline void deserialize(T& obj,const std::vector<char>& buffer)
+ {
+ std::cerr << typeid(obj).name() << " is not deserializable: derive from igl::Serializable or spezialize the template function igl::serialization::deserialize(T& obj, const std::vector<char>& buffer)" << std::endl;
+ }
+
+ // helper functions
+
+ template <typename T>
+ inline void updateMemoryMap(T& obj,size_t size,std::map<std::uintptr_t,IndexedPointerBase*>& memoryMap)
+ {
+ // check if object is already serialized
+ auto startPtr = new IndexedPointer<T>();
+ startPtr->Object = &obj;
+ auto startBasePtr = static_cast<IndexedPointerBase*>(startPtr);
+ startBasePtr->Type = IndexedPointerBase::BEGIN;
+ auto startAddress = reinterpret_cast<std::uintptr_t>(&obj);
+ auto p = std::pair<std::uintptr_t,IndexedPointerBase*>(startAddress,startBasePtr);
+
+ auto el = memoryMap.insert(p);
+ auto iter = ++el.first; // next elememt
+ if(el.second && (iter == memoryMap.end() || iter->second->Type != IndexedPointerBase::END))
+ {
+ // not yet serialized
+ auto endPtr = new IndexedPointer<T>();
+ auto endBasePtr = static_cast<IndexedPointerBase*>(endPtr);
+ endBasePtr->Type = IndexedPointerBase::END;
+ auto endAddress = reinterpret_cast<std::uintptr_t>(&obj) + size - 1;
+ auto p = std::pair<std::uintptr_t,IndexedPointerBase*>(endAddress,endBasePtr);
+
+ // insert end address
+ memoryMap.insert(el.first,p);
+ }
+ else
+ {
+ // already serialized
+
+ // remove inserted address
+ memoryMap.erase(el.first);
+ }
+ }
+ }
+}
+
+#endif
diff --git a/xs/src/igl/setdiff.cpp b/xs/src/igl/setdiff.cpp
new file mode 100644
index 000000000..12404175a
--- /dev/null
+++ b/xs/src/igl/setdiff.cpp
@@ -0,0 +1,83 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "setdiff.h"
+#include "LinSpaced.h"
+#include "list_to_matrix.h"
+#include "sort.h"
+#include "unique.h"
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedIA>
+IGL_INLINE void igl::setdiff(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Eigen::DenseBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA)
+{
+ using namespace Eigen;
+ using namespace std;
+ // boring base cases
+ if(A.size() == 0)
+ {
+ C.resize(0,1);
+ IA.resize(0,1);
+ return;
+ }
+
+ // Get rid of any duplicates
+ typedef Matrix<typename DerivedA::Scalar,Dynamic,1> VectorA;
+ typedef Matrix<typename DerivedB::Scalar,Dynamic,1> VectorB;
+ VectorA uA;
+ VectorB uB;
+ typedef DerivedIA IAType;
+ IAType uIA,uIuA,uIB,uIuB;
+ unique(A,uA,uIA,uIuA);
+ unique(B,uB,uIB,uIuB);
+
+ // Sort both
+ VectorA sA;
+ VectorB sB;
+ IAType sIA,sIB;
+ sort(uA,1,true,sA,sIA);
+ sort(uB,1,true,sB,sIB);
+
+ vector<typename DerivedB::Scalar> vC;
+ vector<typename DerivedIA::Scalar> vIA;
+ int bi = 0;
+ // loop over sA
+ bool past = false;
+ bool sBempty = sB.size()==0;
+ for(int a = 0;a<sA.size();a++)
+ {
+ while(!sBempty && !past && sA(a)>sB(bi))
+ {
+ bi++;
+ past = bi>=sB.size();
+ }
+ if(sBempty || past || sA(a)<sB(bi))
+ {
+ // then sA(a) did not appear in sB
+ vC.push_back(sA(a));
+ vIA.push_back(uIA(sIA(a)));
+ }
+ }
+ list_to_matrix(vC,C);
+ list_to_matrix(vIA,IA);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::setdiff<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::setdiff<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::setdiff<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::setdiff<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/setdiff.h b/xs/src/igl/setdiff.h
new file mode 100644
index 000000000..20e8d6485
--- /dev/null
+++ b/xs/src/igl/setdiff.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SETDIFF_H
+#define IGL_SETDIFF_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Set difference of elements of matrices
+ //
+ // Inputs:
+ // A m-long vector of indices
+ // B n-long vector of indices
+ // Outputs:
+ // C (k<=m)-long vector of unique elements appearing in A but not in B
+ // IA (k<=m)-long list of indices into A so that C = A(IA)
+ //
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedIA>
+ IGL_INLINE void setdiff(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Eigen::DenseBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "setdiff.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/setunion.cpp b/xs/src/igl/setunion.cpp
new file mode 100644
index 000000000..eb0e721d8
--- /dev/null
+++ b/xs/src/igl/setunion.cpp
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "setunion.h"
+#include "unique.h"
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedIA,
+ typename DerivedIB>
+IGL_INLINE void igl::setunion(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Eigen::DenseBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedIB> & IB)
+{
+ DerivedC CS(A.size()+B.size(),1);
+ {
+ int k = 0;
+ for(int j = 0;j<A.cols();j++)
+ {
+ for(int i = 0;i<A.rows();i++)
+ {
+ CS(k++) = A(i,j);
+ }
+ }
+ for(int j = 0;j<B.cols();j++)
+ {
+ for(int i = 0;i<B.rows();i++)
+ {
+ CS(k++) = B(i,j);
+ }
+ }
+ assert(k==CS.size());
+ }
+ DerivedIA IAC;
+ {
+ DerivedIA IC;
+ unique(CS,C,IAC,IC);
+ }
+ const int nia = (IAC.array()<A.size()).count();
+ IA.resize(nia);
+ IB.resize(IAC.size() - nia);
+ {
+ int ka = 0;
+ int kb = 0;
+ for(int i = 0;i<IAC.size();i++)
+ {
+ if(IAC(i)<A.size())
+ {
+ IA(ka++) = IAC(i);
+ }else
+ {
+ IB(kb++) = IAC(i)-A.size();
+ }
+ }
+ assert(ka == IA.size());
+ assert(kb == IB.size());
+ }
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::setunion<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/setunion.h b/xs/src/igl/setunion.h
new file mode 100644
index 000000000..f28bff653
--- /dev/null
+++ b/xs/src/igl/setunion.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SETUNION_H
+#define IGL_SETUNION_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Union of elements of matrices (like matlab's `union`)
+ //
+ // Inputs:
+ // A m-long vector of indices
+ // B n-long vector of indices
+ // Outputs:
+ // C (k>=m)-long vector of unique elements appearing in A and/or B
+ // IA (<k>=m)-long list of indices into A so that C = sort([A(IA);B(IB)])
+ // IB (<k>=m)-long list of indices into B so that C = sort([A(IA);B(IB)])
+ //
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedIA,
+ typename DerivedIB>
+ IGL_INLINE void setunion(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Eigen::DenseBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedIB> & IB);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "setunion.cpp"
+#endif
+#endif
+
+
diff --git a/xs/src/igl/setxor.cpp b/xs/src/igl/setxor.cpp
new file mode 100644
index 000000000..5429abdc2
--- /dev/null
+++ b/xs/src/igl/setxor.cpp
@@ -0,0 +1,32 @@
+#include "setxor.h"
+#include "setdiff.h"
+#include "setunion.h"
+#include "slice.h"
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedIA,
+ typename DerivedIB>
+IGL_INLINE void igl::setxor(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Eigen::DenseBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedIB> & IB)
+{
+ DerivedC AB,BA;
+ DerivedIA IAB,IBA;
+ setdiff(A,B,AB,IAB);
+ setdiff(B,A,BA,IBA);
+ setunion(AB,BA,C,IA,IB);
+ slice(IAB,DerivedIA(IA),IA);
+ slice(IBA,DerivedIB(IB),IB);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::setxor<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/setxor.h b/xs/src/igl/setxor.h
new file mode 100644
index 000000000..bbd1089fa
--- /dev/null
+++ b/xs/src/igl/setxor.h
@@ -0,0 +1,43 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SETXOR_H
+#define IGL_SETXOR_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Set xor of elements of matrices
+ //
+ // Inputs:
+ // A m-long vector of indices
+ // B n-long vector of indices
+ // Outputs:
+ // C (k<=m)-long vector of unique elements appearing in A but not in B or
+ // B but not in A
+ // IA (<k<=m)-long list of indices into A so that C = sort([A(IA);B(IB)])
+ // IB (<k<=m)-long list of indices into B so that C = sort([A(IA);B(IB)])
+ //
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedIA,
+ typename DerivedIB>
+ IGL_INLINE void setxor(
+ const Eigen::DenseBase<DerivedA> & A,
+ const Eigen::DenseBase<DerivedB> & B,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedIB> & IB);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "setxor.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/shape_diameter_function.cpp b/xs/src/igl/shape_diameter_function.cpp
new file mode 100644
index 000000000..db061fe39
--- /dev/null
+++ b/xs/src/igl/shape_diameter_function.cpp
@@ -0,0 +1,182 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "shape_diameter_function.h"
+#include "random_dir.h"
+#include "barycenter.h"
+#include "ray_mesh_intersect.h"
+#include "per_vertex_normals.h"
+#include "per_face_normals.h"
+#include "EPS.h"
+#include "Hit.h"
+#include "parallel_for.h"
+#include <functional>
+#include <vector>
+#include <algorithm>
+
+template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::shape_diameter_function(
+ const std::function<
+ double(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&)
+ > & shoot_ray,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ using namespace Eigen;
+ const int n = P.rows();
+ // Resize output
+ S.resize(n,1);
+ // Embree seems to be parallel when constructing but not when tracing rays
+ const MatrixXf D = random_dir_stratified(num_samples).cast<float>();
+
+ const auto & inner = [&P,&N,&num_samples,&D,&S,&shoot_ray](const int p)
+ {
+ const Vector3f origin = P.row(p).template cast<float>();
+ const Vector3f normal = N.row(p).template cast<float>();
+ int num_hits = 0;
+ double total_distance = 0;
+ for(int s = 0;s<num_samples;s++)
+ {
+ Vector3f d = D.row(s);
+ // Shoot _inward_
+ if(d.dot(normal) > 0)
+ {
+ // reverse ray
+ d *= -1;
+ }
+ const double dist = shoot_ray(origin,d);
+ if(std::isfinite(dist))
+ {
+ total_distance += dist;
+ num_hits++;
+ }
+ }
+ S(p) = total_distance/(double)num_hits;
+ };
+ parallel_for(n,inner,1000);
+}
+
+template <
+ typename DerivedV,
+ int DIM,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::shape_diameter_function(
+ const igl::AABB<DerivedV,DIM> & aabb,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ const auto & shoot_ray = [&aabb,&V,&F](
+ const Eigen::Vector3f& _s,
+ const Eigen::Vector3f& dir)->double
+ {
+ Eigen::Vector3f s = _s+1e-4*dir;
+ igl::Hit hit;
+ if(aabb.intersect_ray(
+ V,
+ F,
+ s .cast<typename DerivedV::Scalar>().eval(),
+ dir.cast<typename DerivedV::Scalar>().eval(),
+ hit))
+ {
+ return hit.t;
+ }else
+ {
+ return std::numeric_limits<double>::infinity();
+ }
+ };
+ return shape_diameter_function(shoot_ray,P,N,num_samples,S);
+
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+IGL_INLINE void igl::shape_diameter_function(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ if(F.rows() < 100)
+ {
+ // Super naive
+ const auto & shoot_ray = [&V,&F](
+ const Eigen::Vector3f& _s,
+ const Eigen::Vector3f& dir)->double
+ {
+ Eigen::Vector3f s = _s+1e-4*dir;
+ igl::Hit hit;
+ if(ray_mesh_intersect(s,dir,V,F,hit))
+ {
+ return hit.t;
+ }else
+ {
+ return std::numeric_limits<double>::infinity();
+ }
+ };
+ return shape_diameter_function(shoot_ray,P,N,num_samples,S);
+ }
+ AABB<DerivedV,3> aabb;
+ aabb.init(V,F);
+ return shape_diameter_function(aabb,V,F,P,N,num_samples,S);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS>
+IGL_INLINE void igl::shape_diameter_function(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const bool per_face,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S)
+{
+ if (per_face)
+ {
+ DerivedV N;
+ igl::per_face_normals(V, F, N);
+ DerivedV P;
+ igl::barycenter(V, F, P);
+ return igl::shape_diameter_function(V, F, P, N, num_samples, S);
+ }
+ else
+ {
+ DerivedV N;
+ igl::per_vertex_normals(V, F, N);
+ return igl::shape_diameter_function(V, F, V, N, num_samples, S);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::shape_diameter_function<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::shape_diameter_function<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::function<double (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::shape_diameter_function<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+#endif
+
diff --git a/xs/src/igl/shape_diameter_function.h b/xs/src/igl/shape_diameter_function.h
new file mode 100644
index 000000000..5460cda7b
--- /dev/null
+++ b/xs/src/igl/shape_diameter_function.h
@@ -0,0 +1,95 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SHAPE_DIAMETER_FUNCTION_H
+#define IGL_SHAPE_DIAMETER_FUNCTION_H
+#include "igl_inline.h"
+#include "AABB.h"
+#include <Eigen/Core>
+#include <functional>
+namespace igl
+{
+ // Compute shape diamater function per given point. In the parlence of the
+ // paper "Consistent Mesh Partitioning and Skeletonisation using the Shape
+ // Diameter Function" [Shapiro et al. 2008], this implementation uses a 180°
+ // cone and a _uniform_ average (_not_ a average weighted by inverse angles).
+ //
+ // 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 shape diamater function values between bounding box
+ // diagonal (perfect sphere) and 0 (perfect needle hook)
+ //
+ template <
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void shape_diameter_function(
+ const std::function<
+ double(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&)
+ > & shoot_ray,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ // Inputs:
+ // AABB axis-aligned bounding box hierarchy around (V,F)
+ template <
+ typename DerivedV,
+ int DIM,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void shape_diameter_function(
+ const igl::AABB<DerivedV,DIM> & aabb,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const 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
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedP,
+ typename DerivedN,
+ typename DerivedS >
+ IGL_INLINE void shape_diameter_function(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+ // per_face whether to compute per face (S is #F by 1) or per vertex (S is
+ // #V by 1)
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS>
+ IGL_INLINE void shape_diameter_function(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const bool per_face,
+ const int num_samples,
+ Eigen::PlainObjectBase<DerivedS> & S);
+};
+#ifndef IGL_STATIC_LIBRARY
+# include "shape_diameter_function.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/shapeup.cpp b/xs/src/igl/shapeup.cpp
new file mode 100644
index 000000000..f352d22bf
--- /dev/null
+++ b/xs/src/igl/shapeup.cpp
@@ -0,0 +1,238 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Amir Vaxman <avaxman@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <igl/shapeup.h>
+#include <igl/min_quad_with_fixed.h>
+#include <igl/igl_inline.h>
+#include <igl/setdiff.h>
+#include <igl/cat.h>
+#include <igl/PI.h>
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+
+ //This projection does nothing but render points into projP. Mostly used for "echoing" the global step
+ IGL_INLINE bool shapeup_identity_projection(const Eigen::PlainObjectBase<Eigen::MatrixXd>& P, const Eigen::PlainObjectBase<Eigen::VectorXi>& SC, const Eigen::PlainObjectBase<Eigen::MatrixXi>& S, Eigen::PlainObjectBase<Eigen::MatrixXd>& projP){
+ projP.conservativeResize(SC.rows(), 3*SC.maxCoeff());
+ for (int i=0;i<S.rows();i++){
+ Eigen::RowVector3d avgCurrP=Eigen::RowVector3d::Zero();
+ for (int j=0;j<SC(i);j++)
+ avgCurrP+=P.row(S(i,j))/(double)(SC(i));
+
+ for (int j=0;j<SC(i);j++)
+ projP.block(i,3*j,1,3)=P.row(S(i,j))-avgCurrP;
+ }
+ return true;
+ }
+
+
+ //the projection assumes that the sets are vertices of polygons in order
+ IGL_INLINE bool shapeup_regular_face_projection(const Eigen::PlainObjectBase<Eigen::MatrixXd>& P, const Eigen::PlainObjectBase<Eigen::VectorXi>& SC, const Eigen::PlainObjectBase<Eigen::MatrixXi>& S, Eigen::PlainObjectBase<Eigen::MatrixXd>& projP){
+ projP.conservativeResize(SC.rows(), 3*SC.maxCoeff());
+ for (int currRow=0;currRow<SC.rows();currRow++){
+ //computing average
+ int N=SC(currRow);
+ const Eigen::RowVectorXi SRow=S.row(currRow);
+ Eigen::RowVector3d avgCurrP=Eigen::RowVector3d::Zero();
+ Eigen::MatrixXd targetPolygon(N, 3);
+ Eigen::MatrixXd sourcePolygon(N, 3);
+ for (int j=0;j<N;j++)
+ avgCurrP+=P.row(SRow(j))/(double)(N);
+
+ for (int j=0;j<N;j++)
+ targetPolygon.row(j)=P.row(SRow(j))-avgCurrP;
+
+ //creating perfectly regular source polygon
+ for (int j=0;j<N;j++)
+ sourcePolygon.row(j)<<cos(2*igl::PI*(double)j/(double(N))), sin(2*igl::PI*(double)j/(double(N))),0.0;
+
+ //finding closest similarity transformation between source and target
+ Eigen::MatrixXd corrMat=sourcePolygon.transpose()*targetPolygon;
+ Eigen::JacobiSVD<Eigen::Matrix3d> svd(corrMat, Eigen::ComputeFullU | Eigen::ComputeFullV);
+ Eigen::MatrixXd R=svd.matrixU()*svd.matrixV().transpose();
+ //getting scale by edge length change average. TODO: by singular values
+ Eigen::VectorXd sourceEdgeLengths(N);
+ Eigen::VectorXd targetEdgeLengths(N);
+ for (int j=0;j<N;j++){
+ sourceEdgeLengths(j)=(sourcePolygon.row((j+1)%N)-sourcePolygon.row(j)).norm();
+ targetEdgeLengths(j)=(targetPolygon.row((j+1)%N)-targetPolygon.row(j)).norm();
+ }
+ double scale=(targetEdgeLengths.cwiseQuotient(sourceEdgeLengths)).mean();
+
+ for (int j=0;j<N;j++)
+ projP.block(currRow,3*j,1,3)=sourcePolygon.row(j)*R*scale;
+ }
+
+ return true;
+ }
+
+ template <
+ typename DerivedP,
+ typename DerivedSC,
+ typename DerivedS,
+ typename Derivedw>
+ IGL_INLINE bool shapeup_precomputation(const Eigen::PlainObjectBase<DerivedP>& P,
+ const Eigen::PlainObjectBase<DerivedSC>& SC,
+ const Eigen::PlainObjectBase<DerivedS>& S,
+ const Eigen::PlainObjectBase<DerivedS>& E,
+ const Eigen::PlainObjectBase<DerivedSC>& b,
+ const Eigen::PlainObjectBase<Derivedw>& wShape,
+ const Eigen::PlainObjectBase<Derivedw>& wSmooth,
+ ShapeupData & sudata)
+ {
+ using namespace std;
+ using namespace Eigen;
+ sudata.P=P;
+ sudata.SC=SC;
+ sudata.S=S;
+ sudata.b=b;
+ typedef typename DerivedP::Scalar Scalar;
+
+ //checking for consistency of the input
+ assert(SC.rows()==S.rows());
+ assert(SC.rows()==wShape.rows());
+ assert(E.rows()==wSmooth.rows());
+ assert(b.rows()!=0); //would lead to matrix becoming SPD
+
+ sudata.DShape.conservativeResize(SC.sum(), P.rows()); //Shape matrix (integration);
+ sudata.DClose.conservativeResize(b.rows(), P.rows()); //Closeness matrix for positional constraints
+ sudata.DSmooth.conservativeResize(E.rows(), P.rows()); //smoothness matrix
+
+ //Building shape matrix
+ std::vector<Triplet<Scalar> > DShapeTriplets;
+ int currRow=0;
+ for (int i=0;i<S.rows();i++){
+ Scalar avgCoeff=1.0/(Scalar)SC(i);
+
+ for (int j=0;j<SC(i);j++){
+ for (int k=0;k<SC(i);k++){
+ if (j==k)
+ DShapeTriplets.push_back(Triplet<Scalar>(currRow+j, S(i,k), (1.0-avgCoeff)));
+ else
+ DShapeTriplets.push_back(Triplet<Scalar>(currRow+j, S(i,k), (-avgCoeff)));
+ }
+ }
+ currRow+=SC(i);
+
+ }
+
+ sudata.DShape.setFromTriplets(DShapeTriplets.begin(), DShapeTriplets.end());
+
+ //Building closeness matrix
+ std::vector<Triplet<Scalar> > DCloseTriplets;
+ for (int i=0;i<b.size();i++)
+ DCloseTriplets.push_back(Triplet<Scalar>(i,b(i), 1.0));
+
+ sudata.DClose.setFromTriplets(DCloseTriplets.begin(), DCloseTriplets.end());
+
+ //Building smoothness matrix
+ std::vector<Triplet<Scalar> > DSmoothTriplets;
+ for (int i=0; i<E.rows(); i++) {
+ DSmoothTriplets.push_back(Triplet<Scalar>(i, E(i, 0), -1));
+ DSmoothTriplets.push_back(Triplet<Scalar>(i, E(i, 1), 1));
+ }
+
+ SparseMatrix<Scalar> tempMat;
+ igl::cat(1, sudata.DShape, sudata.DClose, tempMat);
+ igl::cat(1, tempMat, sudata.DSmooth, sudata.A);
+
+ //weight matrix
+ vector<Triplet<Scalar> > WTriplets;
+
+ //one weight per set in S.
+ currRow=0;
+ for (int i=0;i<SC.rows();i++){
+ for (int j=0;j<SC(i);j++)
+ WTriplets.push_back(Triplet<double>(currRow+j,currRow+j,sudata.shapeCoeff*wShape(i)));
+ currRow+=SC(i);
+ }
+
+ for (int i=0;i<b.size();i++)
+ WTriplets.push_back(Triplet<double>(SC.sum()+i, SC.sum()+i, sudata.closeCoeff));
+
+ for (int i=0;i<E.rows();i++)
+ WTriplets.push_back(Triplet<double>(SC.sum()+b.size()+i, SC.sum()+b.size()+i, sudata.smoothCoeff*wSmooth(i)));
+
+ sudata.W.conservativeResize(SC.sum()+b.size()+E.rows(), SC.sum()+b.size()+E.rows());
+ sudata.W.setFromTriplets(WTriplets.begin(), WTriplets.end());
+
+ sudata.At=sudata.A.transpose(); //for efficieny, as we use the transpose a lot in the iteration
+ sudata.Q=sudata.At*sudata.W*sudata.A;
+
+ return min_quad_with_fixed_precompute(sudata.Q,VectorXi(),SparseMatrix<double>(),true,sudata.solver_data);
+ }
+
+
+ template <
+ typename DerivedP,
+ typename DerivedSC,
+ typename DerivedS>
+ IGL_INLINE bool shapeup_solve(const Eigen::PlainObjectBase<DerivedP>& bc,
+ const std::function<bool(const Eigen::PlainObjectBase<DerivedP>&, const Eigen::PlainObjectBase<DerivedSC>&, const Eigen::PlainObjectBase<DerivedS>&, Eigen::PlainObjectBase<DerivedP>&)>& local_projection,
+ const Eigen::PlainObjectBase<DerivedP>& P0,
+ const ShapeupData & sudata,
+ const bool quietIterations,
+ Eigen::PlainObjectBase<DerivedP>& P)
+ {
+ using namespace Eigen;
+ using namespace std;
+ MatrixXd currP=P0;
+ MatrixXd prevP=P0;
+ MatrixXd projP;
+
+ assert(bc.rows()==sudata.b.rows());
+
+ MatrixXd rhs(sudata.A.rows(), 3); rhs.setZero();
+ rhs.block(sudata.DShape.rows(), 0, sudata.b.rows(),3)=bc; //this stays constant throughout the iterations
+
+ if (!quietIterations){
+ cout<<"Shapeup Iterations, "<<sudata.DShape.rows()<<" constraints, solution size "<<P0.size()<<endl;
+ cout<<"**********************************************************************************************"<<endl;
+ }
+ projP.conservativeResize(sudata.SC.rows(), 3*sudata.SC.maxCoeff());
+ for (int iter=0;iter<sudata.maxIterations;iter++){
+
+ local_projection(currP, sudata.SC,sudata.S,projP);
+
+ //constructing the projection part of the (DShape rows of the) right hand side
+ int currRow=0;
+ for (int i=0;i<sudata.S.rows();i++)
+ for (int j=0;j<sudata.SC(i);j++)
+ rhs.row(currRow++)=projP.block(i, 3*j, 1,3);
+
+ DerivedP lsrhs=-sudata.At*sudata.W*rhs;
+ MatrixXd Y(0,3), Beq(0,3); //We do not use the min_quad_solver fixed variables mechanism; they are treated with the closeness energy of ShapeUp.
+ min_quad_with_fixed_solve(sudata.solver_data, lsrhs,Y,Beq,currP);
+
+ double currChange=(currP-prevP).lpNorm<Infinity>();
+ if (!quietIterations)
+ cout << "Iteration "<<iter<<", integration Linf error: "<<currChange<< endl;
+ prevP=currP;
+ if (currChange<sudata.pTolerance){
+ P=currP;
+ return true;
+ }
+ }
+
+ P=currP;
+ return false; //we went over maxIterations
+
+ }
+}
+
+
+
+
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::shapeup_precomputation< typename Eigen::Matrix<double, -1, -1, 0, -1, -1>, typename Eigen::Matrix<int, -1, 1, 0, -1, 1>, typename Eigen::Matrix<int, -1, -1, 0, -1, -1>, typename Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::ShapeupData&);
+
+template bool igl::shapeup_solve<typename Eigen::Matrix<double, -1, -1, 0, -1, -1>, typename Eigen::Matrix<int, -1, 1, 0, -1, 1>, typename Eigen::Matrix<int, -1, -1, 0, -1, -1> >(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& bc, const std::function<bool(const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, const Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& ) >& local_projection, const Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& P0, const igl::ShapeupData & sudata, const bool quietIterations, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >& P);
+#endif
diff --git a/xs/src/igl/shapeup.h b/xs/src/igl/shapeup.h
new file mode 100644
index 000000000..7230a8dc7
--- /dev/null
+++ b/xs/src/igl/shapeup.h
@@ -0,0 +1,128 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Amir Vaxman <avaxman@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SHAPEUP_H
+#define IGL_SHAPEUP_H
+
+#include <igl/min_quad_with_fixed.h>
+#include <igl/igl_inline.h>
+#include <igl/setdiff.h>
+#include <igl/cat.h>
+#include <Eigen/Core>
+#include <vector>
+#include <igl/PI.h>
+
+
+//This file implements the following algorithm:
+
+//Boaziz et al.
+//Shape-Up: Shaping Discrete Geometry with Projections
+//Computer Graphics Forum (Proc. SGP) 31(5), 2012
+
+namespace igl
+{
+ struct ShapeupData{
+ //input data
+ Eigen::MatrixXd P;
+ Eigen::VectorXi SC;
+ Eigen::MatrixXi S;
+ Eigen::VectorXi b;
+ int maxIterations; //referring to number of local-global pairs.
+ double pTolerance; //algorithm stops when max(|P_k-P_{k-1}|)<pTolerance.
+ double shapeCoeff, closeCoeff, smoothCoeff;
+
+ //Internally-used matrices
+ Eigen::SparseMatrix<double> DShape, DClose, DSmooth, Q, A, At, W;
+
+ min_quad_with_fixed_data<double> solver_data;
+
+ ShapeupData():
+ maxIterations(50),
+ pTolerance(10e-6),
+ shapeCoeff(1.0),
+ closeCoeff(100.0),
+ smoothCoeff(0.0){}
+ };
+
+ //Every function here defines a local projection for ShapeUp, and must have the following structure to qualify:
+ //Input:
+ // P #P by 3 the set of points, either the initial solution, or from previous iteration.
+ // SC #Set by 1 cardinalities of sets in S
+ // S #Sets by max(SC) independent sets where the local projection applies. Values beyond column SC(i)-1 in row S(i,:) are "don't care"
+ //Output:
+ // projP #S by 3*max(SC) in format xyzxyzxyz, where the projected points correspond to each set in S in the same order.
+ typedef std::function<bool(const Eigen::PlainObjectBase<Eigen::MatrixXd>&, const Eigen::PlainObjectBase<Eigen::VectorXi>&, const Eigen::PlainObjectBase<Eigen::MatrixXi>&, Eigen::PlainObjectBase<Eigen::MatrixXd>&)> shapeup_projection_function;
+
+
+ //This projection does nothing but render points into projP. Mostly used for "echoing" the global step
+ IGL_INLINE bool shapeup_identity_projection(const Eigen::PlainObjectBase<Eigen::MatrixXd>& P, const Eigen::PlainObjectBase<Eigen::VectorXi>& SC, const Eigen::PlainObjectBase<Eigen::MatrixXi>& S, Eigen::PlainObjectBase<Eigen::MatrixXd>& projP);
+
+ //the projection assumes that the sets are vertices of polygons in cyclic order
+ IGL_INLINE bool shapeup_regular_face_projection(const Eigen::PlainObjectBase<Eigen::MatrixXd>& P, const Eigen::PlainObjectBase<Eigen::VectorXi>& SC, const Eigen::PlainObjectBase<Eigen::MatrixXi>& S, Eigen::PlainObjectBase<Eigen::MatrixXd>& projP);
+
+
+ //This function precomputation the necessary matrices for the ShapeUp process, and prefactorizes them.
+
+ //input:
+ // P #P by 3 point positions
+ // SC #Set by 1 cardinalities of sets in S
+ // S #Sets by max(SC) independent sets where the local projection applies. Values beyond column SC(i)-1 in row S(i,:) are "don't care"
+ // E #E by 2 the "edges" of the set P; used for the smoothness energy.
+ // b #b by 1 boundary (fixed) vertices from P.
+ // wShape, #Set by 1
+ // wSmooth #b by 1 weights for constraints from S and positional constraints (used in the global step)
+
+ // Output:
+ // sudata struct ShapeupData the data necessary to solve the system in shapeup_solve
+
+ template <
+ typename DerivedP,
+ typename DerivedSC,
+ typename DerivedS,
+ typename Derivedw>
+ IGL_INLINE bool shapeup_precomputation(const Eigen::PlainObjectBase<DerivedP>& P,
+ const Eigen::PlainObjectBase<DerivedSC>& SC,
+ const Eigen::PlainObjectBase<DerivedS>& S,
+ const Eigen::PlainObjectBase<DerivedS>& E,
+ const Eigen::PlainObjectBase<DerivedSC>& b,
+ const Eigen::PlainObjectBase<Derivedw>& wShape,
+ const Eigen::PlainObjectBase<Derivedw>& wSmooth,
+ ShapeupData & sudata);
+
+
+
+ //This function solve the shapeup project optimization. shapeup_precompute must be called before with the same sudata, or results are unpredictable
+
+ //Input:
+ //bc #b by 3 fixed point values corresonding to "b" in sudata
+ //local_projection function pointer taking (P,SC,S,projP),
+ // where the first three parameters are as defined, and "projP" is the output, as a #S by 3*max(SC) function in format xyzxyzxyz, and where it returns the projected points corresponding to each set in S in the same order.
+ //NOTE: the input values in P0 don't need to correspond to prescribed values in bc; the iterations will project them automatically (by design).
+ //P0 #P by 3 initial solution (point positions)
+ //sudata the ShapeUpData structure computed in shapeup_precomputation()
+ //quietIterations flagging if to output iteration information.
+
+ //Output:
+ //P the solution to the problem, indices corresponding to P0.
+ template <
+ typename DerivedP,
+ typename DerivedSC,
+ typename DerivedS>
+ IGL_INLINE bool shapeup_solve(const Eigen::PlainObjectBase<DerivedP>& bc,
+ const std::function<bool(const Eigen::PlainObjectBase<DerivedP>&, const Eigen::PlainObjectBase<DerivedSC>&, const Eigen::PlainObjectBase<DerivedS>&, Eigen::PlainObjectBase<DerivedP>&)>& local_projection,
+ const Eigen::PlainObjectBase<DerivedP>& P0,
+ const ShapeupData & sudata,
+ const bool quietIterations,
+ Eigen::PlainObjectBase<DerivedP>& P);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "shapeup.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/shortest_edge_and_midpoint.cpp b/xs/src/igl/shortest_edge_and_midpoint.cpp
new file mode 100644
index 000000000..db5338d0d
--- /dev/null
+++ b/xs/src/igl/shortest_edge_and_midpoint.cpp
@@ -0,0 +1,23 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "shortest_edge_and_midpoint.h"
+
+IGL_INLINE void igl::shortest_edge_and_midpoint(
+ const int e,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & /*F*/,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & /*EMAP*/,
+ const Eigen::MatrixXi & /*EF*/,
+ const Eigen::MatrixXi & /*EI*/,
+ double & cost,
+ Eigen::RowVectorXd & p)
+{
+ cost = (V.row(E(e,0))-V.row(E(e,1))).norm();
+ p = 0.5*(V.row(E(e,0))+V.row(E(e,1)));
+}
diff --git a/xs/src/igl/shortest_edge_and_midpoint.h b/xs/src/igl/shortest_edge_and_midpoint.h
new file mode 100644
index 000000000..45a4a2abf
--- /dev/null
+++ b/xs/src/igl/shortest_edge_and_midpoint.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SHORTEST_EDGE_AND_MIDPOINT_H
+#define IGL_SHORTEST_EDGE_AND_MIDPOINT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ // Cost and placement function compatible with igl::decimate. The cost of
+ // collapsing an edge is its length (prefer to collapse short edges) and the
+ // placement strategy for the new vertex is the midpoint of the collapsed
+ // edge.
+ //
+ // Inputs:
+ // e index into E of edge to be considered for collapse
+ // V #V by dim list of vertex positions
+ // F #F by 3 list of faces (ignored)
+ // E #E by 2 list of edge indices into V
+ // EMAP #F*3 list of half-edges indices into E (ignored)
+ // EF #E by 2 list of edge-face flaps into F (ignored)
+ // EI #E by 2 list of edge-face opposite corners (ignored)
+ // Outputs:
+ // cost set to edge length
+ // p placed point set to edge midpoint
+ IGL_INLINE void shortest_edge_and_midpoint(
+ const int e,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & /*F*/,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & /*EMAP*/,
+ const Eigen::MatrixXi & /*EF*/,
+ const Eigen::MatrixXi & /*EI*/,
+ double & cost,
+ Eigen::RowVectorXd & p);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "shortest_edge_and_midpoint.cpp"
+#endif
+#endif
+
+
diff --git a/xs/src/igl/signed_angle.cpp b/xs/src/igl/signed_angle.cpp
new file mode 100644
index 000000000..69f8aa6f5
--- /dev/null
+++ b/xs/src/igl/signed_angle.cpp
@@ -0,0 +1,74 @@
+#include "signed_angle.h"
+#include "PI.h"
+#include <cmath>
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedP>
+IGL_INLINE typename DerivedA::Scalar igl::signed_angle(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedP> & P)
+{
+ typedef typename DerivedA::Scalar SType;
+ // Gather vectors to source and destination
+ SType o2A[2];
+ SType o2B[2];
+ // and lengths
+ SType o2Al = 0;
+ SType o2Bl = 0;
+ for(int i = 0;i<2;i++)
+ {
+ o2A[i] = P(i) - A(i);
+ o2B[i] = P(i) - B(i);
+ o2Al += o2A[i]*o2A[i];
+ o2Bl += o2B[i]*o2B[i];
+ }
+ o2Al = sqrt(o2Al);
+ o2Bl = sqrt(o2Bl);
+ // Normalize
+ for(int i = 0;i<2;i++)
+ {
+ // Matlab crashes on NaN
+ if(o2Al!=0)
+ {
+ o2A[i] /= o2Al;
+ }
+ if(o2Bl!=0)
+ {
+ o2B[i] /= o2Bl;
+ }
+ }
+ return
+ -atan2(o2B[0]*o2A[1]-o2B[1]*o2A[0],o2B[0]*o2A[0]+o2B[1]*o2A[1])/
+ (2.*igl::PI);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::signed_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);
+#ifdef WIN32
+template float igl::signed_angle<class Eigen::Block<class Eigen::Matrix<float,-1,3,1,-1,3> const ,1,3,1>,class Eigen::Block<class Eigen::Matrix<float,-1,3,1,-1,3> const ,1,3,1>,class Eigen::Matrix<float,1,2,1,1,2> >(class Eigen::MatrixBase<class Eigen::Block<class Eigen::Matrix<float,-1,3,1,-1,3> const ,1,3,1> > const &,class Eigen::MatrixBase<class Eigen::Block<class Eigen::Matrix<float,-1,3,1,-1,3> const ,1,3,1> > const &,class Eigen::MatrixBase<class Eigen::Matrix<float,1,2,1,1,2> > const &);
+template float igl::signed_angle<class Eigen::Block<class Eigen::Matrix<float,-1,3,0,-1,3> const ,1,3,0>,class Eigen::Block<class Eigen::Matrix<float,-1,3,0,-1,3> const ,1,3,0>,class Eigen::Matrix<float,1,2,1,1,2> >(class Eigen::MatrixBase<class Eigen::Block<class Eigen::Matrix<float,-1,3,0,-1,3> const ,1,3,0> > const &,class Eigen::MatrixBase<class Eigen::Block<class Eigen::Matrix<float,-1,3,0,-1,3> const ,1,3,0> > const &,class Eigen::MatrixBase<class Eigen::Matrix<float,1,2,1,1,2> > const &);
+#endif
+#endif
diff --git a/xs/src/igl/signed_angle.h b/xs/src/igl/signed_angle.h
new file mode 100644
index 000000000..547ba00a4
--- /dev/null
+++ b/xs/src/igl/signed_angle.h
@@ -0,0 +1,27 @@
+#ifndef IGL_SIGNED_ANGLE_H
+#define IGL_SIGNED_ANGLE_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Compute the signed angle subtended by the oriented 3d triangle (A,B,C) at some point P
+ //
+ // Inputs:
+ // A 2D position of corner
+ // B 2D position of corner
+ // P 2D position of query point
+ // returns signed angle
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedP>
+ IGL_INLINE typename DerivedA::Scalar signed_angle(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedP> & P);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "signed_angle.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/signed_distance.cpp b/xs/src/igl/signed_distance.cpp
new file mode 100644
index 000000000..f638b1f58
--- /dev/null
+++ b/xs/src/igl/signed_distance.cpp
@@ -0,0 +1,463 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "signed_distance.h"
+#include "get_seconds.h"
+#include "per_edge_normals.h"
+#include "parallel_for.h"
+#include "per_face_normals.h"
+#include "per_vertex_normals.h"
+#include "point_mesh_squared_distance.h"
+#include "pseudonormal_test.h"
+
+
+template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedI,
+ typename DerivedC,
+ typename DerivedN>
+IGL_INLINE void igl::signed_distance(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const SignedDistanceType sign_type,
+ const typename DerivedV::Scalar lower_bound,
+ const typename DerivedV::Scalar upper_bound,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ using namespace Eigen;
+ using namespace std;
+ const int dim = V.cols();
+ assert((V.cols() == 3||V.cols() == 2) && "V should have 3d or 2d positions");
+ assert((P.cols() == 3||P.cols() == 2) && "P should have 3d or 2d positions");
+ assert(V.cols() == P.cols() && "V should have same dimension as P");
+ // Only unsigned distance is supported for non-triangles
+ if(sign_type != SIGNED_DISTANCE_TYPE_UNSIGNED)
+ {
+ assert(F.cols() == dim && "F should have co-dimension 0 simplices");
+ }
+ typedef Eigen::Matrix<typename DerivedV::Scalar,1,3> RowVector3S;
+
+ // Prepare distance computation
+ AABB<DerivedV,3> tree3;
+ AABB<DerivedV,2> tree2;
+ switch(dim)
+ {
+ default:
+ case 3:
+ tree3.init(V,F);
+ break;
+ case 2:
+ tree2.init(V,F);
+ break;
+ }
+
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,3> FN,VN,EN;
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,2> E;
+ Eigen::Matrix<typename DerivedF::Scalar,Eigen::Dynamic,1> EMAP;
+ WindingNumberAABB<RowVector3S,DerivedV,DerivedF> hier3;
+ switch(sign_type)
+ {
+ default:
+ assert(false && "Unknown SignedDistanceType");
+ case SIGNED_DISTANCE_TYPE_UNSIGNED:
+ // do nothing
+ break;
+ case SIGNED_DISTANCE_TYPE_DEFAULT:
+ case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
+ switch(dim)
+ {
+ default:
+ case 3:
+ hier3.set_mesh(V,F);
+ hier3.grow();
+ break;
+ case 2:
+ // no precomp, no hierarchy
+ break;
+ }
+ break;
+ case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
+ switch(dim)
+ {
+ default:
+ case 3:
+ // "Signed Distance Computation Using the Angle Weighted Pseudonormal"
+ // [Bærentzen & Aanæs 2005]
+ per_face_normals(V,F,FN);
+ per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
+ per_edge_normals(
+ V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP);
+ break;
+ case 2:
+ FN.resize(F.rows(),2);
+ VN = DerivedV::Zero(V.rows(),2);
+ for(int e = 0;e<F.rows();e++)
+ {
+ // rotate edge vector
+ FN(e,0) = (V(F(e,1),1)-V(F(e,0),1));
+ FN(e,1) = -(V(F(e,1),0)-V(F(e,0),0));
+ FN.row(e).normalize();
+ // add to vertex normal
+ VN.row(F(e,1)) += FN.row(e);
+ VN.row(F(e,0)) += FN.row(e);
+ }
+ // normalize to average
+ VN.rowwise().normalize();
+ break;
+ }
+ N.resize(P.rows(),dim);
+ break;
+ }
+ //
+ // convert to bounds on (unsiged) squared distances
+ typedef typename DerivedV::Scalar Scalar;
+ const Scalar max_abs = std::max(std::abs(lower_bound),std::abs(upper_bound));
+ const Scalar up_sqr_d = std::pow(max_abs,2.0);
+ const Scalar low_sqr_d =
+ std::pow(std::max(max_abs-(upper_bound-lower_bound),(Scalar)0.0),2.0);
+
+ S.resize(P.rows(),1);
+ I.resize(P.rows(),1);
+ C.resize(P.rows(),dim);
+
+ parallel_for(P.rows(),[&](const int p)
+ //for(int p = 0;p<P.rows();p++)
+ {
+ RowVector3S q3;
+ Eigen::Matrix<typename DerivedV::Scalar,1,2> q2;
+ switch(P.cols())
+ {
+ default:
+ case 3:
+ q3.head(P.row(p).size()) = P.row(p);
+ break;
+ case 2:
+ q2 = P.row(p).head(2);
+ break;
+ }
+ typename DerivedV::Scalar s=1,sqrd=0;
+ Eigen::Matrix<typename DerivedV::Scalar,1,Eigen::Dynamic> c;
+ RowVector3S c3;
+ Eigen::Matrix<typename DerivedV::Scalar,1,2> c2;
+ int i=-1;
+ // in all cases compute squared unsiged distances
+ sqrd = dim==3?
+ tree3.squared_distance(V,F,q3,low_sqr_d,up_sqr_d,i,c3):
+ tree2.squared_distance(V,F,q2,low_sqr_d,up_sqr_d,i,c2);
+ if(sqrd >= up_sqr_d || sqrd <= low_sqr_d)
+ {
+ // Out of bounds gets a nan (nans on grids can be flood filled later using
+ // igl::flood_fill)
+ S(p) = std::numeric_limits<double>::quiet_NaN();
+ I(p) = F.rows()+1;
+ C.row(p).setConstant(0);
+ }else
+ {
+ // Determine sign
+ switch(sign_type)
+ {
+ default:
+ assert(false && "Unknown SignedDistanceType");
+ case SIGNED_DISTANCE_TYPE_UNSIGNED:
+ break;
+ case SIGNED_DISTANCE_TYPE_DEFAULT:
+ case SIGNED_DISTANCE_TYPE_WINDING_NUMBER:
+ {
+ Scalar w = 0;
+ if(dim == 3)
+ {
+ s = 1.-2.*hier3.winding_number(q3.transpose());
+ }else
+ {
+ assert(!V.derived().IsRowMajor);
+ assert(!F.derived().IsRowMajor);
+ s = 1.-2.*winding_number(V,F,q2);
+ }
+ break;
+ }
+ case SIGNED_DISTANCE_TYPE_PSEUDONORMAL:
+ {
+ RowVector3S n3;
+ Eigen::Matrix<typename DerivedV::Scalar,1,2> n2;
+ dim==3 ?
+ pseudonormal_test(V,F,FN,VN,EN,EMAP,q3,i,c3,s,n3):
+ pseudonormal_test(V,E,EN,VN,q2,i,c2,s,n2);
+ Eigen::Matrix<typename DerivedV::Scalar,1,Eigen::Dynamic> n;
+ (dim==3 ? n = n3 : n = n2);
+ N.row(p) = n;
+ break;
+ }
+ }
+ I(p) = i;
+ S(p) = s*sqrt(sqrd);
+ C.row(p) = (dim==3 ? c=c3 : c=c2);
+ }
+ }
+ ,10000);
+}
+
+template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedI,
+ typename DerivedC,
+ typename DerivedN>
+IGL_INLINE void igl::signed_distance(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const SignedDistanceType sign_type,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ typedef typename DerivedV::Scalar Scalar;
+ Scalar lower = std::numeric_limits<Scalar>::min();
+ Scalar upper = std::numeric_limits<Scalar>::max();
+ return signed_distance(P,V,F,sign_type,lower,upper,S,I,C,N);
+}
+
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename Derivedq>
+IGL_INLINE typename DerivedV::Scalar igl::signed_distance_pseudonormal(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const Eigen::MatrixBase<Derivedq> & q)
+{
+ typename DerivedV::Scalar s,sqrd;
+ Eigen::Matrix<typename DerivedV::Scalar,1,3> n,c;
+ int i = -1;
+ signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
+ return s*sqrt(sqrd);
+}
+
+template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename DerivedS,
+ typename DerivedI,
+ typename DerivedC,
+ typename DerivedN>
+IGL_INLINE void igl::signed_distance_pseudonormal(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedN> & N)
+{
+ using namespace Eigen;
+ const size_t np = P.rows();
+ S.resize(np,1);
+ I.resize(np,1);
+ N.resize(np,3);
+ C.resize(np,3);
+ typedef typename AABB<DerivedV,3>::RowVectorDIMS RowVector3S;
+# pragma omp parallel for if(np>1000)
+ for(size_t p = 0;p<np;p++)
+ {
+ typename DerivedV::Scalar s,sqrd;
+ RowVector3S n,c;
+ int i = -1;
+ RowVector3S q = P.row(p);
+ signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,q,s,sqrd,i,c,n);
+ S(p) = s*sqrt(sqrd);
+ I(p) = i;
+ N.row(p) = n;
+ C.row(p) = c;
+ }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc,
+ typename Derivedn>
+IGL_INLINE void igl::signed_distance_pseudonormal(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Eigen::PlainObjectBase<Derivedn> & n)
+{
+ using namespace Eigen;
+ using namespace std;
+ //typedef Eigen::Matrix<typename DerivedV::Scalar,1,3> RowVector3S;
+ // Alec: Why was this constructor around q necessary?
+ //sqrd = tree.squared_distance(V,F,RowVector3S(q),i,(RowVector3S&)c);
+ // Alec: Why was this constructor around c necessary?
+ //sqrd = tree.squared_distance(V,F,q,i,(RowVector3S&)c);
+ sqrd = tree.squared_distance(V,F,q,i,c);
+ pseudonormal_test(V,F,FN,VN,EN,EMAP,q,i,c,s,n);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedEN,
+ typename DerivedVN,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc,
+ typename Derivedn>
+IGL_INLINE void igl::signed_distance_pseudonormal(
+ const AABB<DerivedV,2> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Eigen::PlainObjectBase<Derivedn> & n)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef Eigen::Matrix<typename DerivedV::Scalar,1,2> RowVector2S;
+ sqrd = tree.squared_distance(V,E,RowVector2S(q),i,(RowVector2S&)c);
+ pseudonormal_test(V,E,EN,VN,q,i,c,s,n);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedq>
+IGL_INLINE typename DerivedV::Scalar igl::signed_distance_winding_number(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const igl::WindingNumberAABB<Derivedq,DerivedV,DerivedF> & hier,
+ const Eigen::MatrixBase<Derivedq> & q)
+{
+ typedef typename DerivedV::Scalar Scalar;
+ Scalar s,sqrd;
+ Eigen::Matrix<Scalar,1,3> c;
+ int i=-1;
+ signed_distance_winding_number(tree,V,F,hier,q,s,sqrd,i,c);
+ return s*sqrt(sqrd);
+}
+
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc>
+IGL_INLINE void igl::signed_distance_winding_number(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const igl::WindingNumberAABB<Derivedq,DerivedV,DerivedF> & hier,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef Eigen::Matrix<typename DerivedV::Scalar,1,3> RowVector3S;
+ sqrd = tree.squared_distance(V,F,RowVector3S(q),i,(RowVector3S&)c);
+ const Scalar w = hier.winding_number(q.transpose());
+ s = 1.-2.*w;
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc>
+IGL_INLINE void igl::signed_distance_winding_number(
+ const AABB<DerivedV,2> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef Eigen::Matrix<typename DerivedV::Scalar,1,2> RowVector2S;
+ sqrd = tree.squared_distance(V,F,RowVector2S(q),i,(RowVector2S&)c);
+ Scalar w;
+ // TODO: using .data() like this is very dangerous... This is assuming
+ // colmajor order
+ assert(!V.derived().IsRowMajor);
+ assert(!F.derived().IsRowMajor);
+ s = 1.-2.*winding_number(V,F,q);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::signed_distance<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::SignedDistanceType, Eigen::Matrix<double, -1, 3, 1, -1, 3>::Scalar, Eigen::Matrix<double, -1, 3, 1, -1, 3>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::signed_distance<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, igl::SignedDistanceType, Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::signed_distance<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::SignedDistanceType, Eigen::Matrix<float, -1, 3, 1, -1, 3>::Scalar, Eigen::Matrix<float, -1, 3, 1, -1, 3>::Scalar, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::signed_distance<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, igl::SignedDistanceType, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::signed_distance_pseudonormal<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, double&, double&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template void igl::signed_distance<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::SignedDistanceType, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar igl::signed_distance_pseudonormal<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+template void igl::signed_distance_pseudonormal<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::signed_distance<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::SignedDistanceType, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::signed_distance_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, double, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::WindingNumberAABB<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, double&, double&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&);
+template Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar igl::signed_distance_winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(igl::AABB<Eigen::Matrix<double, -1, -1, 0, -1, -1>, 3> const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, igl::WindingNumberAABB<Eigen::Matrix<double, 3, 1, 0, 3, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
+#endif
diff --git a/xs/src/igl/signed_distance.h b/xs/src/igl/signed_distance.h
new file mode 100644
index 000000000..3b178d304
--- /dev/null
+++ b/xs/src/igl/signed_distance.h
@@ -0,0 +1,245 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SIGNED_DISTANCE_H
+#define IGL_SIGNED_DISTANCE_H
+
+#include "igl_inline.h"
+#include "AABB.h"
+#include "WindingNumberAABB.h"
+#include <Eigen/Core>
+#include <vector>
+namespace igl
+{
+ enum SignedDistanceType
+ {
+ // Use fast pseudo-normal test [Bærentzen & Aanæs 2005]
+ SIGNED_DISTANCE_TYPE_PSEUDONORMAL = 0,
+ SIGNED_DISTANCE_TYPE_WINDING_NUMBER = 1,
+ SIGNED_DISTANCE_TYPE_DEFAULT = 2,
+ SIGNED_DISTANCE_TYPE_UNSIGNED = 3,
+ NUM_SIGNED_DISTANCE_TYPE = 4
+ };
+ // Computes signed distance to a mesh
+ //
+ // Inputs:
+ // P #P by 3 list of query point positions
+ // V #V by 3 list of vertex positions
+ // F #F by ss list of triangle indices, ss should be 3 unless sign_type ==
+ // SIGNED_DISTANCE_TYPE_UNSIGNED
+ // sign_type method for computing distance _sign_ S
+ // lower_bound lower bound of distances needed {std::numeric_limits::min}
+ // upper_bound lower bound of distances needed {std::numeric_limits::max}
+ // Outputs:
+ // S #P list of smallest signed distances
+ // I #P list of facet indices corresponding to smallest distances
+ // C #P by 3 list of closest points
+ // N #P by 3 list of closest normals (only set if
+ // sign_type=SIGNED_DISTANCE_TYPE_PSEUDONORMAL)
+ //
+ // Known bugs: This only computes distances to triangles. So unreferenced
+ // vertices and degenerate triangles are ignored.
+ template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedI,
+ typename DerivedC,
+ typename DerivedN>
+ IGL_INLINE void signed_distance(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const SignedDistanceType sign_type,
+ const typename DerivedV::Scalar lower_bound,
+ const typename DerivedV::Scalar upper_bound,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Default bounds
+ template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedS,
+ typename DerivedI,
+ typename DerivedC,
+ typename DerivedN>
+ IGL_INLINE void signed_distance(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const SignedDistanceType sign_type,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Computes signed distance to mesh
+ //
+ // Inputs:
+ // tree AABB acceleration tree (see AABB.h)
+ // F #F by 3 list of triangle indices
+ // FN #F by 3 list of triangle normals
+ // VN #V by 3 list of vertex normals (ANGLE WEIGHTING)
+ // EN #E by 3 list of edge normals (UNIFORM WEIGHTING)
+ // EMAP #F*3 mapping edges in F to E
+ // q Query point
+ // Returns signed distance to mesh
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename Derivedq>
+ IGL_INLINE typename DerivedV::Scalar signed_distance_pseudonormal(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const Eigen::MatrixBase<Derivedq> & q);
+ template <
+ typename DerivedP,
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename DerivedS,
+ typename DerivedI,
+ typename DerivedC,
+ typename DerivedN>
+ IGL_INLINE void signed_distance_pseudonormal(
+ const Eigen::MatrixBase<DerivedP> & P,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ Eigen::PlainObjectBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedI> & I,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedN> & N);
+ // Outputs:
+ // s sign
+ // sqrd squared distance
+ // i closest primitive
+ // c closest point
+ // n normal
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedFN,
+ typename DerivedVN,
+ typename DerivedEN,
+ typename DerivedEMAP,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc,
+ typename Derivedn>
+ IGL_INLINE void signed_distance_pseudonormal(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedFN> & FN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Eigen::PlainObjectBase<Derivedn> & n);
+ template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedEN,
+ typename DerivedVN,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc,
+ typename Derivedn>
+ IGL_INLINE void signed_distance_pseudonormal(
+ const AABB<DerivedV,2> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEN> & EN,
+ const Eigen::MatrixBase<DerivedVN> & VN,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c,
+ Eigen::PlainObjectBase<Derivedn> & n);
+ // Inputs:
+ // tree AABB acceleration tree (see cgal/point_mesh_squared_distance.h)
+ // hier Winding number evaluation hierarchy
+ // q Query point
+ // Returns signed distance to mesh
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedq>
+ IGL_INLINE typename DerivedV::Scalar signed_distance_winding_number(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const igl::WindingNumberAABB<Derivedq,DerivedV,DerivedF> & hier,
+ const Eigen::MatrixBase<Derivedq> & q);
+ // Outputs:
+ // s sign
+ // sqrd squared distance
+ // pp closest point and primitve
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc>
+ IGL_INLINE void signed_distance_winding_number(
+ const AABB<DerivedV,3> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const igl::WindingNumberAABB<Derivedq,DerivedV,DerivedF> & hier,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c);
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedq,
+ typename Scalar,
+ typename Derivedc>
+ IGL_INLINE void signed_distance_winding_number(
+ const AABB<DerivedV,2> & tree,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedq> & q,
+ Scalar & s,
+ Scalar & sqrd,
+ int & i,
+ Eigen::PlainObjectBase<Derivedc> & c);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "signed_distance.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/simplify_polyhedron.cpp b/xs/src/igl/simplify_polyhedron.cpp
new file mode 100644
index 000000000..38ba118e7
--- /dev/null
+++ b/xs/src/igl/simplify_polyhedron.cpp
@@ -0,0 +1,107 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "simplify_polyhedron.h"
+#include "decimate.h"
+#include "circulation.h"
+#include "per_face_normals.h"
+#include "infinite_cost_stopping_condition.h"
+#include <functional>
+
+IGL_INLINE void igl::simplify_polyhedron(
+ const Eigen::MatrixXd & OV,
+ const Eigen::MatrixXi & OF,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::VectorXi & J)
+{
+ // TODO: to generalize to open meshes, 0-cost should keep all incident
+ // boundary edges on their original lines. (for non-manifold meshes,
+ // igl::decimate needs to be generalized)
+
+ Eigen::MatrixXd N;
+ // Function for computing cost of collapsing edge (0 if at least one
+ // direction doesn't change pointset, inf otherwise) and placement (in lowest
+ // cost direction).
+ const auto & perfect= [&N](
+ const int e,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ double & cost,
+ Eigen::RowVectorXd & p)
+ {
+ // Function for ocmputing cost (0 or inf) of collapsing edge by placing
+ // vertex at `positive` end of edge.
+ const auto & perfect_directed = [&N](
+ const int e,
+ const bool positive,
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const Eigen::MatrixXi & E,
+ const Eigen::VectorXi & EMAP,
+ const Eigen::MatrixXi & EF,
+ const Eigen::MatrixXi & EI,
+ double & cost,
+ Eigen::RowVectorXd & p)
+ {
+ const auto vi = E(e,positive);
+ const auto vj = E(e,!positive);
+ p = V.row(vj);
+ std::vector<int> faces = igl::circulation(e,positive,F,E,EMAP,EF,EI);
+ cost = 0;
+ for(auto f : faces)
+ {
+ // Skip the faces being collapsed
+ if(f == EF(e,0) || f == EF(e,1))
+ {
+ continue;
+ }
+ const Eigen::RowVectorXd nbefore = N.row(f);
+ // Face with vi replaced with vj
+ const Eigen::RowVector3i fafter(
+ F(f,0) == vi ? vj : F(f,0),
+ F(f,1) == vi ? vj : F(f,1),
+ F(f,2) == vi ? vj : F(f,2));
+ Eigen::RowVectorXd nafter;
+ igl::per_face_normals(V,fafter,nafter);
+ const double epsilon = 1e-10;
+ // if normal changed then not feasible, break
+ if((nbefore-nafter).norm() > epsilon)
+ {
+ cost = std::numeric_limits<double>::infinity();
+ break;
+ }
+ }
+ };
+ p.resize(3);
+ double cost0, cost1;
+ Eigen::RowVectorXd p0, p1;
+ perfect_directed(e,false,V,F,E,EMAP,EF,EI,cost0,p0);
+ perfect_directed(e,true,V,F,E,EMAP,EF,EI,cost1,p1);
+ if(cost0 < cost1)
+ {
+ cost = cost0;
+ p = p0;
+ }else
+ {
+ cost = cost1;
+ p = p1;
+ }
+ };
+ igl::per_face_normals(OV,OF,N);
+ Eigen::VectorXi I;
+ igl::decimate(
+ OV,OF,
+ perfect,
+ igl::infinite_cost_stopping_condition(perfect),
+ V,F,J,I);
+}
+
diff --git a/xs/src/igl/simplify_polyhedron.h b/xs/src/igl/simplify_polyhedron.h
new file mode 100644
index 000000000..5b5018192
--- /dev/null
+++ b/xs/src/igl/simplify_polyhedron.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SIMPLIFY_POLYHEDRON_H
+#define IGL_SIMPLIFY_POLYHEDRON_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Simplify a polyhedron represented as a triangle mesh (OV,OF) by collapsing
+ // any edge that doesn't contribute to defining surface's pointset. This
+ // _would_ also make sense for open and non-manifold meshes, but the current
+ // implementation only works with closed manifold surfaces with well defined
+ // triangle normals.
+ //
+ // Inputs:
+ // OV #OV by 3 list of input mesh vertex positions
+ // OF #OF by 3 list of input mesh triangle indices into OV
+ // Outputs:
+ // V #V by 3 list of output mesh vertex positions
+ // F #F by 3 list of input mesh triangle indices into V
+ // J #F list of indices into OF of birth parents
+ IGL_INLINE void simplify_polyhedron(
+ const Eigen::MatrixXd & OV,
+ const Eigen::MatrixXi & OF,
+ Eigen::MatrixXd & V,
+ Eigen::MatrixXi & F,
+ Eigen::VectorXi & J);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "simplify_polyhedron.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/slice.cpp b/xs/src/igl/slice.cpp
new file mode 100644
index 000000000..df3a8e9ce
--- /dev/null
+++ b/xs/src/igl/slice.cpp
@@ -0,0 +1,362 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "slice.h"
+#include "colon.h"
+
+#include <vector>
+#include <unsupported/Eigen/SparseExtra>
+
+template <typename TX, typename TY>
+IGL_INLINE void igl::slice(
+ const Eigen::SparseMatrix<TX>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::SparseMatrix<TY>& Y)
+{
+#if 1
+ int xm = X.rows();
+ int xn = X.cols();
+ int ym = R.size();
+ int yn = C.size();
+
+ // special case when R or C is empty
+ if(ym == 0 || yn == 0)
+ {
+ Y.resize(ym,yn);
+ return;
+ }
+
+ assert(R.minCoeff() >= 0);
+ assert(R.maxCoeff() < xm);
+ assert(C.minCoeff() >= 0);
+ assert(C.maxCoeff() < xn);
+
+ // Build reindexing maps for columns and rows, -1 means not in map
+ std::vector<std::vector<int> > RI;
+ RI.resize(xm);
+ for(int i = 0;i<ym;i++)
+ {
+ RI[R(i)].push_back(i);
+ }
+ std::vector<std::vector<int> > CI;
+ CI.resize(xn);
+ // initialize to -1
+ for(int i = 0;i<yn;i++)
+ {
+ CI[C(i)].push_back(i);
+ }
+ // Resize output
+ Eigen::DynamicSparseMatrix<TY, Eigen::RowMajor> dyn_Y(ym,yn);
+ // Take a guess at the number of nonzeros (this assumes uniform distribution
+ // not banded or heavily diagonal)
+ dyn_Y.reserve((X.nonZeros()/(X.rows()*X.cols())) * (ym*yn));
+ // Iterate over outside
+ for(int k=0; k<X.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<TX>::InnerIterator it (X,k); it; ++it)
+ {
+ std::vector<int>::iterator rit, cit;
+ for(rit = RI[it.row()].begin();rit != RI[it.row()].end(); rit++)
+ {
+ for(cit = CI[it.col()].begin();cit != CI[it.col()].end(); cit++)
+ {
+ dyn_Y.coeffRef(*rit,*cit) = it.value();
+ }
+ }
+ }
+ }
+ Y = Eigen::SparseMatrix<TY>(dyn_Y);
+#else
+
+ // Alec: This is _not_ valid for arbitrary R,C since they don't necessary
+ // representation a strict permutation of the rows and columns: rows or
+ // columns could be removed or replicated. The removal of rows seems to be
+ // handled here (although it's not clear if there is a performance gain when
+ // the #removals >> #remains). If this is sufficiently faster than the
+ // correct code above, one could test whether all entries in R and C are
+ // unique and apply the permutation version if appropriate.
+ //
+
+ int xm = X.rows();
+ int xn = X.cols();
+ int ym = R.size();
+ int yn = C.size();
+
+ // special case when R or C is empty
+ if(ym == 0 || yn == 0)
+ {
+ Y.resize(ym,yn);
+ return;
+ }
+
+ assert(R.minCoeff() >= 0);
+ assert(R.maxCoeff() < xm);
+ assert(C.minCoeff() >= 0);
+ assert(C.maxCoeff() < xn);
+
+ // initialize row and col permutation vectors
+ Eigen::VectorXi rowIndexVec = igl::LinSpaced<Eigen::VectorXi >(xm,0,xm-1);
+ Eigen::VectorXi rowPermVec = igl::LinSpaced<Eigen::VectorXi >(xm,0,xm-1);
+ for(int i=0;i<ym;i++)
+ {
+ int pos = rowIndexVec.coeffRef(R(i));
+ if(pos != i)
+ {
+ int& val = rowPermVec.coeffRef(i);
+ std::swap(rowIndexVec.coeffRef(val),rowIndexVec.coeffRef(R(i)));
+ std::swap(rowPermVec.coeffRef(i),rowPermVec.coeffRef(pos));
+ }
+ }
+ Eigen::PermutationMatrix<Eigen::Dynamic,Eigen::Dynamic,int> rowPerm(rowIndexVec);
+
+ Eigen::VectorXi colIndexVec = igl::LinSpaced<Eigen::VectorXi >(xn,0,xn-1);
+ Eigen::VectorXi colPermVec = igl::LinSpaced<Eigen::VectorXi >(xn,0,xn-1);
+ for(int i=0;i<yn;i++)
+ {
+ int pos = colIndexVec.coeffRef(C(i));
+ if(pos != i)
+ {
+ int& val = colPermVec.coeffRef(i);
+ std::swap(colIndexVec.coeffRef(val),colIndexVec.coeffRef(C(i)));
+ std::swap(colPermVec.coeffRef(i),colPermVec.coeffRef(pos));
+ }
+ }
+ Eigen::PermutationMatrix<Eigen::Dynamic,Eigen::Dynamic,int> colPerm(colPermVec);
+
+ Eigen::SparseMatrix<T> M = (rowPerm * X);
+ Y = (M * colPerm).block(0,0,ym,yn);
+#endif
+}
+
+template <typename MatX, typename DerivedR, typename MatY>
+IGL_INLINE void igl::slice(
+ const MatX& X,
+ const Eigen::DenseBase<DerivedR> & R,
+ const int dim,
+ MatY& Y)
+{
+ Eigen::Matrix<typename DerivedR::Scalar,Eigen::Dynamic,1> C;
+ switch(dim)
+ {
+ case 1:
+ // boring base case
+ if(X.cols() == 0)
+ {
+ Y.resize(R.size(),0);
+ return;
+ }
+ igl::colon(0,X.cols()-1,C);
+ return slice(X,R,C,Y);
+ case 2:
+ // boring base case
+ if(X.rows() == 0)
+ {
+ Y.resize(0,R.size());
+ return;
+ }
+ igl::colon(0,X.rows()-1,C);
+ return slice(X,C,R,Y);
+ default:
+ assert(false && "Unsupported dimension");
+ return;
+ }
+}
+
+template <
+ typename DerivedX,
+ typename DerivedR,
+ typename DerivedC,
+ typename DerivedY>
+IGL_INLINE void igl::slice(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::DenseBase<DerivedR> & R,
+ const Eigen::DenseBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedY> & Y)
+{
+#ifndef NDEBUG
+ int xm = X.rows();
+ int xn = X.cols();
+#endif
+ int ym = R.size();
+ int yn = C.size();
+
+ // special case when R or C is empty
+ if(ym == 0 || yn == 0)
+ {
+ Y.resize(ym,yn);
+ return;
+ }
+
+ assert(R.minCoeff() >= 0);
+ assert(R.maxCoeff() < xm);
+ assert(C.minCoeff() >= 0);
+ assert(C.maxCoeff() < xn);
+
+ // Resize output
+ Y.resize(ym,yn);
+ // loop over output rows, then columns
+ for(int i = 0;i<ym;i++)
+ {
+ for(int j = 0;j<yn;j++)
+ {
+ Y(i,j) = X(R(i),C(j));
+ }
+ }
+}
+
+
+template <typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::slice(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ Eigen::PlainObjectBase<DerivedY> & Y)
+{
+ // phony column indices
+ Eigen::Matrix<int,Eigen::Dynamic,1> C;
+ C.resize(1);
+ C(0) = 0;
+ return igl::slice(X,R,C,Y);
+}
+
+template <typename DerivedX>
+IGL_INLINE DerivedX igl::slice(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R)
+{
+ DerivedX Y;
+ igl::slice(X,R,Y);
+ return Y;
+}
+
+template <typename DerivedX>
+IGL_INLINE DerivedX igl::slice(
+ const Eigen::DenseBase<DerivedX>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const int dim)
+{
+ DerivedX Y;
+ igl::slice(X,R,dim,Y);
+ return Y;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::slice<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::Matrix<double, -1, -1, 1, -1, -1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 1, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 1, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 1, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Array<bool, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Array<bool, -1, 3, 0, -1, 3> >(Eigen::Array<bool, -1, 3, 0, -1, 3> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Array<bool, -1, 3, 0, -1, 3>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, 2, 0, -1, 2>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::Matrix<int, -1, 2, 0, -1, 2> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<int, -1, 2, 0, -1, 2>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Array<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Array<int, -1, 1, 0, -1, 1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::Array<bool, -1, 1, 0, -1, 1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Array<bool, -1, 1, 0, -1, 1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<int, -1, 2, 0, -1, 2>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::SparseMatrix<bool, 0, int>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::SparseMatrix<bool, 0, int> >(Eigen::SparseMatrix<bool, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::SparseMatrix<bool, 0, int>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, 2, 0, -1, 2>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 1, -1, -1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+// generated by autoexplicit.sh
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > >(Eigen::Matrix<long, -1, 1, 0, -1, 1> const&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > >(Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > >(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::slice<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int);
+template Eigen::Matrix<double, -1, 1, 0, -1, 1> igl::slice<Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+template Eigen::Matrix<int, -1, -1, 0, -1, -1> igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int);
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template void igl::slice<Eigen::Matrix<float, -1, 1, 0, -1, 1>, Eigen::Matrix<float, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 1, 0, -1, 1> >&);
+template void igl::slice<std::complex<double>, std::complex<double> >(Eigen::SparseMatrix<std::complex<double>, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<std::complex<double>, 0, int>&);
+template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int);
+template void igl::slice<Eigen::SparseMatrix<double, 0, int>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::SparseMatrix<double, 0, int> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::slice<double, double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::slice<Eigen::SparseMatrix<double, 0, int>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::SparseMatrix<double, 0, int> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::slice<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice<Eigen::SparseMatrix<int, 0, int>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::SparseMatrix<int, 0, int> >(Eigen::SparseMatrix<int, 0, int> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::SparseMatrix<int, 0, int>&);
+template void igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template void igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice<int, int>(Eigen::SparseMatrix<int, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<int, 0, int>&);
+template void igl::slice<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template Eigen::Matrix<double, -1, -1, 0, -1, -1> igl::slice<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&);
+template void igl::slice<Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, Eigen::Matrix<double, -1, 3, 0, -1, 3>&);
+template void igl::slice<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::slice<unsigned int, unsigned int>(Eigen::SparseMatrix<unsigned int, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<unsigned int, 0, int>&);
+#ifdef WIN32
+template void igl::slice<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>>>(class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> const &, class Eigen::DenseBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> &);
+template void igl::slice<class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>>>(class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::DenseBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>> const &, int, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &);
+#endif
+#endif
diff --git a/xs/src/igl/slice.h b/xs/src/igl/slice.h
new file mode 100644
index 000000000..a25dfa411
--- /dev/null
+++ b/xs/src/igl/slice.h
@@ -0,0 +1,87 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SLICE_H
+#define IGL_SLICE_H
+#include "igl_inline.h"
+
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Act like the matlab X(row_indices,col_indices) operator, where
+ // row_indices, col_indices are non-negative integer indices.
+ //
+ // Inputs:
+ // X m by n matrix
+ // R list of row indices
+ // C list of column indices
+ // Output:
+ // Y #R by #C matrix
+ //
+ // See also: slice_mask
+ template <
+ typename TX,
+ typename TY>
+ IGL_INLINE void slice(
+ const Eigen::SparseMatrix<TX>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::SparseMatrix<TY>& Y);
+ // Wrapper to only slice in one direction
+ //
+ // Inputs:
+ // dim dimension to slice in 1 or 2, dim=1 --> X(R,:), dim=2 --> X(:,R)
+ //
+ // Note: For now this is just a cheap wrapper.
+ template <
+ typename MatX,
+ typename DerivedR,
+ typename MatY>
+ IGL_INLINE void slice(
+ const MatX& X,
+ const Eigen::DenseBase<DerivedR> & R,
+ const int dim,
+ MatY& Y);
+ template <
+ typename DerivedX,
+ typename DerivedR,
+ typename DerivedC,
+ typename DerivedY>
+ IGL_INLINE void slice(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::DenseBase<DerivedR> & R,
+ const Eigen::DenseBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedY> & Y);
+
+ template <typename DerivedX, typename DerivedY>
+ IGL_INLINE void slice(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ Eigen::PlainObjectBase<DerivedY> & Y);
+ // VectorXi Y = slice(X,R);
+ //
+ // This templating is bad because the return type might not have the same
+ // size as `DerivedX`. This will probably only work if DerivedX has Dynamic
+ // as it's non-trivial sizes or if the number of rows in R happens to equal
+ // the number of rows in `DerivedX`.
+ template <typename DerivedX>
+ IGL_INLINE DerivedX slice(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R);
+ template <typename DerivedX>
+ IGL_INLINE DerivedX slice(
+ const Eigen::DenseBase<DerivedX>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const int dim);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "slice.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/slice_cached.cpp b/xs/src/igl/slice_cached.cpp
new file mode 100644
index 000000000..e0f13d804
--- /dev/null
+++ b/xs/src/igl/slice_cached.cpp
@@ -0,0 +1,57 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "slice_cached.h"
+
+#include <iostream>
+#include <vector>
+#include <utility>
+#include "slice.h"
+
+template <typename TX, typename TY, typename DerivedI>
+IGL_INLINE void igl::slice_cached_precompute(
+ const Eigen::SparseMatrix<TX>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::MatrixBase<DerivedI>& data,
+ Eigen::SparseMatrix<TY>& Y
+ )
+{
+ // Create a sparse matrix whose entries are the ids
+ Eigen::SparseMatrix<unsigned> TS = X.template cast<unsigned>();
+
+ TS.makeCompressed();
+ for (unsigned i=0;i<TS.nonZeros();++i)
+ *(TS.valuePtr() + i) = i;
+
+ Eigen::SparseMatrix<unsigned> TS_sliced;
+ igl::slice(TS,R,C,TS_sliced);
+ Y = TS_sliced.cast<TY>();
+
+ data.resize(TS_sliced.nonZeros());
+ for (unsigned i=0;i<data.size();++i)
+ {
+ data[i] = *(TS_sliced.valuePtr() + i);
+ *(Y.valuePtr() + i) = *(X.valuePtr() + data[i]);
+ }
+}
+
+template <typename TX, typename TY, typename DerivedI>
+IGL_INLINE void igl::slice_cached(
+ const Eigen::SparseMatrix<TX>& X,
+ const Eigen::MatrixBase<DerivedI>& data,
+ Eigen::SparseMatrix<TY>& Y
+ )
+{
+ for (unsigned i=0; i<data.size(); ++i)
+ *(Y.valuePtr() + i) = *(X.valuePtr() + data[i]);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::slice_cached<double, double, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::slice_cached_precompute<double, double, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/slice_cached.h b/xs/src/igl/slice_cached.h
new file mode 100644
index 000000000..84ced8dc9
--- /dev/null
+++ b/xs/src/igl/slice_cached.h
@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SLICE_CACHED_H
+#define IGL_SLICE_CACHED_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+
+ // Act like the matlab X(row_indices,col_indices) operator, where row_indices,
+ // col_indices are non-negative integer indices. This is a fast version of
+ // igl::slice that can analyze and store the sparsity structure. It is slower
+ // at the irst evaluation (slice_cached_precompute), but faster on the
+ // subsequent ones.
+ //
+ // Inputs:
+ // X m by n matrix
+ // R list of row indices
+ // C list of column indices
+ //
+ // Output:
+ // Y #R by #C matrix
+ // data Temporary data used by slice_cached to repeat this operation
+ //
+ // Usage:
+ //
+ // // Construct and slice up Laplacian
+ // SparseMatrix<double> L,L_sliced;
+ // igl::cotmatrix(V,F,L);
+
+ // // Normal igl::slice call
+ // igl::slice(L,in,in,L_in_in);
+
+ // // Fast version
+ // static VectorXi data; // static or saved in a global state
+ // if (data.size() == 0)
+ // igl::slice_cached_precompute(L,in,in,data,L_sliced);
+ // else
+ // igl::slice_cached(L,data,L_sliced);
+
+template <typename TX, typename TY, typename DerivedI>
+IGL_INLINE void slice_cached_precompute(
+ const Eigen::SparseMatrix<TX>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::MatrixBase<DerivedI>& data,
+ Eigen::SparseMatrix<TY>& Y
+ );
+
+template <typename TX, typename TY, typename DerivedI>
+IGL_INLINE void slice_cached(
+ const Eigen::SparseMatrix<TX>& X,
+ const Eigen::MatrixBase<DerivedI>& data,
+ Eigen::SparseMatrix<TY>& Y
+ );
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "slice_cached.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/slice_into.cpp b/xs/src/igl/slice_into.cpp
new file mode 100644
index 000000000..aa12d9303
--- /dev/null
+++ b/xs/src/igl/slice_into.cpp
@@ -0,0 +1,153 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "slice_into.h"
+#include "colon.h"
+
+// Bug in unsupported/Eigen/SparseExtra needs iostream first
+#include <iostream>
+#include <unsupported/Eigen/SparseExtra>
+
+template <typename T>
+IGL_INLINE void igl::slice_into(
+ const Eigen::SparseMatrix<T>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::SparseMatrix<T>& Y)
+{
+
+#ifndef NDEBUG
+ int xm = X.rows();
+ int xn = X.cols();
+ assert(R.size() == xm);
+ assert(C.size() == xn);
+ int ym = Y.size();
+ int yn = Y.size();
+ assert(R.minCoeff() >= 0);
+ assert(R.maxCoeff() < ym);
+ assert(C.minCoeff() >= 0);
+ assert(C.maxCoeff() < yn);
+#endif
+
+ // create temporary dynamic sparse matrix
+ Eigen::DynamicSparseMatrix<T, Eigen::RowMajor> dyn_Y(Y);
+ // Iterate over outside
+ for(int k=0; k<X.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<T>::InnerIterator it (X,k); it; ++it)
+ {
+ dyn_Y.coeffRef(R(it.row()),C(it.col())) = it.value();
+ }
+ }
+ Y = Eigen::SparseMatrix<T>(dyn_Y);
+}
+
+template <typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::slice_into(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::PlainObjectBase<DerivedY> & Y)
+{
+
+ int xm = X.rows();
+ int xn = X.cols();
+#ifndef NDEBUG
+ assert(R.size() == xm);
+ assert(C.size() == xn);
+ int ym = Y.size();
+ int yn = Y.size();
+ assert(R.minCoeff() >= 0);
+ assert(R.maxCoeff() < ym);
+ assert(C.minCoeff() >= 0);
+ assert(C.maxCoeff() < yn);
+#endif
+
+ // Build reindexing maps for columns and rows, -1 means not in map
+ Eigen::Matrix<int,Eigen::Dynamic,1> RI;
+ RI.resize(xm);
+ for(int i = 0;i<xm;i++)
+ {
+ for(int j = 0;j<xn;j++)
+ {
+ Y(R(i),C(j)) = X(i,j);
+ }
+ }
+}
+
+template <typename MatX, typename MatY>
+IGL_INLINE void igl::slice_into(
+ const MatX& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const int dim,
+ MatY& Y)
+{
+ Eigen::VectorXi C;
+ switch(dim)
+ {
+ case 1:
+ assert(R.size() == X.rows());
+ // boring base case
+ if(X.cols() == 0)
+ {
+ return;
+ }
+ igl::colon(0,X.cols()-1,C);
+ return slice_into(X,R,C,Y);
+ case 2:
+ assert(R.size() == X.cols());
+ // boring base case
+ if(X.rows() == 0)
+ {
+ return;
+ }
+ igl::colon(0,X.rows()-1,C);
+ return slice_into(X,C,R,Y);
+ default:
+ assert(false && "Unsupported dimension");
+ return;
+ }
+}
+
+template <typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::slice_into(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ Eigen::PlainObjectBase<DerivedY> & Y)
+{
+ // phony column indices
+ Eigen::Matrix<int,Eigen::Dynamic,1> C;
+ C.resize(1);
+ C(0) = 0;
+ return igl::slice_into(X,R,C,Y);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::slice_into<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::Matrix<int, -1, 1, 0, -1, 1>&);
+// generated by autoexplicit.sh
+template void igl::slice_into<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > >(Eigen::Matrix<double, -1, 2, 0, -1, 2> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice_into<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, -1, true>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > >(Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1>, -1, -1, true> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice_into<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::slice_into<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > >(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::slice_into<double>(Eigen::SparseMatrix<double, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::slice_into<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::Matrix<double, -1, 1, 0, -1, 1>&);
+template void igl::slice_into<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::slice_into<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+template void igl::slice_into<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::slice_into<Eigen::SparseMatrix<double, 0, int>, Eigen::SparseMatrix<double, 0, int> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::slice_into<int>(Eigen::SparseMatrix<int, 0, int> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<int, 0, int>&);
+template void igl::slice_into<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice_into<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice_into<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, int, Eigen::Matrix<int, -1, -1, 0, -1, -1>&);
+template void igl::slice_into<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/slice_into.h b/xs/src/igl/slice_into.h
new file mode 100644
index 000000000..83bd8f523
--- /dev/null
+++ b/xs/src/igl/slice_into.h
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SLICE_INTO_H
+#define IGL_SLICE_INTO_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Act like the matlab Y(row_indices,col_indices) = X
+ //
+ // Inputs:
+ // X xm by xn rhs matrix
+ // R list of row indices
+ // C list of column indices
+ // Y ym by yn lhs matrix
+ // Output:
+ // Y ym by yn lhs matrix, same as input but Y(R,C) = X
+ template <typename T>
+ IGL_INLINE void slice_into(
+ const Eigen::SparseMatrix<T>& X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::SparseMatrix<T>& Y);
+
+ template <typename DerivedX, typename DerivedY>
+ IGL_INLINE void slice_into(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & C,
+ Eigen::PlainObjectBase<DerivedY> & Y);
+ // Wrapper to only slice in one direction
+ //
+ // Inputs:
+ // dim dimension to slice in 1 or 2, dim=1 --> X(R,:), dim=2 --> X(:,R)
+ //
+ // Note: For now this is just a cheap wrapper.
+ template <typename MatX, typename MatY>
+ IGL_INLINE void slice_into(
+ const MatX & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ const int dim,
+ MatY& Y);
+
+ template <typename DerivedX, typename DerivedY>
+ IGL_INLINE void slice_into(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Matrix<int,Eigen::Dynamic,1> & R,
+ Eigen::PlainObjectBase<DerivedY> & Y);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "slice_into.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/slice_mask.cpp b/xs/src/igl/slice_mask.cpp
new file mode 100644
index 000000000..63cb82045
--- /dev/null
+++ b/xs/src/igl/slice_mask.cpp
@@ -0,0 +1,168 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "slice_mask.h"
+#include "slice.h"
+#include "find.h"
+#include <cassert>
+
+template <typename DerivedX,typename DerivedY>
+IGL_INLINE void igl::slice_mask(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & C,
+ Eigen::PlainObjectBase<DerivedY> & Y)
+{
+ int xm = X.rows();
+ int xn = X.cols();
+ int ym = R.count();
+ int yn = C.count();
+ assert(R.size() == X.rows() && "R.size() should match X.rows()");
+ assert(C.size() == X.cols() && "C.size() should match X.cols()");
+ Y.resize(ym,yn);
+ {
+ int yi = 0;
+ for(int i = 0;i<xm;i++)
+ {
+ if(R(i))
+ {
+ int yj = 0;
+ for(int j = 0;j<xn;j++)
+ {
+ if(C(j))
+ {
+ Y(yi,yj) = X(i,j);
+ yj++;
+ }
+ }
+ yi++;
+ }
+ }
+ }
+}
+
+template <typename DerivedX, typename DerivedY>
+IGL_INLINE void igl::slice_mask(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY> & Y)
+{
+ switch(dim)
+ {
+ case 1:
+ {
+ const int ym = R.count();
+ assert(X.rows() == R.size() && "X.rows() should match R.size()");
+ Y.resize(ym,X.cols());
+ {
+ int yi = 0;
+ for(int i = 0;i<X.rows();i++)
+ {
+ if(R(i))
+ {
+ Y.row(yi++) = X.row(i);
+ }
+ }
+ }
+ return;
+ }
+ case 2:
+ {
+ const auto & C = R;
+ const int yn = C.count();
+ Y.resize(X.rows(),yn);
+ assert(X.cols() == R.size() && "X.cols() should match R.size()");
+ {
+ int yj = 0;
+ for(int j = 0;j<X.cols();j++)
+ {
+ if(C(j))
+ {
+ Y.col(yj++) = X.col(j);
+ }
+ }
+ }
+ return;
+ }
+ default:
+ assert(false && "Unsupported dimension");
+ return;
+ }
+}
+
+template <typename DerivedX>
+IGL_INLINE DerivedX igl::slice_mask(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & C)
+{
+ DerivedX Y;
+ igl::slice_mask(X,R,C,Y);
+ return Y;
+}
+
+template <typename DerivedX>
+IGL_INLINE DerivedX igl::slice_mask(
+ const Eigen::DenseBase<DerivedX>& X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const int dim)
+{
+ DerivedX Y;
+ igl::slice_mask(X,R,dim,Y);
+ return Y;
+}
+
+
+template <typename XType, typename YType>
+IGL_INLINE void igl::slice_mask(
+ const Eigen::SparseMatrix<XType> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const int dim,
+ Eigen::SparseMatrix<YType> & Y)
+{
+ // Cheapskate solution
+ Eigen::VectorXi Ri;
+ find(R,Ri);
+ return slice(X,Ri,dim,Y);
+}
+
+template <typename XType, typename YType>
+IGL_INLINE void igl::slice_mask(
+ const Eigen::SparseMatrix<XType> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & C,
+ Eigen::SparseMatrix<YType> & Y)
+{
+ // Cheapskate solution
+ Eigen::VectorXi Ri;
+ find(R,Ri);
+ Eigen::VectorXi Ci;
+ find(C,Ci);
+ return slice(X,Ri,Ci,Y);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::Matrix<int, -1, 3, 1, -1, 3> igl::slice_mask<Eigen::Matrix<int, -1, 3, 1, -1, 3> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int);
+// generated by autoexplicit.sh
+template Eigen::Matrix<int, -1, 1, 0, -1, 1> igl::slice_mask<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int);
+// generated by autoexplicit.sh
+template Eigen::Array<int, -1, 3, 1, -1, 3> igl::slice_mask<Eigen::Array<int, -1, 3, 1, -1, 3> >(Eigen::DenseBase<Eigen::Array<int, -1, 3, 1, -1, 3> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int);
+// generated by autoexplicit.sh
+template void igl::slice_mask<bool, bool>(Eigen::SparseMatrix<bool, 0, int> const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::SparseMatrix<bool, 0, int>&);
+template void igl::slice_mask<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+template void igl::slice_mask<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::slice_mask<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice_mask<Eigen::Array<bool, -1, 1, 0, -1, 1>, Eigen::Array<bool, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Array<bool, -1, 1, 0, -1, 1> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Array<bool, -1, 1, 0, -1, 1> >&);
+template void igl::slice_mask<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice_mask<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice_mask<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::slice_mask<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::slice_mask<Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Array<bool, -1, 1, 0, -1, 1> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/slice_mask.h b/xs/src/igl/slice_mask.h
new file mode 100644
index 000000000..0a0dcda7c
--- /dev/null
+++ b/xs/src/igl/slice_mask.h
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SLICE_MASK_H
+#define IGL_SLICE_MASK_H
+#include "igl_inline.h"
+
+#include <Eigen/Sparse>
+#include <Eigen/Core>
+namespace igl
+{
+ // Act like the matlab X(row_mask,col_mask) operator, where
+ // row_mask, col_mask are non-negative integer indices.
+ //
+ // Inputs:
+ // X m by n matrix
+ // R m list of row bools
+ // C n list of column bools
+ // Output:
+ // Y #trues-in-R by #trues-in-C matrix
+ //
+ // See also: slice_mask
+
+ template <typename DerivedX,typename DerivedY>
+ IGL_INLINE void slice_mask(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & C,
+ Eigen::PlainObjectBase<DerivedY> & Y);
+ template <typename DerivedX,typename DerivedY>
+ IGL_INLINE void slice_mask(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedY> & Y);
+ //
+ // This templating is bad because the return type might not have the same
+ // size as `DerivedX`. This will probably only work if DerivedX has Dynamic
+ // as it's non-trivial sizes or if the number of rows in R happens to equal
+ // the number of rows in `DerivedX`.
+ template <typename DerivedX>
+ IGL_INLINE DerivedX slice_mask(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & C);
+ template <typename DerivedX>
+ IGL_INLINE DerivedX slice_mask(
+ const Eigen::DenseBase<DerivedX> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const int dim);
+ template <typename XType, typename YType>
+ IGL_INLINE void slice_mask(
+ const Eigen::SparseMatrix<XType> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const int dim,
+ Eigen::SparseMatrix<YType> & Y);
+ template <typename XType, typename YType>
+ IGL_INLINE void slice_mask(
+ const Eigen::SparseMatrix<XType> & X,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & R,
+ const Eigen::Array<bool,Eigen::Dynamic,1> & C,
+ Eigen::SparseMatrix<YType> & Y);
+}
+
+
+#ifndef IGL_STATIC_LIBRARY
+# include "slice_mask.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/slice_tets.cpp b/xs/src/igl/slice_tets.cpp
new file mode 100644
index 000000000..dbe042fa1
--- /dev/null
+++ b/xs/src/igl/slice_tets.cpp
@@ -0,0 +1,356 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "slice_tets.h"
+#include "LinSpaced.h"
+#include "sort.h"
+#include "edges.h"
+#include "slice.h"
+#include "cat.h"
+#include "ismember.h"
+#include "unique_rows.h"
+#include <cassert>
+#include <algorithm>
+#include <vector>
+
+template <
+ typename DerivedV,
+ typename DerivedT,
+ typename DerivedS,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedJ,
+ typename BCType>
+IGL_INLINE void igl::slice_tets(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ const Eigen::MatrixBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSF>& SF,
+ Eigen::PlainObjectBase<DerivedJ>& J,
+ Eigen::SparseMatrix<BCType> & BC)
+{
+ Eigen::MatrixXi sE;
+ Eigen::Matrix<typename DerivedSV::Scalar,Eigen::Dynamic,1> lambda;
+ igl::slice_tets(V,T,S,SV,SF,J,sE,lambda);
+ const int ns = SV.rows();
+ std::vector<Eigen::Triplet<BCType> > BCIJV(ns*2);
+ for(int i = 0;i<ns;i++)
+ {
+ BCIJV[2*i+0] = Eigen::Triplet<BCType>(i,sE(i,0), lambda(i));
+ BCIJV[2*i+1] = Eigen::Triplet<BCType>(i,sE(i,1),1.0-lambda(i));
+ }
+ BC.resize(SV.rows(),V.rows());
+ BC.setFromTriplets(BCIJV.begin(),BCIJV.end());
+}
+
+template <
+ typename DerivedV,
+ typename DerivedT,
+ typename DerivedS,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedJ>
+IGL_INLINE void igl::slice_tets(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ const Eigen::MatrixBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSF>& SF,
+ Eigen::PlainObjectBase<DerivedJ>& J)
+{
+ Eigen::MatrixXi sE;
+ Eigen::Matrix<typename DerivedSV::Scalar,Eigen::Dynamic,1> lambda;
+ igl::slice_tets(V,T,S,SV,SF,J,sE,lambda);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedT,
+ typename DerivedS,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedJ,
+ typename DerivedsE,
+ typename Derivedlambda>
+IGL_INLINE void igl::slice_tets(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ const Eigen::MatrixBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSF>& SF,
+ Eigen::PlainObjectBase<DerivedJ>& J,
+ Eigen::PlainObjectBase<DerivedsE>& sE,
+ Eigen::PlainObjectBase<Derivedlambda>& lambda)
+{
+
+ using namespace Eigen;
+ using namespace std;
+ assert(V.cols() == 3 && "V should be #V by 3");
+ assert(T.cols() == 4 && "T should be #T by 4");
+
+ static const Eigen::Matrix<int,12,4> flipped_order =
+ (Eigen::Matrix<int,12,4>(12,4)<<
+ 3,2,0,1,
+ 3,1,2,0,
+ 3,0,1,2,
+ 2,3,1,0,
+ 2,1,0,3,
+ 2,0,3,1,
+ 1,3,0,2,
+ 1,2,3,0,
+ 1,0,2,3,
+ 0,3,2,1,
+ 0,2,1,3,
+ 0,1,3,2
+ ).finished();
+
+ // number of tets
+ const size_t m = T.rows();
+
+ typedef typename DerivedS::Scalar Scalar;
+ typedef typename DerivedT::Scalar Index;
+ typedef Matrix<Scalar,Dynamic,1> VectorXS;
+ typedef Matrix<Scalar,Dynamic,4> MatrixX4S;
+ typedef Matrix<Scalar,Dynamic,3> MatrixX3S;
+ typedef Matrix<Scalar,Dynamic,2> MatrixX2S;
+ typedef Matrix<Index,Dynamic,4> MatrixX4I;
+ typedef Matrix<Index,Dynamic,3> MatrixX3I;
+ typedef Matrix<Index,Dynamic,2> MatrixX2I;
+ typedef Matrix<Index,Dynamic,1> VectorXI;
+ typedef Array<bool,Dynamic,1> ArrayXb;
+
+ MatrixX4S IT(m,4);
+ for(size_t t = 0;t<m;t++)
+ {
+ for(size_t c = 0;c<4;c++)
+ {
+ IT(t,c) = S(T(t,c));
+ }
+ }
+
+ // Essentially, just a glorified slice(X,1)
+ //
+ // Inputs:
+ // T #T by 4 list of tet indices into V
+ // IT #IT by 4 list of isosurface values at each tet
+ // I #I list of bools whether to grab data corresponding to each tet
+ const auto & extract_rows = [](
+ const MatrixBase<DerivedT> & T,
+ const MatrixX4S & IT,
+ const ArrayXb & I,
+ MatrixX4I & TI,
+ MatrixX4S & ITI,
+ VectorXI & JI)
+ {
+ const Index num_I = std::count(I.data(),I.data()+I.size(),true);
+ TI.resize(num_I,4);
+ ITI.resize(num_I,4);
+ JI.resize(num_I,1);
+ {
+ size_t k = 0;
+ for(size_t t = 0;t<(size_t)T.rows();t++)
+ {
+ if(I(t))
+ {
+ TI.row(k) = T.row(t);
+ ITI.row(k) = IT.row(t);
+ JI(k) = t;
+ k++;
+ }
+ }
+ assert(k == num_I);
+ }
+ };
+
+ ArrayXb I13 = (IT.array()<0).rowwise().count()==1;
+ ArrayXb I31 = (IT.array()>0).rowwise().count()==1;
+ ArrayXb I22 = (IT.array()<0).rowwise().count()==2;
+ MatrixX4I T13,T31,T22;
+ MatrixX4S IT13,IT31,IT22;
+ VectorXI J13,J31,J22;
+ extract_rows(T,IT,I13,T13,IT13,J13);
+ extract_rows(T,IT,I31,T31,IT31,J31);
+ extract_rows(T,IT,I22,T22,IT22,J22);
+
+ const auto & apply_sort4 = [] (
+ const MatrixX4I & T,
+ const MatrixX4I & sJ,
+ MatrixX4I & sT)
+ {
+ sT.resize(T.rows(),4);
+ for(size_t t = 0;t<(size_t)T.rows();t++)
+ {
+ for(size_t c = 0;c<4;c++)
+ {
+ sT(t,c) = T(t,sJ(t,c));
+ }
+ }
+ };
+
+ const auto & apply_sort2 = [] (
+ const MatrixX2I & E,
+ const MatrixX2I & sJ,
+ Eigen::PlainObjectBase<DerivedsE>& sE)
+ {
+ sE.resize(E.rows(),2);
+ for(size_t t = 0;t<(size_t)E.rows();t++)
+ {
+ for(size_t c = 0;c<2;c++)
+ {
+ sE(t,c) = E(t,sJ(t,c));
+ }
+ }
+ };
+
+ const auto & one_below = [&apply_sort4](
+ const MatrixX4I & T,
+ const MatrixX4S & IT,
+ MatrixX2I & U,
+ MatrixX3I & SF)
+ {
+ // Number of tets
+ const size_t m = T.rows();
+ if(m == 0)
+ {
+ U.resize(0,2);
+ SF.resize(0,3);
+ return;
+ }
+ MatrixX4S sIT;
+ MatrixX4I sJ;
+ sort(IT,2,true,sIT,sJ);
+ MatrixX4I sT;
+ apply_sort4(T,sJ,sT);
+ U.resize(3*m,2);
+ U<<
+ sT.col(0),sT.col(1),
+ sT.col(0),sT.col(2),
+ sT.col(0),sT.col(3);
+ SF.resize(m,3);
+ for(size_t c = 0;c<3;c++)
+ {
+ SF.col(c) =
+ igl::LinSpaced<
+ Eigen::Matrix<typename DerivedSF::Scalar,Eigen::Dynamic,1> >
+ (m,0+c*m,(m-1)+c*m);
+ }
+ ArrayXb flip;
+ {
+ VectorXi _;
+ ismember_rows(sJ,flipped_order,flip,_);
+ }
+ for(int i = 0;i<m;i++)
+ {
+ if(flip(i))
+ {
+ SF.row(i) = SF.row(i).reverse().eval();
+ }
+ }
+ };
+
+ const auto & two_below = [&apply_sort4](
+ const MatrixX4I & T,
+ const MatrixX4S & IT,
+ MatrixX2I & U,
+ MatrixX3I & SF)
+ {
+ // Number of tets
+ const size_t m = T.rows();
+ if(m == 0)
+ {
+ U.resize(0,2);
+ SF.resize(0,3);
+ return;
+ }
+ MatrixX4S sIT;
+ MatrixX4I sJ;
+ sort(IT,2,true,sIT,sJ);
+ MatrixX4I sT;
+ apply_sort4(T,sJ,sT);
+ U.resize(4*m,2);
+ U<<
+ sT.col(0),sT.col(2),
+ sT.col(0),sT.col(3),
+ sT.col(1),sT.col(2),
+ sT.col(1),sT.col(3);
+ SF.resize(2*m,3);
+ SF.block(0,0,m,1) = igl::LinSpaced<VectorXI >(m,0+0*m,(m-1)+0*m);
+ SF.block(0,1,m,1) = igl::LinSpaced<VectorXI >(m,0+1*m,(m-1)+1*m);
+ SF.block(0,2,m,1) = igl::LinSpaced<VectorXI >(m,0+3*m,(m-1)+3*m);
+ SF.block(m,0,m,1) = igl::LinSpaced<VectorXI >(m,0+0*m,(m-1)+0*m);
+ SF.block(m,1,m,1) = igl::LinSpaced<VectorXI >(m,0+3*m,(m-1)+3*m);
+ SF.block(m,2,m,1) = igl::LinSpaced<VectorXI >(m,0+2*m,(m-1)+2*m);
+ ArrayXb flip;
+ {
+ VectorXi _;
+ ismember_rows(sJ,flipped_order,flip,_);
+ }
+ for(int i = 0;i<m;i++)
+ {
+ if(flip(i))
+ {
+ SF.row(i ) = SF.row(i ).reverse().eval();
+ SF.row(i+m) = SF.row(i+m).reverse().eval();
+ }
+ }
+ };
+
+ MatrixX3I SF13,SF31,SF22;
+ MatrixX2I U13,U31,U22;
+ one_below(T13, IT13,U13,SF13);
+ one_below(T31,-IT31,U31,SF31);
+ two_below(T22, IT22,U22,SF22);
+ // https://forum.kde.org/viewtopic.php?f=74&t=107974
+ const MatrixX2I U =
+ (MatrixX2I(U13.rows()+ U31.rows()+ U22.rows(),2)<<U13,U31,U22).finished();
+ MatrixX2I sU;
+ {
+ MatrixX2I _;
+ sort(U,2,true,sU,_);
+ }
+ MatrixX2I E;
+ VectorXI uI,uJ;
+ unique_rows(sU,E,uI,uJ);
+ MatrixX2S IE(E.rows(),2);
+ for(size_t t = 0;t<E.rows();t++)
+ {
+ for(size_t c = 0;c<2;c++)
+ {
+ IE(t,c) = S(E(t,c));
+ }
+ }
+ MatrixX2S sIE;
+ MatrixX2I sJ;
+ sort(IE,2,true,sIE,sJ);
+ apply_sort2(E,sJ,sE);
+ lambda = sIE.col(1).array() / (sIE.col(1)-sIE.col(0)).array();
+ SV.resize(sE.rows(),V.cols());
+ for(int e = 0;e<sE.rows();e++)
+ {
+ SV.row(e) = V.row(sE(e,0)).template cast<Scalar>()*lambda(e) +
+ V.row(sE(e,1)).template cast<Scalar>()*(1.0-lambda(e));
+ }
+ SF.resize( SF13.rows()+SF31.rows()+SF22.rows(),3);
+ SF<<
+ SF13,
+ U13.rows()+ SF31.rowwise().reverse().array(),
+ U13.rows()+U31.rows()+SF22.array();
+
+ std::for_each(
+ SF.data(),
+ SF.data()+SF.size(),
+ [&uJ](typename DerivedSF::Scalar & i){i=uJ(i);});
+
+ J.resize(SF.rows());
+ J<<J13,J31,J22,J22;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::slice_tets<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, double>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/slice_tets.h b/xs/src/igl/slice_tets.h
new file mode 100644
index 000000000..349c5d790
--- /dev/null
+++ b/xs/src/igl/slice_tets.h
@@ -0,0 +1,96 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SLICE_TETS_H
+#define IGL_SLICE_TETS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+#include <vector>
+
+namespace igl
+{
+ // SLICE_TETS Slice through a tet mesh (V,T) along a given plane (via its
+ // implicit equation).
+ //
+ // Inputs:
+ // V #V by 3 list of tet mesh vertices
+ // T #T by 4 list of tet indices into V
+ //// plane list of 4 coefficients in the plane equation: [x y z 1]'*plane = 0
+ // S #V list of values so that S = 0 is the desired isosurface
+ // Outputs:
+ // SV #SV by 3 list of triangle mesh vertices along slice
+ // SF #SF by 3 list of triangles indices into SV
+ // J #SF list of indices into T revealing from which tet each faces comes
+ // BC #SU by #V list of barycentric coordinates (or more generally: linear
+ // interpolation coordinates) so that SV = BC*V
+ //
+ template <
+ typename DerivedV,
+ typename DerivedT,
+ typename DerivedS,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedJ,
+ typename BCType>
+ IGL_INLINE void slice_tets(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ const Eigen::MatrixBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSF>& SF,
+ Eigen::PlainObjectBase<DerivedJ>& J,
+ Eigen::SparseMatrix<BCType> & BC);
+ template <
+ typename DerivedV,
+ typename DerivedT,
+ typename DerivedS,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedJ>
+ IGL_INLINE void slice_tets(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ const Eigen::MatrixBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSF>& SF,
+ Eigen::PlainObjectBase<DerivedJ>& J);
+ // Outputs:
+ // sE #SV by 2 list of sorted edge indices into V
+ // lambda #SV by 1 list of parameters along each edge in sE so that:
+ // SV(i,:) = V(sE(i,1),:)*lambda(i) + V(sE(i,2),:)*(1-lambda(i));
+ template <
+ typename DerivedV,
+ typename DerivedT,
+ typename DerivedS,
+ typename DerivedSV,
+ typename DerivedSF,
+ typename DerivedJ,
+ typename DerivedsE,
+ typename Derivedlambda
+ >
+ IGL_INLINE void slice_tets(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ const Eigen::MatrixBase<DerivedS> & S,
+ Eigen::PlainObjectBase<DerivedSV>& SV,
+ Eigen::PlainObjectBase<DerivedSF>& SF,
+ Eigen::PlainObjectBase<DerivedJ>& J,
+ Eigen::PlainObjectBase<DerivedsE>& sE,
+ Eigen::PlainObjectBase<Derivedlambda>& lambda);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "slice_tets.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/slim.cpp b/xs/src/igl/slim.cpp
new file mode 100644
index 000000000..a88674274
--- /dev/null
+++ b/xs/src/igl/slim.cpp
@@ -0,0 +1,961 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "slim.h"
+
+#include "boundary_loop.h"
+#include "cotmatrix.h"
+#include "edge_lengths.h"
+#include "grad.h"
+#include "local_basis.h"
+#include "repdiag.h"
+#include "vector_area_matrix.h"
+#include "arap.h"
+#include "cat.h"
+#include "doublearea.h"
+#include "grad.h"
+#include "local_basis.h"
+#include "per_face_normals.h"
+#include "slice_into.h"
+#include "volume.h"
+#include "polar_svd.h"
+#include "flip_avoiding_line_search.h"
+
+#include <iostream>
+#include <map>
+#include <set>
+#include <vector>
+
+#include <Eigen/IterativeLinearSolvers>
+#include <Eigen/SparseCholesky>
+#include <Eigen/IterativeLinearSolvers>
+
+#include "Timer.h"
+#include "sparse_cached.h"
+#include "AtA_cached.h"
+
+#ifdef CHOLMOD
+#include <Eigen/CholmodSupport>
+#endif
+
+namespace igl
+{
+ namespace slim
+ {
+ // Definitions of internal functions
+ IGL_INLINE void compute_surface_gradient_matrix(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F,
+ const Eigen::MatrixXd &F1, const Eigen::MatrixXd &F2,
+ Eigen::SparseMatrix<double> &D1, Eigen::SparseMatrix<double> &D2);
+ IGL_INLINE void buildA(igl::SLIMData& s, std::vector<Eigen::Triplet<double> > & IJV);
+ IGL_INLINE void buildRhs(igl::SLIMData& s, const Eigen::SparseMatrix<double> &A);
+ IGL_INLINE void add_soft_constraints(igl::SLIMData& s, Eigen::SparseMatrix<double> &L);
+ IGL_INLINE double compute_energy(igl::SLIMData& s, Eigen::MatrixXd &V_new);
+ IGL_INLINE double compute_soft_const_energy(igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F,
+ Eigen::MatrixXd &V_o);
+ IGL_INLINE double compute_energy_with_jacobians(igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F, const Eigen::MatrixXd &Ji,
+ Eigen::MatrixXd &uv, Eigen::VectorXd &areas);
+ IGL_INLINE void solve_weighted_arap(igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F,
+ Eigen::MatrixXd &uv,
+ Eigen::VectorXi &soft_b_p,
+ Eigen::MatrixXd &soft_bc_p);
+ IGL_INLINE void update_weights_and_closest_rotations( igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F,
+ Eigen::MatrixXd &uv);
+ IGL_INLINE void compute_jacobians(igl::SLIMData& s, const Eigen::MatrixXd &uv);
+ IGL_INLINE void build_linear_system(igl::SLIMData& s, Eigen::SparseMatrix<double> &L);
+ IGL_INLINE void pre_calc(igl::SLIMData& s);
+
+ // Implementation
+ IGL_INLINE void compute_surface_gradient_matrix(const Eigen::MatrixXd &V, const Eigen::MatrixXi &F,
+ const Eigen::MatrixXd &F1, const Eigen::MatrixXd &F2,
+ Eigen::SparseMatrix<double> &D1, Eigen::SparseMatrix<double> &D2)
+ {
+
+ Eigen::SparseMatrix<double> G;
+ igl::grad(V, F, G);
+ Eigen::SparseMatrix<double> Dx = G.block(0, 0, F.rows(), V.rows());
+ Eigen::SparseMatrix<double> Dy = G.block(F.rows(), 0, F.rows(), V.rows());
+ Eigen::SparseMatrix<double> Dz = G.block(2 * F.rows(), 0, F.rows(), V.rows());
+
+ D1 = F1.col(0).asDiagonal() * Dx + F1.col(1).asDiagonal() * Dy + F1.col(2).asDiagonal() * Dz;
+ D2 = F2.col(0).asDiagonal() * Dx + F2.col(1).asDiagonal() * Dy + F2.col(2).asDiagonal() * Dz;
+ }
+
+ IGL_INLINE void compute_jacobians(igl::SLIMData& s, const Eigen::MatrixXd &uv)
+ {
+ if (s.F.cols() == 3)
+ {
+ // Ji=[D1*u,D2*u,D1*v,D2*v];
+ s.Ji.col(0) = s.Dx * uv.col(0);
+ s.Ji.col(1) = s.Dy * uv.col(0);
+ s.Ji.col(2) = s.Dx * uv.col(1);
+ s.Ji.col(3) = s.Dy * uv.col(1);
+ }
+ else /*tet mesh*/{
+ // Ji=[D1*u,D2*u,D3*u, D1*v,D2*v, D3*v, D1*w,D2*w,D3*w];
+ s.Ji.col(0) = s.Dx * uv.col(0);
+ s.Ji.col(1) = s.Dy * uv.col(0);
+ s.Ji.col(2) = s.Dz * uv.col(0);
+ s.Ji.col(3) = s.Dx * uv.col(1);
+ s.Ji.col(4) = s.Dy * uv.col(1);
+ s.Ji.col(5) = s.Dz * uv.col(1);
+ s.Ji.col(6) = s.Dx * uv.col(2);
+ s.Ji.col(7) = s.Dy * uv.col(2);
+ s.Ji.col(8) = s.Dz * uv.col(2);
+ }
+ }
+
+ IGL_INLINE void update_weights_and_closest_rotations(igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F,
+ Eigen::MatrixXd &uv)
+ {
+ compute_jacobians(s, uv);
+
+ const double eps = 1e-8;
+ double exp_f = s.exp_factor;
+
+ if (s.dim == 2)
+ {
+ for (int i = 0; i < s.Ji.rows(); ++i)
+ {
+ typedef Eigen::Matrix<double, 2, 2> Mat2;
+ typedef Eigen::Matrix<double, 2, 1> Vec2;
+ Mat2 ji, ri, ti, ui, vi;
+ Vec2 sing;
+ Vec2 closest_sing_vec;
+ Mat2 mat_W;
+ Vec2 m_sing_new;
+ double s1, s2;
+
+ ji(0, 0) = s.Ji(i, 0);
+ ji(0, 1) = s.Ji(i, 1);
+ ji(1, 0) = s.Ji(i, 2);
+ ji(1, 1) = s.Ji(i, 3);
+
+ igl::polar_svd(ji, ri, ti, ui, sing, vi);
+
+ s1 = sing(0);
+ s2 = sing(1);
+
+ // Update Weights according to energy
+ switch (s.slim_energy)
+ {
+ case igl::SLIMData::ARAP:
+ {
+ m_sing_new << 1, 1;
+ break;
+ }
+ case igl::SLIMData::SYMMETRIC_DIRICHLET:
+ {
+ double s1_g = 2 * (s1 - pow(s1, -3));
+ double s2_g = 2 * (s2 - pow(s2, -3));
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1)));
+ break;
+ }
+ case igl::SLIMData::LOG_ARAP:
+ {
+ double s1_g = 2 * (log(s1) / s1);
+ double s2_g = 2 * (log(s2) / s2);
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1)));
+ break;
+ }
+ case igl::SLIMData::CONFORMAL:
+ {
+ double s1_g = 1 / (2 * s2) - s2 / (2 * pow(s1, 2));
+ double s2_g = 1 / (2 * s1) - s1 / (2 * pow(s2, 2));
+
+ double geo_avg = sqrt(s1 * s2);
+ double s1_min = geo_avg;
+ double s2_min = geo_avg;
+
+ m_sing_new << sqrt(s1_g / (2 * (s1 - s1_min))), sqrt(s2_g / (2 * (s2 - s2_min)));
+
+ // change local step
+ closest_sing_vec << s1_min, s2_min;
+ ri = ui * closest_sing_vec.asDiagonal() * vi.transpose();
+ break;
+ }
+ case igl::SLIMData::EXP_CONFORMAL:
+ {
+ double s1_g = 2 * (s1 - pow(s1, -3));
+ double s2_g = 2 * (s2 - pow(s2, -3));
+
+ double geo_avg = sqrt(s1 * s2);
+ double s1_min = geo_avg;
+ double s2_min = geo_avg;
+
+ double in_exp = exp_f * ((pow(s1, 2) + pow(s2, 2)) / (2 * s1 * s2));
+ double exp_thing = exp(in_exp);
+
+ s1_g *= exp_thing * exp_f;
+ s2_g *= exp_thing * exp_f;
+
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1)));
+ break;
+ }
+ case igl::SLIMData::EXP_SYMMETRIC_DIRICHLET:
+ {
+ double s1_g = 2 * (s1 - pow(s1, -3));
+ double s2_g = 2 * (s2 - pow(s2, -3));
+
+ double in_exp = exp_f * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2));
+ double exp_thing = exp(in_exp);
+
+ s1_g *= exp_thing * exp_f;
+ s2_g *= exp_thing * exp_f;
+
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1)));
+ break;
+ }
+ }
+
+ if (std::abs(s1 - 1) < eps) m_sing_new(0) = 1;
+ if (std::abs(s2 - 1) < eps) m_sing_new(1) = 1;
+ mat_W = ui * m_sing_new.asDiagonal() * ui.transpose();
+
+ s.W_11(i) = mat_W(0, 0);
+ s.W_12(i) = mat_W(0, 1);
+ s.W_21(i) = mat_W(1, 0);
+ s.W_22(i) = mat_W(1, 1);
+
+ // 2) Update local step (doesn't have to be a rotation, for instance in case of conformal energy)
+ s.Ri(i, 0) = ri(0, 0);
+ s.Ri(i, 1) = ri(1, 0);
+ s.Ri(i, 2) = ri(0, 1);
+ s.Ri(i, 3) = ri(1, 1);
+ }
+ }
+ else
+ {
+ typedef Eigen::Matrix<double, 3, 1> Vec3;
+ typedef Eigen::Matrix<double, 3, 3> Mat3;
+ Mat3 ji;
+ Vec3 m_sing_new;
+ Vec3 closest_sing_vec;
+ const double sqrt_2 = sqrt(2);
+ for (int i = 0; i < s.Ji.rows(); ++i)
+ {
+ ji(0, 0) = s.Ji(i, 0);
+ ji(0, 1) = s.Ji(i, 1);
+ ji(0, 2) = s.Ji(i, 2);
+ ji(1, 0) = s.Ji(i, 3);
+ ji(1, 1) = s.Ji(i, 4);
+ ji(1, 2) = s.Ji(i, 5);
+ ji(2, 0) = s.Ji(i, 6);
+ ji(2, 1) = s.Ji(i, 7);
+ ji(2, 2) = s.Ji(i, 8);
+
+ Mat3 ri, ti, ui, vi;
+ Vec3 sing;
+ igl::polar_svd(ji, ri, ti, ui, sing, vi);
+
+ double s1 = sing(0);
+ double s2 = sing(1);
+ double s3 = sing(2);
+
+ // 1) Update Weights
+ switch (s.slim_energy)
+ {
+ case igl::SLIMData::ARAP:
+ {
+ m_sing_new << 1, 1, 1;
+ break;
+ }
+ case igl::SLIMData::LOG_ARAP:
+ {
+ double s1_g = 2 * (log(s1) / s1);
+ double s2_g = 2 * (log(s2) / s2);
+ double s3_g = 2 * (log(s3) / s3);
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1)));
+ break;
+ }
+ case igl::SLIMData::SYMMETRIC_DIRICHLET:
+ {
+ double s1_g = 2 * (s1 - pow(s1, -3));
+ double s2_g = 2 * (s2 - pow(s2, -3));
+ double s3_g = 2 * (s3 - pow(s3, -3));
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1)));
+ break;
+ }
+ case igl::SLIMData::EXP_SYMMETRIC_DIRICHLET:
+ {
+ double s1_g = 2 * (s1 - pow(s1, -3));
+ double s2_g = 2 * (s2 - pow(s2, -3));
+ double s3_g = 2 * (s3 - pow(s3, -3));
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1)));
+
+ double in_exp = exp_f * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2) + pow(s3, 2) + pow(s3, -2));
+ double exp_thing = exp(in_exp);
+
+ s1_g *= exp_thing * exp_f;
+ s2_g *= exp_thing * exp_f;
+ s3_g *= exp_thing * exp_f;
+
+ m_sing_new << sqrt(s1_g / (2 * (s1 - 1))), sqrt(s2_g / (2 * (s2 - 1))), sqrt(s3_g / (2 * (s3 - 1)));
+
+ break;
+ }
+ case igl::SLIMData::CONFORMAL:
+ {
+ double common_div = 9 * (pow(s1 * s2 * s3, 5. / 3.));
+
+ double s1_g = (-2 * s2 * s3 * (pow(s2, 2) + pow(s3, 2) - 2 * pow(s1, 2))) / common_div;
+ double s2_g = (-2 * s1 * s3 * (pow(s1, 2) + pow(s3, 2) - 2 * pow(s2, 2))) / common_div;
+ double s3_g = (-2 * s1 * s2 * (pow(s1, 2) + pow(s2, 2) - 2 * pow(s3, 2))) / common_div;
+
+ double closest_s = sqrt(pow(s1, 2) + pow(s3, 2)) / sqrt_2;
+ double s1_min = closest_s;
+ double s2_min = closest_s;
+ double s3_min = closest_s;
+
+ m_sing_new << sqrt(s1_g / (2 * (s1 - s1_min))), sqrt(s2_g / (2 * (s2 - s2_min))), sqrt(
+ s3_g / (2 * (s3 - s3_min)));
+
+ // change local step
+ closest_sing_vec << s1_min, s2_min, s3_min;
+ ri = ui * closest_sing_vec.asDiagonal() * vi.transpose();
+ break;
+ }
+ case igl::SLIMData::EXP_CONFORMAL:
+ {
+ // E_conf = (s1^2 + s2^2 + s3^2)/(3*(s1*s2*s3)^(2/3) )
+ // dE_conf/ds1 = (-2*(s2*s3)*(s2^2+s3^2 -2*s1^2) ) / (9*(s1*s2*s3)^(5/3))
+ // Argmin E_conf(s1): s1 = sqrt(s1^2+s2^2)/sqrt(2)
+ double common_div = 9 * (pow(s1 * s2 * s3, 5. / 3.));
+
+ double s1_g = (-2 * s2 * s3 * (pow(s2, 2) + pow(s3, 2) - 2 * pow(s1, 2))) / common_div;
+ double s2_g = (-2 * s1 * s3 * (pow(s1, 2) + pow(s3, 2) - 2 * pow(s2, 2))) / common_div;
+ double s3_g = (-2 * s1 * s2 * (pow(s1, 2) + pow(s2, 2) - 2 * pow(s3, 2))) / common_div;
+
+ double in_exp = exp_f * ((pow(s1, 2) + pow(s2, 2) + pow(s3, 2)) / (3 * pow((s1 * s2 * s3), 2. / 3)));;
+ double exp_thing = exp(in_exp);
+
+ double closest_s = sqrt(pow(s1, 2) + pow(s3, 2)) / sqrt_2;
+ double s1_min = closest_s;
+ double s2_min = closest_s;
+ double s3_min = closest_s;
+
+ s1_g *= exp_thing * exp_f;
+ s2_g *= exp_thing * exp_f;
+ s3_g *= exp_thing * exp_f;
+
+ m_sing_new << sqrt(s1_g / (2 * (s1 - s1_min))), sqrt(s2_g / (2 * (s2 - s2_min))), sqrt(
+ s3_g / (2 * (s3 - s3_min)));
+
+ // change local step
+ closest_sing_vec << s1_min, s2_min, s3_min;
+ ri = ui * closest_sing_vec.asDiagonal() * vi.transpose();
+ }
+ }
+ if (std::abs(s1 - 1) < eps) m_sing_new(0) = 1;
+ if (std::abs(s2 - 1) < eps) m_sing_new(1) = 1;
+ if (std::abs(s3 - 1) < eps) m_sing_new(2) = 1;
+ Mat3 mat_W;
+ mat_W = ui * m_sing_new.asDiagonal() * ui.transpose();
+
+ s.W_11(i) = mat_W(0, 0);
+ s.W_12(i) = mat_W(0, 1);
+ s.W_13(i) = mat_W(0, 2);
+ s.W_21(i) = mat_W(1, 0);
+ s.W_22(i) = mat_W(1, 1);
+ s.W_23(i) = mat_W(1, 2);
+ s.W_31(i) = mat_W(2, 0);
+ s.W_32(i) = mat_W(2, 1);
+ s.W_33(i) = mat_W(2, 2);
+
+ // 2) Update closest rotations (not rotations in case of conformal energy)
+ s.Ri(i, 0) = ri(0, 0);
+ s.Ri(i, 1) = ri(1, 0);
+ s.Ri(i, 2) = ri(2, 0);
+ s.Ri(i, 3) = ri(0, 1);
+ s.Ri(i, 4) = ri(1, 1);
+ s.Ri(i, 5) = ri(2, 1);
+ s.Ri(i, 6) = ri(0, 2);
+ s.Ri(i, 7) = ri(1, 2);
+ s.Ri(i, 8) = ri(2, 2);
+ } // for loop end
+
+ } // if dim end
+
+ }
+
+ IGL_INLINE void solve_weighted_arap(igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F,
+ Eigen::MatrixXd &uv,
+ Eigen::VectorXi &soft_b_p,
+ Eigen::MatrixXd &soft_bc_p)
+ {
+ using namespace Eigen;
+
+ Eigen::SparseMatrix<double> L;
+ build_linear_system(s,L);
+
+ igl::Timer t;
+
+ //t.start();
+ // solve
+ Eigen::VectorXd Uc;
+#ifndef CHOLMOD
+ if (s.dim == 2)
+ {
+ SimplicialLDLT<Eigen::SparseMatrix<double> > solver;
+ Uc = solver.compute(L).solve(s.rhs);
+ }
+ else
+ { // seems like CG performs much worse for 2D and way better for 3D
+ Eigen::VectorXd guess(uv.rows() * s.dim);
+ for (int i = 0; i < s.v_num; i++) for (int j = 0; j < s.dim; j++) guess(uv.rows() * j + i) = uv(i, j); // flatten vector
+ ConjugateGradient<Eigen::SparseMatrix<double>, Lower | Upper> cg;
+ cg.setTolerance(1e-8);
+ cg.compute(L);
+ Uc = cg.solveWithGuess(s.rhs, guess);
+ }
+#else
+ CholmodSimplicialLDLT<Eigen::SparseMatrix<double> > solver;
+ Uc = solver.compute(L).solve(s.rhs);
+#endif
+ for (int i = 0; i < s.dim; i++)
+ uv.col(i) = Uc.block(i * s.v_n, 0, s.v_n, 1);
+
+ // t.stop();
+ // std::cerr << "solve: " << t.getElapsedTime() << std::endl;
+
+ }
+
+
+ IGL_INLINE void pre_calc(igl::SLIMData& s)
+ {
+ if (!s.has_pre_calc)
+ {
+ s.v_n = s.v_num;
+ s.f_n = s.f_num;
+
+ if (s.F.cols() == 3)
+ {
+ s.dim = 2;
+ Eigen::MatrixXd F1, F2, F3;
+ igl::local_basis(s.V, s.F, F1, F2, F3);
+ compute_surface_gradient_matrix(s.V, s.F, F1, F2, s.Dx, s.Dy);
+
+ s.W_11.resize(s.f_n);
+ s.W_12.resize(s.f_n);
+ s.W_21.resize(s.f_n);
+ s.W_22.resize(s.f_n);
+ }
+ else
+ {
+ s.dim = 3;
+ Eigen::SparseMatrix<double> G;
+ igl::grad(s.V, s.F, G,
+ s.mesh_improvement_3d /*use normal gradient, or one from a "regular" tet*/);
+ s.Dx = G.block(0, 0, s.F.rows(), s.V.rows());
+ s.Dy = G.block(s.F.rows(), 0, s.F.rows(), s.V.rows());
+ s.Dz = G.block(2 * s.F.rows(), 0, s.F.rows(), s.V.rows());
+
+
+ s.W_11.resize(s.f_n);
+ s.W_12.resize(s.f_n);
+ s.W_13.resize(s.f_n);
+ s.W_21.resize(s.f_n);
+ s.W_22.resize(s.f_n);
+ s.W_23.resize(s.f_n);
+ s.W_31.resize(s.f_n);
+ s.W_32.resize(s.f_n);
+ s.W_33.resize(s.f_n);
+ }
+
+ s.Dx.makeCompressed();
+ s.Dy.makeCompressed();
+ s.Dz.makeCompressed();
+ s.Ri.resize(s.f_n, s.dim * s.dim);
+ s.Ji.resize(s.f_n, s.dim * s.dim);
+ s.rhs.resize(s.dim * s.v_num);
+
+ // flattened weight matrix
+ s.WGL_M.resize(s.dim * s.dim * s.f_n);
+ for (int i = 0; i < s.dim * s.dim; i++)
+ for (int j = 0; j < s.f_n; j++)
+ s.WGL_M(i * s.f_n + j) = s.M(j);
+
+ s.first_solve = true;
+ s.has_pre_calc = true;
+ }
+ }
+
+ IGL_INLINE void build_linear_system(igl::SLIMData& s, Eigen::SparseMatrix<double> &L)
+ {
+ // formula (35) in paper
+ std::vector<Eigen::Triplet<double> > IJV;
+
+ #ifdef SLIM_CACHED
+ buildA(s,IJV);
+ if (s.A.rows() == 0)
+ {
+ s.A = Eigen::SparseMatrix<double>(s.dim * s.dim * s.f_n, s.dim * s.v_n);
+ igl::sparse_cached_precompute(IJV,s.A_data,s.A);
+ }
+ else
+ igl::sparse_cached(IJV,s.A_data,s.A);
+ #else
+ Eigen::SparseMatrix<double> A(s.dim * s.dim * s.f_n, s.dim * s.v_n);
+ buildA(s,IJV);
+ A.setFromTriplets(IJV.begin(),IJV.end());
+ A.makeCompressed();
+ #endif
+
+ #ifdef SLIM_CACHED
+ #else
+ Eigen::SparseMatrix<double> At = A.transpose();
+ At.makeCompressed();
+ #endif
+
+ #ifdef SLIM_CACHED
+ Eigen::SparseMatrix<double> id_m(s.A.cols(), s.A.cols());
+ #else
+ Eigen::SparseMatrix<double> id_m(A.cols(), A.cols());
+ #endif
+
+ id_m.setIdentity();
+
+ // add proximal penalty
+ #ifdef SLIM_CACHED
+ s.AtA_data.W = s.WGL_M;
+ 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);
+
+ L = s.AtA + s.proximal_p * id_m; //add also a proximal
+ L.makeCompressed();
+
+ #else
+ L = At * s.WGL_M.asDiagonal() * A + s.proximal_p * id_m; //add also a proximal term
+ L.makeCompressed();
+ #endif
+
+ #ifdef SLIM_CACHED
+ buildRhs(s, s.A);
+ #else
+ buildRhs(s, A);
+ #endif
+
+ Eigen::SparseMatrix<double> OldL = L;
+ add_soft_constraints(s,L);
+ L.makeCompressed();
+ }
+
+ IGL_INLINE void add_soft_constraints(igl::SLIMData& s, Eigen::SparseMatrix<double> &L)
+ {
+ int v_n = s.v_num;
+ for (int d = 0; d < s.dim; d++)
+ {
+ for (int i = 0; i < s.b.rows(); i++)
+ {
+ int v_idx = s.b(i);
+ s.rhs(d * v_n + v_idx) += s.soft_const_p * s.bc(i, d); // rhs
+ L.coeffRef(d * v_n + v_idx, d * v_n + v_idx) += s.soft_const_p; // diagonal of matrix
+ }
+ }
+ }
+
+ IGL_INLINE double compute_energy(igl::SLIMData& s, Eigen::MatrixXd &V_new)
+ {
+ compute_jacobians(s,V_new);
+ return compute_energy_with_jacobians(s, s.V, s.F, s.Ji, V_new, s.M) +
+ compute_soft_const_energy(s, s.V, s.F, V_new);
+ }
+
+ IGL_INLINE double compute_soft_const_energy(igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F,
+ Eigen::MatrixXd &V_o)
+ {
+ double e = 0;
+ for (int i = 0; i < s.b.rows(); i++)
+ {
+ e += s.soft_const_p * (s.bc.row(i) - V_o.row(s.b(i))).squaredNorm();
+ }
+ return e;
+ }
+
+ IGL_INLINE double compute_energy_with_jacobians(igl::SLIMData& s,
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F, const Eigen::MatrixXd &Ji,
+ Eigen::MatrixXd &uv, Eigen::VectorXd &areas)
+ {
+
+ double energy = 0;
+ if (s.dim == 2)
+ {
+ Eigen::Matrix<double, 2, 2> ji;
+ for (int i = 0; i < s.f_n; i++)
+ {
+ ji(0, 0) = Ji(i, 0);
+ ji(0, 1) = Ji(i, 1);
+ ji(1, 0) = Ji(i, 2);
+ ji(1, 1) = Ji(i, 3);
+
+ typedef Eigen::Matrix<double, 2, 2> Mat2;
+ typedef Eigen::Matrix<double, 2, 1> Vec2;
+ Mat2 ri, ti, ui, vi;
+ Vec2 sing;
+ igl::polar_svd(ji, ri, ti, ui, sing, vi);
+ double s1 = sing(0);
+ double s2 = sing(1);
+
+ switch (s.slim_energy)
+ {
+ case igl::SLIMData::ARAP:
+ {
+ energy += areas(i) * (pow(s1 - 1, 2) + pow(s2 - 1, 2));
+ break;
+ }
+ case igl::SLIMData::SYMMETRIC_DIRICHLET:
+ {
+ energy += areas(i) * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2));
+ break;
+ }
+ case igl::SLIMData::EXP_SYMMETRIC_DIRICHLET:
+ {
+ energy += areas(i) * exp(s.exp_factor * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2)));
+ break;
+ }
+ case igl::SLIMData::LOG_ARAP:
+ {
+ energy += areas(i) * (pow(log(s1), 2) + pow(log(s2), 2));
+ break;
+ }
+ case igl::SLIMData::CONFORMAL:
+ {
+ energy += areas(i) * ((pow(s1, 2) + pow(s2, 2)) / (2 * s1 * s2));
+ break;
+ }
+ case igl::SLIMData::EXP_CONFORMAL:
+ {
+ energy += areas(i) * exp(s.exp_factor * ((pow(s1, 2) + pow(s2, 2)) / (2 * s1 * s2)));
+ break;
+ }
+
+ }
+
+ }
+ }
+ else
+ {
+ Eigen::Matrix<double, 3, 3> ji;
+ for (int i = 0; i < s.f_n; i++)
+ {
+ ji(0, 0) = Ji(i, 0);
+ ji(0, 1) = Ji(i, 1);
+ ji(0, 2) = Ji(i, 2);
+ ji(1, 0) = Ji(i, 3);
+ ji(1, 1) = Ji(i, 4);
+ ji(1, 2) = Ji(i, 5);
+ ji(2, 0) = Ji(i, 6);
+ ji(2, 1) = Ji(i, 7);
+ ji(2, 2) = Ji(i, 8);
+
+ typedef Eigen::Matrix<double, 3, 3> Mat3;
+ typedef Eigen::Matrix<double, 3, 1> Vec3;
+ Mat3 ri, ti, ui, vi;
+ Vec3 sing;
+ igl::polar_svd(ji, ri, ti, ui, sing, vi);
+ double s1 = sing(0);
+ double s2 = sing(1);
+ double s3 = sing(2);
+
+ switch (s.slim_energy)
+ {
+ case igl::SLIMData::ARAP:
+ {
+ energy += areas(i) * (pow(s1 - 1, 2) + pow(s2 - 1, 2) + pow(s3 - 1, 2));
+ break;
+ }
+ case igl::SLIMData::SYMMETRIC_DIRICHLET:
+ {
+ energy += areas(i) * (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2) + pow(s3, 2) + pow(s3, -2));
+ break;
+ }
+ case igl::SLIMData::EXP_SYMMETRIC_DIRICHLET:
+ {
+ energy += areas(i) * exp(s.exp_factor *
+ (pow(s1, 2) + pow(s1, -2) + pow(s2, 2) + pow(s2, -2) + pow(s3, 2) + pow(s3, -2)));
+ break;
+ }
+ case igl::SLIMData::LOG_ARAP:
+ {
+ energy += areas(i) * (pow(log(s1), 2) + pow(log(std::abs(s2)), 2) + pow(log(std::abs(s3)), 2));
+ break;
+ }
+ case igl::SLIMData::CONFORMAL:
+ {
+ energy += areas(i) * ((pow(s1, 2) + pow(s2, 2) + pow(s3, 2)) / (3 * pow(s1 * s2 * s3, 2. / 3.)));
+ break;
+ }
+ case igl::SLIMData::EXP_CONFORMAL:
+ {
+ energy += areas(i) * exp((pow(s1, 2) + pow(s2, 2) + pow(s3, 2)) / (3 * pow(s1 * s2 * s3, 2. / 3.)));
+ break;
+ }
+ }
+ }
+ }
+
+ return energy;
+ }
+
+ IGL_INLINE void buildA(igl::SLIMData& s, std::vector<Eigen::Triplet<double> > & IJV)
+ {
+ // formula (35) in paper
+ if (s.dim == 2)
+ {
+ IJV.reserve(4 * (s.Dx.outerSize() + s.Dy.outerSize()));
+
+ /*A = [W11*Dx, W12*Dx;
+ W11*Dy, W12*Dy;
+ W21*Dx, W22*Dx;
+ W21*Dy, W22*Dy];*/
+ for (int k = 0; k < s.Dx.outerSize(); ++k)
+ {
+ for (Eigen::SparseMatrix<double>::InnerIterator it(s.Dx, k); it; ++it)
+ {
+ int dx_r = it.row();
+ int dx_c = it.col();
+ double val = it.value();
+
+ IJV.push_back(Eigen::Triplet<double>(dx_r, dx_c, val * s.W_11(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(dx_r, s.v_n + dx_c, val * s.W_12(dx_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(2 * s.f_n + dx_r, dx_c, val * s.W_21(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(2 * s.f_n + dx_r, s.v_n + dx_c, val * s.W_22(dx_r)));
+ }
+ }
+
+ for (int k = 0; k < s.Dy.outerSize(); ++k)
+ {
+ for (Eigen::SparseMatrix<double>::InnerIterator it(s.Dy, k); it; ++it)
+ {
+ int dy_r = it.row();
+ int dy_c = it.col();
+ double val = it.value();
+
+ IJV.push_back(Eigen::Triplet<double>(s.f_n + dy_r, dy_c, val * s.W_11(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(s.f_n + dy_r, s.v_n + dy_c, val * s.W_12(dy_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(3 * s.f_n + dy_r, dy_c, val * s.W_21(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(3 * s.f_n + dy_r, s.v_n + dy_c, val * s.W_22(dy_r)));
+ }
+ }
+ }
+ else
+ {
+
+ /*A = [W11*Dx, W12*Dx, W13*Dx;
+ W11*Dy, W12*Dy, W13*Dy;
+ W11*Dz, W12*Dz, W13*Dz;
+ W21*Dx, W22*Dx, W23*Dx;
+ W21*Dy, W22*Dy, W23*Dy;
+ W21*Dz, W22*Dz, W23*Dz;
+ W31*Dx, W32*Dx, W33*Dx;
+ W31*Dy, W32*Dy, W33*Dy;
+ W31*Dz, W32*Dz, W33*Dz;];*/
+ IJV.reserve(9 * (s.Dx.outerSize() + s.Dy.outerSize() + s.Dz.outerSize()));
+ for (int k = 0; k < s.Dx.outerSize(); k++)
+ {
+ for (Eigen::SparseMatrix<double>::InnerIterator it(s.Dx, k); it; ++it)
+ {
+ int dx_r = it.row();
+ int dx_c = it.col();
+ double val = it.value();
+
+ IJV.push_back(Eigen::Triplet<double>(dx_r, dx_c, val * s.W_11(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(dx_r, s.v_n + dx_c, val * s.W_12(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(dx_r, 2 * s.v_n + dx_c, val * s.W_13(dx_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(3 * s.f_n + dx_r, dx_c, val * s.W_21(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(3 * s.f_n + dx_r, s.v_n + dx_c, val * s.W_22(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(3 * s.f_n + dx_r, 2 * s.v_n + dx_c, val * s.W_23(dx_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(6 * s.f_n + dx_r, dx_c, val * s.W_31(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(6 * s.f_n + dx_r, s.v_n + dx_c, val * s.W_32(dx_r)));
+ IJV.push_back(Eigen::Triplet<double>(6 * s.f_n + dx_r, 2 * s.v_n + dx_c, val * s.W_33(dx_r)));
+ }
+ }
+
+ for (int k = 0; k < s.Dy.outerSize(); k++)
+ {
+ for (Eigen::SparseMatrix<double>::InnerIterator it(s.Dy, k); it; ++it)
+ {
+ int dy_r = it.row();
+ int dy_c = it.col();
+ double val = it.value();
+
+ IJV.push_back(Eigen::Triplet<double>(s.f_n + dy_r, dy_c, val * s.W_11(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(s.f_n + dy_r, s.v_n + dy_c, val * s.W_12(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(s.f_n + dy_r, 2 * s.v_n + dy_c, val * s.W_13(dy_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(4 * s.f_n + dy_r, dy_c, val * s.W_21(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(4 * s.f_n + dy_r, s.v_n + dy_c, val * s.W_22(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(4 * s.f_n + dy_r, 2 * s.v_n + dy_c, val * s.W_23(dy_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(7 * s.f_n + dy_r, dy_c, val * s.W_31(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(7 * s.f_n + dy_r, s.v_n + dy_c, val * s.W_32(dy_r)));
+ IJV.push_back(Eigen::Triplet<double>(7 * s.f_n + dy_r, 2 * s.v_n + dy_c, val * s.W_33(dy_r)));
+ }
+ }
+
+ for (int k = 0; k < s.Dz.outerSize(); k++)
+ {
+ for (Eigen::SparseMatrix<double>::InnerIterator it(s.Dz, k); it; ++it)
+ {
+ int dz_r = it.row();
+ int dz_c = it.col();
+ double val = it.value();
+
+ IJV.push_back(Eigen::Triplet<double>(2 * s.f_n + dz_r, dz_c, val * s.W_11(dz_r)));
+ IJV.push_back(Eigen::Triplet<double>(2 * s.f_n + dz_r, s.v_n + dz_c, val * s.W_12(dz_r)));
+ IJV.push_back(Eigen::Triplet<double>(2 * s.f_n + dz_r, 2 * s.v_n + dz_c, val * s.W_13(dz_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(5 * s.f_n + dz_r, dz_c, val * s.W_21(dz_r)));
+ IJV.push_back(Eigen::Triplet<double>(5 * s.f_n + dz_r, s.v_n + dz_c, val * s.W_22(dz_r)));
+ IJV.push_back(Eigen::Triplet<double>(5 * s.f_n + dz_r, 2 * s.v_n + dz_c, val * s.W_23(dz_r)));
+
+ IJV.push_back(Eigen::Triplet<double>(8 * s.f_n + dz_r, dz_c, val * s.W_31(dz_r)));
+ IJV.push_back(Eigen::Triplet<double>(8 * s.f_n + dz_r, s.v_n + dz_c, val * s.W_32(dz_r)));
+ IJV.push_back(Eigen::Triplet<double>(8 * s.f_n + dz_r, 2 * s.v_n + dz_c, val * s.W_33(dz_r)));
+ }
+ }
+ }
+ }
+
+ IGL_INLINE void buildRhs(igl::SLIMData& s, const Eigen::SparseMatrix<double> &A)
+ {
+ Eigen::VectorXd f_rhs(s.dim * s.dim * s.f_n);
+ f_rhs.setZero();
+ if (s.dim == 2)
+ {
+ /*b = [W11*R11 + W12*R21; (formula (36))
+ W11*R12 + W12*R22;
+ W21*R11 + W22*R21;
+ W21*R12 + W22*R22];*/
+ for (int i = 0; i < s.f_n; i++)
+ {
+ f_rhs(i + 0 * s.f_n) = s.W_11(i) * s.Ri(i, 0) + s.W_12(i) * s.Ri(i, 1);
+ f_rhs(i + 1 * s.f_n) = s.W_11(i) * s.Ri(i, 2) + s.W_12(i) * s.Ri(i, 3);
+ f_rhs(i + 2 * s.f_n) = s.W_21(i) * s.Ri(i, 0) + s.W_22(i) * s.Ri(i, 1);
+ f_rhs(i + 3 * s.f_n) = s.W_21(i) * s.Ri(i, 2) + s.W_22(i) * s.Ri(i, 3);
+ }
+ }
+ else
+ {
+ /*b = [W11*R11 + W12*R21 + W13*R31;
+ W11*R12 + W12*R22 + W13*R32;
+ W11*R13 + W12*R23 + W13*R33;
+ W21*R11 + W22*R21 + W23*R31;
+ W21*R12 + W22*R22 + W23*R32;
+ W21*R13 + W22*R23 + W23*R33;
+ W31*R11 + W32*R21 + W33*R31;
+ W31*R12 + W32*R22 + W33*R32;
+ W31*R13 + W32*R23 + W33*R33;];*/
+ for (int i = 0; i < s.f_n; i++)
+ {
+ f_rhs(i + 0 * s.f_n) = s.W_11(i) * s.Ri(i, 0) + s.W_12(i) * s.Ri(i, 1) + s.W_13(i) * s.Ri(i, 2);
+ f_rhs(i + 1 * s.f_n) = s.W_11(i) * s.Ri(i, 3) + s.W_12(i) * s.Ri(i, 4) + s.W_13(i) * s.Ri(i, 5);
+ f_rhs(i + 2 * s.f_n) = s.W_11(i) * s.Ri(i, 6) + s.W_12(i) * s.Ri(i, 7) + s.W_13(i) * s.Ri(i, 8);
+ f_rhs(i + 3 * s.f_n) = s.W_21(i) * s.Ri(i, 0) + s.W_22(i) * s.Ri(i, 1) + s.W_23(i) * s.Ri(i, 2);
+ f_rhs(i + 4 * s.f_n) = s.W_21(i) * s.Ri(i, 3) + s.W_22(i) * s.Ri(i, 4) + s.W_23(i) * s.Ri(i, 5);
+ f_rhs(i + 5 * s.f_n) = s.W_21(i) * s.Ri(i, 6) + s.W_22(i) * s.Ri(i, 7) + s.W_23(i) * s.Ri(i, 8);
+ f_rhs(i + 6 * s.f_n) = s.W_31(i) * s.Ri(i, 0) + s.W_32(i) * s.Ri(i, 1) + s.W_33(i) * s.Ri(i, 2);
+ f_rhs(i + 7 * s.f_n) = s.W_31(i) * s.Ri(i, 3) + s.W_32(i) * s.Ri(i, 4) + s.W_33(i) * s.Ri(i, 5);
+ f_rhs(i + 8 * s.f_n) = s.W_31(i) * s.Ri(i, 6) + s.W_32(i) * s.Ri(i, 7) + s.W_33(i) * s.Ri(i, 8);
+ }
+ }
+ Eigen::VectorXd uv_flat(s.dim *s.v_n);
+ for (int i = 0; i < s.dim; i++)
+ for (int j = 0; j < s.v_n; j++)
+ uv_flat(s.v_n * i + j) = s.V_o(j, i);
+
+ s.rhs = (f_rhs.transpose() * s.WGL_M.asDiagonal() * A).transpose() + s.proximal_p * uv_flat;
+ }
+
+ }
+}
+
+/// Slim Implementation
+
+IGL_INLINE void igl::slim_precompute(
+ const Eigen::MatrixXd &V,
+ const Eigen::MatrixXi &F,
+ const Eigen::MatrixXd &V_init,
+ SLIMData &data,
+ SLIMData::SLIM_ENERGY slim_energy,
+ Eigen::VectorXi &b,
+ Eigen::MatrixXd &bc,
+ double soft_p)
+{
+
+ data.V = V;
+ data.F = F;
+ data.V_o = V_init;
+
+ data.v_num = V.rows();
+ data.f_num = F.rows();
+
+ data.slim_energy = slim_energy;
+
+ data.b = b;
+ data.bc = bc;
+ data.soft_const_p = soft_p;
+
+ data.proximal_p = 0.0001;
+
+ igl::doublearea(V, F, data.M);
+ data.M /= 2.;
+ data.mesh_area = data.M.sum();
+ data.mesh_improvement_3d = false; // whether to use a jacobian derived from a real mesh or an abstract regular mesh (used for mesh improvement)
+ data.exp_factor = 1.0; // param used only for exponential energies (e.g exponential symmetric dirichlet)
+
+ assert (F.cols() == 3 || F.cols() == 4);
+
+ igl::slim::pre_calc(data);
+ data.energy = igl::slim::compute_energy(data,data.V_o) / data.mesh_area;
+}
+
+IGL_INLINE Eigen::MatrixXd igl::slim_solve(SLIMData &data, int iter_num)
+{
+ for (int i = 0; i < iter_num; i++)
+ {
+ Eigen::MatrixXd dest_res;
+ dest_res = data.V_o;
+
+ // Solve Weighted Proxy
+ igl::slim::update_weights_and_closest_rotations(data,data.V, data.F, dest_res);
+ igl::slim::solve_weighted_arap(data,data.V, data.F, dest_res, data.b, data.bc);
+
+ double old_energy = data.energy;
+
+ std::function<double(Eigen::MatrixXd &)> compute_energy = [&](
+ Eigen::MatrixXd &aaa) { return igl::slim::compute_energy(data,aaa); };
+
+ data.energy = igl::flip_avoiding_line_search(data.F, data.V_o, dest_res, compute_energy,
+ data.energy * data.mesh_area) / data.mesh_area;
+ }
+ return data.V_o;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/slim.h b/xs/src/igl/slim.h
new file mode 100644
index 000000000..1965e2bba
--- /dev/null
+++ b/xs/src/igl/slim.h
@@ -0,0 +1,113 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Michael Rabinovich
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef SLIM_H
+#define SLIM_H
+
+#include "igl_inline.h"
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+// This option makes the iterations faster (all except the first) by caching the
+// sparsity pattern of the matrix involved in the assembly. It should be on if you plan to do many iterations, off if you have to change the matrix structure at every iteration.
+#define SLIM_CACHED
+
+#ifdef SLIM_CACHED
+#include <igl/AtA_cached.h>
+#endif
+
+namespace igl
+{
+
+// Compute a SLIM map as derived in "Scalable Locally Injective Maps" [Rabinovich et al. 2016].
+struct SLIMData
+{
+ // Input
+ Eigen::MatrixXd V; // #V by 3 list of mesh vertex positions
+ Eigen::MatrixXi F; // #F by 3/3 list of mesh faces (triangles/tets)
+ enum SLIM_ENERGY
+ {
+ ARAP,
+ LOG_ARAP,
+ SYMMETRIC_DIRICHLET,
+ CONFORMAL,
+ EXP_CONFORMAL,
+ EXP_SYMMETRIC_DIRICHLET
+ };
+ SLIM_ENERGY slim_energy;
+
+ // Optional Input
+ // soft constraints
+ Eigen::VectorXi b;
+ Eigen::MatrixXd bc;
+ double soft_const_p;
+
+ double exp_factor; // used for exponential energies, ignored otherwise
+ bool mesh_improvement_3d; // only supported for 3d
+
+ // Output
+ Eigen::MatrixXd V_o; // #V by dim list of mesh vertex positions (dim = 2 for parametrization, 3 otherwise)
+ double energy; // objective value
+
+ // INTERNAL
+ Eigen::VectorXd M;
+ double mesh_area;
+ double avg_edge_length;
+ int v_num;
+ int f_num;
+ double proximal_p;
+
+ Eigen::VectorXd WGL_M;
+ Eigen::VectorXd rhs;
+ Eigen::MatrixXd Ri,Ji;
+ Eigen::VectorXd W_11; Eigen::VectorXd W_12; Eigen::VectorXd W_13;
+ Eigen::VectorXd W_21; Eigen::VectorXd W_22; Eigen::VectorXd W_23;
+ Eigen::VectorXd W_31; Eigen::VectorXd W_32; Eigen::VectorXd W_33;
+ Eigen::SparseMatrix<double> Dx,Dy,Dz;
+ int f_n,v_n;
+ bool first_solve;
+ bool has_pre_calc = false;
+ int dim;
+
+ #ifdef SLIM_CACHED
+ Eigen::SparseMatrix<double> A;
+ Eigen::VectorXi A_data;
+ Eigen::SparseMatrix<double> AtA;
+ igl::AtA_cached_data AtA_data;
+ #endif
+};
+
+// Compute necessary information to start using SLIM
+// Inputs:
+// V #V by 3 list of mesh vertex positions
+// F #F by 3/3 list of mesh faces (triangles/tets)
+// b list of boundary indices into V
+// bc #b by dim list of boundary conditions
+// soft_p Soft penalty factor (can be zero)
+// slim_energy Energy to minimize
+IGL_INLINE void slim_precompute(
+ const Eigen::MatrixXd& V,
+ const Eigen::MatrixXi& F,
+ const Eigen::MatrixXd& V_init,
+ SLIMData& data,
+ SLIMData::SLIM_ENERGY slim_energy,
+ Eigen::VectorXi& b,
+ Eigen::MatrixXd& bc,
+ double soft_p);
+
+// Run iter_num iterations of SLIM
+// Outputs:
+// V_o (in SLIMData): #V by dim list of mesh vertex positions
+IGL_INLINE Eigen::MatrixXd slim_solve(SLIMData& data, int iter_num);
+
+} // END NAMESPACE
+
+#ifndef IGL_STATIC_LIBRARY
+# include "slim.cpp"
+#endif
+
+#endif // SLIM_H
diff --git a/xs/src/igl/snap_points.cpp b/xs/src/igl/snap_points.cpp
new file mode 100644
index 000000000..1fc136f4c
--- /dev/null
+++ b/xs/src/igl/snap_points.cpp
@@ -0,0 +1,89 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "snap_points.h"
+#include <cassert>
+#include <limits>
+
+template <
+ typename DerivedC,
+ typename DerivedV,
+ typename DerivedI,
+ typename DerivedminD,
+ typename DerivedVI>
+IGL_INLINE void igl::snap_points(
+ const Eigen::PlainObjectBase<DerivedC > & C,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedI > & I,
+ Eigen::PlainObjectBase<DerivedminD > & minD,
+ Eigen::PlainObjectBase<DerivedVI > & VI)
+{
+ snap_points(C,V,I,minD);
+ const int m = C.rows();
+ VI.resize(m,V.cols());
+ for(int c = 0;c<m;c++)
+ {
+ VI.row(c) = V.row(I(c));
+ }
+}
+
+template <
+ typename DerivedC,
+ typename DerivedV,
+ typename DerivedI,
+ typename DerivedminD>
+IGL_INLINE void igl::snap_points(
+ const Eigen::PlainObjectBase<DerivedC > & C,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedI > & I,
+ Eigen::PlainObjectBase<DerivedminD > & minD)
+{
+ using namespace std;
+ const int n = V.rows();
+ const int m = C.rows();
+ assert(V.cols() == C.cols() && "Dimensions should match");
+ // O(m*n)
+ //
+ // I believe there should be a way to do this in O(m*log(n) + n) assuming
+ // reasonably distubed points.
+ I.resize(m,1);
+ typedef typename DerivedV::Scalar Scalar;
+ minD.setConstant(m,1,numeric_limits<Scalar>::max());
+ for(int v = 0;v<n;v++)
+ {
+ for(int c = 0;c<m;c++)
+ {
+ const Scalar d = (C.row(c) - V.row(v)).squaredNorm();
+ if(d < minD(c))
+ {
+ minD(c,0) = d;
+ I(c,0) = v;
+ }
+ }
+ }
+}
+
+template <
+ typename DerivedC,
+ typename DerivedV,
+ typename DerivedI>
+IGL_INLINE void igl::snap_points(
+ const Eigen::PlainObjectBase<DerivedC > & C,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedI > & I)
+{
+ Eigen::Matrix<typename DerivedC::Scalar,DerivedC::RowsAtCompileTime,1> minD;
+ return igl::snap_points(C,V,I,minD);
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::snap_points<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template void igl::snap_points<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
+
diff --git a/xs/src/igl/snap_points.h b/xs/src/igl/snap_points.h
new file mode 100644
index 000000000..dbb850a79
--- /dev/null
+++ b/xs/src/igl/snap_points.h
@@ -0,0 +1,67 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SNAP_POINTS_H
+#define IGL_SNAP_POINTS_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // SNAP_POINTS snap list of points C to closest of another list of points V
+ //
+ // [I,minD,VI] = snap_points(C,V)
+ //
+ // Inputs:
+ // C #C by dim list of query point positions
+ // V #V by dim list of data point positions
+ // Outputs:
+ // I #C list of indices into V of closest points to C
+ // minD #C list of squared (^p) distances to closest points
+ // VI #C by dim list of new point positions, VI = V(I,:)
+ template <
+ typename DerivedC,
+ typename DerivedV,
+ typename DerivedI,
+ typename DerivedminD,
+ typename DerivedVI>
+ IGL_INLINE void snap_points(
+ const Eigen::PlainObjectBase<DerivedC > & C,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedI > & I,
+ Eigen::PlainObjectBase<DerivedminD > & minD,
+ Eigen::PlainObjectBase<DerivedVI > & VI);
+ template <
+ typename DerivedC,
+ typename DerivedV,
+ typename DerivedI,
+ typename DerivedminD>
+ IGL_INLINE void snap_points(
+ const Eigen::PlainObjectBase<DerivedC > & C,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedI > & I,
+ Eigen::PlainObjectBase<DerivedminD > & minD);
+ template <
+ typename DerivedC,
+ typename DerivedV,
+ typename DerivedI >
+ IGL_INLINE void snap_points(
+ const Eigen::PlainObjectBase<DerivedC > & C,
+ const Eigen::PlainObjectBase<DerivedV > & V,
+ Eigen::PlainObjectBase<DerivedI > & I);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "snap_points.cpp"
+#endif
+
+#endif
+
+
+
+
diff --git a/xs/src/igl/snap_to_canonical_view_quat.cpp b/xs/src/igl/snap_to_canonical_view_quat.cpp
new file mode 100644
index 000000000..9fb01724c
--- /dev/null
+++ b/xs/src/igl/snap_to_canonical_view_quat.cpp
@@ -0,0 +1,117 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "snap_to_canonical_view_quat.h"
+
+#include "canonical_quaternions.h"
+#include "normalize_quat.h"
+
+#include <cstdio>
+#include <cassert>
+
+// Note: For the canonical view quaternions it should be completely possible to
+// determine this anaylitcally. That is the max_distance should be a
+// theoretical known value
+// Also: I'm not sure it matters in this case, but. We are dealing with
+// quaternions on the 4d unit sphere, but measuring distance in general 4d
+// space (i.e. not geodesics on the sphere). Probably something with angles
+// would be better.
+template <typename Q_type>
+IGL_INLINE bool igl::snap_to_canonical_view_quat(
+ const Q_type* q,
+ const Q_type threshold,
+ Q_type* s)
+{
+ // Copy input into output
+ // CANNOT use std::copy here according to:
+ // http://www.cplusplus.com/reference/algorithm/copy/
+ s[0] = q[0];
+ s[1] = q[1];
+ s[2] = q[2];
+ s[3] = q[3];
+
+ // Normalize input quaternion
+ Q_type qn[4];
+ bool valid_len =
+ igl::normalize_quat(q,qn);
+ // If normalizing valid then don't bother
+ if(!valid_len)
+ {
+ return false;
+ }
+
+ // 0.290019
+ const Q_type MAX_DISTANCE = 0.4;
+ Q_type min_distance = 2*MAX_DISTANCE;
+ int min_index = -1;
+ double min_sign = 0;
+ // loop over canonical view quaternions
+ for(double sign = -1;sign<=1;sign+=2)
+ {
+ for(int i = 0; i<NUM_CANONICAL_VIEW_QUAT; i++)
+ {
+ Q_type distance = 0.0;
+ // loop over coordinates
+ for(int j = 0;j<4;j++)
+ {
+ // Double cast because of bug in llvm version 4.2 with -O3
+ distance +=
+ (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j))*
+ (qn[j]-sign*igl::CANONICAL_VIEW_QUAT<Q_type>(i,j));
+ }
+ if(min_distance > distance)
+ {
+ min_distance = distance;
+ min_index = i;
+ min_sign = sign;
+ }
+ }
+ }
+
+ if(MAX_DISTANCE < min_distance)
+ {
+ fprintf(
+ stderr,
+ "ERROR: found new max MIN_DISTANCE: %g\n"
+ "PLEASE update snap_to_canonical_quat()",
+ min_distance);
+ }
+
+ assert(min_distance < MAX_DISTANCE);
+ assert(min_index >= 0);
+
+ if( min_distance/MAX_DISTANCE <= threshold)
+ {
+ // loop over coordinates
+ for(int j = 0;j<4;j++)
+ {
+ s[j] = min_sign*igl::CANONICAL_VIEW_QUAT<Q_type>(min_index,j);
+ }
+ return true;
+ }
+ return false;
+}
+
+template <typename Scalarq, typename Scalars>
+IGL_INLINE bool igl::snap_to_canonical_view_quat(
+ const Eigen::Quaternion<Scalarq> & q,
+ const double threshold,
+ Eigen::Quaternion<Scalars> & s)
+{
+ return snap_to_canonical_view_quat<Scalars>(
+ q.coeffs().data(),threshold,s.coeffs().data());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::snap_to_canonical_view_quat<double>(const double*, double, double*);
+// generated by autoexplicit.sh
+template bool igl::snap_to_canonical_view_quat<float>(const float*, float, float*);
+template bool igl::snap_to_canonical_view_quat<float, float>(Eigen::Quaternion<float, 0> const&, double, Eigen::Quaternion<float, 0>&);
+template bool igl::snap_to_canonical_view_quat<double, double>(Eigen::Quaternion<double, 0> const&, double, Eigen::Quaternion<double, 0>&);
+#endif
diff --git a/xs/src/igl/snap_to_canonical_view_quat.h b/xs/src/igl/snap_to_canonical_view_quat.h
new file mode 100644
index 000000000..79bc3e024
--- /dev/null
+++ b/xs/src/igl/snap_to_canonical_view_quat.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SNAP_TO_CANONICAL_VIEW_QUAT_H
+#define IGL_SNAP_TO_CANONICAL_VIEW_QUAT_H
+#include "igl_inline.h"
+#include <Eigen/Geometry>
+// 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
+namespace igl
+{
+ // Snap the quaternion q to the nearest canonical view quaternion
+ // Input:
+ // q quaternion to be snapped (also see Outputs)
+ // threshold (optional) threshold:
+ // 1.0 --> snap any input
+ // 0.5 --> snap inputs somewhat close to canonical views
+ // 0.0 --> snap no input
+ // Output:
+ // q quaternion possibly set to nearest canonical view
+ // Return:
+ // true only if q was snapped to the nearest canonical view
+ template <typename Q_type>
+ IGL_INLINE bool snap_to_canonical_view_quat(
+ const Q_type* q,
+ const Q_type threshold,
+ Q_type* s);
+
+ template <typename Scalarq, typename Scalars>
+ IGL_INLINE bool snap_to_canonical_view_quat(
+ const Eigen::Quaternion<Scalarq> & q,
+ const double threshold,
+ Eigen::Quaternion<Scalars> & s);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "snap_to_canonical_view_quat.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/snap_to_fixed_up.cpp b/xs/src/igl/snap_to_fixed_up.cpp
new file mode 100644
index 000000000..f0fdd7de8
--- /dev/null
+++ b/xs/src/igl/snap_to_fixed_up.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "snap_to_fixed_up.h"
+
+template <typename Qtype>
+IGL_INLINE void igl::snap_to_fixed_up(
+ const Eigen::Quaternion<Qtype> & q,
+ Eigen::Quaternion<Qtype> & s)
+{
+ using namespace Eigen;
+ typedef Eigen::Matrix<Qtype,3,1> Vector3Q;
+ const Vector3Q up = q.matrix() * Vector3Q(0,1,0);
+ Vector3Q proj_up(0,up(1),up(2));
+ if(proj_up.norm() == 0)
+ {
+ proj_up = Vector3Q(0,1,0);
+ }
+ proj_up.normalize();
+ Quaternion<Qtype> dq;
+ dq = Quaternion<Qtype>::FromTwoVectors(up,proj_up);
+ s = dq * q;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiations
+template void igl::snap_to_fixed_up<float>(Eigen::Quaternion<float, 0> const&, Eigen::Quaternion<float, 0>&);
+template void igl::snap_to_fixed_up<double>(Eigen::Quaternion<double, 0> const&, Eigen::Quaternion<double, 0>&);
+#endif
diff --git a/xs/src/igl/snap_to_fixed_up.h b/xs/src/igl/snap_to_fixed_up.h
new file mode 100644
index 000000000..4276fa79c
--- /dev/null
+++ b/xs/src/igl/snap_to_fixed_up.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SNAP_TO_FIXED_UP_H
+#define IGL_SNAP_TO_FIXED_UP_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+namespace igl
+{
+ // Snap an arbitrary rotation to a rotation resulting from a rotation about
+ // the y-axis then the x-axis (maintaining fixed up like
+ // two_axis_valuator_fixed_up.)
+ //
+ // Inputs:
+ // q General rotation as quaternion
+ // Outputs:
+ // s the resulting rotation (as quaternion)
+ //
+ // See also: two_axis_valuator_fixed_up
+ template <typename Qtype>
+ IGL_INLINE void snap_to_fixed_up(
+ const Eigen::Quaternion<Qtype> & q,
+ Eigen::Quaternion<Qtype> & s);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "snap_to_fixed_up.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/solid_angle.cpp b/xs/src/igl/solid_angle.cpp
new file mode 100644
index 000000000..bbb478af3
--- /dev/null
+++ b/xs/src/igl/solid_angle.cpp
@@ -0,0 +1,81 @@
+#include "solid_angle.h"
+#include "PI.h"
+#include <cmath>
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedP>
+IGL_INLINE typename DerivedA::Scalar igl::solid_angle(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ const Eigen::MatrixBase<DerivedP> & P)
+{
+ typedef typename DerivedA::Scalar SType;
+ // Gather vectors to corners
+ Eigen::Matrix<SType,3,3> v;
+ // Don't use this since it will freak out for templates with != 3 size
+ //v<< (A-P),(B-P),(C-P);
+ for(int d = 0;d<3;d++)
+ {
+ v(0,d) = A(d)-P(d);
+ v(1,d) = B(d)-P(d);
+ v(2,d) = C(d)-P(d);
+ }
+ Eigen::Matrix<SType,1,3> vl = v.rowwise().norm();
+ //printf("\n");
+ // Compute determinant
+ SType detf =
+ v(0,0)*v(1,1)*v(2,2)+
+ v(1,0)*v(2,1)*v(0,2)+
+ v(2,0)*v(0,1)*v(1,2)-
+ v(2,0)*v(1,1)*v(0,2)-
+ v(1,0)*v(0,1)*v(2,2)-
+ v(0,0)*v(2,1)*v(1,2);
+ // Compute pairwise dotproducts
+ Eigen::Matrix<SType,1,3> dp;
+ dp(0) = v(1,0)*v(2,0);
+ dp(0) += v(1,1)*v(2,1);
+ dp(0) += v(1,2)*v(2,2);
+ dp(1) = v(2,0)*v(0,0);
+ dp(1) += v(2,1)*v(0,1);
+ dp(1) += v(2,2)*v(0,2);
+ dp(2) = v(0,0)*v(1,0);
+ dp(2) += v(0,1)*v(1,1);
+ dp(2) += v(0,2)*v(1,2);
+ // Compute winding number
+ // Only divide by TWO_PI instead of 4*pi because there was a 2 out front
+ return atan2(detf,
+ vl(0)*vl(1)*vl(2) +
+ dp(0)*vl(0) +
+ dp(1)*vl(1) +
+ dp(2)*vl(2)) / (2.*igl::PI);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 1, -1, 3> const, 1, 3, true> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<float, -1, 3, 0, -1, 3> const, 1, 3, false> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>::Scalar igl::solid_angle<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Block<Eigen::Matrix<double, -1, -1, 0, -1, -1> const, 1, -1, false> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
+#endif
diff --git a/xs/src/igl/solid_angle.h b/xs/src/igl/solid_angle.h
new file mode 100644
index 000000000..2ee98a247
--- /dev/null
+++ b/xs/src/igl/solid_angle.h
@@ -0,0 +1,29 @@
+#ifndef IGL_SOLID_ANGLE_H
+#define IGL_SOLID_ANGLE_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Compute the signed solid angle subtended by the oriented 3d triangle (A,B,C) at some point P
+ //
+ // Inputs:
+ // A 3D position of corner
+ // B 3D position of corner
+ // C 3D position of corner
+ // P 3D position of query point
+ // Returns signed solid angle
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedP>
+ IGL_INLINE typename DerivedA::Scalar solid_angle(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ const Eigen::MatrixBase<DerivedP> & P);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "solid_angle.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/sort.cpp b/xs/src/igl/sort.cpp
new file mode 100644
index 000000000..251b3063e
--- /dev/null
+++ b/xs/src/igl/sort.cpp
@@ -0,0 +1,351 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sort.h"
+
+#include "SortableRow.h"
+#include "reorder.h"
+#include "IndexComparison.h"
+#include "colon.h"
+#include "parallel_for.h"
+
+#include <cassert>
+#include <algorithm>
+#include <iostream>
+
+template <typename DerivedX, typename DerivedY, typename DerivedIX>
+IGL_INLINE void igl::sort(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX)
+{
+ typedef typename DerivedX::Scalar Scalar;
+ // get number of rows (or columns)
+ int num_inner = (dim == 1 ? X.rows() : X.cols() );
+ // Special case for swapping
+ switch(num_inner)
+ {
+ default:
+ break;
+ case 2:
+ return igl::sort2(X,dim,ascending,Y,IX);
+ case 3:
+ return igl::sort3(X,dim,ascending,Y,IX);
+ }
+ using namespace Eigen;
+ // get number of columns (or rows)
+ int num_outer = (dim == 1 ? X.cols() : X.rows() );
+ // dim must be 2 or 1
+ assert(dim == 1 || dim == 2);
+ // Resize output
+ Y.resizeLike(X);
+ IX.resizeLike(X);
+ // idea is to process each column (or row) as a std vector
+ // loop over columns (or rows)
+ for(int i = 0; i<num_outer;i++)
+ {
+ // Unsorted index map for this column (or row)
+ std::vector<size_t> index_map(num_inner);
+ std::vector<Scalar> data(num_inner);
+ for(int j = 0;j<num_inner;j++)
+ {
+ if(dim == 1)
+ {
+ data[j] = (Scalar) X(j,i);
+ }else
+ {
+ data[j] = (Scalar) X(i,j);
+ }
+ }
+ // sort this column (or row)
+ igl::sort( data, ascending, data, index_map);
+ // Copy into Y and IX
+ for(int j = 0;j<num_inner;j++)
+ {
+ if(dim == 1)
+ {
+ Y(j,i) = data[j];
+ IX(j,i) = index_map[j];
+ }else
+ {
+ Y(i,j) = data[j];
+ IX(i,j) = index_map[j];
+ }
+ }
+ }
+}
+
+template <typename DerivedX, typename DerivedY, typename DerivedIX>
+IGL_INLINE void igl::sort_new(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX)
+{
+ // get number of rows (or columns)
+ int num_inner = (dim == 1 ? X.rows() : X.cols() );
+ // Special case for swapping
+ switch(num_inner)
+ {
+ default:
+ break;
+ case 2:
+ return igl::sort2(X,dim,ascending,Y,IX);
+ case 3:
+ return igl::sort3(X,dim,ascending,Y,IX);
+ }
+ using namespace Eigen;
+ // get number of columns (or rows)
+ int num_outer = (dim == 1 ? X.cols() : X.rows() );
+ // dim must be 2 or 1
+ assert(dim == 1 || dim == 2);
+ // Resize output
+ Y.resizeLike(X);
+ IX.resizeLike(X);
+ // idea is to process each column (or row) as a std vector
+ // loop over columns (or rows)
+ for(int i = 0; i<num_outer;i++)
+ {
+ Eigen::VectorXi ix;
+ colon(0,num_inner-1,ix);
+ // Sort the index map, using unsorted for comparison
+ if(dim == 1)
+ {
+ std::sort(
+ ix.data(),
+ ix.data()+ix.size(),
+ igl::IndexVectorLessThan<const typename DerivedX::ConstColXpr >(X.col(i)));
+ }else
+ {
+ std::sort(
+ ix.data(),
+ ix.data()+ix.size(),
+ igl::IndexVectorLessThan<const typename DerivedX::ConstRowXpr >(X.row(i)));
+ }
+ // if not ascending then reverse
+ if(!ascending)
+ {
+ std::reverse(ix.data(),ix.data()+ix.size());
+ }
+ for(int j = 0;j<num_inner;j++)
+ {
+ if(dim == 1)
+ {
+ Y(j,i) = X(ix[j],i);
+ IX(j,i) = ix[j];
+ }else
+ {
+ Y(i,j) = X(i,ix[j]);
+ IX(i,j) = ix[j];
+ }
+ }
+ }
+}
+
+template <typename DerivedX, typename DerivedY, typename DerivedIX>
+IGL_INLINE void igl::sort2(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef typename DerivedY::Scalar YScalar;
+ Y = X.derived().template cast<YScalar>();
+
+
+ // get number of columns (or rows)
+ int num_outer = (dim == 1 ? X.cols() : X.rows() );
+ // get number of rows (or columns)
+ int num_inner = (dim == 1 ? X.rows() : X.cols() );
+ assert(num_inner == 2);(void)num_inner;
+ typedef typename DerivedIX::Scalar Index;
+ IX.resizeLike(X);
+ if(dim==1)
+ {
+ IX.row(0).setConstant(0);// = DerivedIX::Zero(1,IX.cols());
+ IX.row(1).setConstant(1);// = DerivedIX::Ones (1,IX.cols());
+ }else
+ {
+ IX.col(0).setConstant(0);// = DerivedIX::Zero(IX.rows(),1);
+ IX.col(1).setConstant(1);// = DerivedIX::Ones (IX.rows(),1);
+ }
+ // loop over columns (or rows)
+ for(int i = 0;i<num_outer;i++)
+ {
+ YScalar & a = (dim==1 ? Y(0,i) : Y(i,0));
+ YScalar & b = (dim==1 ? Y(1,i) : Y(i,1));
+ Index & ai = (dim==1 ? IX(0,i) : IX(i,0));
+ Index & bi = (dim==1 ? IX(1,i) : IX(i,1));
+ if((ascending && a>b) || (!ascending && a<b))
+ {
+ std::swap(a,b);
+ std::swap(ai,bi);
+ }
+ }
+}
+
+template <typename DerivedX, typename DerivedY, typename DerivedIX>
+IGL_INLINE void igl::sort3(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX)
+{
+ using namespace Eigen;
+ using namespace std;
+ typedef typename DerivedY::Scalar YScalar;
+ Y = X.derived().template cast<YScalar>();
+ Y.resizeLike(X);
+ for(int j=0;j<X.cols();j++)for(int i=0;i<X.rows();i++)Y(i,j)=(YScalar)X(i,j);
+
+ // get number of columns (or rows)
+ int num_outer = (dim == 1 ? X.cols() : X.rows() );
+ // get number of rows (or columns)
+ int num_inner = (dim == 1 ? X.rows() : X.cols() );
+ assert(num_inner == 3);(void)num_inner;
+ typedef typename DerivedIX::Scalar Index;
+ IX.resizeLike(X);
+ if(dim==1)
+ {
+ IX.row(0).setConstant(0);// = DerivedIX::Zero(1,IX.cols());
+ IX.row(1).setConstant(1);// = DerivedIX::Ones (1,IX.cols());
+ IX.row(2).setConstant(2);// = DerivedIX::Ones (1,IX.cols());
+ }else
+ {
+ IX.col(0).setConstant(0);// = DerivedIX::Zero(IX.rows(),1);
+ IX.col(1).setConstant(1);// = DerivedIX::Ones (IX.rows(),1);
+ IX.col(2).setConstant(2);// = DerivedIX::Ones (IX.rows(),1);
+ }
+
+
+ const auto & inner = [&IX,&Y,&dim,&ascending](const Index & i)
+ {
+ YScalar & a = (dim==1 ? Y(0,i) : Y(i,0));
+ YScalar & b = (dim==1 ? Y(1,i) : Y(i,1));
+ YScalar & c = (dim==1 ? Y(2,i) : Y(i,2));
+ Index & ai = (dim==1 ? IX(0,i) : IX(i,0));
+ Index & bi = (dim==1 ? IX(1,i) : IX(i,1));
+ Index & ci = (dim==1 ? IX(2,i) : IX(i,2));
+ if(ascending)
+ {
+ // 123 132 213 231 312 321
+ if(a > b)
+ {
+ std::swap(a,b);
+ std::swap(ai,bi);
+ }
+ // 123 132 123 231 132 231
+ if(b > c)
+ {
+ std::swap(b,c);
+ std::swap(bi,ci);
+ // 123 123 123 213 123 213
+ if(a > b)
+ {
+ std::swap(a,b);
+ std::swap(ai,bi);
+ }
+ // 123 123 123 123 123 123
+ }
+ }else
+ {
+ // 123 132 213 231 312 321
+ if(a < b)
+ {
+ std::swap(a,b);
+ std::swap(ai,bi);
+ }
+ // 213 312 213 321 312 321
+ if(b < c)
+ {
+ std::swap(b,c);
+ std::swap(bi,ci);
+ // 231 321 231 321 321 321
+ if(a < b)
+ {
+ std::swap(a,b);
+ std::swap(ai,bi);
+ }
+ // 321 321 321 321 321 321
+ }
+ }
+ };
+ parallel_for(num_outer,inner,16000);
+}
+
+template <class T>
+IGL_INLINE void igl::sort(
+const std::vector<T> & unsorted,
+const bool ascending,
+std::vector<T> & sorted,
+std::vector<size_t> & index_map)
+{
+// Original unsorted index map
+index_map.resize(unsorted.size());
+for(size_t i=0;i<unsorted.size();i++)
+{
+ index_map[i] = i;
+}
+// Sort the index map, using unsorted for comparison
+std::sort(
+ index_map.begin(),
+ index_map.end(),
+ igl::IndexLessThan<const std::vector<T>& >(unsorted));
+
+// if not ascending then reverse
+if(!ascending)
+{
+ std::reverse(index_map.begin(),index_map.end());
+}
+ // make space for output without clobbering
+ sorted.resize(unsorted.size());
+ // reorder unsorted into sorted using index map
+ igl::reorder(unsorted,index_map,sorted);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::sort<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::sort<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<int>(std::vector<int, std::allocator<int> > const&, bool, std::vector<int, std::allocator<int> >&, std::vector<size_t,class std::allocator<size_t> > &);
+template void igl::sort<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sort_new<Eigen::Matrix<int, 1, 6, 1, 1, 6>, Eigen::Matrix<int, 1, 6, 1, 1, 6>, Eigen::Matrix<int, 1, 6, 1, 1, 6> >(Eigen::DenseBase<Eigen::Matrix<int, 1, 6, 1, 1, 6> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 6, 1, 1, 6> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 6, 1, 1, 6> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, 4, 0, -1, 4> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<long>(std::vector<long, std::allocator<long> > const&, bool, std::vector<long, std::allocator<long> >&, std::vector<size_t, std::allocator<size_t> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::sort<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&);
+template void igl::sort<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, int, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::sort<class Eigen::Matrix<int,-1,1,0,-1,1>,class Eigen::Matrix<int,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<int,-1,1,0,-1,1> > const &,int,bool,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+#endif
+#endif
diff --git a/xs/src/igl/sort.h b/xs/src/igl/sort.h
new file mode 100644
index 000000000..f89f54b13
--- /dev/null
+++ b/xs/src/igl/sort.h
@@ -0,0 +1,88 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SORT_H
+#define IGL_SORT_H
+#include "igl_inline.h"
+
+#include <vector>
+#include <Eigen/Core>
+namespace igl
+{
+
+ // Sort the elements of a matrix X along a given dimension like matlabs sort
+ // function
+ //
+ // Templates:
+ // DerivedX derived scalar type, e.g. MatrixXi or MatrixXd
+ // DerivedIX derived integer type, e.g. MatrixXi
+ // Inputs:
+ // X m by n matrix whose entries are to be sorted
+ // dim dimensional along which to sort:
+ // 1 sort each column (matlab default)
+ // 2 sort each row
+ // ascending sort ascending (true, matlab default) or descending (false)
+ // Outputs:
+ // Y m by n matrix whose entries are sorted
+ // IX m by n matrix of indices so that if dim = 1, then in matlab notation
+ // for j = 1:n, Y(:,j) = X(I(:,j),j); end
+ template <typename DerivedX, typename DerivedY, typename DerivedIX>
+ IGL_INLINE void sort(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX);
+ template <typename DerivedX, typename DerivedY, typename DerivedIX>
+ // Only better if size(X,dim) is small
+ IGL_INLINE void sort_new(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX);
+ // Special case if size(X,dim) == 2
+ template <typename DerivedX, typename DerivedY, typename DerivedIX>
+ IGL_INLINE void sort2(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX);
+ // Special case if size(X,dim) == 3
+ template <typename DerivedX, typename DerivedY, typename DerivedIX>
+ IGL_INLINE void sort3(
+ const Eigen::DenseBase<DerivedX>& X,
+ const int dim,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedY>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX);
+
+
+ // Act like matlab's [Y,I] = SORT(X) for std library vectors
+ // Templates:
+ // T should be a class that implements the '<' comparator operator
+ // Input:
+ // unsorted unsorted vector
+ // ascending sort ascending (true, matlab default) or descending (false)
+ // Output:
+ // sorted sorted vector, allowed to be same as unsorted
+ // index_map an index map such that sorted[i] = unsorted[index_map[i]]
+ template <class T>
+ IGL_INLINE void sort(
+ const std::vector<T> &unsorted,
+ const bool ascending,
+ std::vector<T> &sorted,
+ std::vector<size_t> &index_map);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "sort.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/sort_angles.cpp b/xs/src/igl/sort_angles.cpp
new file mode 100644
index 000000000..486f621ea
--- /dev/null
+++ b/xs/src/igl/sort_angles.cpp
@@ -0,0 +1,114 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sort_angles.h"
+#include "LinSpaced.h"
+#include <algorithm>
+
+template <typename DerivedM, typename DerivedR>
+IGL_INLINE void igl::sort_angles(
+ const Eigen::PlainObjectBase<DerivedM>& M,
+ Eigen::PlainObjectBase<DerivedR>& R) {
+ const size_t num_rows = M.rows();
+ const size_t num_cols = M.cols();
+ assert(num_cols >= 2);
+
+ R.resize(num_rows);
+ // Have to use << instead of = because Eigen's PlainObjectBase is annoying
+ R << igl::LinSpaced<
+ Eigen::Matrix<typename DerivedR::Scalar, Eigen::Dynamic, 1> >
+ (num_rows, 0, num_rows-1);
+
+ // |
+ // (pi/2, pi) | (0, pi/2)
+ // |
+ // -------------+--------------
+ // |
+ // (-pi, -pi/2) | (-pi/2, 0)
+ // |
+ auto comp = [&](size_t i, size_t j) {
+ auto yi = M(i, 0);
+ auto xi = M(i, 1);
+ auto yj = M(j, 0);
+ auto xj = M(j, 1);
+
+ if (xi == xj && yi == yj) {
+ for (size_t idx=2; idx<num_cols; idx++) {
+ auto i_val = M(i, idx);
+ auto j_val = M(j, idx);
+ if (i_val != j_val) {
+ return i_val < j_val;
+ }
+ }
+ // If the entire rows are equal, use the row index.
+ return i < j;
+ }
+
+ if (xi >= 0 && yi >= 0) {
+ if (xj >=0 && yj >= 0) {
+ if (xi != xj) {
+ return xi > xj;
+ } else {
+ return yi < yj;
+ }
+ } else if (xj < 0 && yj >= 0) {
+ return true;
+ } else if (xj < 0 && yj < 0) {
+ return false;
+ } else {
+ return false;
+ }
+ } else if (xi < 0 && yi >= 0) {
+ if (xj >= 0 && yj >= 0) {
+ return false;
+ } else if (xj < 0 && yj >= 0) {
+ if (xi != xj) {
+ return xi > xj;
+ } else {
+ return yi > yj;
+ }
+ } else if (xj < 0 && yj < 0) {
+ return false;
+ } else {
+ return false;
+ }
+ } else if (xi < 0 && yi < 0) {
+ if (xj >= 0 && yj >= 0) {
+ return true;
+ } else if (xj < 0 && yj >= 0) {
+ return true;
+ } else if (xj < 0 && yj < 0) {
+ if (xi != xj) {
+ return xi < xj;
+ } else {
+ return yi > yj;
+ }
+ } else {
+ return true;
+ }
+ } else {
+ if (xj >= 0 && yj >= 0) {
+ return true;
+ } else if (xj < 0 && yj >= 0) {
+ return true;
+ } else if (xj < 0 && yj < 0) {
+ return false;
+ } else {
+ if (xi != xj) {
+ return xi < xj;
+ } else {
+ return yi < yj;
+ }
+ }
+ }
+ };
+ std::sort(R.data(), R.data() + num_rows, comp);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::sort_angles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/sort_angles.h b/xs/src/igl/sort_angles.h
new file mode 100644
index 000000000..4763c981e
--- /dev/null
+++ b/xs/src/igl/sort_angles.h
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef SORT_ANGLES_H
+#define SORT_ANGLES_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl {
+ // Sort angles in ascending order in a numerically robust way.
+ //
+ // Instead of computing angles using atan2(y, x), sort directly on (y, x).
+ //
+ // Inputs:
+ // M: m by n matrix of scalars. (n >= 2). Assuming the first column of M
+ // contains values for y, and the second column is x. Using the rest
+ // of the columns as tie-breaker.
+ // R: an array of m indices. M.row(R[i]) contains the i-th smallest
+ // angle.
+ template<typename DerivedM, typename DerivedR>
+ IGL_INLINE void sort_angles(
+ const Eigen::PlainObjectBase<DerivedM>& M,
+ Eigen::PlainObjectBase<DerivedR>& R);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "sort_angles.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/sort_triangles.cpp b/xs/src/igl/sort_triangles.cpp
new file mode 100644
index 000000000..98fd8ab1a
--- /dev/null
+++ b/xs/src/igl/sort_triangles.cpp
@@ -0,0 +1,498 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sort_triangles.h"
+#include "barycenter.h"
+#include "sort.h"
+#include "sortrows.h"
+#include "slice.h"
+#include "round.h"
+#include "colon.h"
+
+#include <iostream>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedMV,
+ typename DerivedP,
+ typename DerivedFF,
+ typename DerivedI>
+IGL_INLINE void igl::sort_triangles(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedMV> & MV,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I)
+{
+ using namespace Eigen;
+ using namespace std;
+
+
+ // Barycenter, centroid
+ Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,1> D,sD;
+ Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,4> BC,PBC;
+ barycenter(V,F,BC);
+ D = BC*(MV.transpose()*P.transpose().eval().col(2));
+ sort(D,1,false,sD,I);
+
+ //// Closest corner
+ //Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,1> D,sD;
+ //D.setConstant(F.rows(),1,-1e26);
+ //for(int c = 0;c<3;c++)
+ //{
+ // Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,4> C;
+ // Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,1> DC;
+ // C.resize(F.rows(),4);
+ // for(int f = 0;f<F.rows();f++)
+ // {
+ // C(f,0) = V(F(f,c),0);
+ // C(f,1) = V(F(f,c),1);
+ // C(f,2) = V(F(f,c),2);
+ // C(f,3) = 1;
+ // }
+ // DC = C*(MV.transpose()*P.transpose().eval().col(2));
+ // D = (DC.array()>D.array()).select(DC,D).eval();
+ //}
+ //sort(D,1,false,sD,I);
+
+ //// Closest corner with tie breaks
+ //Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,3> D,sD,ssD;
+ //D.resize(F.rows(),3);
+ //for(int c = 0;c<3;c++)
+ //{
+ // Eigen::Matrix<typename DerivedV::Scalar, DerivedF::RowsAtCompileTime,4> C;
+ // C.resize(F.rows(),4);
+ // for(int f = 0;f<F.rows();f++)
+ // {
+ // C(f,0) = V(F(f,c),0);
+ // C(f,1) = V(F(f,c),1);
+ // C(f,2) = V(F(f,c),2);
+ // C(f,3) = 1;
+ // }
+ // D.col(c) = C*(MV.transpose()*P.transpose().eval().col(2));
+ //}
+ //VectorXi _;
+ //sort(D,2,false,sD,_);
+ //sortrows(sD,false,ssD,I);
+
+
+ slice(F,I,1,FF);
+}
+
+//#include "EPS.h"
+//#include <functional>
+//#include <algorithm>
+//
+//static int tough_count = 0;
+//template <typename Vec3>
+//class Triangle
+//{
+// public:
+// static inline bool z_comp(const Vec3 & A, const Vec3 & B)
+// {
+// return A(2) > B(2);
+// }
+// static typename Vec3::Scalar ZERO()
+// {
+// return igl::EPS<typename Vec3::Scalar>();
+// return 0;
+// }
+// public:
+// int id;
+// // Sorted projected coners: c[0] has smallest z value
+// Vec3 c[3];
+// Vec3 n;
+// public:
+// Triangle():id(-1) { };
+// Triangle(int id, const Vec3 c0, const Vec3 c1, const Vec3 c2):
+// id(id)
+// {
+// using namespace std;
+// c[0] = c0;
+// c[1] = c1;
+// c[2] = c2;
+// sort(c,c+3,Triangle<Vec3>::z_comp);
+// // normal pointed toward viewpoint
+// n = (c0-c1).cross(c2-c0);
+// if(n(2) < 0)
+// {
+// n *= -1.0;
+// }
+// // Avoid NaNs
+// typename Vec3::Scalar len = n.norm();
+// if(len == 0)
+// {
+// cout<<"avoid NaN"<<endl;
+// assert(false);
+// len = 1;
+// }
+// n /= len;
+// };
+//
+// typename Vec3::Scalar project(const Vec3 & r) const
+// {
+// //return n.dot(r-c[2]);
+// int closest = -1;
+// typename Vec3::Scalar min_dist = 1e26;
+// for(int ci = 0;ci<3;ci++)
+// {
+// typename Vec3::Scalar dist = (c[ci]-r).norm();
+// if(dist < min_dist)
+// {
+// min_dist = dist;
+// closest = ci;
+// }
+// }
+// assert(closest>=0);
+// return n.dot(r-c[closest]);
+// }
+//
+// // Z-values of this are < z-values of that
+// bool is_completely_behind(const Triangle & that) const
+// {
+// const typename Vec3::Scalar ac0 = that.c[0](2);
+// const typename Vec3::Scalar ac1 = that.c[1](2);
+// const typename Vec3::Scalar ac2 = that.c[2](2);
+// const typename Vec3::Scalar ic0 = this->c[0](2);
+// const typename Vec3::Scalar ic1 = this->c[1](2);
+// const typename Vec3::Scalar ic2 = this->c[2](2);
+// return
+// (ic0 < ac2 && ic1 <= ac2 && ic2 <= ac2) ||
+// (ic0 <= ac2 && ic1 < ac2 && ic2 <= ac2) ||
+// (ic0 <= ac2 && ic1 <= ac2 && ic2 < ac2);
+// }
+//
+// bool is_behind_plane(const Triangle &that) const
+// {
+// using namespace std;
+// const typename Vec3::Scalar apc0 = that.project(this->c[0]);
+// const typename Vec3::Scalar apc1 = that.project(this->c[1]);
+// const typename Vec3::Scalar apc2 = that.project(this->c[2]);
+// cout<<" "<<
+// apc0<<", "<<
+// apc1<<", "<<
+// apc2<<", "<<endl;
+// return (apc0 < ZERO() && apc1 < ZERO() && apc2 < ZERO());
+// }
+//
+// bool is_in_front_of_plane(const Triangle &that) const
+// {
+// using namespace std;
+// const typename Vec3::Scalar apc0 = that.project(this->c[0]);
+// const typename Vec3::Scalar apc1 = that.project(this->c[1]);
+// const typename Vec3::Scalar apc2 = that.project(this->c[2]);
+// cout<<" "<<
+// apc0<<", "<<
+// apc1<<", "<<
+// apc2<<", "<<endl;
+// return (apc0 > ZERO() && apc1 > ZERO() && apc2 > ZERO());
+// }
+//
+// bool is_coplanar(const Triangle &that) const
+// {
+// using namespace std;
+// const typename Vec3::Scalar apc0 = that.project(this->c[0]);
+// const typename Vec3::Scalar apc1 = that.project(this->c[1]);
+// const typename Vec3::Scalar apc2 = that.project(this->c[2]);
+// return (fabs(apc0)<=ZERO() && fabs(apc1)<=ZERO() && fabs(apc2)<=ZERO());
+// }
+//
+// // http://stackoverflow.com/a/14561664/148668
+// // a1 is line1 start, a2 is line1 end, b1 is line2 start, b2 is line2 end
+// static bool seg_seg_intersect(const Vec3 & a1, const Vec3 & a2, const Vec3 & b1, const Vec3 & b2)
+// {
+// Vec3 b = a2-a1;
+// Vec3 d = b2-b1;
+// typename Vec3::Scalar bDotDPerp = b(0) * d(1) - b(1) * d(0);
+//
+// // if b dot d == 0, it means the lines are parallel so have infinite intersection points
+// if (bDotDPerp == 0)
+// return false;
+//
+// Vec3 c = b1-a1;
+// typename Vec3::Scalar t = (c(0) * d(1) - c(1) * d(0)) / bDotDPerp;
+// if (t < 0 || t > 1)
+// return false;
+//
+// typename Vec3::Scalar u = (c(0) * b(1) - c(1) * b(0)) / bDotDPerp;
+// if (u < 0 || u > 1)
+// return false;
+//
+// return true;
+// }
+// bool has_corner_inside(const Triangle & that) const
+// {
+// // http://www.blackpawn.com/texts/pointinpoly/
+// // Compute vectors
+// Vec3 A = that.c[0];
+// Vec3 B = that.c[1];
+// Vec3 C = that.c[2];
+// A(2) = B(2) = C(2) = 0;
+// for(int ci = 0;ci<3;ci++)
+// {
+// Vec3 P = this->c[ci];
+// P(2) = 0;
+//
+// Vec3 v0 = C - A;
+// Vec3 v1 = B - A;
+// Vec3 v2 = P - A;
+//
+// // Compute dot products
+// typename Vec3::Scalar dot00 = v0.dot(v0);
+// typename Vec3::Scalar dot01 = v0.dot(v1);
+// typename Vec3::Scalar dot02 = v0.dot(v2);
+// typename Vec3::Scalar dot11 = v1.dot(v1);
+// typename Vec3::Scalar dot12 = v1.dot(v2);
+//
+// // Compute barycentric coordinates
+// typename Vec3::Scalar invDenom = 1 / (dot00 * dot11 - dot01 * dot01);
+// typename Vec3::Scalar u = (dot11 * dot02 - dot01 * dot12) * invDenom;
+// typename Vec3::Scalar v = (dot00 * dot12 - dot01 * dot02) * invDenom;
+//
+// // Check if point is in triangle
+// if((u >= 0) && (v >= 0) && (u + v < 1))
+// {
+// return true;
+// }
+// }
+// return false;
+// }
+//
+// bool overlaps(const Triangle &that) const
+// {
+// // Edges cross
+// for(int e = 0;e<3;e++)
+// {
+// for(int f = 0;f<3;f++)
+// {
+// if(seg_seg_intersect(
+// this->c[e],this->c[(e+1)%3],
+// that.c[e],that.c[(e+1)%3]))
+// {
+// return true;
+// }
+// }
+// }
+// // This could be entirely inside that
+// if(this->has_corner_inside(that))
+// {
+// return true;
+// }
+// // vice versa
+// if(that.has_corner_inside(*this))
+// {
+// return true;
+// }
+// return false;
+// }
+//
+//
+// bool operator< (const Triangle &that) const
+// {
+// // THIS < THAT if "depth" of THIS < "depth" of THAT
+// // " if THIS should be draw before THAT
+// using namespace std;
+// bool ret = false;
+// // Self compare
+// if(that.id == this->id)
+// {
+// ret = false;
+// }
+// if(this->is_completely_behind(that))
+// {
+// cout<<" "<<this->id<<" completely behind "<<that.id<<endl;
+// ret = false;
+// }else if(that.is_completely_behind(*this))
+// {
+// cout<<" "<<that.id<<" completely behind "<<this->id<<endl;
+// ret = true;
+// }else
+// {
+// if(!this->overlaps(that))
+// {
+// assert(!that.overlaps(*this));
+// cout<<" THIS does not overlap THAT"<<endl;
+// // No overlap use barycenter
+// return
+// 1./3.*(this->c[0](2) + this->c[1](2) + this->c[2](2)) >
+// 1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2));
+// }else
+// {
+// if(this->is_coplanar(that) || that.is_coplanar(*this))
+// {
+// cout<<" coplanar"<<endl;
+// // co-planar: decide based on barycenter depth
+// ret =
+// 1./3.*(this->c[0](2) + this->c[1](2) + this->c[2](2)) >
+// 1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2));
+// }else if(this->is_behind_plane(that))
+// {
+// cout<<" THIS behind plane of THAT"<<endl;
+// ret = true;
+// }else if(that.is_behind_plane(*this))
+// {
+// cout<<" THAT behind of plane of THIS"<<endl;
+// ret = false;
+// // THAT is in front of plane of THIS
+// }else if(that.is_in_front_of_plane(*this))
+// {
+// cout<<" THAT in front of plane of THIS"<<endl;
+// ret = true;
+// // THIS is in front of plane of THAT
+// }else if(this->is_in_front_of_plane(that))
+// {
+// cout<<" THIS in front plane of THAT"<<endl;
+// ret = false;
+// }else
+// {
+// cout<<" compare bary"<<endl;
+// ret =
+// 1./3.*(this->c[0](2) + this->c[1](2) + this->c[2](2)) >
+// 1./3.*(that.c[0](2) + that.c[1](2) + that.c[2](2));
+// }
+// }
+// }
+// if(ret)
+// {
+// // THIS < THAT so better not be THAT < THIS
+// cout<<this->id<<" < "<<that.id<<endl;
+// assert(!(that < *this));
+// }else
+// {
+// // THIS >= THAT so could be THAT < THIS or THAT == THIS
+// }
+// return ret;
+// }
+//};
+//#include <igl/matlab/MatlabWorkspace.h>
+//
+//template <
+// typename DerivedV,
+// typename DerivedF,
+// typename DerivedMV,
+// typename DerivedP,
+// typename DerivedFF,
+// typename DerivedI>
+//IGL_INLINE void igl::sort_triangles_robust(
+// const Eigen::PlainObjectBase<DerivedV> & V,
+// const Eigen::PlainObjectBase<DerivedF> & F,
+// const Eigen::PlainObjectBase<DerivedMV> & MV,
+// const Eigen::PlainObjectBase<DerivedP> & P,
+// Eigen::PlainObjectBase<DerivedFF> & FF,
+// Eigen::PlainObjectBase<DerivedI> & I)
+//{
+// assert(false &&
+// "THIS WILL NEVER WORK because depth sorting is not a numerical sort where"
+// "pairwise comparisons of triangles are transitive. Rather it is a"
+// "topological sort on a dependency graph. Dependency encodes 'This triangle"
+// "must be drawn before that one'");
+// using namespace std;
+// using namespace Eigen;
+// typedef Matrix<typename DerivedV::Scalar,3,1> Vec3;
+// assert(V.cols() == 4);
+// Matrix<typename DerivedV::Scalar, DerivedV::RowsAtCompileTime,3> VMVP =
+// V*(MV.transpose()*P.transpose().eval().block(0,0,4,3));
+//
+// MatrixXd projV(V.rows(),3);
+// for(int v = 0;v<V.rows();v++)
+// {
+// Vector3d vv;
+// vv(0) = V(v,0);
+// vv(1) = V(v,1);
+// vv(2) = V(v,2);
+// Vector3d p;
+// project(vv,p);
+// projV.row(v) = p;
+// }
+//
+// vector<Triangle<Vec3> > vF(F.rows());
+// MatrixXd N(F.rows(),3);
+// MatrixXd C(F.rows()*3,3);
+// for(int f = 0;f<F.rows();f++)
+// {
+// vF[f] =
+// //Triangle<Vec3>(f,VMVP.row(F(f,0)),VMVP.row(F(f,1)),VMVP.row(F(f,2)));
+// Triangle<Vec3>(f,projV.row(F(f,0)),projV.row(F(f,1)),projV.row(F(f,2)));
+// N.row(f) = vF[f].n;
+// for(int c = 0;c<3;c++)
+// for(int d = 0;d<3;d++)
+// C(f*3+c,d) = vF[f].c[c](d);
+// }
+// MatlabWorkspace mw;
+// mw.save_index(F,"F");
+// mw.save(V,"V");
+// mw.save(MV,"MV");
+// mw.save(P,"P");
+// Vector4i VP;
+// glGetIntegerv(GL_VIEWPORT, VP.data());
+// mw.save(projV,"projV");
+// mw.save(VP,"VP");
+// mw.save(VMVP,"VMVP");
+// mw.save(N,"N");
+// mw.save(C,"C");
+// mw.write("ao.mat");
+// sort(vF.begin(),vF.end());
+//
+// // check
+// for(int f = 0;f<F.rows();f++)
+// {
+// for(int g = f+1;g<F.rows();g++)
+// {
+// assert(!(vF[g] < vF[f])); // should never happen
+// }
+// }
+// FF.resize(F.rows(),3);
+// I.resize(F.rows(),1);
+// for(int f = 0;f<F.rows();f++)
+// {
+// FF.row(f) = F.row(vF[f].id);
+// I(f) = vF[f].id;
+// }
+//
+// mw.save_index(FF,"FF");
+// mw.save_index(I,"I");
+// mw.write("ao.mat");
+//}
+
+//template <
+// typename DerivedV,
+// typename DerivedF,
+// typename DerivedFF,
+// typename DerivedI>
+//IGL_INLINE void igl::sort_triangles_robust(
+// const Eigen::PlainObjectBase<DerivedV> & V,
+// const Eigen::PlainObjectBase<DerivedF> & F,
+// Eigen::PlainObjectBase<DerivedFF> & FF,
+// Eigen::PlainObjectBase<DerivedI> & I)
+//{
+// using namespace Eigen;
+// using namespace std;
+// // Put model, projection, and viewport matrices into double arrays
+// Matrix4d MV;
+// Matrix4d P;
+// glGetDoublev(GL_MODELVIEW_MATRIX, MV.data());
+// glGetDoublev(GL_PROJECTION_MATRIX, P.data());
+// if(V.cols() == 3)
+// {
+// Matrix<typename DerivedV::Scalar, DerivedV::RowsAtCompileTime,4> hV;
+// hV.resize(V.rows(),4);
+// hV.block(0,0,V.rows(),V.cols()) = V;
+// hV.col(3).setConstant(1);
+// return sort_triangles_robust(hV,F,MV,P,FF,I);
+// }else
+// {
+// return sort_triangles_robust(V,F,MV,P,FF,I);
+// }
+//}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::sort_triangles<Eigen::Matrix<double, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 0, 4, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 0, 4, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sort_triangles<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<double, 4, 4, 0, 4, 4>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 0, 4, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 4, 4, 0, 4, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/sort_triangles.h b/xs/src/igl/sort_triangles.h
new file mode 100644
index 000000000..b334e6530
--- /dev/null
+++ b/xs/src/igl/sort_triangles.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SORT_TRIANGLES_H
+#define IGL_SORT_TRIANGLES_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // Inputs:
+ // V #V by **4** list of homogeneous vertex positions
+ // F #F by 3 list of triangle indices
+ // MV 4 by 4 model view matrix
+ // P 4 by 4 projection matrix
+ // Outputs:
+ // FF #F by 3 list of sorted triangles indices
+ // I #F list of sorted indices
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedMV,
+ typename DerivedP,
+ typename DerivedFF,
+ typename DerivedI>
+ IGL_INLINE void sort_triangles(
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedMV> & MV,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ Eigen::PlainObjectBase<DerivedFF> & FF,
+ Eigen::PlainObjectBase<DerivedI> & I);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "sort_triangles.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/sort_vectors_ccw.cpp b/xs/src/igl/sort_vectors_ccw.cpp
new file mode 100644
index 000000000..ea613c51b
--- /dev/null
+++ b/xs/src/igl/sort_vectors_ccw.cpp
@@ -0,0 +1,103 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include <igl/sort_vectors_ccw.h>
+#include <igl/sort.h>
+#include <Eigen/Dense>
+
+template <typename DerivedS, typename DerivedI>
+IGL_INLINE void igl::sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order)
+{
+ int half_degree = P.cols()/3;
+ //local frame
+ Eigen::Matrix<typename DerivedS::Scalar,1,3> e1 = P.head(3).normalized();
+ Eigen::Matrix<typename DerivedS::Scalar,1,3> e3 = N.normalized();
+ Eigen::Matrix<typename DerivedS::Scalar,1,3> e2 = e3.cross(e1);
+
+ Eigen::Matrix<typename DerivedS::Scalar,3,3> F; F<<e1.transpose(),e2.transpose(),e3.transpose();
+
+ Eigen::Matrix<typename DerivedS::Scalar,Eigen::Dynamic,1> angles(half_degree,1);
+ for (int i=0; i<half_degree; ++i)
+ {
+ Eigen::Matrix<typename DerivedS::Scalar,1,3> Pl = F.colPivHouseholderQr().solve(P.segment(i*3,3).transpose()).transpose();
+// assert(fabs(Pl(2))/Pl.cwiseAbs().maxCoeff() <1e-5);
+ angles[i] = atan2(Pl(1),Pl(0));
+ }
+
+ igl::sort( angles, 1, true, angles, order);
+ //make sure that the first element is always at the top
+ while (order[0] != 0)
+ {
+ //do a circshift
+ int temp = order[0];
+ for (int i =0; i< half_degree-1; ++i)
+ order[i] = order[i+1];
+ order(half_degree-1) = temp;
+ }
+}
+
+template <typename DerivedS, typename DerivedI>
+IGL_INLINE void igl::sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order,
+ Eigen::PlainObjectBase<DerivedS> &sorted)
+ {
+ int half_degree = P.cols()/3;
+ igl::sort_vectors_ccw(P,N,order);
+ sorted.resize(1,half_degree*3);
+ for (int i=0; i<half_degree; ++i)
+ sorted.segment(i*3,3) = P.segment(order[i]*3,3);
+ }
+
+template <typename DerivedS, typename DerivedI>
+IGL_INLINE void igl::sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order,
+ Eigen::PlainObjectBase<DerivedI> &inv_order)
+ {
+ int half_degree = P.cols()/3;
+ igl::sort_vectors_ccw(P,N,order);
+ inv_order.resize(half_degree,1);
+ for (int i=0; i<half_degree; ++i)
+ {
+ for (int j=0; j<half_degree; ++j)
+ if (order[j] ==i)
+ {
+ inv_order(i) = j;
+ break;
+ }
+ }
+ assert(inv_order[0] == 0);
+ }
+
+template <typename DerivedS, typename DerivedI>
+IGL_INLINE void igl::sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order,
+ Eigen::PlainObjectBase<DerivedS> &sorted,
+ Eigen::PlainObjectBase<DerivedI> &inv_order)
+{
+ int half_degree = P.cols()/3;
+
+ igl::sort_vectors_ccw(P,N,order,inv_order);
+
+ sorted.resize(1,half_degree*3);
+ for (int i=0; i<half_degree; ++i)
+ sorted.segment(i*3,3) = P.segment(order[i]*3,3);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::sort_vectors_ccw<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sort_vectors_ccw<Eigen::Matrix<double, 1, -1, 1, 1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, -1, 1, 1, -1> >&);
+#endif
diff --git a/xs/src/igl/sort_vectors_ccw.h b/xs/src/igl/sort_vectors_ccw.h
new file mode 100644
index 000000000..73c2f6fba
--- /dev/null
+++ b/xs/src/igl/sort_vectors_ccw.h
@@ -0,0 +1,68 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Olga Diamanti <olga.diam@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef IGL_SORT_VECTORS_CCW
+#define IGL_SORT_VECTORS_CCW
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl {
+ // Sorts a set of N coplanar vectors in a ccw order, and returns their order.
+ // Optionally it also returns a copy of the ordered vector set, or the indices,
+ // in the original unordered set, of the vectors in the ordered set (called here
+ // the "inverse" set of indices).
+
+ // Inputs:
+ // P 1 by 3N row vector of the vectors to be sorted, stacked horizontally
+ // N #1 by 3 normal of the plane where the vectors lie
+ // Output:
+ // order N by 1 order of the vectors (indices of the unordered vectors into
+ // the ordered vector set)
+ // sorted 1 by 3N row vector of the ordered vectors, stacked horizontally
+ // inv_order N by 1 "inverse" order of the vectors (the indices of the ordered
+ // vectors into the unordered vector set)
+ //
+ template <typename DerivedS, typename DerivedI>
+ IGL_INLINE void sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order,
+ Eigen::PlainObjectBase<DerivedS> &sorted,
+ Eigen::PlainObjectBase<DerivedI> &inv_order);
+
+ template <typename DerivedS, typename DerivedI>
+ IGL_INLINE void sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order,
+ Eigen::PlainObjectBase<DerivedS> &sorted);
+
+ template <typename DerivedS, typename DerivedI>
+ IGL_INLINE void sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order,
+ Eigen::PlainObjectBase<DerivedI> &inv_order);
+
+
+ template <typename DerivedS, typename DerivedI>
+ IGL_INLINE void sort_vectors_ccw(
+ const Eigen::PlainObjectBase<DerivedS>& P,
+ const Eigen::PlainObjectBase<DerivedS>& N,
+ Eigen::PlainObjectBase<DerivedI> &order);
+
+};
+
+
+#ifndef IGL_STATIC_LIBRARY
+#include "sort_vectors_ccw.cpp"
+#endif
+
+
+#endif /* defined(IGL_FIELD_LOCAL_GLOBAL_CONVERSIONS) */
diff --git a/xs/src/igl/sortrows.cpp b/xs/src/igl/sortrows.cpp
new file mode 100644
index 000000000..a5e084fd8
--- /dev/null
+++ b/xs/src/igl/sortrows.cpp
@@ -0,0 +1,142 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sortrows.h"
+#include "get_seconds.h"
+
+#include "SortableRow.h"
+#include "sort.h"
+#include "colon.h"
+#include "IndexComparison.h"
+
+#include <vector>
+
+// Obsolete slower version converst to vector
+//template <typename DerivedX, typename DerivedIX>
+//IGL_INLINE void igl::sortrows(
+// const Eigen::DenseBase<DerivedX>& X,
+// const bool ascending,
+// Eigen::PlainObjectBase<DerivedX>& Y,
+// Eigen::PlainObjectBase<DerivedIX>& IX)
+//{
+// using namespace std;
+// using namespace Eigen;
+// typedef Eigen::Matrix<typename DerivedX::Scalar, Eigen::Dynamic, 1> RowVector;
+// vector<SortableRow<RowVector> > rows;
+// rows.resize(X.rows());
+// // Loop over rows
+// for(int i = 0;i<X.rows();i++)
+// {
+// RowVector ri = X.row(i);
+// rows[i] = SortableRow<RowVector>(ri);
+// }
+// vector<SortableRow<RowVector> > sorted;
+// std::vector<size_t> index_map;
+// // Perform sort on rows
+// igl::sort(rows,ascending,sorted,index_map);
+// // Resize output
+// Y.resizeLike(X);
+// IX.resize(X.rows(),1);
+// // Convert to eigen
+// for(int i = 0;i<X.rows();i++)
+// {
+// Y.row(i) = sorted[i].data;
+// IX(i,0) = index_map[i];
+// }
+//}
+
+template <typename DerivedX, typename DerivedIX>
+IGL_INLINE void igl::sortrows(
+ const Eigen::DenseBase<DerivedX>& X,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedX>& Y,
+ Eigen::PlainObjectBase<DerivedIX>& IX)
+{
+ // This is already 2x faster than matlab's builtin `sortrows`. I have tried
+ // implementing a "multiple-pass" sort on each column, but see no performance
+ // improvement.
+ using namespace std;
+ using namespace Eigen;
+ // Resize output
+ const size_t num_rows = X.rows();
+ const size_t num_cols = X.cols();
+ Y.resize(num_rows,num_cols);
+ IX.resize(num_rows,1);
+ for(int i = 0;i<num_rows;i++)
+ {
+ IX(i) = i;
+ }
+ if (ascending) {
+ auto index_less_than = [&X, num_cols](size_t i, size_t j) {
+ for (size_t c=0; c<num_cols; c++) {
+ if (X.coeff(i, c) < X.coeff(j, c)) return true;
+ else if (X.coeff(j,c) < X.coeff(i,c)) return false;
+ }
+ return false;
+ };
+ std::sort(
+ IX.data(),
+ IX.data()+IX.size(),
+ index_less_than
+ );
+ } else {
+ auto index_greater_than = [&X, num_cols](size_t i, size_t j) {
+ for (size_t c=0; c<num_cols; c++) {
+ if (X.coeff(i, c) > X.coeff(j, c)) return true;
+ else if (X.coeff(j,c) > X.coeff(i,c)) return false;
+ }
+ return false;
+ };
+ std::sort(
+ IX.data(),
+ IX.data()+IX.size(),
+ index_greater_than
+ );
+ }
+ for (size_t j=0; j<num_cols; j++) {
+ for(int i = 0;i<num_rows;i++)
+ {
+ Y(i,j) = X(IX(i), j);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::sortrows<Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<long long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long long, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Matrix<long long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long long, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::sortrows<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::sortrows<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::sortrows<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::sortrows<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::sortrows<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sortrows<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sortrows<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::sortrows<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::sortrows<class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,bool,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+template void igl::sortrows<class Eigen::Matrix<int,-1,2,0,-1,2>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<int,-1,2,0,-1,2> > const &,bool,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+template void igl::sortrows<class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,bool,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+template void igl::sortrows<class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<double,-1,3,0,-1,3> > const &,bool,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+#endif
+#endif
diff --git a/xs/src/igl/sortrows.h b/xs/src/igl/sortrows.h
new file mode 100644
index 000000000..c0b15f29e
--- /dev/null
+++ b/xs/src/igl/sortrows.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SORTROWS_H
+#define IGL_SORTROWS_H
+#include "igl_inline.h"
+
+#include <vector>
+#include <Eigen/Core>
+namespace igl
+{
+ // Act like matlab's [Y,I] = sortrows(X)
+ //
+ // Templates:
+ // DerivedX derived scalar type, e.g. MatrixXi or MatrixXd
+ // DerivedI derived integer type, e.g. MatrixXi
+ // Inputs:
+ // X m by n matrix whose entries are to be sorted
+ // ascending sort ascending (true, matlab default) or descending (false)
+ // Outputs:
+ // Y m by n matrix whose entries are sorted (**should not** be same
+ // reference as X)
+ // I m list of indices so that
+ // Y = X(I,:);
+ template <typename DerivedX, typename DerivedI>
+ IGL_INLINE void sortrows(
+ const Eigen::DenseBase<DerivedX>& X,
+ const bool ascending,
+ Eigen::PlainObjectBase<DerivedX>& Y,
+ Eigen::PlainObjectBase<DerivedI>& I);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "sortrows.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/sparse.cpp b/xs/src/igl/sparse.cpp
new file mode 100644
index 000000000..ed9cd4a49
--- /dev/null
+++ b/xs/src/igl/sparse.cpp
@@ -0,0 +1,123 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sparse.h"
+
+#include <iostream>
+#include <vector>
+
+template <class IndexVector, class ValueVector, typename T>
+IGL_INLINE void igl::sparse(
+ const IndexVector & I,
+ const IndexVector & J,
+ const ValueVector & V,
+ Eigen::SparseMatrix<T>& X)
+{
+ size_t m = (size_t)I.maxCoeff()+1;
+ size_t n = (size_t)J.maxCoeff()+1;
+ return igl::sparse(I,J,V,m,n,X);
+}
+
+#include "verbose.h"
+template <
+ class IndexVectorI,
+ class IndexVectorJ,
+ class ValueVector,
+ typename T>
+IGL_INLINE void igl::sparse(
+ const IndexVectorI & I,
+ const IndexVectorJ & J,
+ const ValueVector & V,
+ const size_t m,
+ const size_t n,
+ Eigen::SparseMatrix<T>& X)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert((int)I.maxCoeff() < (int)m);
+ assert((int)I.minCoeff() >= 0);
+ assert((int)J.maxCoeff() < (int)n);
+ assert((int)J.minCoeff() >= 0);
+ assert(I.size() == J.size());
+ assert(J.size() == V.size());
+ // Really we just need .size() to be the same, but this is safer
+ assert(I.rows() == J.rows());
+ assert(J.rows() == V.rows());
+ assert(I.cols() == J.cols());
+ assert(J.cols() == V.cols());
+ //// number of values
+ //int nv = V.size();
+
+ //Eigen::DynamicSparseMatrix<T, Eigen::RowMajor> dyn_X(m,n);
+ //// over estimate the number of entries
+ //dyn_X.reserve(I.size());
+ //for(int i = 0;i < nv;i++)
+ //{
+ // dyn_X.coeffRef((int)I(i),(int)J(i)) += (T)V(i);
+ //}
+ //X = Eigen::SparseMatrix<T>(dyn_X);
+ vector<Triplet<T> > IJV;
+ IJV.reserve(I.size());
+ for(int x = 0;x<I.size();x++)
+ {
+ IJV.push_back(Triplet<T >(I(x),J(x),V(x)));
+ }
+ X.resize(m,n);
+ X.setFromTriplets(IJV.begin(),IJV.end());
+}
+
+template <typename DerivedD, typename T>
+IGL_INLINE void igl::sparse(
+ const Eigen::PlainObjectBase<DerivedD>& D,
+ Eigen::SparseMatrix<T>& X)
+{
+ assert(false && "Obsolete. Just call D.sparseView() directly");
+ using namespace std;
+ using namespace Eigen;
+ vector<Triplet<T> > DIJV;
+ const int m = D.rows();
+ const int n = D.cols();
+ for(int i = 0;i<m;i++)
+ {
+ for(int j = 0;j<n;j++)
+ {
+ if(D(i,j)!=0)
+ {
+ DIJV.push_back(Triplet<T>(i,j,D(i,j)));
+ }
+ }
+ }
+ X.resize(m,n);
+ X.setFromTriplets(DIJV.begin(),DIJV.end());
+}
+
+template <typename DerivedD>
+IGL_INLINE Eigen::SparseMatrix<typename DerivedD::Scalar > igl::sparse(
+ const Eigen::PlainObjectBase<DerivedD>& D)
+{
+ assert(false && "Obsolete. Just call D.sparseView() directly");
+ Eigen::SparseMatrix<typename DerivedD::Scalar > X;
+ igl::sparse(D,X);
+ return X;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+#ifndef WIN32
+//template void igl::sparse<Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<bool>, Eigen::Array<bool, -1, 2, 0, -1, 2> >, bool>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::Matrix<int, -1, -1, 0, -1, -1> const&, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<bool>, Eigen::Array<bool, -1, 2, 0, -1, 2> > const&, unsigned long, unsigned long, Eigen::SparseMatrix<bool, 0, int>&);
+//template void igl::sparse<Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<bool>, Eigen::Array<bool, -1, 3, 0, -1, 3> >, bool>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<bool>, Eigen::Array<bool, -1, 3, 0, -1, 3> > const&, unsigned long, unsigned long, Eigen::SparseMatrix<bool, 0, int>&);
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+#else
+//template void igl::sparse<Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<int, true>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<bool>, Eigen::Array<bool, -1, 1, 0, -1, 1> >, bool>(Eigen::CwiseNullaryOp<Eigen::internal::linspaced_op<int, true>, Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::CwiseNullaryOp<Eigen::internal::scalar_constant_op<bool>, Eigen::Array<bool, -1, 1, 0, -1, 1> > const&, unsigned long, unsigned long, Eigen::SparseMatrix<bool, 0, int>&);
+#endif
+#endif
+
+template void igl::sparse<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, std::complex<double> >(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, size_t, size_t, Eigen::SparseMatrix<std::complex<double>, 0, int>&);
+template void igl::sparse<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::sparse<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double>(Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::Matrix<double, -1, 1, 0, -1, 1> const&, size_t, size_t, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/sparse.h b/xs/src/igl/sparse.h
new file mode 100644
index 000000000..a947978ab
--- /dev/null
+++ b/xs/src/igl/sparse.h
@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SPARSE_H
+#define IGL_SPARSE_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Build a sparse matrix from list of indices and values (I,J,V), functions
+ // like the sparse function in matlab
+ //
+ // Templates:
+ // IndexVector list of indices, value should be non-negative and should
+ // expect to be cast to an index. Must implement operator(i) to retrieve
+ // ith element
+ // ValueVector list of values, value should be expect to be cast to type
+ // T. Must implement operator(i) to retrieve ith element
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Input:
+ // I nnz vector of row indices of non zeros entries in X
+ // J nnz vector of column indices of non zeros entries in X
+ // V nnz vector of non-zeros entries in X
+ // Optional:
+ // m number of rows
+ // n number of cols
+ // Outputs:
+ // X m by n matrix of type T whose entries are to be found
+ //
+ template <class IndexVector, class ValueVector, typename T>
+ IGL_INLINE void sparse(
+ const IndexVector & I,
+ const IndexVector & J,
+ const ValueVector & V,
+ Eigen::SparseMatrix<T>& X);
+ template <
+ class IndexVectorI,
+ class IndexVectorJ,
+ class ValueVector,
+ typename T>
+ IGL_INLINE void sparse(
+ const IndexVectorI & I,
+ const IndexVectorJ & J,
+ const ValueVector & V,
+ const size_t m,
+ const size_t n,
+ Eigen::SparseMatrix<T>& X);
+ // THIS MAY BE SUPERSEDED BY EIGEN'S .sparseView Indeed it is.
+ // Convert a full, dense matrix to a sparse one
+ //
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Input:
+ // D m by n full, dense matrix
+ // Output:
+ // X m by n sparse matrix
+ template <typename DerivedD, typename T>
+ IGL_INLINE void sparse(
+ const Eigen::PlainObjectBase<DerivedD>& D,
+ Eigen::SparseMatrix<T>& X);
+ // Wrapper with return
+ template <typename DerivedD>
+ IGL_INLINE Eigen::SparseMatrix<typename DerivedD::Scalar > sparse(
+ const Eigen::PlainObjectBase<DerivedD>& D);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "sparse.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/sparse_cached.cpp b/xs/src/igl/sparse_cached.cpp
new file mode 100644
index 000000000..ddd65aadf
--- /dev/null
+++ b/xs/src/igl/sparse_cached.cpp
@@ -0,0 +1,127 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sparse_cached.h"
+
+#include <iostream>
+#include <vector>
+#include <array>
+#include <unordered_map>
+#include <map>
+#include <utility>
+
+template <typename DerivedI, typename Scalar>
+IGL_INLINE void igl::sparse_cached_precompute(
+ const Eigen::MatrixBase<DerivedI> & I,
+ const Eigen::MatrixBase<DerivedI> & J,
+ Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X)
+{
+ // Generates the triplets
+ std::vector<Eigen::Triplet<double> > t(I.size());
+ for (unsigned i = 0; i<I.size(); ++i)
+ t[i] = Eigen::Triplet<double>(I[i],J[i],1);
+
+ // Call the triplets version
+ sparse_cached_precompute(t,X,data);
+}
+
+template <typename Scalar>
+IGL_INLINE void igl::sparse_cached_precompute(
+ const std::vector<Eigen::Triplet<Scalar> >& triplets,
+ Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X)
+{
+ // Construct an empty sparse matrix
+ X.setFromTriplets(triplets.begin(),triplets.end());
+ X.makeCompressed();
+
+ std::vector<std::array<int,3> > T(triplets.size());
+ for (unsigned i=0; i<triplets.size(); ++i)
+ {
+ T[i][0] = triplets[i].col();
+ T[i][1] = triplets[i].row();
+ T[i][2] = i;
+ }
+
+ std::sort(T.begin(), T.end());
+
+ data.resize(triplets.size());
+
+ int t = 0;
+
+ for (unsigned k=0; k<X.outerSize(); ++k)
+ {
+ unsigned outer_index = *(X.outerIndexPtr()+k);
+ unsigned next_outer_index = (k+1 == X.outerSize()) ? X.nonZeros() : *(X.outerIndexPtr()+k+1);
+
+ for (unsigned l=outer_index; l<next_outer_index; ++l)
+ {
+ int col = k;
+ int row = *(X.innerIndexPtr()+l);
+ int value_index = l;
+ assert(col < X.cols());
+ assert(col >= 0);
+ assert(row < X.rows());
+ assert(row >= 0);
+ assert(value_index >= 0);
+ assert(value_index < X.nonZeros());
+
+ std::pair<int,int> p_m = std::make_pair(row,col);
+
+ while (t<T.size() && (p_m == std::make_pair(T[t][1],T[t][0])))
+ data[T[t++][2]] = value_index;
+ }
+ }
+ assert(t==T.size());
+
+}
+
+template <typename Scalar>
+IGL_INLINE void igl::sparse_cached(
+ const std::vector<Eigen::Triplet<Scalar> >& triplets,
+ const Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X)
+{
+ assert(triplets.size() == data.size());
+
+ // Clear it first
+ for (unsigned i = 0; i<data.size(); ++i)
+ *(X.valuePtr() + data[i]) = 0;
+
+ // Then sum them up
+ for (unsigned i = 0; i<triplets.size(); ++i)
+ *(X.valuePtr() + data[i]) += triplets[i].value();
+}
+
+template <typename DerivedV, typename Scalar>
+IGL_INLINE void igl::sparse_cached(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X)
+{
+ assert(V.size() == data.size());
+
+ // Clear it first
+ for (unsigned i = 0; i<data.size(); ++i)
+ *(X.valuePtr() + data[i]) = 0;
+
+ // Then sum them up
+ for (unsigned i = 0; i<V.size(); ++i)
+ *(X.valuePtr() + data[i]) += V[i];
+}
+
+
+#ifdef IGL_STATIC_LIBRARY
+#if EIGEN_VERSION_AT_LEAST(3,3,0)
+ template void igl::sparse_cached<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+ template void igl::sparse_cached_precompute<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::StorageIndex> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&, Eigen::SparseMatrix<double, 0, int>&);
+#else
+ template void igl::sparse_cached<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1> const&, Eigen::SparseMatrix<double, 0, int>&);
+ template void igl::sparse_cached_precompute<double>(std::vector<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index>, std::allocator<Eigen::Triplet<double, Eigen::SparseMatrix<double, 0, int>::Index> > > const&, Eigen::Matrix<int, -1, 1, 0, -1, 1>&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
+#endif
diff --git a/xs/src/igl/sparse_cached.h b/xs/src/igl/sparse_cached.h
new file mode 100644
index 000000000..40d288962
--- /dev/null
+++ b/xs/src/igl/sparse_cached.h
@@ -0,0 +1,85 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SPARSE_CACHED_H
+#define IGL_SPARSE_CACHED_H
+#include "igl_inline.h"
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+namespace igl
+{
+ // Build a sparse matrix from list of indices and values (I,J,V), similarly to
+ // the sparse function in matlab. Divides the construction in two phases, one
+ // for fixing the sparsity pattern, and one to populate it with values. Compared to
+ // igl::sparse, this version is slower for the first time (since it requires a
+ // precomputation), but faster to the subsequent evaluations.
+ //
+ // Templates:
+ // IndexVector list of indices, value should be non-negative and should
+ // expect to be cast to an index. Must implement operator(i) to retrieve
+ // ith element
+ // ValueVector list of values, value should be expect to be cast to type
+ // T. Must implement operator(i) to retrieve ith element
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Input:
+ // I nnz vector of row indices of non zeros entries in X
+ // J nnz vector of column indices of non zeros entries in X
+ // V nnz vector of non-zeros entries in X
+ // Optional:
+ // m number of rows
+ // n number of cols
+ // Outputs:
+ // X m by n matrix of type T whose entries are to be found
+ //
+ // Example:
+ // Eigen::SparseMatrix<double> A;
+ // std::vector<Eigen::Triplet<double> > IJV;
+ // buildA(IJV);
+ // if (A.rows() == 0)
+ // {
+ // A = Eigen::SparseMatrix<double>(rows,cols);
+ // igl::sparse_cached_precompute(IJV,A,A_data);
+ // }
+ // else
+ // igl::sparse_cached(IJV,s.A,s.A_data);
+
+ template <typename DerivedI, typename Scalar>
+ IGL_INLINE void sparse_cached_precompute(
+ const Eigen::MatrixBase<DerivedI> & I,
+ const Eigen::MatrixBase<DerivedI> & J,
+ Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X
+ );
+
+ template <typename Scalar>
+ IGL_INLINE void sparse_cached_precompute(
+ const std::vector<Eigen::Triplet<Scalar> >& triplets,
+ Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X
+ );
+
+ template <typename Scalar>
+ IGL_INLINE void sparse_cached(
+ const std::vector<Eigen::Triplet<Scalar> >& triplets,
+ const Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X);
+
+ template <typename DerivedV, typename Scalar>
+ IGL_INLINE void sparse_cached(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::VectorXi& data,
+ Eigen::SparseMatrix<Scalar>& X
+ );
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "sparse_cached.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/speye.cpp b/xs/src/igl/speye.cpp
new file mode 100644
index 000000000..54af00c71
--- /dev/null
+++ b/xs/src/igl/speye.cpp
@@ -0,0 +1,35 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "speye.h"
+
+template <typename T>
+IGL_INLINE void igl::speye(const int m, const int n, Eigen::SparseMatrix<T> & I)
+{
+ // size of diagonal
+ int d = (m<n?m:n);
+ I = Eigen::SparseMatrix<T>(m,n);
+ I.reserve(d);
+ for(int i = 0;i<d;i++)
+ {
+ I.insert(i,i) = 1.0;
+ }
+ I.finalize();
+}
+
+template <typename T>
+IGL_INLINE void igl::speye(const int n, Eigen::SparseMatrix<T> & I)
+{
+ return igl::speye(n,n,I);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::speye<double>(int, Eigen::SparseMatrix<double, 0, int>&);
+template void igl::speye<std::complex<double> >(int, int, Eigen::SparseMatrix<std::complex<double>, 0, int>&);
+#endif
diff --git a/xs/src/igl/speye.h b/xs/src/igl/speye.h
new file mode 100644
index 000000000..4c2425571
--- /dev/null
+++ b/xs/src/igl/speye.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SPEYE_H
+#define IGL_SPEYE_H
+#include "igl_inline.h"
+
+#define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Builds an m by n sparse identity matrix like matlab's speye function
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // m number of rows
+ // n number of cols
+ // Outputs:
+ // I m by n sparse matrix with 1's on the main diagonal
+ template <typename T>
+ IGL_INLINE void speye(const int n,const int m, Eigen::SparseMatrix<T> & I);
+ // Builds an n by n sparse identity matrix like matlab's speye function
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // n number of rows and cols
+ // Outputs:
+ // I n by n sparse matrix with 1's on the main diagonal
+ template <typename T>
+ IGL_INLINE void speye(const int n, Eigen::SparseMatrix<T> & I);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "speye.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/squared_edge_lengths.cpp b/xs/src/igl/squared_edge_lengths.cpp
new file mode 100644
index 000000000..d15e6c13e
--- /dev/null
+++ b/xs/src/igl/squared_edge_lengths.cpp
@@ -0,0 +1,106 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "squared_edge_lengths.h"
+#include "parallel_for.h"
+#include <iostream>
+
+template <typename DerivedV, typename DerivedF, typename DerivedL>
+IGL_INLINE void igl::squared_edge_lengths(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedL>& L)
+{
+ using namespace std;
+ const int m = F.rows();
+ switch(F.cols())
+ {
+ case 2:
+ {
+ L.resize(F.rows(),1);
+ for(int i = 0;i<F.rows();i++)
+ {
+ L(i,0) = (V.row(F(i,1))-V.row(F(i,0))).squaredNorm();
+ }
+ break;
+ }
+ case 3:
+ {
+ L.resize(m,3);
+ // loop over faces
+ parallel_for(
+ m,
+ [&V,&F,&L](const int i)
+ {
+ L(i,0) = (V.row(F(i,1))-V.row(F(i,2))).squaredNorm();
+ L(i,1) = (V.row(F(i,2))-V.row(F(i,0))).squaredNorm();
+ L(i,2) = (V.row(F(i,0))-V.row(F(i,1))).squaredNorm();
+ },
+ 1000);
+ break;
+ }
+ case 4:
+ {
+ L.resize(m,6);
+ // loop over faces
+ parallel_for(
+ m,
+ [&V,&F,&L](const int i)
+ {
+ L(i,0) = (V.row(F(i,3))-V.row(F(i,0))).squaredNorm();
+ L(i,1) = (V.row(F(i,3))-V.row(F(i,1))).squaredNorm();
+ L(i,2) = (V.row(F(i,3))-V.row(F(i,2))).squaredNorm();
+ L(i,3) = (V.row(F(i,1))-V.row(F(i,2))).squaredNorm();
+ L(i,4) = (V.row(F(i,2))-V.row(F(i,0))).squaredNorm();
+ L(i,5) = (V.row(F(i,0))-V.row(F(i,1))).squaredNorm();
+ },
+ 1000);
+ break;
+ }
+ default:
+ {
+ cerr<< "squared_edge_lengths.h: Error: Simplex size ("<<F.cols()<<
+ ") not supported"<<endl;
+ assert(false);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+// generated by autoexplicit.sh
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+// generated by autoexplicit.sh
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 2, 0, -1, 2>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 2, 0, -1, 2> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 2, 0, -1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 1, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<double, -1, 6, 0, -1, 6> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> >&);
+template void igl::squared_edge_lengths<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&);
+#endif
diff --git a/xs/src/igl/squared_edge_lengths.h b/xs/src/igl/squared_edge_lengths.h
new file mode 100644
index 000000000..2f374d6c3
--- /dev/null
+++ b/xs/src/igl/squared_edge_lengths.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SQUARED_EDGE_LENGTHS_H
+#define IGL_SQUARED_EDGE_LENGTHS_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Constructs a list of squared lengths of edges opposite each index in a face
+ // (triangle/tet) list
+ //
+ // 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 2 list of mesh edges
+ // or
+ // F #F by 3 list of mesh faces (must be triangles)
+ // or
+ // T #T by 4 list of mesh elements (must be tets)
+ // Outputs:
+ // L #F by {1|3|6} list of edge lengths squared
+ // for edges, column of lengths
+ // for triangles, columns correspond to edges [1,2],[2,0],[0,1]
+ // for tets, columns correspond to edges
+ // [3 0],[3 1],[3 2],[1 2],[2 0],[0 1]
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedL>
+ IGL_INLINE void squared_edge_lengths(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedL>& L);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "squared_edge_lengths.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/stdin_to_temp.cpp b/xs/src/igl/stdin_to_temp.cpp
new file mode 100644
index 000000000..a7a7fbd70
--- /dev/null
+++ b/xs/src/igl/stdin_to_temp.cpp
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "stdin_to_temp.h"
+
+#include <iostream>
+
+IGL_INLINE bool igl::stdin_to_temp(FILE ** temp_file)
+{
+ // get a temporary file
+ *temp_file = tmpfile();
+ if(*temp_file == NULL)
+ {
+ fprintf(stderr,"IOError: temp file could not be created.\n");
+ return false;
+ }
+ char c;
+ // c++'s cin handles the stdind input in a reasonable way
+ while (std::cin.good())
+ {
+ c = std::cin.get();
+ if(std::cin.good())
+ {
+ if(1 != fwrite(&c,sizeof(char),1,*temp_file))
+ {
+ fprintf(stderr,"IOError: error writing to tempfile.\n");
+ return false;
+ }
+ }
+ }
+ // rewind file getting it ready to read from
+ rewind(*temp_file);
+ return true;
+}
diff --git a/xs/src/igl/stdin_to_temp.h b/xs/src/igl/stdin_to_temp.h
new file mode 100644
index 000000000..ae35219ea
--- /dev/null
+++ b/xs/src/igl/stdin_to_temp.h
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_STDIN_TO_TEMP_H
+#define IGL_STDIN_TO_TEMP_H
+#include "igl_inline.h"
+#include <cstdio>
+namespace igl
+{
+ // Write stdin/piped input to a temporary file which can than be preprocessed as it
+ // is (a normal file). This is often useful if you want to process stdin/piped
+ // with library functions that expect to be able to fseek(), rewind() etc..
+ //
+ // If your application is not using fseek(), rewind(), etc. but just reading
+ // from stdin then this will likely cause a bottle neck as it defeats the whole
+ // purpose of piping.
+ //
+ // Outputs:
+ // temp_file pointer to temp file pointer, rewound to beginning of file so
+ // its ready to be read
+ // Return true only if no errors were found
+ //
+ // Note: Caller is responsible for closing the file (tmpfile() automatically
+ // unlinks the file so there is no need to remove/delete/unlink the file)
+ IGL_INLINE bool stdin_to_temp(FILE ** temp_file);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "stdin_to_temp.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/straighten_seams.cpp b/xs/src/igl/straighten_seams.cpp
new file mode 100644
index 000000000..0aef2b316
--- /dev/null
+++ b/xs/src/igl/straighten_seams.cpp
@@ -0,0 +1,370 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "straighten_seams.h"
+#include "LinSpaced.h"
+#include "on_boundary.h"
+#include "sparse.h"
+#include "max.h"
+#include "count.h"
+#include "any.h"
+#include "slice_mask.h"
+#include "slice_into.h"
+#include "unique_simplices.h"
+#include "adjacency_matrix.h"
+#include "setxor.h"
+#include "edges_to_path.h"
+#include "ramer_douglas_peucker.h"
+#include "components.h"
+#include "list_to_matrix.h"
+#include "ears.h"
+#include "slice.h"
+#include "sum.h"
+#include "find.h"
+#include <iostream>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVT,
+ typename DerivedFT,
+ typename Scalar,
+ typename DerivedUE,
+ typename DerivedUT,
+ typename DerivedOT>
+IGL_INLINE void igl::straighten_seams(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedVT> & VT,
+ const Eigen::MatrixBase<DerivedFT> & FT,
+ const Scalar tol,
+ Eigen::PlainObjectBase<DerivedUE> & UE,
+ Eigen::PlainObjectBase<DerivedUT> & UT,
+ Eigen::PlainObjectBase<DerivedOT> & OT)
+{
+ using namespace Eigen;
+ // number of faces
+ assert(FT.rows() == F.rows() && "#FT must == #F");
+ assert(F.cols() == 3 && "F should contain triangles");
+ assert(FT.cols() == 3 && "FT should contain triangles");
+ const int m = F.rows();
+ // Boundary edges of the texture map and 3d meshes
+ Array<bool,Dynamic,1> _;
+ Array<bool,Dynamic,3> BT,BF;
+ on_boundary(FT,_,BT);
+ on_boundary(F,_,BF);
+ assert((!((BF && (BT!=true)).any())) &&
+ "Not dealing with boundaries of mesh that get 'stitched' in texture mesh");
+ typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
+ const MatrixX2I ET = (MatrixX2I(FT.rows()*3,2)
+ <<FT.col(1),FT.col(2),FT.col(2),FT.col(0),FT.col(0),FT.col(1)).finished();
+ // "half"-edges with indices into 3D-mesh
+ const MatrixX2I EF = (MatrixX2I(F.rows()*3,2)
+ <<F.col(1),F.col(2),F.col(2),F.col(0),F.col(0),F.col(1)).finished();
+ // Find unique (undirected) edges in F
+ VectorXi EFMAP;
+ {
+ MatrixX2I _1;
+ VectorXi _2;
+ unique_simplices(EF,_1,_2,EFMAP);
+ }
+ Array<bool,Dynamic,1>vBT = Map<Array<bool,Dynamic,1> >(BT.data(),BT.size(),1);
+ Array<bool,Dynamic,1>vBF = Map<Array<bool,Dynamic,1> >(BF.data(),BF.size(),1);
+ MatrixX2I OF;
+ slice_mask(ET,vBT,1,OT);
+ slice_mask(EF,vBT,1,OF);
+ VectorXi OFMAP;
+ slice_mask(EFMAP,vBT,1,OFMAP);
+ // Two boundary edges on the texture-mapping are "equivalent" to each other on
+ // the 3D-mesh if their 3D-mesh vertex indices match
+ SparseMatrix<bool> OEQ;
+ {
+ SparseMatrix<bool> OEQR;
+ sparse(
+ igl::LinSpaced<VectorXi >(OT.rows(),0,OT.rows()-1),
+ OFMAP,
+ Array<bool,Dynamic,1>::Ones(OT.rows(),1),
+ OT.rows(),
+ m*3,
+ OEQR);
+ OEQ = OEQR * OEQR.transpose();
+ // Remove diagonal
+ OEQ.prune([](const int r, const int c, const bool)->bool{return r!=c;});
+ }
+ // For each edge in OT, for each endpoint, how many _other_ texture-vertices
+ // are images of all the 3d-mesh vertices in F who map from "corners" in F/FT
+ // mapping to this endpoint.
+ //
+ // Adjacency matrix between 3d-vertices and texture-vertices
+ SparseMatrix<bool> V2VT;
+ sparse(
+ F,
+ FT,
+ Array<bool,Dynamic,3>::Ones(F.rows(),F.cols()),
+ V.rows(),
+ VT.rows(),
+ V2VT);
+ // For each 3d-vertex count how many different texture-coordinates its getting
+ // from different incident corners
+ VectorXi DV;
+ count(V2VT,2,DV);
+ VectorXi M,I;
+ max(V2VT,1,M,I);
+ assert( (M.array() == 1).all() );
+ VectorXi DT;
+ // Map counts onto texture-vertices
+ slice(DV,I,1,DT);
+ // Boundary in 3D && UV
+ Array<bool,Dynamic,1> BTF;
+ slice_mask(vBF, vBT, 1, BTF);
+ // Texture-vertex is "sharp" if incident on "half-"edge that is not a
+ // boundary in the 3D mesh but is a boundary in the texture-mesh AND is not
+ // "cut cleanly" (the vertex is mapped to exactly 2 locations)
+ Array<bool,Dynamic,1> SV = Array<bool,Dynamic,1>::Zero(VT.rows(),1);
+ //std::cout<<"#SV: "<<SV.count()<<std::endl;
+ assert(BTF.size() == OT.rows());
+ for(int h = 0;h<BTF.size();h++)
+ {
+ if(!BTF(h))
+ {
+ SV(OT(h,0)) = true;
+ SV(OT(h,1)) = true;
+ }
+ }
+ //std::cout<<"#SV: "<<SV.count()<<std::endl;
+ Array<bool,Dynamic,1> CL = DT.array()==2;
+ SparseMatrix<bool> VTOT;
+ {
+ Eigen::MatrixXi I =
+ igl::LinSpaced<VectorXi >(OT.rows(),0,OT.rows()-1).replicate(1,2);
+ sparse(
+ OT,
+ I,
+ Array<bool,Dynamic,2>::Ones(OT.rows(),OT.cols()),
+ VT.rows(),
+ OT.rows(),
+ VTOT);
+ Array<int,Dynamic,1> cuts;
+ count( (VTOT*OEQ).eval(), 2, cuts);
+ CL = (CL && (cuts.array() == 2)).eval();
+ }
+ //std::cout<<"#CL: "<<CL.count()<<std::endl;
+ assert(CL.size() == SV.size());
+ for(int c = 0;c<CL.size();c++) if(CL(c)) SV(c) = false;
+ {}
+ //std::cout<<"#SV: "<<SV.count()<<std::endl;
+
+ {
+ // vertices at the corner of ears are declared to be sharp. This is
+ // conservative: for example, if the ear is strictly convex and stays
+ // strictly convex then the ear won't be flipped.
+ VectorXi ear,ear_opp;
+ ears(FT,ear,ear_opp);
+ //std::cout<<"#ear: "<<ear.size()<<std::endl;
+ // There might be an ear on one copy, so mark vertices on other copies, too
+ // ears as they live on the 3D mesh
+ Array<bool,Dynamic,1> earT = Array<bool,Dynamic,1>::Zero(VT.rows(),1);
+ for(int e = 0;e<ear.size();e++) earT(FT(ear(e),ear_opp(e))) = 1;
+ //std::cout<<"#earT: "<<earT.count()<<std::endl;
+ // Even if ear-vertices are marked as sharp if it changes, e.g., from
+ // convex to concave then it will _force_ a flip of the ear triangle. So,
+ // declare that neighbors of ears are also sharp.
+ SparseMatrix<bool> A;
+ adjacency_matrix(FT,A);
+ earT = (earT || (A*earT.matrix()).array()).eval();
+ //std::cout<<"#earT: "<<earT.count()<<std::endl;
+ assert(earT.size() == SV.size());
+ for(int e = 0;e<earT.size();e++) if(earT(e)) SV(e) = true;
+ //std::cout<<"#SV: "<<SV.count()<<std::endl;
+ }
+
+ {
+ SparseMatrix<bool> V2VTSV,V2VTC;
+ slice_mask(V2VT,SV,2,V2VTSV);
+ Array<bool,Dynamic,1> Cb;
+ any(V2VTSV,2,Cb);
+ slice_mask(V2VT,Cb,1,V2VTC);
+ any(V2VTC,1,SV);
+ }
+ //std::cout<<"#SV: "<<SV.count()<<std::endl;
+
+ SparseMatrix<bool> OTVT = VTOT.transpose();
+ int nc;
+ ArrayXi C;
+ {
+ // Doesn't Compile on older Eigen:
+ //SparseMatrix<bool> A = OTVT * (!SV).matrix().asDiagonal() * VTOT;
+ SparseMatrix<bool> A = OTVT * (SV!=true).matrix().asDiagonal() * VTOT;
+ components(A,C);
+ nc = C.maxCoeff()+1;
+ }
+ //std::cout<<"nc: "<<nc<<std::endl;
+ // New texture-vertex locations
+ UT = VT;
+ // Indices into UT of coarse output polygon edges
+ std::vector<std::vector<typename DerivedUE::Scalar> > vUE;
+ // loop over each component
+ std::vector<bool> done(nc,false);
+ for(int c = 0;c<nc;c++)
+ {
+ if(done[c])
+ {
+ continue;
+ }
+ done[c] = true;
+ // edges of this component
+ Eigen::VectorXi Ic;
+ find(C==c,Ic);
+ if(Ic.size() == 0)
+ {
+ continue;
+ }
+ SparseMatrix<bool> OEQIc;
+ slice(OEQ,Ic,1,OEQIc);
+ Eigen::VectorXi N;
+ sum(OEQIc,2,N);
+ const int ncopies = N(0)+1;
+ assert((N.array() == ncopies-1).all());
+ assert((ncopies == 1 || ncopies == 2) &&
+ "Not dealing with non-manifold meshes");
+ Eigen::VectorXi vpath,epath,eend;
+ typedef Eigen::Matrix<Scalar,Eigen::Dynamic,2> MatrixX2S;
+ switch(ncopies)
+ {
+ case 1:
+ {
+ MatrixX2I OTIc;
+ slice(OT,Ic,1,OTIc);
+ edges_to_path(OTIc,vpath,epath,eend);
+ Array<bool,Dynamic,1> SVvpath;
+ slice(SV,vpath,1,SVvpath);
+ assert(
+ (vpath(0) != vpath(vpath.size()-1) || !SVvpath.any()) &&
+ "Not dealing with 1-loops touching 'sharp' corners");
+ // simple open boundary
+ MatrixX2S PI;
+ slice(VT,vpath,1,PI);
+ const Scalar bbd =
+ (PI.colwise().maxCoeff() - PI.colwise().minCoeff()).norm();
+ // Do not collapse boundaries to fewer than 3 vertices
+ const bool allow_boundary_collapse = false;
+ assert(PI.size() >= 2);
+ const bool is_closed = PI(0) == PI(PI.size()-1);
+ assert(!is_closed || vpath.size() >= 4);
+ Scalar eff_tol = std::min(tol,2.);
+ VectorXi UIc;
+ while(true)
+ {
+ MatrixX2S UPI,UTvpath;
+ ramer_douglas_peucker(PI,eff_tol*bbd,UPI,UIc,UTvpath);
+ slice_into(UTvpath,vpath,1,UT);
+ if(!is_closed || allow_boundary_collapse)
+ {
+ break;
+ }
+ if(UPI.rows()>=4)
+ {
+ break;
+ }
+ eff_tol = eff_tol*0.5;
+ }
+ for(int i = 0;i<UIc.size()-1;i++)
+ {
+ vUE.push_back({vpath(UIc(i)),vpath(UIc(i+1))});
+ }
+ }
+ break;
+ case 2:
+ {
+ // Find copies
+ VectorXi Icc;
+ {
+ VectorXi II;
+ Array<bool,Dynamic,1> IV;
+ SparseMatrix<bool> OEQIcT = OEQIc.transpose().eval();
+ find(OEQIcT,Icc,II,IV);
+ assert(II.size() == Ic.size() &&
+ (II.array() ==
+ igl::LinSpaced<VectorXi >(Ic.size(),0,Ic.size()-1).array()).all());
+ assert(Icc.size() == Ic.size());
+ const int cc = C(Icc(0));
+ Eigen::VectorXi CIcc;
+ slice(C,Icc,1,CIcc);
+ assert((CIcc.array() == cc).all());
+ assert(!done[cc]);
+ done[cc] = true;
+ }
+ Array<bool,Dynamic,1> flipped;
+ {
+ MatrixX2I OFIc,OFIcc;
+ slice(OF,Ic,1,OFIc);
+ slice(OF,Icc,1,OFIcc);
+ Eigen::VectorXi XOR,IA,IB;
+ setxor(OFIc,OFIcc,XOR,IA,IB);
+ assert(XOR.size() == 0);
+ flipped = OFIc.array().col(0) != OFIcc.array().col(0);
+ }
+ if(Ic.size() == 1)
+ {
+ // No change to UT
+ vUE.push_back({OT(Ic(0),0),OT(Ic(0),1)});
+ assert(Icc.size() == 1);
+ vUE.push_back({OT(Icc(0),flipped(0)?1:0),OT(Icc(0),flipped(0)?0:1)});
+ }else
+ {
+ MatrixX2I OTIc;
+ slice(OT,Ic,1,OTIc);
+ edges_to_path(OTIc,vpath,epath,eend);
+ // Flip endpoints if needed
+ for(int e = 0;e<eend.size();e++)if(flipped(e))eend(e)=1-eend(e);
+ VectorXi vpathc(epath.size()+1);
+ for(int e = 0;e<epath.size();e++)
+ {
+ vpathc(e) = OT(Icc(epath(e)),eend(e));
+ }
+ vpathc(epath.size()) =
+ OT(Icc(epath(epath.size()-1)),1-eend(eend.size()-1));
+ assert(vpath.size() == vpathc.size());
+ Matrix<Scalar,Dynamic,Dynamic> PI(vpath.size(),VT.cols()*2);
+ for(int p = 0;p<PI.rows();p++)
+ {
+ for(int d = 0;d<VT.cols();d++)
+ {
+ PI(p, d) = VT( vpath(p),d);
+ PI(p,VT.cols()+d) = VT(vpathc(p),d);
+ }
+ }
+ const Scalar bbd =
+ (PI.colwise().maxCoeff() - PI.colwise().minCoeff()).norm();
+ Matrix<Scalar,Dynamic,Dynamic> UPI,SI;
+ VectorXi UIc;
+ ramer_douglas_peucker(PI,tol*bbd,UPI,UIc,SI);
+ slice_into(SI.leftCols (VT.cols()), vpath,1,UT);
+ slice_into(SI.rightCols(VT.cols()),vpathc,1,UT);
+ for(int i = 0;i<UIc.size()-1;i++)
+ {
+ vUE.push_back({vpath(UIc(i)),vpath(UIc(i+1))});
+ }
+ for(int i = 0;i<UIc.size()-1;i++)
+ {
+ vUE.push_back({vpathc(UIc(i)),vpathc(UIc(i+1))});
+ }
+ }
+ }
+ break;
+ default:
+ assert(false && "Should never reach here");
+ }
+ }
+ list_to_matrix(vUE,UE);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::straighten_seams<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, double, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/straighten_seams.h b/xs/src/igl/straighten_seams.h
new file mode 100644
index 000000000..2eb0e9d46
--- /dev/null
+++ b/xs/src/igl/straighten_seams.h
@@ -0,0 +1,57 @@
+#ifndef IGL_STRAIGHTEN_SEAMS_H
+#define IGL_STRAIGHTEN_SEAMS_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ // STRAIGHTEN_SEAMS Given a obj-style mesh with (V,F) defining the geometric
+ // surface of the mesh and (VT,FT) defining the
+ // parameterization/texture-mapping of the mesh in the uv-domain, find all
+ // seams and boundaries in the texture-mapping and "straighten" them,
+ // remapping vertices along the boundary and in the interior. This will be
+ // careful to consistently straighten multiple seams in the texture-mesh
+ // corresponding to the same edge chains in the surface-mesh.
+ //
+ // [UT] = straighten_seams(V,F,VT,FT)
+ //
+ // Inputs:
+ // V #V by 3 list of vertices
+ // F #F by 3 list of triangle indices
+ // VT #VT by 2 list of texture coordinates
+ // FT #F by 3 list of triangle texture coordinates
+ // Optional:
+ // 'Tol' followed by Ramer-Douglas-Peucker tolerance as a fraction of the
+ // curves bounding box diagonal (see dpsimplify)
+ // Outputs:
+ // UE #UE by 2 list of indices into VT of coarse output polygon edges
+ // UT #VT by 3 list of new texture coordinates
+ // OT #OT by 2 list of indices into VT of boundary edges
+ //
+ // See also: simplify_curve, dpsimplify
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedVT,
+ typename DerivedFT,
+ typename Scalar,
+ typename DerivedUE,
+ typename DerivedUT,
+ typename DerivedOT>
+ IGL_INLINE void straighten_seams(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedVT> & VT,
+ const Eigen::MatrixBase<DerivedFT> & FT,
+ const Scalar tol,
+ Eigen::PlainObjectBase<DerivedUE> & UE,
+ Eigen::PlainObjectBase<DerivedUT> & UT,
+ Eigen::PlainObjectBase<DerivedOT> & OT);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "straighten_seams.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/sum.cpp b/xs/src/igl/sum.cpp
new file mode 100644
index 000000000..b994ce405
--- /dev/null
+++ b/xs/src/igl/sum.cpp
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "sum.h"
+#include "redux.h"
+
+template <typename T>
+IGL_INLINE void igl::sum(
+ const Eigen::SparseMatrix<T>& X,
+ const int dim,
+ Eigen::SparseVector<T>& S)
+{
+ assert((dim == 1 || dim == 2) && "dim must be 2 or 1");
+ // Get size of input
+ int m = X.rows();
+ int n = X.cols();
+ // resize output
+ if(dim==1)
+ {
+ S = Eigen::SparseVector<T>(n);
+ }else
+ {
+ S = Eigen::SparseVector<T>(m);
+ }
+
+ // Iterate over outside
+ for(int k=0; k<X.outerSize(); ++k)
+ {
+ // Iterate over inside
+ for(typename Eigen::SparseMatrix<T>::InnerIterator it (X,k); it; ++it)
+ {
+ if(dim == 1)
+ {
+ S.coeffRef(it.col()) += it.value();
+ }else
+ {
+ S.coeffRef(it.row()) += it.value();
+ }
+ }
+ }
+}
+
+template <typename AType, typename DerivedB>
+IGL_INLINE void igl::sum(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB>& B)
+{
+ typedef typename DerivedB::Scalar Scalar;
+ igl::redux(A,dim,[](Scalar a, Scalar b){ return a+b;},B);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::sum<double, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::sum<bool, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<bool, 0, int> const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::sum<double>(Eigen::SparseMatrix<double, 0, int> const&, int, Eigen::SparseVector<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/sum.h b/xs/src/igl/sum.h
new file mode 100644
index 000000000..6caeac344
--- /dev/null
+++ b/xs/src/igl/sum.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SUM_H
+#define IGL_SUM_H
+#include "igl_inline.h"
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Note: If your looking for dense matrix matlab like sum for eigen matrics
+ // just use:
+ // M.colwise().sum() or M.rowwise().sum()
+ //
+
+ // Sum the columns or rows of a sparse matrix
+ // Templates:
+ // T should be a eigen sparse matrix primitive type like int or double
+ // Inputs:
+ // X m by n sparse matrix
+ // dim dimension along which to sum (1 or 2)
+ // Output:
+ // S n-long sparse vector (if dim == 1)
+ // or
+ // S m-long sparse vector (if dim == 2)
+ template <typename T>
+ IGL_INLINE void sum(
+ const Eigen::SparseMatrix<T>& X,
+ const int dim,
+ Eigen::SparseVector<T>& S);
+ // Sum is "conducted" in the type of DerivedB::Scalar
+ template <typename AType, typename DerivedB>
+ IGL_INLINE void sum(
+ const Eigen::SparseMatrix<AType> & A,
+ const int dim,
+ Eigen::PlainObjectBase<DerivedB>& B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "sum.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/svd3x3.cpp b/xs/src/igl/svd3x3.cpp
new file mode 100644
index 000000000..dd65e0cf3
--- /dev/null
+++ b/xs/src/igl/svd3x3.cpp
@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "svd3x3.h"
+
+#include <cmath>
+#include <algorithm>
+
+#define USE_SCALAR_IMPLEMENTATION
+#undef USE_SSE_IMPLEMENTATION
+#undef USE_AVX_IMPLEMENTATION
+#define COMPUTE_U_AS_MATRIX
+#define COMPUTE_V_AS_MATRIX
+#include "Singular_Value_Decomposition_Preamble.hpp"
+
+#pragma runtime_checks( "u", off ) // disable runtime asserts on xor eax,eax type of stuff (doesn't always work, disable explicitly in compiler settings)
+template<typename T>
+IGL_INLINE void igl::svd3x3(const Eigen::Matrix<T, 3, 3>& A, Eigen::Matrix<T, 3, 3> &U, Eigen::Matrix<T, 3, 1> &S, Eigen::Matrix<T, 3, 3>&V)
+{
+ // this code only supports the scalar version (otherwise we'd need to pass arrays of matrices)
+
+#include "Singular_Value_Decomposition_Kernel_Declarations.hpp"
+
+ ENABLE_SCALAR_IMPLEMENTATION(Sa11.f=A(0,0);) ENABLE_SSE_IMPLEMENTATION(Va11=_mm_loadu_ps(a11);) ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_loadu_ps(a11);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa21.f=A(1,0);) ENABLE_SSE_IMPLEMENTATION(Va21=_mm_loadu_ps(a21);) ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_loadu_ps(a21);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa31.f=A(2,0);) ENABLE_SSE_IMPLEMENTATION(Va31=_mm_loadu_ps(a31);) ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_loadu_ps(a31);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa12.f=A(0,1);) ENABLE_SSE_IMPLEMENTATION(Va12=_mm_loadu_ps(a12);) ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_loadu_ps(a12);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa22.f=A(1,1);) ENABLE_SSE_IMPLEMENTATION(Va22=_mm_loadu_ps(a22);) ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_loadu_ps(a22);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa32.f=A(2,1);) ENABLE_SSE_IMPLEMENTATION(Va32=_mm_loadu_ps(a32);) ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_loadu_ps(a32);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa13.f=A(0,2);) ENABLE_SSE_IMPLEMENTATION(Va13=_mm_loadu_ps(a13);) ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_loadu_ps(a13);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa23.f=A(1,2);) ENABLE_SSE_IMPLEMENTATION(Va23=_mm_loadu_ps(a23);) ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_loadu_ps(a23);)
+ ENABLE_SCALAR_IMPLEMENTATION(Sa33.f=A(2,2);) ENABLE_SSE_IMPLEMENTATION(Va33=_mm_loadu_ps(a33);) ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_loadu_ps(a33);)
+
+#include "Singular_Value_Decomposition_Main_Kernel_Body.hpp"
+
+ ENABLE_SCALAR_IMPLEMENTATION(U(0,0)=Su11.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u11,Vu11);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u11,Vu11);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(1,0)=Su21.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u21,Vu21);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u21,Vu21);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(2,0)=Su31.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u31,Vu31);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u31,Vu31);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(0,1)=Su12.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u12,Vu12);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u12,Vu12);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(1,1)=Su22.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u22,Vu22);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u22,Vu22);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(2,1)=Su32.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u32,Vu32);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u32,Vu32);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(0,2)=Su13.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u13,Vu13);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u13,Vu13);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(1,2)=Su23.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u23,Vu23);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u23,Vu23);)
+ ENABLE_SCALAR_IMPLEMENTATION(U(2,2)=Su33.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(u33,Vu33);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(u33,Vu33);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(V(0,0)=Sv11.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v11,Vv11);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v11,Vv11);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(1,0)=Sv21.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v21,Vv21);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v21,Vv21);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(2,0)=Sv31.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v31,Vv31);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v31,Vv31);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(0,1)=Sv12.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v12,Vv12);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v12,Vv12);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(1,1)=Sv22.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v22,Vv22);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v22,Vv22);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(2,1)=Sv32.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v32,Vv32);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v32,Vv32);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(0,2)=Sv13.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v13,Vv13);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v13,Vv13);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(1,2)=Sv23.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v23,Vv23);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v23,Vv23);)
+ ENABLE_SCALAR_IMPLEMENTATION(V(2,2)=Sv33.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(v33,Vv33);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(v33,Vv33);)
+
+ ENABLE_SCALAR_IMPLEMENTATION(S(0,0)=Sa11.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(sigma1,Va11);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(sigma1,Va11);)
+ ENABLE_SCALAR_IMPLEMENTATION(S(1,0)=Sa22.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(sigma2,Va22);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(sigma2,Va22);)
+ ENABLE_SCALAR_IMPLEMENTATION(S(2,0)=Sa33.f;) ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(sigma3,Va33);) ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(sigma3,Va33);)
+}
+#pragma runtime_checks( "u", restore )
+
+// forced instantiation
+template void igl::svd3x3(const Eigen::Matrix<float, 3, 3>& A, Eigen::Matrix<float, 3, 3> &U, Eigen::Matrix<float, 3, 1> &S, Eigen::Matrix<float, 3, 3>&V);
+template void igl::svd3x3<double>(Eigen::Matrix<double, 3, 3, 0, 3, 3> const&, Eigen::Matrix<double, 3, 3, 0, 3, 3>&, Eigen::Matrix<double, 3, 1, 0, 3, 1>&, Eigen::Matrix<double, 3, 3, 0, 3, 3>&);
+// doesn't even make sense with double because this SVD code is only single precision anyway...
diff --git a/xs/src/igl/svd3x3.h b/xs/src/igl/svd3x3.h
new file mode 100644
index 000000000..900d459f4
--- /dev/null
+++ b/xs/src/igl/svd3x3.h
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SVD3X3_H
+#define IGL_SVD3X3_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Super fast 3x3 SVD according to http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html
+ // The resulting decomposition is A = U * diag(S[0], S[1], S[2]) * V'
+ // BEWARE: this SVD algorithm guarantees that det(U) = det(V) = 1, but this
+ // comes at the cost that 'sigma3' can be negative
+ // for computing polar decomposition it's great because all we need to do is U*V'
+ // and the result will automatically have positive determinant
+ //
+ // Inputs:
+ // A 3x3 matrix
+ // Outputs:
+ // U 3x3 left singular vectors
+ // S 3x1 singular values
+ // V 3x3 right singular vectors
+ //
+ // Known bugs: this will not work correctly for double precision.
+ template<typename T>
+ IGL_INLINE void svd3x3(
+ const Eigen::Matrix<T, 3, 3>& A,
+ Eigen::Matrix<T, 3, 3> &U,
+ Eigen::Matrix<T, 3, 1> &S,
+ Eigen::Matrix<T, 3, 3>&V);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "svd3x3.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/svd3x3_avx.cpp b/xs/src/igl/svd3x3_avx.cpp
new file mode 100644
index 000000000..db56ee30a
--- /dev/null
+++ b/xs/src/igl/svd3x3_avx.cpp
@@ -0,0 +1,108 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifdef __AVX__
+#include "svd3x3_avx.h"
+
+#include <cmath>
+#include <algorithm>
+
+#undef USE_SCALAR_IMPLEMENTATION
+#undef USE_SSE_IMPLEMENTATION
+#define USE_AVX_IMPLEMENTATION
+#define COMPUTE_U_AS_MATRIX
+#define COMPUTE_V_AS_MATRIX
+#include "Singular_Value_Decomposition_Preamble.hpp"
+
+#pragma runtime_checks( "u", off ) // disable runtime asserts on xor eax,eax type of stuff (doesn't always work, disable explicitly in compiler settings)
+template<typename T>
+IGL_INLINE void igl::svd3x3_avx(
+ const Eigen::Matrix<T, 3*8, 3>& A,
+ Eigen::Matrix<T, 3*8, 3> &U,
+ Eigen::Matrix<T, 3*8, 1> &S,
+ Eigen::Matrix<T, 3*8, 3>&V)
+{
+ // this code assumes USE_AVX_IMPLEMENTATION is defined
+ float Ashuffle[9][8], Ushuffle[9][8], Vshuffle[9][8], Sshuffle[3][8];
+ for (int i=0; i<3; i++)
+ {
+ for (int j=0; j<3; j++)
+ {
+ for (int k=0; k<8; k++)
+ {
+ Ashuffle[i + j*3][k] = A(i + 3*k, j);
+ }
+ }
+ }
+
+#include "Singular_Value_Decomposition_Kernel_Declarations.hpp"
+
+ ENABLE_AVX_IMPLEMENTATION(Va11=_mm256_loadu_ps(Ashuffle[0]);)
+ ENABLE_AVX_IMPLEMENTATION(Va21=_mm256_loadu_ps(Ashuffle[1]);)
+ ENABLE_AVX_IMPLEMENTATION(Va31=_mm256_loadu_ps(Ashuffle[2]);)
+ ENABLE_AVX_IMPLEMENTATION(Va12=_mm256_loadu_ps(Ashuffle[3]);)
+ ENABLE_AVX_IMPLEMENTATION(Va22=_mm256_loadu_ps(Ashuffle[4]);)
+ ENABLE_AVX_IMPLEMENTATION(Va32=_mm256_loadu_ps(Ashuffle[5]);)
+ ENABLE_AVX_IMPLEMENTATION(Va13=_mm256_loadu_ps(Ashuffle[6]);)
+ ENABLE_AVX_IMPLEMENTATION(Va23=_mm256_loadu_ps(Ashuffle[7]);)
+ ENABLE_AVX_IMPLEMENTATION(Va33=_mm256_loadu_ps(Ashuffle[8]);)
+
+#include "Singular_Value_Decomposition_Main_Kernel_Body.hpp"
+
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[0],Vu11);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[1],Vu21);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[2],Vu31);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[3],Vu12);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[4],Vu22);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[5],Vu32);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[6],Vu13);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[7],Vu23);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Ushuffle[8],Vu33);)
+
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[0],Vv11);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[1],Vv21);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[2],Vv31);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[3],Vv12);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[4],Vv22);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[5],Vv32);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[6],Vv13);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[7],Vv23);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Vshuffle[8],Vv33);)
+
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Sshuffle[0],Va11);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Sshuffle[1],Va22);)
+ ENABLE_AVX_IMPLEMENTATION(_mm256_storeu_ps(Sshuffle[2],Va33);)
+
+ for (int i=0; i<3; i++)
+ {
+ for (int j=0; j<3; j++)
+ {
+ for (int k=0; k<8; k++)
+ {
+ U(i + 3*k, j) = Ushuffle[i + j*3][k];
+ V(i + 3*k, j) = Vshuffle[i + j*3][k];
+ }
+ }
+ }
+
+ for (int i=0; i<3; i++)
+ {
+ for (int k=0; k<8; k++)
+ {
+ S(i + 3*k, 0) = Sshuffle[i][k];
+ }
+ }
+}
+#pragma runtime_checks( "u", restore )
+
+#ifdef IGL_STATIC_LIBRARY
+// forced instantiation
+//template void igl::svd3x3_avx(const Eigen::Matrix<float, 3*8, 3>& A, Eigen::Matrix<float, 3*8, 3> &U, Eigen::Matrix<float, 3*8, 1> &S, Eigen::Matrix<float, 3*8, 3>&V);
+// doesn't even make sense with double because the wunder-SVD code is only single precision anyway...
+template void igl::svd3x3_avx<float>(Eigen::Matrix<float, 24, 3, 0, 24, 3> const&, Eigen::Matrix<float, 24, 3, 0, 24, 3>&, Eigen::Matrix<float, 24, 1, 0, 24, 1>&, Eigen::Matrix<float, 24, 3, 0, 24, 3>&);
+#endif
+#endif
diff --git a/xs/src/igl/svd3x3_avx.h b/xs/src/igl/svd3x3_avx.h
new file mode 100644
index 000000000..b814acc95
--- /dev/null
+++ b/xs/src/igl/svd3x3_avx.h
@@ -0,0 +1,40 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SVD3X3_AVX_H
+#define IGL_SVD3X3_AVX_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Super fast 3x3 SVD according to
+ // http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html This is AVX
+ // version of svd3x3 (see svd3x3.h) which works on 8 matrices at a time These
+ // eight matrices are simply stacked in columns, the rest is the same as for
+ // svd3x3
+ //
+ // Inputs:
+ // A 12 by 3 stack of 3x3 matrices
+ // Outputs:
+ // U 12x3 left singular vectors stacked
+ // S 12x1 singular values stacked
+ // V 12x3 right singular vectors stacked
+ //
+ // Known bugs: this will not work correctly for double precision.
+ template<typename T>
+ IGL_INLINE void svd3x3_avx(
+ const Eigen::Matrix<T, 3*8, 3>& A,
+ Eigen::Matrix<T, 3*8, 3> &U,
+ Eigen::Matrix<T, 3*8, 1> &S,
+ Eigen::Matrix<T, 3*8, 3>&V);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "svd3x3_avx.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/svd3x3_sse.cpp b/xs/src/igl/svd3x3_sse.cpp
new file mode 100644
index 000000000..2ef4e0fe8
--- /dev/null
+++ b/xs/src/igl/svd3x3_sse.cpp
@@ -0,0 +1,108 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifdef __SSE__
+#include "svd3x3_sse.h"
+
+#include <cmath>
+#include <algorithm>
+
+#undef USE_SCALAR_IMPLEMENTATION
+#define USE_SSE_IMPLEMENTATION
+#undef USE_AVX_IMPLEMENTATION
+#define COMPUTE_U_AS_MATRIX
+#define COMPUTE_V_AS_MATRIX
+#include "Singular_Value_Decomposition_Preamble.hpp"
+
+// disable runtime asserts on xor eax,eax type of stuff (doesn't always work,
+// disable explicitly in compiler settings)
+#pragma runtime_checks( "u", off )
+template<typename T>
+IGL_INLINE void igl::svd3x3_sse(
+ const Eigen::Matrix<T, 3*4, 3>& A,
+ Eigen::Matrix<T, 3*4, 3> &U,
+ Eigen::Matrix<T, 3*4, 1> &S,
+ Eigen::Matrix<T, 3*4, 3>&V)
+{
+ // this code assumes USE_SSE_IMPLEMENTATION is defined
+ float Ashuffle[9][4], Ushuffle[9][4], Vshuffle[9][4], Sshuffle[3][4];
+ for (int i=0; i<3; i++)
+ {
+ for (int j=0; j<3; j++)
+ {
+ for (int k=0; k<4; k++)
+ {
+ Ashuffle[i + j*3][k] = A(i + 3*k, j);
+ }
+ }
+ }
+
+#include "Singular_Value_Decomposition_Kernel_Declarations.hpp"
+
+ ENABLE_SSE_IMPLEMENTATION(Va11=_mm_loadu_ps(Ashuffle[0]);)
+ ENABLE_SSE_IMPLEMENTATION(Va21=_mm_loadu_ps(Ashuffle[1]);)
+ ENABLE_SSE_IMPLEMENTATION(Va31=_mm_loadu_ps(Ashuffle[2]);)
+ ENABLE_SSE_IMPLEMENTATION(Va12=_mm_loadu_ps(Ashuffle[3]);)
+ ENABLE_SSE_IMPLEMENTATION(Va22=_mm_loadu_ps(Ashuffle[4]);)
+ ENABLE_SSE_IMPLEMENTATION(Va32=_mm_loadu_ps(Ashuffle[5]);)
+ ENABLE_SSE_IMPLEMENTATION(Va13=_mm_loadu_ps(Ashuffle[6]);)
+ ENABLE_SSE_IMPLEMENTATION(Va23=_mm_loadu_ps(Ashuffle[7]);)
+ ENABLE_SSE_IMPLEMENTATION(Va33=_mm_loadu_ps(Ashuffle[8]);)
+
+#include "Singular_Value_Decomposition_Main_Kernel_Body.hpp"
+
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[0],Vu11);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[1],Vu21);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[2],Vu31);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[3],Vu12);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[4],Vu22);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[5],Vu32);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[6],Vu13);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[7],Vu23);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Ushuffle[8],Vu33);)
+
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[0],Vv11);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[1],Vv21);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[2],Vv31);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[3],Vv12);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[4],Vv22);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[5],Vv32);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[6],Vv13);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[7],Vv23);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Vshuffle[8],Vv33);)
+
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Sshuffle[0],Va11);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Sshuffle[1],Va22);)
+ ENABLE_SSE_IMPLEMENTATION(_mm_storeu_ps(Sshuffle[2],Va33);)
+
+ for (int i=0; i<3; i++)
+ {
+ for (int j=0; j<3; j++)
+ {
+ for (int k=0; k<4; k++)
+ {
+ U(i + 3*k, j) = Ushuffle[i + j*3][k];
+ V(i + 3*k, j) = Vshuffle[i + j*3][k];
+ }
+ }
+ }
+
+ for (int i=0; i<3; i++)
+ {
+ for (int k=0; k<4; k++)
+ {
+ S(i + 3*k, 0) = Sshuffle[i][k];
+ }
+ }
+}
+#pragma runtime_checks( "u", restore )
+
+// forced instantiation
+template void igl::svd3x3_sse(const Eigen::Matrix<float, 3*4, 3>& A, Eigen::Matrix<float, 3*4, 3> &U, Eigen::Matrix<float, 3*4, 1> &S, Eigen::Matrix<float, 3*4, 3>&V);
+//// doesn't even make sense with double because the wunder-SVD code is only single precision anyway...
+//template void wunderSVD3x3_SSE<float>(Eigen::Matrix<float, 12, 3, 0, 12, 3> const&, Eigen::Matrix<float, 12, 3, 0, 12, 3>&, Eigen::Matrix<float, 12, 1, 0, 12, 1>&, Eigen::Matrix<float, 12, 3, 0, 12, 3>&);
+#endif
diff --git a/xs/src/igl/svd3x3_sse.h b/xs/src/igl/svd3x3_sse.h
new file mode 100644
index 000000000..1fcff988a
--- /dev/null
+++ b/xs/src/igl/svd3x3_sse.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SVD3X3_SSE_H
+#define IGL_SVD3X3_SSE_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+
+namespace igl
+{
+ // Super fast 3x3 SVD according to http://pages.cs.wisc.edu/~sifakis/project_pages/svd.html
+ // This is SSE version of svd3x3 (see svd3x3.h) which works on 4 matrices at a time
+ // These four matrices are simply stacked in columns, the rest is the same as for svd3x3
+ //
+ // Inputs:
+ // A 12 by 3 stack of 3x3 matrices
+ // Outputs:
+ // U 12x3 left singular vectors stacked
+ // S 12x1 singular values stacked
+ // V 12x3 right singular vectors stacked
+ //
+ // Known bugs: this will not work correctly for double precision.
+ template<typename T>
+ IGL_INLINE void svd3x3_sse(
+ const Eigen::Matrix<T, 3*4, 3>& A,
+ Eigen::Matrix<T, 3*4, 3> &U,
+ Eigen::Matrix<T, 3*4, 1> &S,
+ Eigen::Matrix<T, 3*4, 3>&V);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "svd3x3_sse.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/swept_volume_bounding_box.cpp b/xs/src/igl/swept_volume_bounding_box.cpp
new file mode 100644
index 000000000..7fc12e2f1
--- /dev/null
+++ b/xs/src/igl/swept_volume_bounding_box.cpp
@@ -0,0 +1,28 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "swept_volume_bounding_box.h"
+#include "LinSpaced.h"
+
+IGL_INLINE void igl::swept_volume_bounding_box(
+ const size_t & n,
+ const std::function<Eigen::RowVector3d(const size_t vi, const double t)> & V,
+ const size_t & steps,
+ Eigen::AlignedBox3d & box)
+{
+ using namespace Eigen;
+ box.setEmpty();
+ const VectorXd t = igl::LinSpaced<VectorXd >(steps,0,1);
+ // Find extent over all time steps
+ for(int ti = 0;ti<t.size();ti++)
+ {
+ for(size_t vi = 0;vi<n;vi++)
+ {
+ box.extend(V(vi,t(ti)).transpose());
+ }
+ }
+}
diff --git a/xs/src/igl/swept_volume_bounding_box.h b/xs/src/igl/swept_volume_bounding_box.h
new file mode 100644
index 000000000..f44f1f77d
--- /dev/null
+++ b/xs/src/igl/swept_volume_bounding_box.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SWEPT_VOLUME_BOUNDING_BOX_H
+#define IGL_SWEPT_VOLUME_BOUNDING_BOX_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <functional>
+namespace igl
+{
+ // Construct an axis-aligned bounding box containing a shape undergoing a
+ // motion sampled at `steps` discrete momements.
+ //
+ // Inputs:
+ // n number of mesh vertices
+ // V function handle so that V(i,t) returns the 3d position of vertex
+ // i at time t, for t∈[0,1]
+ // steps number of time steps: steps=3 --> t∈{0,0.5,1}
+ // Outputs:
+ // box box containing mesh under motion
+ IGL_INLINE void swept_volume_bounding_box(
+ const size_t & n,
+ const std::function<
+ Eigen::RowVector3d(const size_t vi, const double t)> & V,
+ const size_t & steps,
+ Eigen::AlignedBox3d & box);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "swept_volume_bounding_box.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/swept_volume_signed_distance.cpp b/xs/src/igl/swept_volume_signed_distance.cpp
new file mode 100644
index 000000000..2571a7d12
--- /dev/null
+++ b/xs/src/igl/swept_volume_signed_distance.cpp
@@ -0,0 +1,122 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "swept_volume_signed_distance.h"
+#include "LinSpaced.h"
+#include "flood_fill.h"
+#include "signed_distance.h"
+#include "AABB.h"
+#include "pseudonormal_test.h"
+#include "per_face_normals.h"
+#include "per_vertex_normals.h"
+#include "per_edge_normals.h"
+#include <Eigen/Geometry>
+#include <cmath>
+#include <algorithm>
+
+IGL_INLINE void igl::swept_volume_signed_distance(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<Eigen::Affine3d(const double t)> & transform,
+ const size_t & steps,
+ const Eigen::MatrixXd & GV,
+ const Eigen::RowVector3i & res,
+ const double h,
+ const double isolevel,
+ const Eigen::VectorXd & S0,
+ Eigen::VectorXd & S)
+{
+ using namespace std;
+ using namespace igl;
+ using namespace Eigen;
+ S = S0;
+ const VectorXd t = igl::LinSpaced<VectorXd >(steps,0,1);
+ const bool finite_iso = isfinite(isolevel);
+ const double extension = (finite_iso ? isolevel : 0) + sqrt(3.0)*h;
+ Eigen::AlignedBox3d box(
+ V.colwise().minCoeff().array()-extension,
+ V.colwise().maxCoeff().array()+extension);
+ // Precomputation
+ Eigen::MatrixXd FN,VN,EN;
+ Eigen::MatrixXi E;
+ Eigen::VectorXi EMAP;
+ per_face_normals(V,F,FN);
+ per_vertex_normals(V,F,PER_VERTEX_NORMALS_WEIGHTING_TYPE_ANGLE,FN,VN);
+ per_edge_normals(
+ V,F,PER_EDGE_NORMALS_WEIGHTING_TYPE_UNIFORM,FN,EN,E,EMAP);
+ AABB<MatrixXd,3> tree;
+ tree.init(V,F);
+ for(int ti = 0;ti<t.size();ti++)
+ {
+ const Affine3d At = transform(t(ti));
+ for(int g = 0;g<GV.rows();g++)
+ {
+ // Don't bother finding out how deep inside points are.
+ if(finite_iso && S(g)==S(g) && S(g)<isolevel-sqrt(3.0)*h)
+ {
+ continue;
+ }
+ const RowVector3d gv =
+ (GV.row(g) - At.translation().transpose())*At.linear();
+ // If outside of extended box, then consider it "far away enough"
+ if(finite_iso && !box.contains(gv.transpose()))
+ {
+ continue;
+ }
+ RowVector3d c,n;
+ int i;
+ double sqrd,s;
+ //signed_distance_pseudonormal(tree,V,F,FN,VN,EN,EMAP,gv,s,sqrd,i,c,n);
+ const double min_sqrd =
+ finite_iso ?
+ pow(sqrt(3.)*h+isolevel,2) :
+ numeric_limits<double>::infinity();
+ sqrd = tree.squared_distance(V,F,gv,min_sqrd,i,c);
+ if(sqrd<min_sqrd)
+ {
+ pseudonormal_test(V,F,FN,VN,EN,EMAP,gv,i,c,s,n);
+ if(S(g) == S(g))
+ {
+ S(g) = std::min(S(g),s*sqrt(sqrd));
+ }else
+ {
+ S(g) = s*sqrt(sqrd);
+ }
+ }
+ }
+ }
+
+ if(finite_iso)
+ {
+ flood_fill(res,S);
+ }else
+ {
+#ifndef NDEBUG
+ // Check for nans
+ std::for_each(S.data(),S.data()+S.size(),[](const double s){assert(s==s);});
+#endif
+ }
+}
+
+IGL_INLINE void igl::swept_volume_signed_distance(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<Eigen::Affine3d(const double t)> & transform,
+ const size_t & steps,
+ const Eigen::MatrixXd & GV,
+ const Eigen::RowVector3i & res,
+ const double h,
+ const double isolevel,
+ Eigen::VectorXd & S)
+{
+ using namespace std;
+ using namespace igl;
+ using namespace Eigen;
+ S = VectorXd::Constant(GV.rows(),1,numeric_limits<double>::quiet_NaN());
+ return
+ swept_volume_signed_distance(V,F,transform,steps,GV,res,h,isolevel,S,S);
+}
diff --git a/xs/src/igl/swept_volume_signed_distance.h b/xs/src/igl/swept_volume_signed_distance.h
new file mode 100644
index 000000000..86074fb67
--- /dev/null
+++ b/xs/src/igl/swept_volume_signed_distance.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_SWEPT_VOLUME_SIGNED_DISTANCE_H
+#define IGL_SWEPT_VOLUME_SIGNED_DISTANCE_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+#include <functional>
+namespace igl
+{
+ // Compute the signed distance to a sweep surface of a mesh under-going
+ // an arbitrary motion V(t) discretely sampled at `steps`-many moments in
+ // time at a grid.
+ //
+ // Inputs:
+ // V #V by 3 list of mesh positions in reference pose
+ // F #F by 3 list of triangle indices [0,n)
+ // transform function handle so that transform(t) returns the rigid
+ // transformation at time t∈[0,1]
+ // steps number of time steps: steps=3 --> t∈{0,0.5,1}
+ // GV #GV by 3 list of evaluation point grid positions
+ // res 3-long resolution of GV grid
+ // h edge-length of grid
+ // isolevel isolevel to "focus" on; grid positions far enough away from
+ // isolevel (based on h) will get approximate values). Set
+ // isolevel=infinity to get good values everywhere (slow and
+ // unnecessary if just trying to extract isolevel-level set).
+ // S0 #GV initial values (will take minimum with these), can be same
+ // as S)
+ // Outputs:
+ // S #GV list of signed distances
+ IGL_INLINE void swept_volume_signed_distance(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<Eigen::Affine3d(const double t)> & transform,
+ const size_t & steps,
+ const Eigen::MatrixXd & GV,
+ const Eigen::RowVector3i & res,
+ const double h,
+ const double isolevel,
+ const Eigen::VectorXd & S0,
+ Eigen::VectorXd & S);
+ IGL_INLINE void swept_volume_signed_distance(
+ const Eigen::MatrixXd & V,
+ const Eigen::MatrixXi & F,
+ const std::function<Eigen::Affine3d(const double t)> & transform,
+ const size_t & steps,
+ const Eigen::MatrixXd & GV,
+ const Eigen::RowVector3i & res,
+ const double h,
+ const double isolevel,
+ Eigen::VectorXd & S);
+ }
+
+#ifndef IGL_STATIC_LIBRARY
+# include "swept_volume_signed_distance.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/trackball.cpp b/xs/src/igl/trackball.cpp
new file mode 100644
index 000000000..3a5fa2e9f
--- /dev/null
+++ b/xs/src/igl/trackball.cpp
@@ -0,0 +1,168 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "trackball.h"
+
+#include "EPS.h"
+#include "dot.h"
+#include "cross.h"
+#include "axis_angle_to_quat.h"
+#include "quat_mult.h"
+#include <cmath>
+#include <cstdlib>
+#include <cassert>
+#include <algorithm>
+#include <iostream>
+
+// Utility IGL_INLINE functions
+template <typename Q_type>
+static IGL_INLINE Q_type _QuatD(double w, double h)
+{
+ using namespace std;
+ return (Q_type)(std::abs(w) < std::abs(h) ? std::abs(w) : std::abs(h)) - 4;
+}
+template <typename Q_type>
+static IGL_INLINE Q_type _QuatIX(double x, double w, double h)
+{
+ return (2.0f*(Q_type)x - (Q_type)w - 1.0f)/_QuatD<Q_type>(w, h);
+}
+template <typename Q_type>
+static IGL_INLINE Q_type _QuatIY(double y, double w, double h)
+{
+ return (-2.0f*(Q_type)y + (Q_type)h - 1.0f)/_QuatD<Q_type>(w, h);
+}
+
+// This is largely the trackball as implemented in AntTweakbar. Much of the
+// code is straight from its source in TwMgr.cpp
+// http://www.antisphere.com/Wiki/tools:anttweakbar
+template <typename Q_type>
+IGL_INLINE void igl::trackball(
+ const double w,
+ const double h,
+ const Q_type speed_factor,
+ const double down_mouse_x,
+ const double down_mouse_y,
+ const double mouse_x,
+ const double mouse_y,
+ Q_type * quat)
+{
+ assert(speed_factor > 0);
+
+ double original_x =
+ _QuatIX<Q_type>(speed_factor*(down_mouse_x-w/2)+w/2, w, h);
+ double original_y =
+ _QuatIY<Q_type>(speed_factor*(down_mouse_y-h/2)+h/2, w, h);
+
+ double x = _QuatIX<Q_type>(speed_factor*(mouse_x-w/2)+w/2, w, h);
+ double y = _QuatIY<Q_type>(speed_factor*(mouse_y-h/2)+h/2, w, h);
+
+ double z = 1;
+ double n0 = sqrt(original_x*original_x + original_y*original_y + z*z);
+ double n1 = sqrt(x*x + y*y + z*z);
+ if(n0>igl::DOUBLE_EPS && n1>igl::DOUBLE_EPS)
+ {
+ double v0[] = { original_x/n0, original_y/n0, z/n0 };
+ double v1[] = { x/n1, y/n1, z/n1 };
+ double axis[3];
+ cross(v0,v1,axis);
+ double sa = sqrt(dot(axis, axis));
+ double ca = dot(v0, v1);
+ double angle = atan2(sa, ca);
+ if( x*x+y*y>1.0 )
+ {
+ angle *= 1.0 + 0.2f*(sqrt(x*x+y*y)-1.0);
+ }
+ double qrot[4];
+ axis_angle_to_quat(axis,angle,qrot);
+ quat[0] = qrot[0];
+ quat[1] = qrot[1];
+ quat[2] = qrot[2];
+ quat[3] = qrot[3];
+ }
+}
+
+
+template <typename Q_type>
+IGL_INLINE void igl::trackball(
+ const double w,
+ const double h,
+ const Q_type speed_factor,
+ const Q_type * down_quat,
+ const double down_mouse_x,
+ const double down_mouse_y,
+ const double mouse_x,
+ const double mouse_y,
+ Q_type * quat)
+{
+ double qrot[4], qres[4], qorig[4];
+ igl::trackball<double>(
+ w,h,
+ speed_factor,
+ down_mouse_x,down_mouse_y,
+ mouse_x,mouse_y,
+ qrot);
+ double nqorig =
+ sqrt(down_quat[0]*down_quat[0]+
+ down_quat[1]*down_quat[1]+
+ down_quat[2]*down_quat[2]+
+ down_quat[3]*down_quat[3]);
+
+ if( fabs(nqorig)>igl::DOUBLE_EPS_SQ )
+ {
+ qorig[0] = down_quat[0]/nqorig;
+ qorig[1] = down_quat[1]/nqorig;
+ qorig[2] = down_quat[2]/nqorig;
+ qorig[3] = down_quat[3]/nqorig;
+ igl::quat_mult<double>(qrot,qorig,qres);
+ quat[0] = qres[0];
+ quat[1] = qres[1];
+ quat[2] = qres[2];
+ quat[3] = qres[3];
+ }
+ else
+ {
+ quat[0] = qrot[0];
+ quat[1] = qrot[1];
+ quat[2] = qrot[2];
+ quat[3] = qrot[3];
+ }
+}
+
+template <typename Scalardown_quat, typename Scalarquat>
+IGL_INLINE void igl::trackball(
+ const double w,
+ const double h,
+ const double speed_factor,
+ const Eigen::Quaternion<Scalardown_quat> & down_quat,
+ const double down_mouse_x,
+ const double down_mouse_y,
+ const double mouse_x,
+ const double mouse_y,
+ Eigen::Quaternion<Scalarquat> & quat)
+{
+ using namespace std;
+ return trackball(
+ w,
+ h,
+ (Scalarquat)speed_factor,
+ down_quat.coeffs().data(),
+ down_mouse_x,
+ down_mouse_y,
+ mouse_x,
+ mouse_y,
+ quat.coeffs().data());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::trackball<double>(double, double, double, double const*, double, double, double, double, double*);
+// generated by autoexplicit.sh
+template void igl::trackball<float>(double, double, float, float const*, double, double, double, double, float*);
+template void igl::trackball<float, float>(double, double, double, Eigen::Quaternion<float, 0> const&, double, double, double, double, Eigen::Quaternion<float, 0>&);
+template void igl::trackball<double, double>(double, double, double, Eigen::Quaternion<double, 0> const&, double, double, double, double, Eigen::Quaternion<double, 0>&);
+#endif
diff --git a/xs/src/igl/trackball.h b/xs/src/igl/trackball.h
new file mode 100644
index 000000000..6bf79e019
--- /dev/null
+++ b/xs/src/igl/trackball.h
@@ -0,0 +1,80 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_TRACKBALL_H
+#define IGL_TRACKBALL_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+namespace igl
+{
+ // Applies a trackball drag to identity
+ // Inputs:
+ // w width of the trackball context
+ // h height of the trackball context
+ // speed_factor controls how fast the trackball feels, 1 is normal
+ // down_mouse_x x position of mouse down
+ // down_mouse_y y position of mouse down
+ // mouse_x current x position of mouse
+ // mouse_y current y position of mouse
+ // Outputs:
+ // quat the resulting rotation (as quaternion)
+ template <typename Q_type>
+ IGL_INLINE void trackball(
+ const double w,
+ const double h,
+ const Q_type speed_factor,
+ const double down_mouse_x,
+ const double down_mouse_y,
+ const double mouse_x,
+ const double mouse_y,
+ Q_type * quat);
+
+ // Applies a trackball drag to a given rotation
+ // Inputs:
+ // w width of the trackball context
+ // h height of the trackball context
+ // speed_factor controls how fast the trackball feels, 1 is normal
+ // down_quat rotation at mouse down, i.e. the rotation we're applying the
+ // trackball motion to (as quaternion)
+ // down_mouse_x x position of mouse down
+ // down_mouse_y y position of mouse down
+ // mouse_x current x position of mouse
+ // mouse_y current y position of mouse
+ // Outputs:
+ // quat the resulting rotation (as quaternion)
+ template <typename Q_type>
+ IGL_INLINE void trackball(
+ const double w,
+ const double h,
+ const Q_type speed_factor,
+ const Q_type * down_quat,
+ const double down_mouse_x,
+ const double down_mouse_y,
+ const double mouse_x,
+ const double mouse_y,
+ Q_type * quat);
+ // Eigen wrapper.
+ template <typename Scalardown_quat, typename Scalarquat>
+ IGL_INLINE void trackball(
+ const double w,
+ const double h,
+ const double speed_factor,
+ const Eigen::Quaternion<Scalardown_quat> & down_quat,
+ const double down_mouse_x,
+ const double down_mouse_y,
+ const double mouse_x,
+ const double mouse_y,
+ Eigen::Quaternion<Scalarquat> & quat);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "trackball.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/transpose_blocks.cpp b/xs/src/igl/transpose_blocks.cpp
new file mode 100644
index 000000000..004edd7ac
--- /dev/null
+++ b/xs/src/igl/transpose_blocks.cpp
@@ -0,0 +1,63 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "transpose_blocks.h"
+
+#include <cassert>
+
+template <typename T>
+IGL_INLINE void igl::transpose_blocks(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
+ const size_t k,
+ const size_t dim,
+ Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B)
+{
+ // Eigen matrices must be 2d so dim must be only 1 or 2
+ assert(dim == 1 || dim == 2);
+ // Output is not allowed to be input
+ assert(&A != &B);
+
+
+ // block height, width, and number of blocks
+ int m,n;
+ if(dim == 1)
+ {
+ m = A.rows()/k;
+ n = A.cols();
+ }else// dim == 2
+ {
+ m = A.rows();
+ n = A.cols()/k;
+ }
+
+ // resize output
+ if(dim == 1)
+ {
+ B.resize(n*k,m);
+ }else//dim ==2
+ {
+ B.resize(n,m*k);
+ }
+
+ // loop over blocks
+ for(int b = 0;b<(int)k;b++)
+ {
+ if(dim == 1)
+ {
+ B.block(b*n,0,n,m) = A.block(b*m,0,m,n).transpose();
+ }else//dim ==2
+ {
+ B.block(0,b*m,n,m) = A.block(0,b*n,m,n).transpose();
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::transpose_blocks<double>(Eigen::Matrix<double, -1, -1, 0, -1, -1> const&, size_t, size_t, Eigen::Matrix<double, -1, -1, 0, -1, -1>&);
+#endif
diff --git a/xs/src/igl/transpose_blocks.h b/xs/src/igl/transpose_blocks.h
new file mode 100644
index 000000000..65ce89fbd
--- /dev/null
+++ b/xs/src/igl/transpose_blocks.h
@@ -0,0 +1,61 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_TRANSPOSE_BLOCKS_H
+#define IGL_TRANSPOSE_BLOCKS_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+
+namespace igl
+{
+ // 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 to transpose
+ // Output
+ // B n*k by m (dim: 1) or n by m*k (dim: 2) eigen Matrix of type T values,
+ // NOT allowed to be the same as A
+ //
+ // Example:
+ // A = [
+ // 1 2 3 4
+ // 5 6 7 8
+ // 101 102 103 104
+ // 105 106 107 108
+ // 201 202 203 204
+ // 205 206 207 208];
+ // transpose_blocks(A,1,3,B);
+ // B -> [
+ // 1 5
+ // 2 6
+ // 3 7
+ // 4 8
+ // 101 105
+ // 102 106
+ // 103 107
+ // 104 108
+ // 201 205
+ // 202 206
+ // 203 207
+ // 204 208];
+ //
+ template <typename T>
+ IGL_INLINE void transpose_blocks(
+ const Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & A,
+ const size_t k,
+ const size_t dim,
+ Eigen::Matrix<T,Eigen::Dynamic,Eigen::Dynamic> & B);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "transpose_blocks.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/triangle/cdt.cpp b/xs/src/igl/triangle/cdt.cpp
new file mode 100644
index 000000000..cbe1b3e1a
--- /dev/null
+++ b/xs/src/igl/triangle/cdt.cpp
@@ -0,0 +1,58 @@
+#include "cdt.h"
+#include "../bounding_box.h"
+#include "../triangle/triangulate.h"
+#include "../remove_duplicate_vertices.h"
+#include "../remove_unreferenced.h"
+#include "../slice_mask.h"
+
+template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedWV,
+ typename DerivedWF,
+ typename DerivedWE,
+ typename DerivedJ>
+IGL_INLINE void igl::triangle::cdt(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const std::string & flags,
+ Eigen::PlainObjectBase<DerivedWV> & WV,
+ Eigen::PlainObjectBase<DerivedWF> & WF,
+ Eigen::PlainObjectBase<DerivedWE> & WE,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ assert(V.cols() == 2);
+ assert(E.cols() == 2);
+ typedef typename DerivedV::Scalar Scalar;
+ typedef Eigen::Matrix<Scalar,Eigen::Dynamic,2> MatrixX2S;
+ //MatrixX2S BV;
+ //Eigen::MatrixXi BE;
+ //igl::bounding_box(V,BV,BE);
+ //WV.resize(V.rows()+BV.rows(),2);
+ //WV<<V,BV;
+ //WE.resize(E.rows()+BE.rows(),2);
+ //WE<<E,(BE.array()+V.rows());
+ WV = V;
+ WE = E;
+ Eigen::VectorXi _;
+ igl::remove_duplicate_vertices(DerivedWV(WV),DerivedWE(WE),1e-10,WV,_,J,WE);
+ // Remove degenerate edges
+ igl::slice_mask(DerivedWE(WE),(WE.array().col(0) != WE.array().col(1)).eval(),1,WE);
+ // c flag must be present
+ igl::triangle::triangulate(DerivedWV(WV),WE,DerivedWV(),flags,WV,WF);
+ Eigen::VectorXi UJ;
+ igl::remove_unreferenced(DerivedV(WV),Eigen::MatrixXi(WF),WV,WF,UJ);
+ for(int i=0;i<WE.rows();i++) for(int j=0;j<WE.cols();j++) WE(i,j)=UJ(WE(i,j));
+ // Remove edges from box
+ //WE.conservativeResize(WE.rows()-BE.rows(),2);
+ for(int i=0;i<J.size();i++) J(i)=UJ(J(i));
+ //J.conservativeResize(J.size()-BV.rows());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::triangle::cdt<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::triangle::cdt<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#endif
diff --git a/xs/src/igl/triangle/cdt.h b/xs/src/igl/triangle/cdt.h
new file mode 100644
index 000000000..9f513e853
--- /dev/null
+++ b/xs/src/igl/triangle/cdt.h
@@ -0,0 +1,54 @@
+#ifndef IGL_TRIANGLE_CDT_H
+#define IGL_TRIANGLE_CDT_H
+
+#include "../igl_inline.h"
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace triangle
+ {
+ // CDT Construct the constrained delaunay triangulation of the convex hull
+ // of a given set of points and segments in 2D. This differs from a direct
+ // call to triangulate because it will preprocess the input to remove
+ // duplicates and return an adjusted segment list on the output.
+ //
+ //
+ // BACKGROUND_MESH Construct a background mesh for a (messy) texture mesh with
+ // cosntraint edges that are about to deform.
+ //
+ // Inputs:
+ // V #V by 2 list of texture mesh vertices
+ // E #E by 2 list of constraint edge indices into V
+ // flags string of triangle flags should contain "-c" unless the
+ // some subset of segments are known to enclose all other
+ // points/segments.
+ // Outputs:
+ // WV #WV by 2 list of background mesh vertices
+ // WF #WF by 2 list of background mesh triangle indices into WV
+ // WE #WE by 2 list of constraint edge indices into WV (might be smaller
+ // than E because degenerate constraints have been removed)
+ // J #V list of indices into WF/WE for each vertex in V
+ //
+ template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedWV,
+ typename DerivedWF,
+ typename DerivedWE,
+ typename DerivedJ>
+ IGL_INLINE void cdt(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const std::string & flags,
+ Eigen::PlainObjectBase<DerivedWV> & WV,
+ Eigen::PlainObjectBase<DerivedWF> & WF,
+ Eigen::PlainObjectBase<DerivedWE> & WE,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "cdt.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/triangle/triangulate.cpp b/xs/src/igl/triangle/triangulate.cpp
new file mode 100644
index 000000000..5ee1d4be8
--- /dev/null
+++ b/xs/src/igl/triangle/triangulate.cpp
@@ -0,0 +1,181 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "triangulate.h"
+#ifdef ANSI_DECLARATORS
+# define IGL_PREVIOUSLY_DEFINED_ANSI_DECLARATORS ANSI_DECLARATORS
+# undef ANSI_DECLARATORS
+#endif
+#ifdef REAL
+# define IGL_PREVIOUSLY_DEFINED_REAL REAL
+# undef REAL
+#endif
+#ifdef VOID
+# define IGL_PREVIOUSLY_DEFINED_VOID VOID
+# undef VOID
+#endif
+#define ANSI_DECLARATORS
+#define REAL double
+#define VOID int
+
+extern "C"
+{
+#include <triangle.h>
+}
+
+#undef ANSI_DECLARATORS
+#ifdef IGL_PREVIOUSLY_DEFINED_ANSI_DECLARATORS
+# define ANSI_DECLARATORS IGL_PREVIOUSLY_DEFINED_ANSI_DECLARATORS
+#endif
+
+#undef REAL
+#ifdef IGL_PREVIOUSLY_DEFINED_REAL
+# define REAL IGL_PREVIOUSLY_DEFINED_REAL
+#endif
+
+#undef VOID
+#ifdef IGL_PREVIOUSLY_DEFINED_VOID
+# define VOID IGL_PREVIOUSLY_DEFINED_VOID
+#endif
+
+template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedH,
+ typename DerivedV2,
+ typename DerivedF2>
+IGL_INLINE void igl::triangle::triangulate(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedH> & H,
+ const std::string flags,
+ Eigen::PlainObjectBase<DerivedV2> & V2,
+ Eigen::PlainObjectBase<DerivedF2> & F2)
+{
+ Eigen::VectorXi VM,EM,VM2,EM2;
+ return triangulate(V,E,H,VM,EM,flags,V2,F2,VM2,EM2);
+}
+
+template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedH,
+ typename DerivedVM,
+ typename DerivedEM,
+ typename DerivedV2,
+ typename DerivedF2,
+ typename DerivedVM2,
+ typename DerivedEM2>
+IGL_INLINE void igl::triangle::triangulate(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedH> & H,
+ const Eigen::MatrixBase<DerivedVM> & VM,
+ const Eigen::MatrixBase<DerivedEM> & EM,
+ const std::string flags,
+ Eigen::PlainObjectBase<DerivedV2> & V2,
+ Eigen::PlainObjectBase<DerivedF2> & F2,
+ Eigen::PlainObjectBase<DerivedVM2> & VM2,
+ Eigen::PlainObjectBase<DerivedEM2> & EM2)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ assert( (VM.size() == 0 || V.rows() == VM.size()) &&
+ "Vertex markers must be empty or same size as V");
+ assert( (EM.size() == 0 || E.rows() == EM.size()) &&
+ "Segment markers must be empty or same size as E");
+ assert(V.cols() == 2);
+ assert(E.size() == 0 || E.cols() == 2);
+ assert(H.size() == 0 || H.cols() == 2);
+
+ // Prepare the flags
+ string full_flags = flags + "pz" + (EM.size() || VM.size() ? "" : "B");
+
+ typedef Map< Matrix<double,Dynamic,Dynamic,RowMajor> > MapXdr;
+ typedef Map< Matrix<int,Dynamic,Dynamic,RowMajor> > MapXir;
+
+ // Prepare the input struct
+ triangulateio in;
+ in.numberofpoints = V.rows();
+ in.pointlist = (double*)calloc(V.size(),sizeof(double));
+ {
+ MapXdr inpl(in.pointlist,V.rows(),V.cols());
+ inpl = V.template cast<double>();
+ }
+
+ in.numberofpointattributes = 0;
+ in.pointmarkerlist = (int*)calloc(V.size(),sizeof(int)) ;
+ for(unsigned i=0;i<V.rows();++i) in.pointmarkerlist[i] = VM.size()?VM(i):1;
+
+ in.trianglelist = NULL;
+ in.numberoftriangles = 0;
+ in.numberofcorners = 0;
+ in.numberoftriangleattributes = 0;
+ in.triangleattributelist = NULL;
+
+ in.numberofsegments = E.size()?E.rows():0;
+ in.segmentlist = (int*)calloc(E.size(),sizeof(int));
+ {
+ MapXir insl(in.segmentlist,E.rows(),E.cols());
+ insl = E.template cast<int>();
+ }
+ in.segmentmarkerlist = (int*)calloc(E.rows(),sizeof(int));
+ for (unsigned i=0;i<E.rows();++i) in.segmentmarkerlist[i] = EM.size()?EM(i):1;
+
+ in.numberofholes = H.size()?H.rows():0;
+ in.holelist = (double*)calloc(H.size(),sizeof(double));
+ {
+ MapXdr inhl(in.holelist,H.rows(),H.cols());
+ inhl = H.template cast<double>();
+ }
+ in.numberofregions = 0;
+
+ // Prepare the output struct
+ triangulateio out;
+ out.pointlist = NULL;
+ out.trianglelist = NULL;
+ out.segmentlist = NULL;
+ out.segmentmarkerlist = NULL;
+ out.pointmarkerlist = NULL;
+
+ // Call triangle
+ ::triangulate(const_cast<char*>(full_flags.c_str()), &in, &out, 0);
+
+ // Return the mesh
+ V2 = MapXdr(out.pointlist,out.numberofpoints,2).cast<typename DerivedV2::Scalar>();
+ F2 = MapXir(out.trianglelist,out.numberoftriangles,3).cast<typename DerivedF2::Scalar>();
+ if(VM.size())
+ {
+ VM2 = MapXir(out.pointmarkerlist,out.numberofpoints,1).cast<typename DerivedVM2::Scalar>();
+ }
+ if(EM.size())
+ {
+ EM2 = MapXir(out.segmentmarkerlist,out.numberofsegments,1).cast<typename DerivedEM2::Scalar>();
+ }
+
+ // Cleanup in
+ free(in.pointlist);
+ free(in.pointmarkerlist);
+ free(in.segmentlist);
+ free(in.segmentmarkerlist);
+ free(in.holelist);
+ // Cleanup out
+ free(out.pointlist);
+ free(out.trianglelist);
+ free(out.segmentlist);
+ free(out.segmentmarkerlist);
+ free(out.pointmarkerlist);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::triangle::triangulate<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::triangle::triangulate<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#endif
diff --git a/xs/src/igl/triangle/triangulate.h b/xs/src/igl/triangle/triangulate.h
new file mode 100644
index 000000000..90abdac9d
--- /dev/null
+++ b/xs/src/igl/triangle/triangulate.h
@@ -0,0 +1,87 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+// Copyright (C) 2017 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_TRIANGLE_TRIANGULATE_H
+#define IGL_TRIANGLE_TRIANGULATE_H
+#include "../igl_inline.h"
+#include <string>
+#include <Eigen/Core>
+
+namespace igl
+{
+ namespace triangle
+ {
+ // Triangulate the interior of a polygon using the triangle library.
+ //
+ // Inputs:
+ // V #V by 2 list of 2D vertex positions
+ // E #E by 2 list of vertex ids forming unoriented edges of the boundary of the polygon
+ // H #H by 2 coordinates of points contained inside holes of the polygon
+ // flags string of options pass to triangle (see triangle documentation)
+ // Outputs:
+ // V2 #V2 by 2 coordinates of the vertives of the generated triangulation
+ // F2 #F2 by 3 list of indices forming the faces of the generated triangulation
+ //
+ template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedH,
+ typename DerivedV2,
+ typename DerivedF2>
+ IGL_INLINE void triangulate(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedH> & H,
+ const std::string flags,
+ Eigen::PlainObjectBase<DerivedV2> & V2,
+ Eigen::PlainObjectBase<DerivedF2> & F2);
+
+ // Triangulate the interior of a polygon using the triangle library.
+ //
+ // Inputs:
+ // V #V by 2 list of 2D vertex positions
+ // E #E by 2 list of vertex ids forming unoriented edges of the boundary of the polygon
+ // H #H by 2 coordinates of points contained inside holes of the polygon
+ // M #V list of markers for input vertices
+ // flags string of options pass to triangle (see triangle documentation)
+ // Outputs:
+ // V2 #V2 by 2 coordinates of the vertives of the generated triangulation
+ // F2 #F2 by 3 list of indices forming the faces of the generated triangulation
+ // M2 #V2 list of markers for output vertices
+ //
+ // TODO: expose the option to prevent Steiner points on the boundary
+ //
+ template <
+ typename DerivedV,
+ typename DerivedE,
+ typename DerivedH,
+ typename DerivedVM,
+ typename DerivedEM,
+ typename DerivedV2,
+ typename DerivedF2,
+ typename DerivedVM2,
+ typename DerivedEM2>
+ IGL_INLINE void triangulate(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedH> & H,
+ const Eigen::MatrixBase<DerivedVM> & VM,
+ const Eigen::MatrixBase<DerivedEM> & EM,
+ const std::string flags,
+ Eigen::PlainObjectBase<DerivedV2> & V2,
+ Eigen::PlainObjectBase<DerivedF2> & F2,
+ Eigen::PlainObjectBase<DerivedVM2> & VM2,
+ Eigen::PlainObjectBase<DerivedEM2> & EM2);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "triangulate.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/triangle_fan.cpp b/xs/src/igl/triangle_fan.cpp
new file mode 100644
index 000000000..35944d026
--- /dev/null
+++ b/xs/src/igl/triangle_fan.cpp
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "triangle_fan.h"
+#include "exterior_edges.h"
+#include "list_to_matrix.h"
+
+IGL_INLINE void igl::triangle_fan(
+ const Eigen::MatrixXi & E,
+ Eigen::MatrixXi & cap)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ // Handle lame base case
+ if(E.size() == 0)
+ {
+ cap.resize(0,E.cols()+1);
+ return;
+ }
+ // "Triangulate" aka "close" the E trivially with facets
+ // Note: in 2D we need to know if E endpoints are incoming or
+ // outgoing (left or right). Thus this will not work.
+ assert(E.cols() == 2);
+ // Arbitrary starting vertex
+ //int s = E(int(((double)rand() / RAND_MAX)*E.rows()),0);
+ int s = E(rand()%E.rows(),0);
+ vector<vector<int> > lcap;
+ for(int i = 0;i<E.rows();i++)
+ {
+ // Skip edges incident on s (they would be zero-area)
+ if(E(i,0) == s || E(i,1) == s)
+ {
+ continue;
+ }
+ vector<int> e(3);
+ e[0] = s;
+ e[1] = E(i,0);
+ e[2] = E(i,1);
+ lcap.push_back(e);
+ }
+ list_to_matrix(lcap,cap);
+}
+
+IGL_INLINE Eigen::MatrixXi igl::triangle_fan( const Eigen::MatrixXi & E)
+{
+ Eigen::MatrixXi cap;
+ triangle_fan(E,cap);
+ return cap;
+}
diff --git a/xs/src/igl/triangle_fan.h b/xs/src/igl/triangle_fan.h
new file mode 100644
index 000000000..b56a05bc7
--- /dev/null
+++ b/xs/src/igl/triangle_fan.h
@@ -0,0 +1,30 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_TRIANGLE_FAN_H
+#define IGL_TRIANGLE_FAN_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Given a list of faces tessellate all of the "exterior" edges forming another
+ // list of
+ //
+ // Inputs:
+ // E #E by simplex_size-1 list of exterior edges (see exterior_edges.h)
+ // Outputs:
+ // cap #cap by simplex_size list of "faces" tessellating the boundary edges
+ IGL_INLINE void triangle_fan(
+ const Eigen::MatrixXi & E,
+ Eigen::MatrixXi & cap);
+ // In-line version
+ IGL_INLINE Eigen::MatrixXi triangle_fan( const Eigen::MatrixXi & E);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "triangle_fan.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/triangle_triangle_adjacency.cpp b/xs/src/igl/triangle_triangle_adjacency.cpp
new file mode 100644
index 000000000..62e8fbe1c
--- /dev/null
+++ b/xs/src/igl/triangle_triangle_adjacency.cpp
@@ -0,0 +1,274 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2018 Alec Jacobson, Marc Alexa
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "triangle_triangle_adjacency.h"
+#include "vertex_triangle_adjacency.h"
+#include "parallel_for.h"
+#include "unique_edge_map.h"
+#include <algorithm>
+#include <iostream>
+
+// Extract the face adjacencies
+template <typename DerivedF, typename TTT_type, typename DerivedTT>
+IGL_INLINE void igl::triangle_triangle_adjacency_extractTT(
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<TTT_type> >& TTT,
+ Eigen::PlainObjectBase<DerivedTT>& TT)
+{
+ TT.setConstant((int)(F.rows()),F.cols(),-1);
+
+ for(int i=1;i<(int)TTT.size();++i)
+ {
+ std::vector<int>& r1 = TTT[i-1];
+ std::vector<int>& r2 = TTT[i];
+ if ((r1[0] == r2[0]) && (r1[1] == r2[1]))
+ {
+ TT(r1[2],r1[3]) = r2[2];
+ TT(r2[2],r2[3]) = r1[2];
+ }
+ }
+}
+
+template <typename DerivedF, typename DerivedTT>
+IGL_INLINE void igl::triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedTT>& TT)
+{
+ const int n = F.maxCoeff()+1;
+ typedef Eigen::Matrix<typename DerivedTT::Scalar,Eigen::Dynamic,1> VectorXI;
+ VectorXI VF,NI;
+ vertex_triangle_adjacency(F,n,VF,NI);
+ TT = DerivedTT::Constant(F.rows(),3,-1);
+ // Loop over faces
+ igl::parallel_for(F.rows(),[&](int f)
+ {
+ // Loop over corners
+ for (int k = 0; k < 3; k++)
+ {
+ int vi = F(f,k), vin = F(f,(k+1)%3);
+ // Loop over face neighbors incident on this corner
+ for (int j = NI[vi]; j < NI[vi+1]; j++)
+ {
+ int fn = VF[j];
+ // Not this face
+ if (fn != f)
+ {
+ // Face neighbor also has [vi,vin] edge
+ if (F(fn,0) == vin || F(fn,1) == vin || F(fn,2) == vin)
+ {
+ TT(f,k) = fn;
+ break;
+ }
+ }
+ }
+ }
+ });
+}
+
+template <typename DerivedF, typename TTT_type>
+IGL_INLINE void igl::triangle_triangle_adjacency_preprocess(
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<TTT_type> >& TTT)
+{
+ for(int f=0;f<F.rows();++f)
+ for (int i=0;i<F.cols();++i)
+ {
+ // v1 v2 f ei
+ int v1 = F(f,i);
+ int v2 = F(f,(i+1)%F.cols());
+ if (v1 > v2) std::swap(v1,v2);
+ std::vector<int> r(4);
+ r[0] = v1; r[1] = v2;
+ r[2] = f; r[3] = i;
+ TTT.push_back(r);
+ }
+ std::sort(TTT.begin(),TTT.end());
+}
+
+// Extract the face adjacencies indices (needed for fast traversal)
+template <typename DerivedF, typename TTT_type, typename DerivedTTi>
+IGL_INLINE void igl::triangle_triangle_adjacency_extractTTi(
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<TTT_type> >& TTT,
+ Eigen::PlainObjectBase<DerivedTTi>& TTi)
+{
+ TTi.setConstant((int)(F.rows()),F.cols(),-1);
+
+ for(int i=1;i<(int)TTT.size();++i)
+ {
+ std::vector<int>& r1 = TTT[i-1];
+ std::vector<int>& r2 = TTT[i];
+ if ((r1[0] == r2[0]) && (r1[1] == r2[1]))
+ {
+ TTi(r1[2],r1[3]) = r2[3];
+ TTi(r2[2],r2[3]) = r1[3];
+ }
+ }
+}
+
+// Compute triangle-triangle adjacency with indices
+template <typename DerivedF, typename DerivedTT, typename DerivedTTi>
+IGL_INLINE void igl::triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTTi>& TTi)
+{
+ triangle_triangle_adjacency(F,TT);
+ TTi = DerivedTTi::Constant(TT.rows(),TT.cols(),-1);
+ //for(int f = 0; f<F.rows(); f++)
+ igl::parallel_for(F.rows(),[&](int f)
+ {
+ for(int k = 0;k<3;k++)
+ {
+ int vi = F(f,k), vj = F(f,(k+1)%3);
+ int fn = TT(f,k);
+ if(fn >= 0)
+ {
+ for(int kn = 0;kn<3;kn++)
+ {
+ int vin = F(fn,kn), vjn = F(fn,(kn+1)%3);
+ if(vi == vjn && vin == vj)
+ {
+ TTi(f,k) = kn;
+ break;
+ }
+ }
+ }
+ }
+ });
+}
+
+template <
+ typename DerivedF,
+ typename TTIndex,
+ typename TTiIndex>
+ IGL_INLINE void igl::triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT,
+ std::vector<std::vector<std::vector<TTiIndex> > > & TTi)
+{
+ return triangle_triangle_adjacency(F,true,TT,TTi);
+}
+
+template <
+ typename DerivedF,
+ typename TTIndex>
+ IGL_INLINE void igl::triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT)
+{
+ std::vector<std::vector<std::vector<TTIndex> > > not_used;
+ return triangle_triangle_adjacency(F,false,TT,not_used);
+}
+
+template <
+ typename DerivedF,
+ typename TTIndex,
+ typename TTiIndex>
+ IGL_INLINE void igl::triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ const bool construct_TTi,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT,
+ std::vector<std::vector<std::vector<TTiIndex> > > & TTi)
+{
+ using namespace Eigen;
+ using namespace std;
+ assert(F.cols() == 3 && "Faces must be triangles");
+ // number of faces
+ typedef typename DerivedF::Index Index;
+ typedef Matrix<typename DerivedF::Scalar,Dynamic,2> MatrixX2I;
+ typedef Matrix<typename DerivedF::Index,Dynamic,1> VectorXI;
+ MatrixX2I E,uE;
+ VectorXI EMAP;
+ vector<vector<Index> > uE2E;
+ unique_edge_map(F,E,uE,EMAP,uE2E);
+ return triangle_triangle_adjacency(E,EMAP,uE2E,construct_TTi,TT,TTi);
+}
+
+template <
+ typename DerivedE,
+ typename DerivedEMAP,
+ typename uE2EType,
+ typename TTIndex,
+ typename TTiIndex>
+ IGL_INLINE void igl::triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const std::vector<std::vector<uE2EType> > & uE2E,
+ const bool construct_TTi,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT,
+ std::vector<std::vector<std::vector<TTiIndex> > > & TTi)
+{
+ using namespace std;
+ using namespace Eigen;
+ typedef typename DerivedE::Index Index;
+ const size_t m = E.rows()/3;
+ assert((size_t)E.rows() == m*3 && "E should come from list of triangles.");
+ // E2E[i] --> {j,k,...} means face edge i corresponds to other faces edges j
+ // and k
+ TT.resize (m,vector<vector<TTIndex> >(3));
+ if(construct_TTi)
+ {
+ TTi.resize(m,vector<vector<TTiIndex> >(3));
+ }
+
+ // No race conditions because TT*[f][c]'s are in bijection with e's
+ // Minimum number of items per thread
+ //const size_t num_e = E.rows();
+ // Slightly better memory access than loop over E
+ igl::parallel_for(
+ m,
+ [&](const Index & f)
+ {
+ for(Index c = 0;c<3;c++)
+ {
+ const Index e = f + m*c;
+ //const Index c = e/m;
+ const vector<uE2EType> & N = uE2E[EMAP(e)];
+ for(const auto & ne : N)
+ {
+ const Index nf = ne%m;
+ // don't add self
+ if(nf != f)
+ {
+ TT[f][c].push_back(nf);
+ if(construct_TTi)
+ {
+ const Index nc = ne/m;
+ TTi[f][c].push_back(nc);
+ }
+ }
+ }
+ }
+ },
+ 1000ul);
+
+
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
+// generated by autoexplicit.sh
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+// generated by autoexplicit.sh
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
+#ifdef WIN32
+template void igl::triangle_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, __int64, __int64>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>, class std::allocator<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>>> &, class std::vector<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>, class std::allocator<class std::vector<class std::vector<__int64, class std::allocator<__int64>>, class std::allocator<class std::vector<__int64, class std::allocator<__int64>>>>>> &);
+template void igl::triangle_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64, int, int>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> const &, bool, class std::vector<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>, class std::allocator<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>>> &, class std::vector<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>, class std::allocator<class std::vector<class std::vector<int, class std::allocator<int>>, class std::allocator<class std::vector<int, class std::allocator<int>>>>>> &);
+#endif
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long, long, long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::MatrixBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > const&, bool, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&, std::vector<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >, std::allocator<std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > > > >&);
+template void igl::triangle_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long, int, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > > const&, bool, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&, std::vector<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >, std::allocator<std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > > >&);
+#endif
diff --git a/xs/src/igl/triangle_triangle_adjacency.h b/xs/src/igl/triangle_triangle_adjacency.h
new file mode 100644
index 000000000..632141bd0
--- /dev/null
+++ b/xs/src/igl/triangle_triangle_adjacency.h
@@ -0,0 +1,115 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_TRIANGLE_TRIANGLE_ADJACENCY_H
+#define IGL_TRIANGLE_TRIANGLE_ADJACENCY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+
+namespace igl
+{
+ // Constructs the triangle-triangle adjacency matrix for a given
+ // mesh (V,F).
+ //
+ // Inputs:
+ // F #F by simplex_size list of mesh faces (must be triangles)
+ // Outputs:
+ // TT #F by #3 adjacent matrix, the element i,j is the id of the triangle
+ // adjacent to the j edge of triangle i
+ // TTi #F by #3 adjacent matrix, the element i,j is the id of edge of the
+ // triangle TT(i,j) that is adjacent with triangle i
+ //
+ // NOTE: the first edge of a triangle is [0,1] the second [1,2] and the third
+ // [2,3]. this convention is DIFFERENT from cotmatrix_entries.h
+ template <typename DerivedF, typename DerivedTT, typename DerivedTTi>
+ IGL_INLINE void triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedTT>& TT,
+ Eigen::PlainObjectBase<DerivedTTi>& TTi);
+ template <typename DerivedF, typename DerivedTT>
+ IGL_INLINE void triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedTT>& TT);
+ // Preprocessing
+ template <typename DerivedF, typename TTT_type>
+ IGL_INLINE void triangle_triangle_adjacency_preprocess(
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<TTT_type> >& TTT);
+ // Extract the face adjacencies
+ template <typename DerivedF, typename TTT_type, typename DerivedTT>
+ IGL_INLINE void triangle_triangle_adjacency_extractTT(
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<TTT_type> >& TTT,
+ Eigen::PlainObjectBase<DerivedTT>& TT);
+ // Extract the face adjacencies indices (needed for fast traversal)
+ template <typename DerivedF, typename TTT_type, typename DerivedTTi>
+ IGL_INLINE void triangle_triangle_adjacency_extractTTi(
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<TTT_type> >& TTT,
+ Eigen::PlainObjectBase<DerivedTTi>& TTi);
+ // Adjacency list version, which works with non-manifold meshes
+ //
+ // Inputs:
+ // F #F by 3 list of triangle indices
+ // Outputs:
+ // TT #F by 3 list of lists so that TT[i][c] --> {j,k,...} means that
+ // faces j and k etc. are edge-neighbors of face i on face i's edge
+ // opposite corner c
+ // TTj #F list of lists so that TTj[i][c] --> {j,k,...} means that face
+ // TT[i][c][0] is an edge-neighbor of face i incident on the edge of face
+ // TT[i][c][0] opposite corner j, and TT[i][c][1] " corner k, etc.
+ template <
+ typename DerivedF,
+ typename TTIndex,
+ typename TTiIndex>
+ IGL_INLINE void triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT,
+ std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
+ template < typename DerivedF, typename TTIndex>
+ IGL_INLINE void triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT);
+ // Wrapper with bool to choose whether to compute TTi (this prototype should
+ // be "hidden").
+ template <
+ typename DerivedF,
+ typename TTIndex,
+ typename TTiIndex>
+ IGL_INLINE void triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ const bool construct_TTi,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT,
+ std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
+ // Inputs:
+ // E #F*3 by 2 list of all of directed edges in order (see
+ // `oriented_facets`)
+ // EMAP #F*3 list of indices into uE, mapping each directed edge to unique
+ // undirected edge
+ // uE2E #uE list of lists of indices into E of coexisting edges
+ // See also: unique_edge_map, oriented_facets
+ template <
+ typename DerivedE,
+ typename DerivedEMAP,
+ typename uE2EType,
+ typename TTIndex,
+ typename TTiIndex>
+ IGL_INLINE void triangle_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedE> & E,
+ const Eigen::MatrixBase<DerivedEMAP> & EMAP,
+ const std::vector<std::vector<uE2EType > > & uE2E,
+ const bool construct_TTi,
+ std::vector<std::vector<std::vector<TTIndex> > > & TT,
+ std::vector<std::vector<std::vector<TTiIndex> > > & TTi);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "triangle_triangle_adjacency.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/triangles_from_strip.cpp b/xs/src/igl/triangles_from_strip.cpp
new file mode 100644
index 000000000..1db854834
--- /dev/null
+++ b/xs/src/igl/triangles_from_strip.cpp
@@ -0,0 +1,36 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "triangles_from_strip.h"
+#include <iostream>
+
+template <typename DerivedS, typename DerivedF>
+IGL_INLINE void igl::triangles_from_strip(
+ const Eigen::MatrixBase<DerivedS>& S,
+ Eigen::PlainObjectBase<DerivedF>& F)
+{
+ using namespace std;
+ F.resize(S.size()-2,3);
+ for(int s = 0;s < S.size()-2;s++)
+ {
+ if(s%2 == 0)
+ {
+ F(s,0) = S(s+2);
+ F(s,1) = S(s+1);
+ F(s,2) = S(s+0);
+ }else
+ {
+ F(s,0) = S(s+0);
+ F(s,1) = S(s+1);
+ F(s,2) = S(s+2);
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+#endif
diff --git a/xs/src/igl/triangles_from_strip.h b/xs/src/igl/triangles_from_strip.h
new file mode 100644
index 000000000..01ffd6402
--- /dev/null
+++ b/xs/src/igl/triangles_from_strip.h
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_TRIANGLES_FROM_STRIP_H
+#define IGL_TRIANGLES_FROM_STRIP_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // TRIANGLES_FROM_STRIP Create a list of triangles from a stream of indices
+ // along a strip.
+ //
+ // Inputs:
+ // S #S list of indices
+ // Outputs:
+ // F #S-2 by 3 list of triangle indices
+ //
+ template <typename DerivedS, typename DerivedF>
+ IGL_INLINE void triangles_from_strip(
+ const Eigen::MatrixBase<DerivedS>& S,
+ Eigen::PlainObjectBase<DerivedF>& F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "triangles_from_strip.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/two_axis_valuator_fixed_up.cpp b/xs/src/igl/two_axis_valuator_fixed_up.cpp
new file mode 100644
index 000000000..4ffb607f4
--- /dev/null
+++ b/xs/src/igl/two_axis_valuator_fixed_up.cpp
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "two_axis_valuator_fixed_up.h"
+#include "PI.h"
+
+template <typename Scalardown_quat, typename Scalarquat>
+IGL_INLINE void igl::two_axis_valuator_fixed_up(
+ const int w,
+ const int h,
+ const double speed,
+ const Eigen::Quaternion<Scalardown_quat> & down_quat,
+ const int down_x,
+ const int down_y,
+ const int mouse_x,
+ const int mouse_y,
+ Eigen::Quaternion<Scalarquat> & quat)
+{
+ using namespace Eigen;
+ Matrix<Scalarquat,3,1> axis(0,1,0);
+ quat = down_quat *
+ Quaternion<Scalarquat>(
+ AngleAxis<Scalarquat>(
+ PI*((Scalarquat)(mouse_x-down_x))/(Scalarquat)w*speed/2.0,
+ axis.normalized()));
+ quat.normalize();
+ {
+ Matrix<Scalarquat,3,1> axis(1,0,0);
+ if(axis.norm() != 0)
+ {
+ quat =
+ Quaternion<Scalarquat>(
+ AngleAxis<Scalarquat>(
+ PI*(mouse_y-down_y)/(Scalarquat)h*speed/2.0,
+ axis.normalized())) * quat;
+ quat.normalize();
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::two_axis_valuator_fixed_up<float, float>(int, int, double, Eigen::Quaternion<float, 0> const&, int, int, int, int, Eigen::Quaternion<float, 0>&);
+template void igl::two_axis_valuator_fixed_up<double, double>(int, int, double, Eigen::Quaternion<double, 0> const&, int, int, int, int, Eigen::Quaternion<double, 0>&);
+#endif
diff --git a/xs/src/igl/two_axis_valuator_fixed_up.h b/xs/src/igl/two_axis_valuator_fixed_up.h
new file mode 100644
index 000000000..7b2e9aabf
--- /dev/null
+++ b/xs/src/igl/two_axis_valuator_fixed_up.h
@@ -0,0 +1,51 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_TWO_AXIS_VALUATOR_FIXED_AXIS_UP_H
+#define IGL_TWO_AXIS_VALUATOR_FIXED_AXIS_UP_H
+
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+
+namespace igl
+{
+ // Applies a two-axis valuator drag rotation (as seen in Maya/Studio max) to a given rotation.
+ // Inputs:
+ // w width of the trackball context
+ // h height of the trackball context
+ // speed controls how fast the trackball feels, 1 is normal
+ // down_quat rotation at mouse down, i.e. the rotation we're applying the
+ // trackball motion to (as quaternion). **Note:** Up-vector that is fixed
+ // is with respect to this rotation.
+ // down_x position of mouse down
+ // down_y position of mouse down
+ // mouse_x current x position of mouse
+ // mouse_y current y position of mouse
+ // Outputs:
+ // quat the resulting rotation (as quaternion)
+ //
+ // See also: snap_to_fixed_up
+ template <typename Scalardown_quat, typename Scalarquat>
+ IGL_INLINE void two_axis_valuator_fixed_up(
+ const int w,
+ const int h,
+ const double speed,
+ const Eigen::Quaternion<Scalardown_quat> & down_quat,
+ const int down_x,
+ const int down_y,
+ const int mouse_x,
+ const int mouse_y,
+ Eigen::Quaternion<Scalarquat> & quat);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "two_axis_valuator_fixed_up.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/uniformly_sample_two_manifold.cpp b/xs/src/igl/uniformly_sample_two_manifold.cpp
new file mode 100644
index 000000000..d35f74113
--- /dev/null
+++ b/xs/src/igl/uniformly_sample_two_manifold.cpp
@@ -0,0 +1,427 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "uniformly_sample_two_manifold.h"
+#include "verbose.h"
+#include "slice.h"
+#include "colon.h"
+#include "all_pairs_distances.h"
+#include "mat_max.h"
+#include "vertex_triangle_adjacency.h"
+#include "get_seconds.h"
+#include "cat.h"
+//#include "MT19937.h"
+#include "partition.h"
+
+//////////////////////////////////////////////////////////////////////////////
+// Helper functions
+//////////////////////////////////////////////////////////////////////////////
+
+IGL_INLINE void igl::uniformly_sample_two_manifold(
+ const Eigen::MatrixXd & W,
+ const Eigen::MatrixXi & F,
+ const int k,
+ const double push,
+ Eigen::MatrixXd & WS)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ // Euclidean distance between two points on a mesh given as barycentric
+ // coordinates
+ // Inputs:
+ // W #W by dim positions of mesh in weight space
+ // F #F by 3 indices of triangles
+ // face_A face index where 1st point lives
+ // bary_A barycentric coordinates of 1st point on face_A
+ // face_B face index where 2nd point lives
+ // bary_B barycentric coordinates of 2nd point on face_B
+ // Returns distance in euclidean space
+ const auto & bary_dist = [] (
+ const Eigen::MatrixXd & W,
+ const Eigen::MatrixXi & F,
+ const int face_A,
+ const Eigen::Vector3d & bary_A,
+ const int face_B,
+ const Eigen::Vector3d & bary_B) -> double
+ {
+ return
+ ((bary_A(0)*W.row(F(face_A,0)) +
+ bary_A(1)*W.row(F(face_A,1)) +
+ bary_A(2)*W.row(F(face_A,2)))
+ -
+ (bary_B(0)*W.row(F(face_B,0)) +
+ bary_B(1)*W.row(F(face_B,1)) +
+ bary_B(2)*W.row(F(face_B,2)))).norm();
+ };
+
+ // Base case if F is a tet list, find all faces and pass as non-manifold
+ // triangle mesh
+ if(F.cols() == 4)
+ {
+ verbose("uniform_sample.h: sampling tet mesh\n");
+ MatrixXi T0 = F.col(0);
+ MatrixXi T1 = F.col(1);
+ MatrixXi T2 = F.col(2);
+ MatrixXi T3 = F.col(3);
+ // Faces from tets
+ MatrixXi TF =
+ cat(1,
+ cat(1,
+ cat(2,T0, cat(2,T1,T2)),
+ cat(2,T0, cat(2,T2,T3))),
+ cat(1,
+ cat(2,T0, cat(2,T3,T1)),
+ cat(2,T1, cat(2,T3,T2)))
+ );
+ assert(TF.rows() == 4*F.rows());
+ assert(TF.cols() == 3);
+ uniformly_sample_two_manifold(W,TF,k,push,WS);
+ return;
+ }
+
+ double start = get_seconds();
+
+ VectorXi S;
+ // First get sampling as best as possible on mesh
+ uniformly_sample_two_manifold_at_vertices(W,k,push,S);
+ verbose("Lap: %g\n",get_seconds()-start);
+ slice(W,S,colon<int>(0,W.cols()-1),WS);
+ //cout<<"WSmesh=["<<endl<<WS<<endl<<"];"<<endl;
+
+//#ifdef EXTREME_VERBOSE
+ //cout<<"S=["<<endl<<S<<endl<<"];"<<endl;
+//#endif
+
+ // Build map from vertices to list of incident faces
+ vector<vector<int> > VF,VFi;
+ vertex_triangle_adjacency(W,F,VF,VFi);
+
+ // List of list of face indices, for each sample gives index to face it is on
+ vector<vector<int> > sample_faces; sample_faces.resize(k);
+ // List of list of barycentric coordinates, for each sample gives b-coords in
+ // face its on
+ vector<vector<Eigen::Vector3d> > sample_barys; sample_barys.resize(k);
+ // List of current maxmins amongst samples
+ vector<int> cur_maxmin; cur_maxmin.resize(k);
+ // List of distance matrices, D(i)(s,j) reveals distance from i's sth sample
+ // to jth seed if j<k or (j-k)th "pushed" corner
+ vector<MatrixXd> D; D.resize(k);
+
+ // Precompute an W.cols() by W.cols() identity matrix
+ MatrixXd I(MatrixXd::Identity(W.cols(),W.cols()));
+
+ // Describe each seed as a face index and barycentric coordinates
+ for(int i = 0;i < k;i++)
+ {
+ // Unreferenced vertex?
+ assert(VF[S(i)].size() > 0);
+ sample_faces[i].push_back(VF[S(i)][0]);
+ // We're right on a face vertex so barycentric coordinates are 0, but 1 at
+ // that vertex
+ Eigen::Vector3d bary(0,0,0);
+ bary( VFi[S(i)][0] ) = 1;
+ sample_barys[i].push_back(bary);
+ // initialize this to current maxmin
+ cur_maxmin[i] = 0;
+ }
+
+ // initialize radius
+ double radius = 1.0;
+ // minimum radius (bound on precision)
+ //double min_radius = 1e-5;
+ double min_radius = 1e-5;
+ int max_num_rand_samples_per_triangle = 100;
+ int max_sample_attempts_per_triangle = 1000;
+ // Max number of outer iterations for a given radius
+ int max_iters = 1000;
+
+ // continue iterating until radius is smaller than some threshold
+ while(radius > min_radius)
+ {
+ // initialize each seed
+ for(int i = 0;i < k;i++)
+ {
+ // Keep track of cur_maxmin data
+ int face_i = sample_faces[i][cur_maxmin[i]];
+ Eigen::Vector3d bary(sample_barys[i][cur_maxmin[i]]);
+ // Find index in face of closest mesh vertex (on this face)
+ int index_in_face =
+ (bary(0) > bary(1) ? (bary(0) > bary(2) ? 0 : 2)
+ : (bary(1) > bary(2) ? 1 : 2));
+ // find closest mesh vertex
+ int vertex_i = F(face_i,index_in_face);
+ // incident triangles
+ vector<int> incident_F = VF[vertex_i];
+ // We're going to try to place num_rand_samples_per_triangle samples on
+ // each sample *after* this location
+ sample_barys[i].clear();
+ sample_faces[i].clear();
+ cur_maxmin[i] = 0;
+ sample_barys[i].push_back(bary);
+ sample_faces[i].push_back(face_i);
+ // Current seed location in weight space
+ VectorXd seed =
+ bary(0)*W.row(F(face_i,0)) +
+ bary(1)*W.row(F(face_i,1)) +
+ bary(2)*W.row(F(face_i,2));
+#ifdef EXTREME_VERBOSE
+ verbose("i: %d\n",i);
+ verbose("face_i: %d\n",face_i);
+ //cout<<"bary: "<<bary<<endl;
+ verbose("index_in_face: %d\n",index_in_face);
+ verbose("vertex_i: %d\n",vertex_i);
+ verbose("incident_F.size(): %d\n",incident_F.size());
+ //cout<<"seed: "<<seed<<endl;
+#endif
+ // loop over indcident triangles
+ for(int f=0;f<(int)incident_F.size();f++)
+ {
+#ifdef EXTREME_VERBOSE
+ verbose("incident_F[%d]: %d\n",f,incident_F[f]);
+#endif
+ int face_f = incident_F[f];
+ int num_samples_f = 0;
+ for(int s=0;s<max_sample_attempts_per_triangle;s++)
+ {
+ // Randomly sample unit square
+ double u,v;
+// double ru = fgenrand();
+// double rv = fgenrand();
+ double ru = (double)rand() / RAND_MAX;
+ double rv = (double)rand() / RAND_MAX;
+ // Reflect to lower triangle if above
+ if((ru+rv)>1)
+ {
+ u = 1-rv;
+ v = 1-ru;
+ }else
+ {
+ u = ru;
+ v = rv;
+ }
+ Eigen::Vector3d sample_bary(u,v,1-u-v);
+ double d = bary_dist(W,F,face_i,bary,face_f,sample_bary);
+ // check that sample is close enough
+ if(d<radius)
+ {
+ // add sample to list
+ sample_faces[i].push_back(face_f);
+ sample_barys[i].push_back(sample_bary);
+ num_samples_f++;
+ }
+ // Keep track of which random samples came from which face
+ if(num_samples_f >= max_num_rand_samples_per_triangle)
+ {
+#ifdef EXTREME_VERBOSE
+ verbose("Reached maximum number of samples per face\n");
+#endif
+ break;
+ }
+ if(s==(max_sample_attempts_per_triangle-1))
+ {
+#ifdef EXTREME_VERBOSE
+ verbose("Reached maximum sample attempts per triangle\n");
+#endif
+ }
+ }
+#ifdef EXTREME_VERBOSE
+ verbose("sample_faces[%d].size(): %d\n",i,sample_faces[i].size());
+ verbose("sample_barys[%d].size(): %d\n",i,sample_barys[i].size());
+#endif
+ }
+ }
+
+ // Precompute distances from each seed's random samples to each "pushed"
+ // corner
+ // Put -1 in entries corresponding distance of a seed's random samples to
+ // self
+ // Loop over seeds
+ for(int i = 0;i < k;i++)
+ {
+ // resize distance matrix for new samples
+ D[i].resize(sample_faces[i].size(),k+W.cols());
+ // Loop over i's samples
+ for(int s = 0;s<(int)sample_faces[i].size();s++)
+ {
+ int sample_face = sample_faces[i][s];
+ Eigen::Vector3d sample_bary = sample_barys[i][s];
+ // Loop over other seeds
+ for(int j = 0;j < k;j++)
+ {
+ // distance from sample(i,s) to seed j
+ double d;
+ if(i==j)
+ {
+ // phony self distance: Ilya's idea of infinite
+ d = 10;
+ }else
+ {
+ int seed_j_face = sample_faces[j][cur_maxmin[j]];
+ Eigen::Vector3d seed_j_bary(sample_barys[j][cur_maxmin[j]]);
+ d = bary_dist(W,F,sample_face,sample_bary,seed_j_face,seed_j_bary);
+ }
+ D[i](s,j) = d;
+ }
+ // Loop over corners
+ for(int j = 0;j < W.cols();j++)
+ {
+ // distance from sample(i,s) to corner j
+ double d =
+ ((sample_bary(0)*W.row(F(sample_face,0)) +
+ sample_bary(1)*W.row(F(sample_face,1)) +
+ sample_bary(2)*W.row(F(sample_face,2)))
+ - I.row(j)).norm()/push;
+ // append after distances to seeds
+ D[i](s,k+j) = d;
+ }
+ }
+ }
+
+ int iters = 0;
+ while(true)
+ {
+ bool has_changed = false;
+ // try to move each seed
+ for(int i = 0;i < k;i++)
+ {
+ // for each sample look at distance to closest seed/corner
+ VectorXd minD = D[i].rowwise().minCoeff();
+ assert(minD.size() == (int)sample_faces[i].size());
+ // find random sample with maximum minimum distance to other seeds
+ int old_cur_maxmin = cur_maxmin[i];
+ double max_min = -2;
+ for(int s = 0;s<(int)sample_faces[i].size();s++)
+ {
+ if(max_min < minD(s))
+ {
+ max_min = minD(s);
+ // Set this as the new seed location
+ cur_maxmin[i] = s;
+ }
+ }
+#ifdef EXTREME_VERBOSE
+ verbose("max_min: %g\n",max_min);
+ verbose("cur_maxmin[%d]: %d->%d\n",i,old_cur_maxmin,cur_maxmin[i]);
+#endif
+ // did location change?
+ has_changed |= (old_cur_maxmin!=cur_maxmin[i]);
+ // update distances of random samples of other seeds
+ }
+ // if no seed moved, exit
+ if(!has_changed)
+ {
+ break;
+ }
+ iters++;
+ if(iters>=max_iters)
+ {
+ verbose("Hit max iters (%d) before converging\n",iters);
+ }
+ }
+ // shrink radius
+ //radius *= 0.9;
+ //radius *= 0.99;
+ radius *= 0.9;
+ }
+ // Collect weight space locations
+ WS.resize(k,W.cols());
+ for(int i = 0;i<k;i++)
+ {
+ int face_i = sample_faces[i][cur_maxmin[i]];
+ Eigen::Vector3d bary(sample_barys[i][cur_maxmin[i]]);
+ WS.row(i) =
+ bary(0)*W.row(F(face_i,0)) +
+ bary(1)*W.row(F(face_i,1)) +
+ bary(2)*W.row(F(face_i,2));
+ }
+ verbose("Lap: %g\n",get_seconds()-start);
+ //cout<<"WSafter=["<<endl<<WS<<endl<<"];"<<endl;
+}
+
+IGL_INLINE void igl::uniformly_sample_two_manifold_at_vertices(
+ const Eigen::MatrixXd & OW,
+ const int k,
+ const double push,
+ Eigen::VectorXi & S)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ // Copy weights and faces
+ const MatrixXd & W = OW;
+ /*const MatrixXi & F = OF;*/
+
+ // Initialize seeds
+ VectorXi G;
+ Matrix<double,Dynamic,1> ignore;
+ partition(W,k+W.cols(),G,S,ignore);
+ // Remove corners, which better be at top
+ S = S.segment(W.cols(),k).eval();
+
+ MatrixXd WS;
+ slice(W,S,colon<int>(0,W.cols()-1),WS);
+ //cout<<"WSpartition=["<<endl<<WS<<endl<<"];"<<endl;
+
+ // number of vertices
+ int n = W.rows();
+ // number of dimensions in weight space
+ int m = W.cols();
+ // Corners of weight space
+ MatrixXd I = MatrixXd::Identity(m,m);
+ // append corners to bottom of weights
+ MatrixXd WI(n+m,m);
+ WI << W,I;
+ // Weights at seeds and corners
+ MatrixXd WSC(k+m,m);
+ for(int i = 0;i<k;i++)
+ {
+ WSC.row(i) = W.row(S(i));
+ }
+ for(int i = 0;i<m;i++)
+ {
+ WSC.row(i+k) = WI.row(n+i);
+ }
+ // initialize all pairs sqaured distances
+ MatrixXd sqrD;
+ all_pairs_distances(WI,WSC,true,sqrD);
+ // bring in corners by push factor (squared because distances are squared)
+ sqrD.block(0,k,sqrD.rows(),m) /= push*push;
+
+ int max_iters = 30;
+ int j = 0;
+ for(;j<max_iters;j++)
+ {
+ bool has_changed = false;
+ // loop over seeds
+ for(int i =0;i<k;i++)
+ {
+ int old_si = S(i);
+ // set distance to ilya's idea of infinity
+ sqrD.col(i).setZero();
+ sqrD.col(i).array() += 10;
+ // find vertex farthers from all other seeds
+ MatrixXd minsqrD = sqrD.rowwise().minCoeff();
+ MatrixXd::Index si,PHONY;
+ minsqrD.maxCoeff(&si,&PHONY);
+ MatrixXd Wsi = W.row(si);
+ MatrixXd sqrDi;
+ all_pairs_distances(WI,Wsi,true,sqrDi);
+ sqrD.col(i) = sqrDi;
+ S(i) = si;
+ has_changed |= si!=old_si;
+ }
+ if(j == max_iters)
+ {
+ verbose("uniform_sample.h: Warning: hit max iters\n");
+ }
+ if(!has_changed)
+ {
+ break;
+ }
+ }
+}
diff --git a/xs/src/igl/uniformly_sample_two_manifold.h b/xs/src/igl/uniformly_sample_two_manifold.h
new file mode 100644
index 000000000..2c8400e94
--- /dev/null
+++ b/xs/src/igl/uniformly_sample_two_manifold.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNIFORMLY_SAMPLE_TWO_MANIFOLD_H
+#define IGL_UNIFORMLY_SAMPLE_TWO_MANIFOLD_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // UNIFORMLY_SAMPLE_TWO_MANIFOLD Attempt to sample a mesh uniformly by
+ // furthest point relaxation as described in "Fast Automatic Skinning
+ // Transformations"
+ //
+ // [Jacobson et al. 12] Section 3.3.
+ //
+ // Inputs:
+ // W #W by dim positions of mesh in weight space
+ // F #F by 3 indices of triangles
+ // k number of samplse
+ // push factor by which corners should be pushed away
+ // Outputs
+ // WS k by dim locations in weights space
+ //
+ IGL_INLINE void uniformly_sample_two_manifold(
+ const Eigen::MatrixXd & W,
+ const Eigen::MatrixXi & F,
+ const int k,
+ const double push,
+ Eigen::MatrixXd & WS);
+ // Find uniform sampling up to placing samples on mesh vertices
+ IGL_INLINE void uniformly_sample_two_manifold_at_vertices(
+ const Eigen::MatrixXd & OW,
+ const int k,
+ const double push,
+ Eigen::VectorXi & S);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "uniformly_sample_two_manifold.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/unique.cpp b/xs/src/igl/unique.cpp
new file mode 100644
index 000000000..9c5c7cb8d
--- /dev/null
+++ b/xs/src/igl/unique.cpp
@@ -0,0 +1,222 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unique.h"
+#include "sort.h"
+#include "IndexComparison.h"
+#include "SortableRow.h"
+#include "sortrows.h"
+#include "list_to_matrix.h"
+#include "matrix_to_list.h"
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+
+template <typename T>
+IGL_INLINE void igl::unique(
+ const std::vector<T> & A,
+ std::vector<T> & C,
+ std::vector<size_t> & IA,
+ std::vector<size_t> & IC)
+{
+ using namespace std;
+ std::vector<size_t> IM;
+ std::vector<T> sortA;
+ igl::sort(A,true,sortA,IM);
+ // Original unsorted index map
+ IA.resize(sortA.size());
+ for(int i=0;i<(int)sortA.size();i++)
+ {
+ IA[i] = i;
+ }
+ IA.erase(
+ std::unique(
+ IA.begin(),
+ IA.end(),
+ igl::IndexEquals<const std::vector<T>& >(sortA)),IA.end());
+
+ IC.resize(A.size());
+ {
+ int j = 0;
+ for(int i = 0;i<(int)sortA.size();i++)
+ {
+ if(sortA[IA[j]] != sortA[i])
+ {
+ j++;
+ }
+ IC[IM[i]] = j;
+ }
+ }
+ C.resize(IA.size());
+ // Reindex IA according to IM
+ for(int i = 0;i<(int)IA.size();i++)
+ {
+ IA[i] = IM[IA[i]];
+ C[i] = A[IA[i]];
+ }
+
+}
+
+template <typename T>
+IGL_INLINE void igl::unique(
+ const std::vector<T> & A,
+ std::vector<T> & C)
+{
+ std::vector<size_t> IA,IC;
+ return igl::unique(A,C,IA,IC);
+}
+
+template <
+ typename DerivedA,
+ typename DerivedC,
+ typename DerivedIA,
+ typename DerivedIC>
+IGL_INLINE void igl::unique(
+ const Eigen::DenseBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedIC> & IC)
+{
+ using namespace std;
+ using namespace Eigen;
+ vector<typename DerivedA::Scalar > vA;
+ vector<typename DerivedC::Scalar > vC;
+ vector<size_t> vIA,vIC;
+ matrix_to_list(A,vA);
+ unique(vA,vC,vIA,vIC);
+ list_to_matrix(vC,C);
+ list_to_matrix(vIA,IA);
+ list_to_matrix(vIC,IC);
+}
+
+template <
+ typename DerivedA,
+ typename DerivedC
+ >
+IGL_INLINE void igl::unique(
+ const Eigen::DenseBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedC> & C)
+{
+ using namespace std;
+ using namespace Eigen;
+ vector<typename DerivedA::Scalar > vA;
+ vector<typename DerivedC::Scalar > vC;
+ vector<size_t> vIA,vIC;
+ matrix_to_list(A,vA);
+ unique(vA,vC,vIA,vIC);
+ list_to_matrix(vC,C);
+}
+
+// Obsolete slow version converting to vectors
+// template <typename DerivedA, typename DerivedIA, typename DerivedIC>
+// IGL_INLINE void igl::unique_rows(
+// const Eigen::PlainObjectBase<DerivedA>& A,
+// Eigen::PlainObjectBase<DerivedA>& C,
+// Eigen::PlainObjectBase<DerivedIA>& IA,
+// Eigen::PlainObjectBase<DerivedIC>& IC)
+// {
+// using namespace std;
+//
+// typedef Eigen::Matrix<typename DerivedA::Scalar, Eigen::Dynamic, 1> RowVector;
+// vector<SortableRow<RowVector> > rows;
+// rows.resize(A.rows());
+// // Loop over rows
+// for(int i = 0;i<A.rows();i++)
+// {
+// RowVector ri = A.row(i);
+// rows[i] = SortableRow<RowVector>(ri);
+// }
+// vector<SortableRow<RowVector> > vC;
+//
+// // unique on rows
+// vector<size_t> vIA;
+// vector<size_t> vIC;
+// unique(rows,vC,vIA,vIC);
+//
+// // Convert to eigen
+// C.resize(vC.size(),A.cols());
+// IA.resize(vIA.size(),1);
+// IC.resize(vIC.size(),1);
+// for(int i = 0;i<C.rows();i++)
+// {
+// C.row(i) = vC[i].data;
+// IA(i) = vIA[i];
+// }
+// for(int i = 0;i<A.rows();i++)
+// {
+// IC(i) = vIC[i];
+// }
+// }
+
+// Obsolete
+// template <typename DerivedA, typename DerivedIA, typename DerivedIC>
+// IGL_INLINE void igl::unique_rows_many(
+// const Eigen::PlainObjectBase<DerivedA>& A,
+// Eigen::PlainObjectBase<DerivedA>& C,
+// Eigen::PlainObjectBase<DerivedIA>& IA,
+// Eigen::PlainObjectBase<DerivedIC>& IC)
+// {
+// using namespace std;
+// // frequency map
+// typedef Eigen::Matrix<typename DerivedA::Scalar, Eigen::Dynamic, 1> RowVector;
+// IC.resize(A.rows(),1);
+// map<SortableRow<RowVector>, int> fm;
+// const int m = A.rows();
+// for(int i = 0;i<m;i++)
+// {
+// RowVector ri = A.row(i);
+// if(fm.count(SortableRow<RowVector>(ri)) == 0)
+// {
+// fm[SortableRow<RowVector>(ri)] = i;
+// }
+// IC(i) = fm[SortableRow<RowVector>(ri)];
+// }
+// IA.resize(fm.size(),1);
+// Eigen::VectorXi RIA(m);
+// C.resize(fm.size(),A.cols());
+// {
+// int i = 0;
+// for(typename map<SortableRow<RowVector > , int >::const_iterator fit = fm.begin();
+// fit != fm.end();
+// fit++)
+// {
+// IA(i) = fit->second;
+// RIA(fit->second) = i;
+// C.row(i) = fit->first.data;
+// i++;
+// }
+// }
+// // IC should index C
+// for(int i = 0;i<m;i++)
+// {
+// IC(i) = RIA(IC(i));
+// }
+// }
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::unique<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::unique<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::unique<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique<double>(std::vector<double, std::allocator<double> > const&, std::vector<double, std::allocator<double> >&);
+template void igl::unique<int>(std::vector<int, std::allocator<int> > const&, std::vector<int, std::allocator<int> >&);
+template void igl::unique<int>(std::vector<int, std::allocator<int> > const&, std::vector<int, std::allocator<int> >&, std::vector<size_t, std::allocator<size_t> >&, std::vector<size_t, std::allocator<size_t> >&);
+template void igl::unique<long>(std::vector<long, std::allocator<long> > const&, std::vector<long, std::allocator<long> >&, std::vector<size_t, std::allocator<size_t> >&, std::vector<size_t, std::allocator<size_t> >&);
+#ifdef WIN32
+template void igl::unique<class Eigen::Matrix<int,-1,1,0,-1,1>,class Eigen::Matrix<int,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<int,-1,1,0,-1,1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+#endif
+#endif
diff --git a/xs/src/igl/unique.h b/xs/src/igl/unique.h
new file mode 100644
index 000000000..8618da15e
--- /dev/null
+++ b/xs/src/igl/unique.h
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNIQUE_H
+#define IGL_UNIQUE_H
+#include "igl_inline.h"
+
+#include <vector>
+#include <Eigen/Core>
+namespace igl
+{
+ // Act like matlab's [C,IA,IC] = unique(X)
+ //
+ // Templates:
+ // T comparable type T
+ // Inputs:
+ // A #A vector of type T
+ // Outputs:
+ // C #C vector of unique entries in A
+ // IA #C index vector so that C = A(IA);
+ // IC #A index vector so that A = C(IC);
+ template <typename T>
+ IGL_INLINE void unique(
+ const std::vector<T> & A,
+ std::vector<T> & C,
+ std::vector<size_t> & IA,
+ std::vector<size_t> & IC);
+ template <typename T>
+ IGL_INLINE void unique(
+ const std::vector<T> & A,
+ std::vector<T> & C);
+ template <
+ typename DerivedA,
+ typename DerivedC,
+ typename DerivedIA,
+ typename DerivedIC>
+ IGL_INLINE void unique(
+ const Eigen::DenseBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedC> & C,
+ Eigen::PlainObjectBase<DerivedIA> & IA,
+ Eigen::PlainObjectBase<DerivedIC> & IC);
+ template <
+ typename DerivedA,
+ typename DerivedC>
+ IGL_INLINE void unique(
+ const Eigen::DenseBase<DerivedA> & A,
+ Eigen::PlainObjectBase<DerivedC> & C);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "unique.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/unique_edge_map.cpp b/xs/src/igl/unique_edge_map.cpp
new file mode 100644
index 000000000..a69be58a0
--- /dev/null
+++ b/xs/src/igl/unique_edge_map.cpp
@@ -0,0 +1,69 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unique_edge_map.h"
+#include "oriented_facets.h"
+#include "unique_simplices.h"
+#include <cassert>
+#include <algorithm>
+template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DeriveduE,
+ typename DerivedEMAP,
+ typename uE2EType>
+IGL_INLINE void igl::unique_edge_map(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DeriveduE> & uE,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
+ std::vector<std::vector<uE2EType> > & uE2E)
+{
+ using namespace Eigen;
+ using namespace std;
+ // All occurrences of directed edges
+ oriented_facets(F,E);
+ const size_t ne = E.rows();
+ // This is 2x faster to create than a map from pairs to lists of edges and 5x
+ // faster to access (actually access is probably assympotically faster O(1)
+ // vs. O(log m)
+ Matrix<typename DerivedEMAP::Scalar,Dynamic,1> IA;
+ unique_simplices(E,uE,IA,EMAP);
+ uE2E.resize(uE.rows());
+ // This does help a little
+ for_each(uE2E.begin(),uE2E.end(),[](vector<uE2EType > & v){v.reserve(2);});
+ assert((size_t)EMAP.size() == ne);
+ for(uE2EType e = 0;e<(uE2EType)ne;e++)
+ {
+ uE2E[EMAP(e)].push_back(e);
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
+// generated by autoexplicit.sh
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+// generated by autoexplicit.sh
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::unique_edge_map<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, long>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, int>(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::unique_edge_map<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned long>(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
+
+#ifdef WIN32
+template void igl::unique_edge_map<class Eigen::Matrix<int, -1, 3, 0, -1, 3>, class Eigen::Matrix<int, -1, 2, 0, -1, 2>, class Eigen::Matrix<int, -1, 2, 0, -1, 2>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, __int64>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 3, 0, -1, 3> > const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 2, 0, -1, 2> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 2, 0, -1, 2> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> > &, class std::vector<class std::vector<__int64, class std::allocator<__int64> >, class std::allocator<class std::vector<__int64, class std::allocator<__int64> > > > &);
+template void igl::unique_edge_map<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,2,0,-1,2>,class Eigen::Matrix<int,-1,2,0,-1,2>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,__int64>(class Eigen::MatrixBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class std::vector<class std::vector<__int64,class std::allocator<__int64> >,class std::allocator<class std::vector<__int64,class std::allocator<__int64> > > > &);
+template void igl::unique_edge_map<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
+template void igl::unique_edge_map<class Eigen::Matrix<int, -1, 3, 1, -1, 3>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<int, -1, 1, 0, -1, 1>, unsigned __int64>(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 1, 0, -1, 1>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
+#endif
+
+#endif
diff --git a/xs/src/igl/unique_edge_map.h b/xs/src/igl/unique_edge_map.h
new file mode 100644
index 000000000..4915db66f
--- /dev/null
+++ b/xs/src/igl/unique_edge_map.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNIQUE_EDGE_MAP_H
+#define IGL_UNIQUE_EDGE_MAP_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+#include <vector>
+namespace igl
+{
+ // Construct relationships between facet "half"-(or rather "viewed")-edges E
+ // to unique edges of the mesh seen as a graph.
+ //
+ // Inputs:
+ // F #F by 3 list of simplices
+ // Outputs:
+ // E #F*3 by 2 list of all of directed edges
+ // uE #uE by 2 list of unique undirected edges
+ // EMAP #F*3 list of indices into uE, mapping each directed edge to unique
+ // undirected edge
+ // uE2E #uE list of lists of indices into E of coexisting edges
+ template <
+ typename DerivedF,
+ typename DerivedE,
+ typename DeriveduE,
+ typename DerivedEMAP,
+ typename uE2EType>
+ IGL_INLINE void unique_edge_map(
+ const Eigen::MatrixBase<DerivedF> & F,
+ Eigen::PlainObjectBase<DerivedE> & E,
+ Eigen::PlainObjectBase<DeriveduE> & uE,
+ Eigen::PlainObjectBase<DerivedEMAP> & EMAP,
+ std::vector<std::vector<uE2EType> > & uE2E);
+
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "unique_edge_map.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/unique_rows.cpp b/xs/src/igl/unique_rows.cpp
new file mode 100644
index 000000000..1973a80c2
--- /dev/null
+++ b/xs/src/igl/unique_rows.cpp
@@ -0,0 +1,111 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unique_rows.h"
+#include "sortrows.h"
+
+#include <algorithm>
+#include <iostream>
+#include <map>
+
+
+template <typename DerivedA, typename DerivedC, typename DerivedIA, typename DerivedIC>
+IGL_INLINE void igl::unique_rows(
+ const Eigen::DenseBase<DerivedA>& A,
+ Eigen::PlainObjectBase<DerivedC>& C,
+ Eigen::PlainObjectBase<DerivedIA>& IA,
+ Eigen::PlainObjectBase<DerivedIC>& IC)
+{
+ using namespace std;
+ using namespace Eigen;
+ VectorXi IM;
+ DerivedA sortA;
+ sortrows(A,true,sortA,IM);
+
+
+ const int num_rows = sortA.rows();
+ const int num_cols = sortA.cols();
+ vector<int> vIA(num_rows);
+ for(int i=0;i<num_rows;i++)
+ {
+ vIA[i] = i;
+ }
+
+ auto index_equal = [&sortA, &num_cols](const size_t i, const size_t j) {
+ for (size_t c=0; c<num_cols; c++) {
+ if (sortA(i,c) != sortA(j,c))
+ return false;
+ }
+ return true;
+ };
+ vIA.erase(
+ std::unique(
+ vIA.begin(),
+ vIA.end(),
+ index_equal
+ ),vIA.end());
+
+ IC.resize(A.rows(),1);
+ {
+ int j = 0;
+ for(int i = 0;i<num_rows;i++)
+ {
+ if(sortA.row(vIA[j]) != sortA.row(i))
+ {
+ j++;
+ }
+ IC(IM(i,0),0) = j;
+ }
+ }
+ const int unique_rows = vIA.size();
+ C.resize(unique_rows,A.cols());
+ IA.resize(unique_rows,1);
+ // Reindex IA according to IM
+ for(int i = 0;i<unique_rows;i++)
+ {
+ IA(i,0) = IM(vIA[i],0);
+ C.row(i) = A.row(IA(i,0));
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::unique_rows<Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<long long, -1, 1, 0, -1, 1>, Eigen::Matrix<long long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long long, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Matrix<long long, -1, 1, 0, -1, 1>, Eigen::Matrix<long long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long long, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::unique_rows<Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<int, -1, 4, 0, -1, 4>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 4, 0, -1, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::unique_rows<Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Matrix<int, 12, 4, 0, 12, 4>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 4, 0, 12, 4> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::unique_rows<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::DenseBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::unique_rows<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::DenseBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_rows<Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1> >(Eigen::DenseBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&);
+template void igl::unique_rows<Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,1,0,-1,1>,Eigen::Matrix<int,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<double,-1,-1,0,-1,-1>,Eigen::Matrix<long,-1,1,0,-1,1>,Eigen::Matrix<long,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<double,-1,-1,0,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<double,-1,-1,1,-1,-1>,Eigen::Matrix<double,-1,-1,1,-1,-1>,Eigen::Matrix<int,-1,1,0,-1,1>,Eigen::Matrix<int,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<double,-1,-1,1,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,-1,1,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<double,-1,3,0,-1,3>,Eigen::Matrix<double,-1,3,0,-1,3>,Eigen::Matrix<int,-1,1,0,-1,1>,Eigen::Matrix<int,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<double,-1,3,0,-1,3> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,3,0,-1,3> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<double,-1,3,0,-1,3>,Eigen::Matrix<double,-1,3,0,-1,3>,Eigen::Matrix<long,-1,1,0,-1,1>,Eigen::Matrix<long,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<double,-1,3,0,-1,3> > const&,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,3,0,-1,3> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<float,-1,3,0,-1,3>,Eigen::Matrix<float,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1> >(Eigen::DenseBase<Eigen::Matrix<float,-1,3,0,-1,3> > const&,Eigen::PlainObjectBase<Eigen::Matrix<float,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&);
+template void igl::unique_rows<Eigen::Matrix<float,-1,3,0,-1,3>,Eigen::Matrix<float,-1,3,0,-1,3>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1> >(Eigen::DenseBase<Eigen::Matrix<float,-1,3,0,-1,3> > const&,Eigen::PlainObjectBase<Eigen::Matrix<float,-1,3,0,-1,3> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&);
+template void igl::unique_rows<Eigen::Matrix<float,-1,3,1,-1,3>,Eigen::Matrix<float,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1> >(Eigen::DenseBase<Eigen::Matrix<float,-1,3,1,-1,3> > const&,Eigen::PlainObjectBase<Eigen::Matrix<float,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&);
+template void igl::unique_rows<Eigen::Matrix<float,-1,3,1,-1,3>,Eigen::Matrix<float,-1,3,1,-1,3>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1> >(Eigen::DenseBase<Eigen::Matrix<float,-1,3,1,-1,3> > const&,Eigen::PlainObjectBase<Eigen::Matrix<float,-1,3,1,-1,3> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&);
+template void igl::unique_rows<Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,1,0,-1,1>,Eigen::Matrix<int,-1,-1,0,-1,-1> >(Eigen::DenseBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&);
+template void igl::unique_rows<Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,1,0,-1,1>,Eigen::Matrix<int,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<int,-1,-1,0,-1,-1>,Eigen::Matrix<long,-1,1,0,-1,1>,Eigen::Matrix<long,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<int,-1,-1,0,-1,-1> > const&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,-1,0,-1,-1> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<int,-1,2,0,-1,2>,Eigen::Matrix<int,-1,2,0,-1,2>,Eigen::Matrix<int,-1,1,0,-1,1>,Eigen::Matrix<int,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<int,-1,2,0,-1,2> > const&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,2,0,-1,2> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,1,0,-1,1> >&);
+template void igl::unique_rows<Eigen::Matrix<int,-1,2,0,-1,2>,Eigen::Matrix<int,-1,2,0,-1,2>,Eigen::Matrix<long,-1,1,0,-1,1>,Eigen::Matrix<long,-1,1,0,-1,1> >(Eigen::DenseBase<Eigen::Matrix<int,-1,2,0,-1,2> > const&,Eigen::PlainObjectBase<Eigen::Matrix<int,-1,2,0,-1,2> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&,Eigen::PlainObjectBase<Eigen::Matrix<long,-1,1,0,-1,1> >&);
+#ifdef WIN32
+template void igl::unique_rows<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> >(class Eigen::DenseBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> > &);
+template void igl::unique_rows<class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<int,-1,-1,0,-1,-1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+template void igl::unique_rows<class Eigen::Matrix<int,-1,2,0,-1,2>,class Eigen::Matrix<int,-1,2,0,-1,2>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<int,-1,2,0,-1,2> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<int,-1,2,0,-1,2> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+template void igl::unique_rows<class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<double,-1,-1,0,-1,-1>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,-1,0,-1,-1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+template void igl::unique_rows<class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<double,-1,3,0,-1,3>,class Eigen::Matrix<__int64,-1,1,0,-1,1>,class Eigen::Matrix<__int64,-1,1,0,-1,1> >(class Eigen::DenseBase<class Eigen::Matrix<double,-1,3,0,-1,3> > const &,class Eigen::PlainObjectBase<class Eigen::Matrix<double,-1,3,0,-1,3> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &,class Eigen::PlainObjectBase<class Eigen::Matrix<__int64,-1,1,0,-1,1> > &);
+#endif
+#endif
diff --git a/xs/src/igl/unique_rows.h b/xs/src/igl/unique_rows.h
new file mode 100644
index 000000000..c612c8b1d
--- /dev/null
+++ b/xs/src/igl/unique_rows.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2017 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNIQUE_ROWS_H
+#define IGL_UNIQUE_ROWS_H
+#include "igl_inline.h"
+
+#include <vector>
+#include <Eigen/Core>
+namespace igl
+{
+ // Act like matlab's [C,IA,IC] = unique(X,'rows')
+ //
+ // Templates:
+ // DerivedA derived scalar type, e.g. MatrixXi or MatrixXd
+ // DerivedIA derived integer type, e.g. MatrixXi
+ // DerivedIC derived integer type, e.g. MatrixXi
+ // Inputs:
+ // A m by n matrix whose entries are to unique'd according to rows
+ // Outputs:
+ // C #C vector of unique rows in A
+ // IA #C index vector so that C = A(IA,:);
+ // IC #A index vector so that A = C(IC,:);
+ template <typename DerivedA, typename DerivedC, typename DerivedIA, typename DerivedIC>
+ IGL_INLINE void unique_rows(
+ const Eigen::DenseBase<DerivedA>& A,
+ Eigen::PlainObjectBase<DerivedC>& C,
+ Eigen::PlainObjectBase<DerivedIA>& IA,
+ Eigen::PlainObjectBase<DerivedIC>& IC);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "unique_rows.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/unique_simplices.cpp b/xs/src/igl/unique_simplices.cpp
new file mode 100644
index 000000000..463459866
--- /dev/null
+++ b/xs/src/igl/unique_simplices.cpp
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unique_simplices.h"
+#include "sort.h"
+#include "unique_rows.h"
+#include "parallel_for.h"
+
+template <
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedIA,
+ typename DerivedIC>
+IGL_INLINE void igl::unique_simplices(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedFF>& FF,
+ Eigen::PlainObjectBase<DerivedIA>& IA,
+ Eigen::PlainObjectBase<DerivedIC>& IC)
+{
+ using namespace Eigen;
+ using namespace std;
+ // Sort each face
+ MatrixXi sortF, unusedI;
+ igl::sort(F,2,true,sortF,unusedI);
+ // Find unique faces
+ MatrixXi C;
+ igl::unique_rows(sortF,C,IA,IC);
+ FF.resize(IA.size(),F.cols());
+ const size_t mff = FF.rows();
+ parallel_for(mff,[&F,&IA,&FF](size_t & i){FF.row(i) = F.row(IA(i));},1000ul);
+}
+
+template <
+ typename DerivedF,
+ typename DerivedFF>
+IGL_INLINE void igl::unique_simplices(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedFF>& FF)
+{
+ Eigen::VectorXi IA,IC;
+ return unique_simplices(F,FF,IA,IC);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::unique_simplices<Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_simplices<Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<double, -1, 2, 0, -1, 2>, Eigen::Matrix<long, -1, 1, 0, -1, 1>, Eigen::Matrix<long, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<long, -1, 1, 0, -1, 1> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 2, 0, -1, 2>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::unique_simplices<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+#ifdef WIN32
+template void igl::unique_simplices<class Eigen::Matrix<int, -1, 2, 0, -1, 2>, class Eigen::Matrix<int, -1, 2, 0, -1, 2>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1>, class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> >(class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 2, 0, -1, 2> > const &, class Eigen::PlainObjectBase<class Eigen::Matrix<int, -1, 2, 0, -1, 2> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> > &, class Eigen::PlainObjectBase<class Eigen::Matrix<__int64, -1, 1, 0, -1, 1> > &);
+#endif
+#endif
diff --git a/xs/src/igl/unique_simplices.h b/xs/src/igl/unique_simplices.h
new file mode 100644
index 000000000..a7c13849e
--- /dev/null
+++ b/xs/src/igl/unique_simplices.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNIQUE_SIMPLICES_H
+#define IGL_UNIQUE_SIMPLICES_H
+#include "igl_inline.h"
+#include <Eigen/Dense>
+namespace igl
+{
+ // Find *combinatorially* unique simplices in F. **Order independent**
+ //
+ // Inputs:
+ // F #F by simplex-size list of simplices
+ // Outputs:
+ // FF #FF by simplex-size list of unique simplices in F
+ // IA #FF index vector so that FF == sort(F(IA,:),2);
+ // IC #F index vector so that sort(F,2) == FF(IC,:);
+ template <
+ typename DerivedF,
+ typename DerivedFF,
+ typename DerivedIA,
+ typename DerivedIC>
+ IGL_INLINE void unique_simplices(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedFF>& FF,
+ Eigen::PlainObjectBase<DerivedIA>& IA,
+ Eigen::PlainObjectBase<DerivedIC>& IC);
+ template <
+ typename DerivedF,
+ typename DerivedFF>
+ IGL_INLINE void unique_simplices(
+ const Eigen::MatrixBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedFF>& FF);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "unique_simplices.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/unproject.cpp b/xs/src/igl/unproject.cpp
new file mode 100644
index 000000000..702d77fee
--- /dev/null
+++ b/xs/src/igl/unproject.cpp
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject.h"
+
+#include <Eigen/Dense>
+#include <Eigen/LU>
+
+template <
+ typename Derivedwin,
+ typename Derivedmodel,
+ typename Derivedproj,
+ typename Derivedviewport,
+ typename Derivedscene>
+IGL_INLINE void igl::unproject(
+ const Eigen::MatrixBase<Derivedwin>& win,
+ const Eigen::MatrixBase<Derivedmodel>& model,
+ const Eigen::MatrixBase<Derivedproj>& proj,
+ const Eigen::MatrixBase<Derivedviewport>& viewport,
+ Eigen::PlainObjectBase<Derivedscene> & scene)
+{
+ if(win.cols() != 3)
+ {
+ assert(win.rows() == 3);
+ // needless transposes
+ Eigen::Matrix<typename Derivedscene::Scalar,1,3> sceneT;
+ unproject(win.transpose().eval(),model,proj,viewport,sceneT);
+ scene = sceneT.head(3);
+ return;
+ }
+ assert(win.cols() == 3);
+ const int n = win.rows();
+ scene.resize(n,3);
+ for(int i = 0;i<n;i++)
+ {
+ typedef typename Derivedscene::Scalar Scalar;
+ Eigen::Matrix<Scalar,4,4> Inverse =
+ (proj.template cast<Scalar>() * model.template cast<Scalar>()).inverse();
+
+ Eigen::Matrix<Scalar,4,1> tmp;
+ tmp << win.row(i).head(3).transpose(), 1;
+ tmp(0) = (tmp(0) - viewport(0)) / viewport(2);
+ tmp(1) = (tmp(1) - viewport(1)) / viewport(3);
+ tmp = tmp.array() * 2.0f - 1.0f;
+
+ Eigen::Matrix<Scalar,4,1> obj = Inverse * tmp;
+ obj /= obj(3);
+
+ scene.row(i).head(3) = obj.head(3);
+ }
+}
+
+template <typename Scalar>
+IGL_INLINE Eigen::Matrix<Scalar,3,1> igl::unproject(
+ const Eigen::Matrix<Scalar,3,1>& win,
+ const Eigen::Matrix<Scalar,4,4>& model,
+ const Eigen::Matrix<Scalar,4,4>& proj,
+ const Eigen::Matrix<Scalar,4,1>& viewport)
+{
+ Eigen::Matrix<Scalar,3,1> scene;
+ unproject(win,model,proj,viewport,scene);
+ return scene;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template Eigen::Matrix<float, 3, 1, 0, 3, 1> igl::unproject<float>(Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&);
+template Eigen::Matrix<double, 3, 1, 0, 3, 1> igl::unproject<double>(Eigen::Matrix<double, 3, 1, 0, 3, 1> const&, Eigen::Matrix<double, 4, 4, 0, 4, 4> const&, Eigen::Matrix<double, 4, 4, 0, 4, 4> const&, Eigen::Matrix<double, 4, 1, 0, 4, 1> const&);
+template void igl::unproject<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
+template void igl::unproject<Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
+#endif
diff --git a/xs/src/igl/unproject.h b/xs/src/igl/unproject.h
new file mode 100644
index 000000000..f34e87513
--- /dev/null
+++ b/xs/src/igl/unproject.h
@@ -0,0 +1,47 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNPROJECT_H
+#define IGL_UNPROJECT_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Eigen reimplementation of gluUnproject
+ //
+ // Inputs:
+ // win #P by 3 or 3-vector (#P=1) of screen space x, y, and z coordinates
+ // model 4x4 model-view matrix
+ // proj 4x4 projection matrix
+ // viewport 4-long viewport vector
+ // Outputs:
+ // scene #P by 3 or 3-vector (#P=1) the unprojected x, y, and z coordinates
+ template <
+ typename Derivedwin,
+ typename Derivedmodel,
+ typename Derivedproj,
+ typename Derivedviewport,
+ typename Derivedscene>
+ IGL_INLINE void unproject(
+ const Eigen::MatrixBase<Derivedwin>& win,
+ const Eigen::MatrixBase<Derivedmodel>& model,
+ const Eigen::MatrixBase<Derivedproj>& proj,
+ const Eigen::MatrixBase<Derivedviewport>& viewport,
+ Eigen::PlainObjectBase<Derivedscene> & scene);
+ template <typename Scalar>
+ IGL_INLINE Eigen::Matrix<Scalar,3,1> unproject(
+ const Eigen::Matrix<Scalar,3,1>& win,
+ const Eigen::Matrix<Scalar,4,4>& model,
+ const Eigen::Matrix<Scalar,4,4>& proj,
+ const Eigen::Matrix<Scalar,4,1>& viewport);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/unproject_in_mesh.cpp b/xs/src/igl/unproject_in_mesh.cpp
new file mode 100644
index 000000000..6238aaf2a
--- /dev/null
+++ b/xs/src/igl/unproject_in_mesh.cpp
@@ -0,0 +1,97 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject_in_mesh.h"
+#include "unproject_ray.h"
+#include "ray_mesh_intersect.h"
+
+template < typename Derivedobj>
+ IGL_INLINE int igl::unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const std::function<
+ void(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&,
+ std::vector<igl::Hit> &)
+ > & shoot_ray,
+ Eigen::PlainObjectBase<Derivedobj> & obj,
+ std::vector<igl::Hit > & hits)
+{
+ using namespace std;
+ using namespace Eigen;
+ Vector3f s,dir;
+ unproject_ray(pos,model,proj,viewport,s,dir);
+ shoot_ray(s,dir,hits);
+ switch(hits.size())
+ {
+ case 0:
+ break;
+ case 1:
+ {
+ obj = (s + dir*hits[0].t).cast<typename Derivedobj::Scalar>();
+ break;
+ }
+ case 2:
+ default:
+ {
+ obj = 0.5*((s + dir*hits[0].t) + (s + dir*hits[1].t)).cast<typename Derivedobj::Scalar>();
+ break;
+ }
+ }
+ return hits.size();
+}
+
+extern "C"
+{
+#include "raytri.c"
+}
+
+template < typename DerivedV, typename DerivedF, typename Derivedobj>
+ IGL_INLINE int igl::unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<Derivedobj> & obj,
+ std::vector<igl::Hit > & hits)
+{
+ using namespace std;
+ using namespace Eigen;
+ const auto & shoot_ray = [&V,&F](
+ const Eigen::Vector3f& s,
+ const Eigen::Vector3f& dir,
+ std::vector<igl::Hit> & hits)
+ {
+ ray_mesh_intersect(s,dir,V,F,hits);
+ };
+ return unproject_in_mesh(pos,model,proj,viewport,shoot_ray,obj,hits);
+}
+
+template < typename DerivedV, typename DerivedF, typename Derivedobj>
+ IGL_INLINE int igl::unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<Derivedobj> & obj)
+{
+ std::vector<igl::Hit> hits;
+ return unproject_in_mesh(pos,model,proj,viewport,V,F,obj,hits);
+}
+#ifdef IGL_STATIC_LIBRARY
+template int igl::unproject_in_mesh<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, std::function<void (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+template int igl::unproject_in_mesh<Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, std::function<void (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+template int igl::unproject_in_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, std::function<void (Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, Eigen::Matrix<float, 3, 1, 0, 3, 1> const&, std::vector<igl::Hit, std::allocator<igl::Hit> >&)> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, std::vector<igl::Hit, std::allocator<igl::Hit> >&);
+template int igl::unproject_in_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> >&);
+#endif
diff --git a/xs/src/igl/unproject_in_mesh.h b/xs/src/igl/unproject_in_mesh.h
new file mode 100644
index 000000000..edb1a0e65
--- /dev/null
+++ b/xs/src/igl/unproject_in_mesh.h
@@ -0,0 +1,88 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNPROJECT_IN_MESH
+#define IGL_UNPROJECT_IN_MESH
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+#include <vector>
+#include "Hit.h"
+
+namespace igl
+{
+ // Unproject a screen location (using current opengl viewport, projection, and
+ // model view) to a 3D position _inside_ a given mesh. If the ray through the
+ // given screen location (x,y) _hits_ the mesh more than twice then the 3D
+ // midpoint between the first two hits is return. If it hits once, then that
+ // point is return. If it does not hit the mesh then obj is not set.
+ //
+ // Inputs:
+ // pos screen space coordinates
+ // model model matrix
+ // proj projection matrix
+ // viewport vieweport vector
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of mesh triangle indices into V
+ // Outputs:
+ // obj 3d unprojected mouse point in mesh
+ // hits vector of hits
+ // Returns number of hits
+ //
+ template < typename DerivedV, typename DerivedF, typename Derivedobj>
+ IGL_INLINE int unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<Derivedobj> & obj,
+ std::vector<igl::Hit > & hits);
+ //
+ // Inputs:
+ // pos screen space coordinates
+ // model model matrix
+ // proj projection matrix
+ // viewport vieweport vector
+ // shoot_ray function handle that outputs first hit of a given ray
+ // against a mesh (embedded in function handles as captured
+ // variable/data)
+ // Outputs:
+ // obj 3d unprojected mouse point in mesh
+ // hits vector of hits
+ // Returns number of hits
+ //
+ template < typename Derivedobj>
+ IGL_INLINE int unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const std::function<
+ void(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&,
+ std::vector<igl::Hit> &)
+ > & shoot_ray,
+ Eigen::PlainObjectBase<Derivedobj> & obj,
+ std::vector<igl::Hit > & hits);
+ template < typename DerivedV, typename DerivedF, typename Derivedobj>
+ IGL_INLINE int unproject_in_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::PlainObjectBase<Derivedobj> & obj);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject_in_mesh.cpp"
+#endif
+#endif
+
diff --git a/xs/src/igl/unproject_onto_mesh.cpp b/xs/src/igl/unproject_onto_mesh.cpp
new file mode 100644
index 000000000..897d206c1
--- /dev/null
+++ b/xs/src/igl/unproject_onto_mesh.cpp
@@ -0,0 +1,78 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject_onto_mesh.h"
+#include "unproject.h"
+#include "unproject_ray.h"
+#include "ray_mesh_intersect.h"
+#include <vector>
+
+template < typename DerivedV, typename DerivedF, typename Derivedbc>
+IGL_INLINE bool igl::unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ int & fid,
+ Eigen::PlainObjectBase<Derivedbc> & bc)
+{
+ using namespace std;
+ using namespace Eigen;
+ const auto & shoot_ray = [&V,&F](
+ const Eigen::Vector3f& s,
+ const Eigen::Vector3f& dir,
+ igl::Hit & hit)->bool
+ {
+ std::vector<igl::Hit> hits;
+ if(!ray_mesh_intersect(s,dir,V,F,hits))
+ {
+ return false;
+ }
+ hit = hits[0];
+ return true;
+ };
+ return unproject_onto_mesh(pos,model,proj,viewport,shoot_ray,fid,bc);
+}
+
+template <typename Derivedbc>
+IGL_INLINE bool igl::unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const std::function<
+ bool(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&,
+ igl::Hit &)
+ > & shoot_ray,
+ int & fid,
+ Eigen::PlainObjectBase<Derivedbc> & bc)
+{
+ using namespace std;
+ using namespace Eigen;
+ Vector3f s,dir;
+ unproject_ray(pos,model,proj,viewport,s,dir);
+ Hit hit;
+ if(!shoot_ray(s,dir,hit))
+ {
+ return false;
+ }
+ bc.resize(3);
+ bc << 1.0-hit.u-hit.v, hit.u, hit.v;
+ fid = hit.id;
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::unproject_onto_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
+template bool igl::unproject_onto_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::Matrix<float, 2, 1, 0, 2, 1> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 4, 0, 4, 4> const&, Eigen::Matrix<float, 4, 1, 0, 4, 1> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+#endif
+
diff --git a/xs/src/igl/unproject_onto_mesh.h b/xs/src/igl/unproject_onto_mesh.h
new file mode 100644
index 000000000..57252f99b
--- /dev/null
+++ b/xs/src/igl/unproject_onto_mesh.h
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNPROJECT_ONTO_MESH
+#define IGL_UNPROJECT_ONTO_MESH
+#include "igl_inline.h"
+#include "Hit.h"
+#include <Eigen/Core>
+#include <functional>
+
+namespace igl
+{
+ // Unproject a screen location (using current opengl viewport, projection, and
+ // model view) to a 3D position _onto_ a given mesh, if the ray through the
+ // given screen location (x,y) _hits_ the mesh.
+ //
+ // Inputs:
+ // pos screen space coordinates
+ // model model matrix
+ // proj projection matrix
+ // viewport vieweport vector
+ // V #V by 3 list of mesh vertex positions
+ // F #F by 3 list of mesh triangle indices into V
+ // Outputs:
+ // fid id of the first face hit
+ // bc barycentric coordinates of hit
+ // Returns true if there's a hit
+ template < typename DerivedV, typename DerivedF, typename Derivedbc>
+ IGL_INLINE bool unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ int & fid,
+ Eigen::PlainObjectBase<Derivedbc> & bc);
+ //
+ // Inputs:
+ // pos screen space coordinates
+ // model model matrix
+ // proj projection matrix
+ // viewport vieweport vector
+ // shoot_ray function handle that outputs hits of a given ray against a
+ // mesh (embedded in function handles as captured variable/data)
+ // Outputs:
+ // fid id of the first face hit
+ // bc barycentric coordinates of hit
+ // Returns true if there's a hit
+ template <typename Derivedbc>
+ IGL_INLINE bool unproject_onto_mesh(
+ const Eigen::Vector2f& pos,
+ const Eigen::Matrix4f& model,
+ const Eigen::Matrix4f& proj,
+ const Eigen::Vector4f& viewport,
+ const std::function<
+ bool(
+ const Eigen::Vector3f&,
+ const Eigen::Vector3f&,
+ igl::Hit &)
+ > & shoot_ray,
+ int & fid,
+ Eigen::PlainObjectBase<Derivedbc> & bc);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject_onto_mesh.cpp"
+#endif
+#endif
+
+
diff --git a/xs/src/igl/unproject_ray.cpp b/xs/src/igl/unproject_ray.cpp
new file mode 100644
index 000000000..f6eb7ebdd
--- /dev/null
+++ b/xs/src/igl/unproject_ray.cpp
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unproject_ray.h"
+#include "unproject.h"
+
+template <
+ typename Derivedpos,
+ typename Derivedmodel,
+ typename Derivedproj,
+ typename Derivedviewport,
+ typename Deriveds,
+ typename Deriveddir>
+IGL_INLINE void igl::unproject_ray(
+ const Eigen::PlainObjectBase<Derivedpos> & pos,
+ const Eigen::PlainObjectBase<Derivedmodel> & model,
+ const Eigen::PlainObjectBase<Derivedproj> & proj,
+ const Eigen::PlainObjectBase<Derivedviewport> & viewport,
+ Eigen::PlainObjectBase<Deriveds> & s,
+ Eigen::PlainObjectBase<Deriveddir> & dir)
+{
+ using namespace std;
+ using namespace Eigen;
+ // Source and direction on screen
+ typedef Eigen::Matrix<typename Deriveds::Scalar,3,1> Vec3;
+ Vec3 win_s(pos(0),pos(1),0);
+ Vec3 win_d(pos(0),pos(1),1);
+ // Source, destination and direction in world
+ Vec3 d;
+ igl::unproject(win_s,model,proj,viewport,s);
+ igl::unproject(win_d,model,proj,viewport,d);
+ dir = d-s;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template void igl::unproject_ray<Eigen::Matrix<float, 2, 1, 0, 2, 1>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 4, 0, 4, 4>, Eigen::Matrix<float, 4, 1, 0, 4, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1>, Eigen::Matrix<float, 3, 1, 0, 3, 1> >(Eigen::PlainObjectBase<Eigen::Matrix<float, 2, 1, 0, 2, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 4, 0, 4, 4> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 4, 1, 0, 4, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<float, 3, 1, 0, 3, 1> >&);
+#endif
diff --git a/xs/src/igl/unproject_ray.h b/xs/src/igl/unproject_ray.h
new file mode 100644
index 000000000..4ef66f266
--- /dev/null
+++ b/xs/src/igl/unproject_ray.h
@@ -0,0 +1,44 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNPROJECT_RAY_H
+#define IGL_UNPROJECT_RAY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // Construct a ray (source point + direction vector) given a screen space
+ // positions (e.g. mouse) and a model-view projection constellation.
+ //
+ // Inputs:
+ // pos 2d screen-space position (x,y)
+ // model 4x4 model-view matrix
+ // proj 4x4 projection matrix
+ // viewport 4-long viewport vector
+ // Outputs:
+ // s source of ray (pos unprojected with z=0)
+ /// dir direction of ray (d - s) where d is pos unprojected with z=1
+ //
+ template <
+ typename Derivedpos,
+ typename Derivedmodel,
+ typename Derivedproj,
+ typename Derivedviewport,
+ typename Deriveds,
+ typename Deriveddir>
+ IGL_INLINE void unproject_ray(
+ const Eigen::PlainObjectBase<Derivedpos> & pos,
+ const Eigen::PlainObjectBase<Derivedmodel> & model,
+ const Eigen::PlainObjectBase<Derivedproj> & proj,
+ const Eigen::PlainObjectBase<Derivedviewport> & viewport,
+ Eigen::PlainObjectBase<Deriveds> & s,
+ Eigen::PlainObjectBase<Deriveddir> & dir);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "unproject_ray.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/unzip_corners.cpp b/xs/src/igl/unzip_corners.cpp
new file mode 100644
index 000000000..0a2ed004c
--- /dev/null
+++ b/xs/src/igl/unzip_corners.cpp
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "unzip_corners.h"
+
+#include "unique_rows.h"
+#include "slice.h"
+
+template < typename DerivedA, typename DerivedU, typename DerivedG, typename DerivedJ >
+IGL_INLINE void igl::unzip_corners(
+ const std::vector<std::reference_wrapper<DerivedA> > & A,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J)
+{
+ if(A.size() == 0)
+ {
+ U.resize(0,0);
+ G.resize(0,3);
+ J.resize(0,0);
+ return;
+ }
+ const size_t num_a = A.size();
+ const typename DerivedA::Index m = A[0].get().rows();
+ DerivedU C(m*3,num_a);
+ for(int a = 0;a<num_a;a++)
+ {
+ assert(A[a].get().rows() == m && "All attributes should be same size");
+ assert(A[a].get().cols() == 3 && "Must be triangles");
+ C.block(0*m,a,m,1) = A[a].get().col(0);
+ C.block(1*m,a,m,1) = A[a].get().col(1);
+ C.block(2*m,a,m,1) = A[a].get().col(2);
+ }
+ DerivedJ I;
+ igl::unique_rows(C,U,I,J);
+ G.resize(m,3);
+ for(int f = 0;f<m;f++)
+ {
+ for(int c = 0;c<3;c++)
+ {
+ G(f,c) = J(f+c*m);
+ }
+ }
+}
diff --git a/xs/src/igl/unzip_corners.h b/xs/src/igl/unzip_corners.h
new file mode 100644
index 000000000..4d7dfdf69
--- /dev/null
+++ b/xs/src/igl/unzip_corners.h
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UNZIP_CORNERS_H
+#define IGL_UNZIP_CORNERS_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <vector>
+#include <functional>
+
+namespace igl
+{
+ // UNZIP_CORNERS Given a triangle mesh where corners of each triangle index
+ // different matrices of attributes (e.g. read from an OBJ file), unzip the
+ // corners into unique efficiently: attributes become properly vertex valued
+ // (usually creating greater than #V but less than #F*3 vertices).
+ //
+ // To pass a list of attributes this function takes an std::vector of
+ // std::reference_wrapper of an Eigen::... type. This allows you to use list
+ // initializers **without** incurring a copy, but means you'll need to
+ // provide the derived type of A as an explicit template parameter:
+ //
+ // unzip_corners<Eigen::MatrixXi>({F,FTC,FN},U,G,J);
+ //
+ // Inputs:
+ // A #A list of #F by 3 attribute indices, typically {F,FTC,FN}
+ // Outputs:
+ // U #U by #A list of indices into each attribute for each unique mesh
+ // vertex: U(v,a) is the attribute index of vertex v in attribute a.
+ // G #F by 3 list of triangle indices into U
+ // Example:
+ // [V,F,TC,FTC] = readOBJ('~/Downloads/kiwis/kiwi.obj');
+ // [U,G] = unzip_corners(cat(3,F,FTC));
+ // % display mesh
+ // tsurf(G,V(U(:,1),:));
+ // % display texture coordinates
+ // tsurf(G,TC(U(:,2),:));
+ //
+ template < typename DerivedA, typename DerivedU, typename DerivedG, typename DerivedJ>
+ IGL_INLINE void unzip_corners(
+ const std::vector<std::reference_wrapper<DerivedA> > & A,
+ Eigen::PlainObjectBase<DerivedU> & U,
+ Eigen::PlainObjectBase<DerivedG> & G,
+ Eigen::PlainObjectBase<DerivedJ> & J);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "unzip_corners.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/upsample.cpp b/xs/src/igl/upsample.cpp
new file mode 100644
index 000000000..8b5e3da24
--- /dev/null
+++ b/xs/src/igl/upsample.cpp
@@ -0,0 +1,145 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "upsample.h"
+
+#include "triangle_triangle_adjacency.h"
+
+
+template <
+ typename DerivedF,
+ typename SType,
+ typename DerivedNF>
+IGL_INLINE void igl::upsample(
+ const int n_verts,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::SparseMatrix<SType>& S,
+ Eigen::PlainObjectBase<DerivedNF>& NF)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ typedef Eigen::Triplet<SType> Triplet_t;
+
+ Eigen::Matrix< typename DerivedF::Scalar,Eigen::Dynamic,Eigen::Dynamic>
+ FF,FFi;
+ triangle_triangle_adjacency(F,FF,FFi);
+
+ // TODO: Cache optimization missing from here, it is a mess
+
+ // Compute the number and positions of the vertices to insert (on edges)
+ Eigen::MatrixXi NI = Eigen::MatrixXi::Constant(FF.rows(),FF.cols(),-1);
+ Eigen::MatrixXi NIdoubles = Eigen::MatrixXi::Zero(FF.rows(), FF.cols());
+ int counter = 0;
+
+ for(int i=0;i<FF.rows();++i)
+ {
+ for(int j=0;j<3;++j)
+ {
+ if(NI(i,j) == -1)
+ {
+ NI(i,j) = counter;
+ NIdoubles(i,j) = 0;
+ if (FF(i,j) != -1) {
+ //If it is not a boundary
+ NI(FF(i,j), FFi(i,j)) = counter;
+ NIdoubles(i,j) = 1;
+ }
+ ++counter;
+ }
+ }
+ }
+
+ const int& n_odd = n_verts;
+ const int& n_even = counter;
+ const int n_newverts = n_odd + n_even;
+
+ //Construct vertex positions
+ std::vector<Triplet_t> tripletList;
+
+ // Fill the odd vertices position
+ for (int i=0; i<n_odd; ++i)
+ {
+ tripletList.emplace_back(i, i, 1.);
+ }
+
+ for(int i=0;i<FF.rows();++i)
+ {
+ for(int j=0;j<3;++j)
+ {
+ if(NIdoubles(i,j)==0) {
+ tripletList.emplace_back(NI(i,j) + n_odd, F(i,j), 1./2.);
+ tripletList.emplace_back(NI(i,j) + n_odd, F(i,(j+1)%3), 1./2.);
+ }
+ }
+ }
+ S.resize(n_newverts, n_verts);
+ S.setFromTriplets(tripletList.begin(), tripletList.end());
+
+ // Build the new topology (Every face is replaced by four)
+ NF.resize(F.rows()*4,3);
+ for(int i=0; i<F.rows();++i)
+ {
+ VectorXi VI(6);
+ VI << F(i,0), F(i,1), F(i,2), NI(i,0) + n_odd, NI(i,1) + n_odd, NI(i,2) + n_odd;
+
+ VectorXi f0(3), f1(3), f2(3), f3(3);
+ f0 << VI(0), VI(3), VI(5);
+ f1 << VI(1), VI(4), VI(3);
+ f2 << VI(3), VI(4), VI(5);
+ f3 << VI(4), VI(2), VI(5);
+
+ NF.row((i*4)+0) = f0;
+ NF.row((i*4)+1) = f1;
+ NF.row((i*4)+2) = f2;
+ NF.row((i*4)+3) = f3;
+ }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF>
+IGL_INLINE void igl::upsample(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedNV>& NV,
+ Eigen::PlainObjectBase<DerivedNF>& NF,
+ const int number_of_subdivs)
+{
+ NV = V;
+ NF = F;
+ for(int i=0; i<number_of_subdivs; ++i)
+ {
+ DerivedNF tempF = NF;
+ Eigen::SparseMatrix<typename DerivedV::Scalar >S;
+ upsample(NV.rows(), tempF, S, NF);
+ // This .eval is super important
+ NV = (S*NV).eval();
+ }
+}
+
+template <
+ typename MatV,
+ typename MatF>
+IGL_INLINE void igl::upsample(
+ MatV& V,
+ MatF& F,
+ const int number_of_subdivs)
+{
+ const MatV V_copy = V;
+ const MatF F_copy = F;
+ return upsample(V_copy,F_copy,V,F,number_of_subdivs);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::upsample<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&, int);
+template void igl::upsample<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> >&);
+template void igl::upsample<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(Eigen::Matrix<double, -1, -1, 0, -1, -1>&, Eigen::Matrix<int, -1, -1, 0, -1, -1>&, int);
+#endif
diff --git a/xs/src/igl/upsample.h b/xs/src/igl/upsample.h
new file mode 100644
index 000000000..51608aef6
--- /dev/null
+++ b/xs/src/igl/upsample.h
@@ -0,0 +1,82 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_UPSAMPLE_H
+#define IGL_UPSAMPLE_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <Eigen/Sparse>
+
+// History:
+// changed templates from generic matrices to PlainObjectBase Alec May 7, 2011
+namespace igl
+{
+ // Subdivide without moving vertices: Given the triangle mesh [V, F],
+ // where n_verts = V.rows(), computes newV and a sparse matrix S s.t.
+ // [newV, newF] is the subdivided mesh where newV = S*V.
+ //
+ // Inputs:
+ // n_verts an integer (number of mesh vertices)
+ // F an m by 3 matrix of integers of triangle faces
+ // Outputs:
+ // S a sparse matrix (will become the subdivision matrix)
+ // newF a matrix containing the new faces
+ template <
+ typename DerivedF,
+ typename SType,
+ typename DerivedNF>
+ IGL_INLINE void upsample(
+ const int n_verts,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::SparseMatrix<SType>& S,
+ Eigen::PlainObjectBase<DerivedNF>& NF);
+ // Subdivide a mesh without moving vertices: loop subdivision but odd
+ // vertices stay put and even vertices are just edge midpoints
+ //
+ // Templates:
+ // MatV matrix for vertex positions, e.g. MatrixXd
+ // MatF matrix for vertex positions, e.g. MatrixXi
+ // Inputs:
+ // V #V by dim mesh vertices
+ // F #F by 3 mesh triangles
+ // Outputs:
+ // NV new vertex positions, V is guaranteed to be at top
+ // NF new list of face indices
+ //
+ // NOTE: V should not be the same as NV,
+ // NOTE: F should not be the same as NF, use other proto
+ //
+ // Known issues:
+ // - assumes (V,F) is edge-manifold.
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedNV,
+ typename DerivedNF>
+ IGL_INLINE void upsample(
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ Eigen::PlainObjectBase<DerivedNV>& NV,
+ Eigen::PlainObjectBase<DerivedNF>& NF,
+ const int number_of_subdivs = 1);
+
+ // Virtually in place wrapper
+ template <
+ typename MatV,
+ typename MatF>
+ IGL_INLINE void upsample(
+ MatV& V,
+ MatF& F,
+ const int number_of_subdivs = 1);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "upsample.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/vector_area_matrix.cpp b/xs/src/igl/vector_area_matrix.cpp
new file mode 100644
index 000000000..6464c14a7
--- /dev/null
+++ b/xs/src/igl/vector_area_matrix.cpp
@@ -0,0 +1,54 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "vector_area_matrix.h"
+#include <vector>
+
+// Bug in unsupported/Eigen/SparseExtra needs iostream first
+#include <iostream>
+#include <unsupported/Eigen/SparseExtra>
+
+//#include <igl/boundary_loop.h>
+#include <igl/boundary_facets.h>
+
+template <typename DerivedF, typename Scalar>
+IGL_INLINE void igl::vector_area_matrix(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& A)
+{
+ using namespace Eigen;
+ using namespace std;
+
+ // number of vertices
+ const int n = F.maxCoeff()+1;
+
+ MatrixXi E;
+ boundary_facets(F,E);
+
+ //Prepare a vector of triplets to set the matrix
+ vector<Triplet<Scalar> > tripletList;
+ tripletList.reserve(4*E.rows());
+
+ for(int k = 0; k < E.rows(); k++)
+ {
+ int i = E(k,0);
+ int j = E(k,1);
+ tripletList.push_back(Triplet<Scalar>(i+n, j, -0.25));
+ tripletList.push_back(Triplet<Scalar>(j, i+n, -0.25));
+ tripletList.push_back(Triplet<Scalar>(i, j+n, 0.25));
+ tripletList.push_back(Triplet<Scalar>(j+n, i, 0.25));
+ }
+
+ //Set A from triplets (Eigen will sum triplets with same coordinates)
+ A.resize(n * 2, n * 2);
+ A.setFromTriplets(tripletList.begin(), tripletList.end());
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::vector_area_matrix<Eigen::Matrix<int, -1, -1, 0, -1, -1>, double>(Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::SparseMatrix<double, 0, int>&);
+#endif
diff --git a/xs/src/igl/vector_area_matrix.h b/xs/src/igl/vector_area_matrix.h
new file mode 100644
index 000000000..6d385329c
--- /dev/null
+++ b/xs/src/igl/vector_area_matrix.h
@@ -0,0 +1,41 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VECTOR_AREA_MATRIX_H
+#define IGL_VECTOR_AREA_MATRIX_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+
+namespace igl
+{
+ // Constructs the symmetric area matrix A, s.t. [V.col(0)' V.col(1)'] * A *
+ // [V.col(0); V.col(1)] is the **vector area** of the mesh (V,F).
+ //
+ // Templates:
+ // DerivedV derived type of eigen matrix for V (e.g. derived from
+ // MatrixXd)
+ // DerivedF derived type of eigen matrix for F (e.g. derived from
+ // MatrixXi)
+ // Scalar scalar type for eigen sparse matrix (e.g. double)
+ // Inputs:
+ // F #F by 3 list of mesh faces (must be triangles)
+ // Outputs:
+ // A #Vx2 by #Vx2 area matrix
+ //
+ template <typename DerivedF, typename Scalar>
+ IGL_INLINE void vector_area_matrix(
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ Eigen::SparseMatrix<Scalar>& A);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "vector_area_matrix.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/verbose.h b/xs/src/igl/verbose.h
new file mode 100644
index 000000000..e4aa86958
--- /dev/null
+++ b/xs/src/igl/verbose.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VERBOSE_H
+#define IGL_VERBOSE_H
+
+// This function is only useful as a header-only inlined function
+
+namespace igl
+{
+ // Provide a wrapper for printf, called verbose that functions exactly like
+ // printf if VERBOSE is defined and does exactly nothing if VERBOSE is
+ // undefined
+ inline int verbose(const char * msg,...);
+}
+
+
+
+#include <cstdio>
+#ifdef VERBOSE
+# include <cstdarg>
+#endif
+
+#include <string>
+// http://channel9.msdn.com/forums/techoff/254707-wrapping-printf-in-c/
+#ifdef VERBOSE
+inline int igl::verbose(const char * msg,...)
+{
+ va_list argList;
+ va_start(argList, msg);
+ int count = vprintf(msg, argList);
+ va_end(argList);
+ return count;
+}
+#else
+inline int igl::verbose(const char * /*msg*/,...)
+{
+ return 0;
+}
+#endif
+
+#endif
diff --git a/xs/src/igl/vertex_triangle_adjacency.cpp b/xs/src/igl/vertex_triangle_adjacency.cpp
new file mode 100644
index 000000000..352d06244
--- /dev/null
+++ b/xs/src/igl/vertex_triangle_adjacency.cpp
@@ -0,0 +1,102 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "vertex_triangle_adjacency.h"
+#include "cumsum.h"
+
+template <typename DerivedF, typename VFType, typename VFiType>
+IGL_INLINE void igl::vertex_triangle_adjacency(
+ const typename DerivedF::Scalar n,
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<VFType> >& VF,
+ std::vector<std::vector<VFiType> >& VFi)
+{
+ VF.clear();
+ VFi.clear();
+
+ VF.resize(n);
+ VFi.resize(n);
+
+ typedef typename DerivedF::Index Index;
+ for(Index fi=0; fi<F.rows(); ++fi)
+ {
+ for(Index i = 0; i < F.cols(); ++i)
+ {
+ VF[F(fi,i)].push_back(fi);
+ VFi[F(fi,i)].push_back(i);
+ }
+ }
+}
+
+
+template <typename DerivedV, typename DerivedF, typename IndexType>
+IGL_INLINE void igl::vertex_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<IndexType> >& VF,
+ std::vector<std::vector<IndexType> >& VFi)
+{
+ return vertex_triangle_adjacency(V.rows(),F,VF,VFi);
+}
+
+template <
+ typename DerivedF,
+ typename DerivedVF,
+ typename DerivedNI>
+IGL_INLINE void igl::vertex_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ const int n,
+ Eigen::PlainObjectBase<DerivedVF> & VF,
+ Eigen::PlainObjectBase<DerivedNI> & NI)
+{
+ typedef Eigen::Matrix<typename DerivedVF::Scalar,Eigen::Dynamic,1> VectorXI;
+ // vfd #V list so that vfd(i) contains the vertex-face degree (number of
+ // faces incident on vertex i)
+ VectorXI vfd = VectorXI::Zero(n);
+ for (int i = 0; i < F.rows(); i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ vfd[F(i,j)]++;
+ }
+ }
+ igl::cumsum(vfd,1,NI);
+ // Prepend a zero
+ NI = (DerivedNI(n+1)<<0,NI).finished();
+ // vfd now acts as a counter
+ vfd = NI;
+
+ VF.derived()= Eigen::VectorXi(3*F.rows());
+ for (int i = 0; i < F.rows(); i++)
+ {
+ for (int j = 0; j < 3; j++)
+ {
+ VF[vfd[F(i,j)]] = i;
+ vfd[F(i,j)]++;
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, 3, 1, -1, 3>, unsigned long, unsigned long>(Eigen::Matrix<int, -1, 3, 1, -1, 3>::Scalar, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
+// generated by autoexplicit.sh
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, unsigned int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > >&, std::vector<std::vector<unsigned int, std::allocator<unsigned int> >, std::allocator<std::vector<unsigned int, std::allocator<unsigned int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, -1, 0, -1, -1>, long, long>(Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, long, long>(Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&, std::vector<std::vector<long, std::allocator<long> >, std::allocator<std::vector<long, std::allocator<long> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned long, unsigned long>(Eigen::Matrix<int, -1, -1, 0, -1, -1>::Scalar, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&, std::vector<std::vector<unsigned long, std::allocator<unsigned long> >, std::allocator<std::vector<unsigned long, std::allocator<unsigned long> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, int>(Eigen::MatrixBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+template void igl::vertex_triangle_adjacency<Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, int, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> >&);
+#ifdef WIN32
+template void igl::vertex_triangle_adjacency<class Eigen::Matrix<int, -1, -1, 0, -1, -1>, unsigned __int64, unsigned __int64>(int, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, -1, 0, -1, -1>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
+template void igl::vertex_triangle_adjacency<class Eigen::Matrix<int, -1, 3, 1, -1, 3>, unsigned __int64, unsigned __int64>(int, class Eigen::MatrixBase<class Eigen::Matrix<int, -1, 3, 1, -1, 3>> const &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &, class std::vector<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>, class std::allocator<class std::vector<unsigned __int64, class std::allocator<unsigned __int64>>>> &);
+#endif
+#endif
diff --git a/xs/src/igl/vertex_triangle_adjacency.h b/xs/src/igl/vertex_triangle_adjacency.h
new file mode 100644
index 000000000..ce67b1f3d
--- /dev/null
+++ b/xs/src/igl/vertex_triangle_adjacency.h
@@ -0,0 +1,71 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Daniele Panozzo <daniele.panozzo@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VERTEX_TRIANGLE_ADJACENCY_H
+#define IGL_VERTEX_TRIANGLE_ADJACENCY_H
+#include "igl_inline.h"
+
+#include <Eigen/Dense>
+#include <vector>
+
+namespace igl
+{
+ // vertex_face_adjacency constructs the vertex-face topology of a given mesh (V,F)
+ //
+ // Inputs:
+ // //V #V by 3 list of vertex coordinates
+ // n number of vertices #V (e.g. `F.maxCoeff()+1` or `V.rows()`)
+ // F #F by dim list of mesh faces (must be triangles)
+ // Outputs:
+ // VF #V list of lists of incident faces (adjacency list)
+ // VI #V list of lists of index of incidence within incident faces listed
+ // in VF
+ //
+ // See also: edges, cotmatrix, diag, vv
+ //
+ // Known bugs: this should not take V as an input parameter.
+ // Known bugs/features: if a facet is combinatorially degenerate then faces
+ // will appear multiple times in VF and correspondingly in VFI (j appears
+ // twice in F.row(i) then i will appear twice in VF[j])
+ template <typename DerivedF, typename VFType, typename VFiType>
+ IGL_INLINE void vertex_triangle_adjacency(
+ const typename DerivedF::Scalar n,
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<VFType> >& VF,
+ std::vector<std::vector<VFiType> >& VFi);
+ template <typename DerivedV, typename DerivedF, typename IndexType>
+ IGL_INLINE void vertex_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ std::vector<std::vector<IndexType> >& VF,
+ std::vector<std::vector<IndexType> >& VFi);
+ // Inputs:
+ // F #F by 3 list of triangle indices into some vertex list V
+ // n number of vertices, #V (e.g., F.maxCoeff()+1)
+ // Outputs:
+ // VF 3*#F list List of faces indice on each vertex, so that VF(NI(i)+j) =
+ // f, means that face f is the jth face (in no particular order) incident
+ // on vertex i.
+ // NI #V+1 list cumulative sum of vertex-triangle degrees with a
+ // preceeding zero. "How many faces" have been seen before visiting this
+ // vertex and its incident faces.
+ template <
+ typename DerivedF,
+ typename DerivedVF,
+ typename DerivedNI>
+ IGL_INLINE void vertex_triangle_adjacency(
+ const Eigen::MatrixBase<DerivedF> & F,
+ const int n,
+ Eigen::PlainObjectBase<DerivedVF> & VF,
+ Eigen::PlainObjectBase<DerivedNI> & NI);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "vertex_triangle_adjacency.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/volume.cpp b/xs/src/igl/volume.cpp
new file mode 100644
index 000000000..68568cf45
--- /dev/null
+++ b/xs/src/igl/volume.cpp
@@ -0,0 +1,120 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "volume.h"
+#include "cross.h"
+#include <Eigen/Geometry>
+template <
+ typename DerivedV,
+ typename DerivedT,
+ typename Derivedvol>
+IGL_INLINE void igl::volume(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ Eigen::PlainObjectBase<Derivedvol>& vol)
+{
+ using namespace Eigen;
+ const int m = T.rows();
+ vol.resize(m,1);
+ for(int t = 0;t<m;t++)
+ {
+ typedef Eigen::Matrix<typename DerivedV::Scalar,1,3> RowVector3S;
+ const RowVector3S & a = V.row(T(t,0));
+ const RowVector3S & b = V.row(T(t,1));
+ const RowVector3S & c = V.row(T(t,2));
+ const RowVector3S & d = V.row(T(t,3));
+ vol(t) = -(a-d).dot((b-d).cross(c-d))/6.;
+ }
+}
+
+template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedD,
+ typename Derivedvol>
+IGL_INLINE void igl::volume(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ const Eigen::MatrixBase<DerivedD> & D,
+ Eigen::PlainObjectBase<Derivedvol> & vol)
+{
+ const auto & AmD = A-D;
+ const auto & BmD = B-D;
+ const auto & CmD = C-D;
+ DerivedA BmDxCmD;
+ cross(BmD.eval(),CmD.eval(),BmDxCmD);
+ const auto & AmDdx = (AmD.array() * BmDxCmD.array()).rowwise().sum();
+ vol = -AmDdx/6.;
+}
+
+template <
+ typename VecA,
+ typename VecB,
+ typename VecC,
+ typename VecD>
+IGL_INLINE typename VecA::Scalar igl::volume_single(
+ const VecA & a,
+ const VecB & b,
+ const VecC & c,
+ const VecD & d)
+{
+ return -(a-d).dot((b-d).cross(c-d))/6.;
+}
+
+
+template <
+ typename DerivedL,
+ typename Derivedvol>
+IGL_INLINE void igl::volume(
+ const Eigen::MatrixBase<DerivedL>& L,
+ Eigen::PlainObjectBase<Derivedvol>& vol)
+{
+ using namespace Eigen;
+ const int m = L.rows();
+ typedef typename Derivedvol::Scalar ScalarS;
+ vol.resize(m,1);
+ for(int t = 0;t<m;t++)
+ {
+ const ScalarS u = L(t,0);
+ const ScalarS v = L(t,1);
+ const ScalarS w = L(t,2);
+ const ScalarS U = L(t,3);
+ const ScalarS V = L(t,4);
+ const ScalarS W = L(t,5);
+ const ScalarS X = (w - U + v)*(U + v + w);
+ const ScalarS x = (U - v + w)*(v - w + U);
+ const ScalarS Y = (u - V + w)*(V + w + u);
+ const ScalarS y = (V - w + u)*(w - u + V);
+ const ScalarS Z = (v - W + u)*(W + u + v);
+ const ScalarS z = (W - u + v)*(u - v + W);
+ const ScalarS a = sqrt(x*Y*Z);
+ const ScalarS b = sqrt(y*Z*X);
+ const ScalarS c = sqrt(z*X*Y);
+ const ScalarS d = sqrt(x*y*z);
+ vol(t) = sqrt(
+ (-a + b + c + d)*
+ ( a - b + c + d)*
+ ( a + b - c + d)*
+ ( a + b + c - d))/
+ (192.*u*v*w);
+ }
+}
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::volume<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::volume<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::volume<Eigen::Matrix<double, -1, 6, 0, -1, 6>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 6, 0, -1, 6> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template void igl::volume<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+template Eigen::Matrix<double, 1, 3, 1, 1, 3>::Scalar igl::volume_single<Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&, Eigen::Matrix<double, 1, 3, 1, 1, 3> const&);
+template void igl::volume<Eigen::Matrix<double,-1,3,0,-1,3>,Eigen::Matrix<int,-1,3,0,-1,3>,Eigen::Matrix<double,-1,1,0,-1,1> >(Eigen::MatrixBase<Eigen::Matrix<double,-1,3,0,-1,3> > const &,Eigen::MatrixBase<Eigen::Matrix<int,-1,3,0,-1,3> > const &,Eigen::PlainObjectBase<Eigen::Matrix<double,-1,1,0,-1,1> > &);
+#endif
diff --git a/xs/src/igl/volume.h b/xs/src/igl/volume.h
new file mode 100644
index 000000000..2dee7cc95
--- /dev/null
+++ b/xs/src/igl/volume.h
@@ -0,0 +1,74 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VOLUME_H
+#define IGL_VOLUME_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+namespace igl
+{
+ // VOLUME Compute volume for all tets of a given tet mesh
+ // (V,T)
+ //
+ // vol = volume(V,T)
+ //
+ // Inputs:
+ // V #V by dim list of vertex positions
+ // T #V by 4 list of tet indices
+ // Outputs:
+ // vol #T list of dihedral angles (in radians)
+ //
+ template <
+ typename DerivedV,
+ typename DerivedT,
+ typename Derivedvol>
+ IGL_INLINE void volume(
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedT>& T,
+ Eigen::PlainObjectBase<Derivedvol>& vol);
+ template <
+ typename DerivedA,
+ typename DerivedB,
+ typename DerivedC,
+ typename DerivedD,
+ typename Derivedvol>
+ IGL_INLINE void volume(
+ const Eigen::MatrixBase<DerivedA> & A,
+ const Eigen::MatrixBase<DerivedB> & B,
+ const Eigen::MatrixBase<DerivedC> & C,
+ const Eigen::MatrixBase<DerivedD> & D,
+ Eigen::PlainObjectBase<Derivedvol> & vol);
+ // Single tet
+ template <
+ typename VecA,
+ typename VecB,
+ typename VecC,
+ typename VecD>
+ IGL_INLINE typename VecA::Scalar volume_single(
+ const VecA & a,
+ const VecB & b,
+ const VecC & c,
+ const VecD & d);
+ // Intrinsic version:
+ //
+ // Inputs:
+ // L #V by 6 list of edge lengths (see edge_lengths)
+ template <
+ typename DerivedL,
+ typename Derivedvol>
+ IGL_INLINE void volume(
+ const Eigen::MatrixBase<DerivedL>& L,
+ Eigen::PlainObjectBase<Derivedvol>& vol);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "volume.cpp"
+#endif
+
+#endif
+
+
diff --git a/xs/src/igl/voxel_grid.cpp b/xs/src/igl/voxel_grid.cpp
new file mode 100644
index 000000000..388e58af4
--- /dev/null
+++ b/xs/src/igl/voxel_grid.cpp
@@ -0,0 +1,73 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "voxel_grid.h"
+#include "grid.h"
+
+template <
+ typename Scalar,
+ typename DerivedGV,
+ typename Derivedside>
+IGL_INLINE void igl::voxel_grid(
+ const Eigen::AlignedBox<Scalar,3> & box,
+ const int in_s,
+ const int pad_count,
+ Eigen::PlainObjectBase<DerivedGV> & GV,
+ Eigen::PlainObjectBase<Derivedside> & side)
+{
+ using namespace Eigen;
+ using namespace std;
+ typename DerivedGV::Index si = -1;
+ box.diagonal().maxCoeff(&si);
+ //DerivedGV::Index si = 0;
+ //assert(si>=0);
+ const Scalar s_len = box.diagonal()(si);
+ assert(in_s>(pad_count*2+1) && "s should be > 2*pad_count+1");
+ const Scalar s = in_s - 2*pad_count;
+ side(si) = s;
+ for(int i = 0;i<3;i++)
+ {
+ if(i!=si)
+ {
+ side(i) = std::ceil(s * (box.max()(i)-box.min()(i))/s_len);
+ }
+ }
+ side.array() += 2*pad_count;
+ grid(side,GV);
+ // A * p/s + B = min
+ // A * (1-p/s) + B = max
+ // B = min - A * p/s
+ // A * (1-p/s) + min - A * p/s = max
+ // A * (1-p/s) - A * p/s = max-min
+ // A * (1-2p/s) = max-min
+ // A = (max-min)/(1-2p/s)
+ const Array<Scalar,3,1> ps=
+ (Scalar)(pad_count)/(side.transpose().template cast<Scalar>().array()-1.);
+ const Array<Scalar,3,1> A = box.diagonal().array()/(1.0-2.*ps);
+ //// This would result in an "anamorphic", but perfectly fit grid:
+ //const Array<Scalar,3,1> B = box.min().array() - A.array()*ps;
+ //GV.array().rowwise() *= A.transpose();
+ //GV.array().rowwise() += B.transpose();
+ // Instead scale by largest factor and move to match center
+ typename Array<Scalar,3,1>::Index ai = -1;
+ Scalar a = A.maxCoeff(&ai);
+ const Array<Scalar,1,3> ratio =
+ a*(side.template cast<Scalar>().array()-1.0)/(Scalar)(side(ai)-1.0);
+ GV.array().rowwise() *= ratio;
+ const Eigen::Matrix<Scalar,1,3> offset = (box.center().transpose()-GV.colwise().mean()).eval();
+ GV.rowwise() += offset;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template void igl::voxel_grid<float, Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3> >(Eigen::AlignedBox<float, 3> const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&);
+template void igl::voxel_grid<float, Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, 3, 1, 0, 3, 1> >(Eigen::AlignedBox<float, 3> const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> >&);
+template void igl::voxel_grid<float, Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, 3, 1, 0, 3, 1> >(Eigen::AlignedBox<float, 3> const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> >&);
+template void igl::voxel_grid<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 3, 1, 0, 3, 1> >(Eigen::AlignedBox<double, 3> const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 3, 1, 0, 3, 1> >&);
+template void igl::voxel_grid<double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 1, 3, 1, 1, 3> >(Eigen::AlignedBox<double, 3> const&, int, int, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<int, 1, 3, 1, 1, 3> >&);
+#endif
diff --git a/xs/src/igl/voxel_grid.h b/xs/src/igl/voxel_grid.h
new file mode 100644
index 000000000..4f8ac1bcb
--- /dev/null
+++ b/xs/src/igl/voxel_grid.h
@@ -0,0 +1,39 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_VOXEL_GRID_H
+#define IGL_VOXEL_GRID_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <Eigen/Geometry>
+namespace igl
+{
+ // Construct the cell center positions of a regular voxel grid (lattice) made
+ // of perfectly square voxels.
+ //
+ // Inputs:
+ // box bounding box to enclose by grid
+ // s number of cell centers on largest side (including 2*pad_count)
+ // pad_count number of cells beyond box
+ // Outputs:
+ // GV side(0)*side(1)*side(2) by 3 list of cell center positions
+ // side 3-long list of dimension of voxel grid
+ template <
+ typename Scalar,
+ typename DerivedGV,
+ typename Derivedside>
+ IGL_INLINE void voxel_grid(
+ const Eigen::AlignedBox<Scalar,3> & box,
+ const int s,
+ const int pad_count,
+ Eigen::PlainObjectBase<DerivedGV> & GV,
+ Eigen::PlainObjectBase<Derivedside> & side);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "voxel_grid.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/winding_number.cpp b/xs/src/igl/winding_number.cpp
new file mode 100644
index 000000000..d6af18d98
--- /dev/null
+++ b/xs/src/igl/winding_number.cpp
@@ -0,0 +1,117 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "winding_number.h"
+#include "WindingNumberAABB.h"
+#include "signed_angle.h"
+#include "parallel_for.h"
+#include "solid_angle.h"
+#include "PI.h"
+
+#include <cmath>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedO,
+ typename DerivedW>
+IGL_INLINE void igl::winding_number(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedO> & O,
+ Eigen::PlainObjectBase<DerivedW> & W)
+{
+ using namespace Eigen;
+ // make room for output
+ W.resize(O.rows(),1);
+ switch(F.cols())
+ {
+ case 2:
+ {
+ igl::parallel_for(O.rows(),[&](const int o)
+ {
+ W(o) = winding_number(V,F,O.row(o));
+ },10000);
+ return;
+ }
+ case 3:
+ {
+ WindingNumberAABB<
+ Eigen::Matrix<typename DerivedV::Scalar,1,3>,
+ DerivedV,
+ DerivedF>
+ hier(V,F);
+ hier.grow();
+ // loop over origins
+ igl::parallel_for(O.rows(),[&](const int o)
+ {
+ W(o) = hier.winding_number(O.row(o));
+ },10000);
+ break;
+ }
+ default: assert(false && "Bad simplex size"); break;
+ }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedp>
+IGL_INLINE typename DerivedV::Scalar igl::winding_number(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedp> & p)
+{
+ typedef typename DerivedV::Scalar wType;
+ const int ss = F.cols();
+ const int m = F.rows();
+ wType w = 0;
+ for(int f = 0;f<m;f++)
+ {
+ switch(ss)
+ {
+ case 2:
+ {
+ w += igl::signed_angle( V.row(F(f,0)),V.row(F(f,1)),p);
+ break;
+ }
+ case 3:
+ {
+ w += igl::solid_angle(V.row(F(f,0)), V.row(F(f,1)), V.row(F(f,2)),p);
+ break;
+ }
+ default: assert(false); break;
+ }
+ }
+ return w;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template Eigen::Matrix<double, -1, 3, 1, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<double, -1, 3, 1, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
+// generated by autoexplicit.sh
+template void igl::winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<float, -1, -1, 0, -1, -1>::Scalar igl::winding_number<Eigen::Matrix<float, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<float, -1, 3, 1, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<float, -1, 3, 1, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<float, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<float, -1, 3, 0, -1, 3>::Scalar igl::winding_number<Eigen::Matrix<float, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3>, Eigen::Matrix<float, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<float, 1, 2, 1, 1, 2> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar igl::winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 3, 1, 0, 3, 1> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 3, 1, 0, 3, 1> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar igl::winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 3, 1, 1, 3> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&);
+// generated by autoexplicit.sh
+template Eigen::Matrix<double, -1, -1, 0, -1, -1>::Scalar igl::winding_number<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, 1, 2, 1, 1, 2> >(Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 1, 2, 1, 1, 2> > const&);
+#endif
diff --git a/xs/src/igl/winding_number.h b/xs/src/igl/winding_number.h
new file mode 100644
index 000000000..4a1c51d81
--- /dev/null
+++ b/xs/src/igl/winding_number.h
@@ -0,0 +1,64 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WINDING_NUMBER_H
+#define IGL_WINDING_NUMBER_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+
+// Minimum number of iterms per openmp thread
+#ifndef IGL_WINDING_NUMBER_OMP_MIN_VALUE
+# define IGL_WINDING_NUMBER_OMP_MIN_VALUE 1000
+#endif
+namespace igl
+{
+ // WINDING_NUMBER Compute the sum of solid angles of a triangle/tetrahedron
+ // described by points (vectors) V
+ //
+ // Templates:
+ // dim dimension of input
+ // Inputs:
+ // V n by 3 list of vertex positions
+ // F #F by 3 list of triangle indices, minimum index is 0
+ // O no by 3 list of origin positions
+ // Outputs:
+ // S no by 1 list of winding numbers
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedO,
+ typename DerivedW>
+ IGL_INLINE void winding_number(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedO> & O,
+ Eigen::PlainObjectBase<DerivedW> & W);
+ // Compute winding number of a single point
+ //
+ // Inputs:
+ // V n by dim list of vertex positions
+ // F #F by dim list of triangle indices, minimum index is 0
+ // p single origin position
+ // Outputs:
+ // w winding number of this point
+ //
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename Derivedp>
+ IGL_INLINE typename DerivedV::Scalar winding_number(
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<Derivedp> & p);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "winding_number.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/writeBF.cpp b/xs/src/igl/writeBF.cpp
new file mode 100644
index 000000000..18dc6a934
--- /dev/null
+++ b/xs/src/igl/writeBF.cpp
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeBF.h"
+#include <fstream>
+#include <cassert>
+template <
+ typename DerivedWI,
+ typename DerivedP,
+ typename DerivedO>
+IGL_INLINE bool igl::writeBF(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedWI> & WI,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedO> & O)
+{
+ using namespace Eigen;
+ using namespace std;
+ const int n = WI.rows();
+ assert(n == WI.rows() && "WI must have n rows");
+ assert(n == P.rows() && "P must have n rows");
+ assert(n == O.rows() && "O must have n rows");
+ MatrixXd WIPO(n,1+1+3);
+ for(int i = 0;i<n;i++)
+ {
+ WIPO(i,0) = WI(i);
+ WIPO(i,1) = P(i);
+ WIPO(i,2+0) = O(i,0);
+ WIPO(i,2+1) = O(i,1);
+ WIPO(i,2+2) = O(i,2);
+ }
+ ofstream s(filename);
+ if(!s.is_open())
+ {
+ fprintf(stderr,"IOError: writeBF() could not open %s\n",filename.c_str());
+ return false;
+ }
+ s<<
+ WIPO.format(IOFormat(FullPrecision,DontAlignCols," ","\n","","","","\n"));
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+template bool igl::writeBF<Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/writeBF.h b/xs/src/igl/writeBF.h
new file mode 100644
index 000000000..5ea51f1bc
--- /dev/null
+++ b/xs/src/igl/writeBF.h
@@ -0,0 +1,37 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITEBF_H
+#define IGL_WRITEBF_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+namespace igl
+{
+ // Write a bones forest to a file
+ //
+ // Input:
+ // file_name path to .bf bones tree file
+ // WI #B list of unique weight indices
+ // P #B list of parent indices into B, -1 for roots
+ // O #B list of tip offsets
+ // Returns true on success, false on errors
+ template <
+ typename DerivedWI,
+ typename DerivedP,
+ typename DerivedO>
+ IGL_INLINE bool writeBF(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedWI> & WI,
+ const Eigen::PlainObjectBase<DerivedP> & P,
+ const Eigen::PlainObjectBase<DerivedO> & O);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writeBF.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/writeDMAT.cpp b/xs/src/igl/writeDMAT.cpp
new file mode 100644
index 000000000..c8f6ae0f6
--- /dev/null
+++ b/xs/src/igl/writeDMAT.cpp
@@ -0,0 +1,92 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeDMAT.h"
+#include "list_to_matrix.h"
+#include <Eigen/Core>
+
+#include <cstdio>
+
+template <typename DerivedW>
+IGL_INLINE bool igl::writeDMAT(
+ const std::string file_name,
+ const Eigen::MatrixBase<DerivedW> & W,
+ const bool ascii)
+{
+ FILE * fp = fopen(file_name.c_str(),"wb");
+ if(fp == NULL)
+ {
+ fprintf(stderr,"IOError: writeDMAT() could not open %s...",file_name.c_str());
+ return false;
+ }
+ if(ascii)
+ {
+ // first line contains number of rows and number of columns
+ fprintf(fp,"%d %d\n",(int)W.cols(),(int)W.rows());
+ // Loop over columns slowly
+ for(int j = 0;j < W.cols();j++)
+ {
+ // loop over rows (down columns) quickly
+ for(int i = 0;i < W.rows();i++)
+ {
+ fprintf(fp,"%0.17lg\n",(double)W(i,j));
+ }
+ }
+ }else
+ {
+ // write header for ascii
+ fprintf(fp,"0 0\n");
+ // first line contains number of rows and number of columns
+ fprintf(fp,"%d %d\n",(int)W.cols(),(int)W.rows());
+ // reader assumes the binary part is double precision
+ Eigen::MatrixXd Wd = W.template cast<double>();
+ fwrite(Wd.data(),sizeof(double),Wd.size(),fp);
+ //// Loop over columns slowly
+ //for(int j = 0;j < W.cols();j++)
+ //{
+ // // loop over rows (down columns) quickly
+ // for(int i = 0;i < W.rows();i++)
+ // {
+ // double d = (double)W(i,j);
+ // fwrite(&d,sizeof(double),1,fp);
+ // }
+ //}
+ }
+ fclose(fp);
+ return true;
+}
+
+template <typename Scalar>
+IGL_INLINE bool igl::writeDMAT(
+ const std::string file_name,
+ const std::vector<std::vector<Scalar> > & W,
+ const bool ascii)
+{
+ Eigen::Matrix<Scalar,Eigen::Dynamic,Eigen::Dynamic> mW;
+ list_to_matrix(W,mW);
+ return igl::writeDMAT(file_name,mW,ascii);
+}
+
+template <typename Scalar>
+IGL_INLINE bool igl::writeDMAT(
+ const std::string file_name,
+ const std::vector<Scalar > & W,
+ const bool ascii)
+{
+ Eigen::Matrix<Scalar,Eigen::Dynamic,1> mW;
+ list_to_matrix(W,mW);
+ return igl::writeDMAT(file_name,mW,ascii);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template bool igl::writeDMAT<Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<double, 1, 3, 1, 1, 3> >(std::string, Eigen::MatrixBase<Eigen::Matrix<double, 1, 3, 1, 1, 3> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<float, 1, 3, 1, 1, 3> >(std::string, Eigen::MatrixBase<Eigen::Matrix<float, 1, 3, 1, 1, 3> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool);
+template bool igl::writeDMAT<Eigen::Matrix<int, -1, 2, 0, -1, 2> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<int, -1, 2, 0, -1, 2> > const&, bool);
+#endif
diff --git a/xs/src/igl/writeDMAT.h b/xs/src/igl/writeDMAT.h
new file mode 100644
index 000000000..08409ef67
--- /dev/null
+++ b/xs/src/igl/writeDMAT.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITEDMAT_H
+#define IGL_WRITEDMAT_H
+#include "igl_inline.h"
+// See writeDMAT.h for a description of the .dmat file type
+#include <Eigen/Core>
+#include <string>
+#include <vector>
+namespace igl
+{
+ // Write a matrix using ascii dmat file type
+ //
+ // Template:
+ // Mat matrix type that supports .rows(), .cols(), operator(i,j)
+ // Inputs:
+ // file_name path to .dmat file
+ // W eigen matrix containing to-be-written coefficients
+ // ascii write ascii file {true}
+ // Returns true on success, false on error
+ //
+ template <typename DerivedW>
+ IGL_INLINE bool writeDMAT(
+ const std::string file_name,
+ const Eigen::MatrixBase<DerivedW> & W,
+ const bool ascii=true);
+ template <typename Scalar>
+ IGL_INLINE bool writeDMAT(
+ const std::string file_name,
+ const std::vector<std::vector<Scalar> > & W,
+ const bool ascii=true);
+ template <typename Scalar>
+ IGL_INLINE bool writeDMAT(
+ const std::string file_name,
+ const std::vector<Scalar > &W,
+ const bool ascii=true);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writeDMAT.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/writeMESH.cpp b/xs/src/igl/writeMESH.cpp
new file mode 100644
index 000000000..27b0123cb
--- /dev/null
+++ b/xs/src/igl/writeMESH.cpp
@@ -0,0 +1,152 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeMESH.h"
+
+#include "verbose.h"
+#include "list_to_matrix.h"
+#include <Eigen/Core>
+
+#include <iostream>
+#include <fstream>
+#include <cstdio>
+
+template <typename Scalar, typename Index>
+IGL_INLINE bool igl::writeMESH(
+ const std::string mesh_file_name,
+ const std::vector<std::vector<Scalar > > & V,
+ const std::vector<std::vector<Index > > & T,
+ const std::vector<std::vector<Index > > & F)
+{
+ Eigen::MatrixXd mV;
+ Eigen::MatrixXi mT,mF;
+ bool is_rect;
+ is_rect = list_to_matrix(V,mV);
+ if(!is_rect)
+ {
+ return false;
+ }
+ is_rect = list_to_matrix(T,mT);
+ if(!is_rect)
+ {
+ return false;
+ }
+ is_rect = list_to_matrix(F,mF);
+ if(!is_rect)
+ {
+ return false;
+ }
+ return igl::writeMESH(mesh_file_name,mV,mT,mF);
+}
+
+
+template <typename DerivedV, typename DerivedT, typename DerivedF>
+IGL_INLINE bool igl::writeMESH(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const Eigen::PlainObjectBase<DerivedF> & F)
+{
+ using namespace std;
+ using namespace Eigen;
+
+ //// This is (surprisingly) slower than the C-ish code below
+ //ofstream mesh_file;
+ //mesh_file.open(str.c_str());
+ //if(!mesh_file.is_open())
+ //{
+ // cerr<<"IOError: "<<str<<" could not be opened..."<<endl;
+ // return false;
+ //}
+ //IOFormat format(FullPrecision,DontAlignCols," ","\n",""," 1","","");
+ //mesh_file<<"MeshVersionFormatted 1\n";
+ //mesh_file<<"Dimension 3\n";
+ //mesh_file<<"Vertices\n";
+ //mesh_file<<V.rows()<<"\n";
+ //mesh_file<<V.format(format)<<"\n";
+ //mesh_file<<"Triangles\n";
+ //mesh_file<<F.rows()<<"\n";
+ //mesh_file<<(F.array()+1).eval().format(format)<<"\n";
+ //mesh_file<<"Tetrahedra\n";
+ //mesh_file<<T.rows()<<"\n";
+ //mesh_file<<(T.array()+1).eval().format(format)<<"\n";
+ //mesh_file.close();
+
+ FILE * mesh_file = fopen(str.c_str(),"w");
+ if(NULL==mesh_file)
+ {
+ fprintf(stderr,"IOError: %s could not be opened...",str.c_str());
+ return false;
+ }
+ // print header
+ fprintf(mesh_file,"MeshVersionFormatted 1\n");
+ fprintf(mesh_file,"Dimension 3\n");
+ // print tet vertices
+ fprintf(mesh_file,"Vertices\n");
+ // print number of tet vertices
+ int number_of_tet_vertices = V.rows();
+ fprintf(mesh_file,"%d\n",number_of_tet_vertices);
+ // loop over tet vertices
+ for(int i = 0;i<number_of_tet_vertices;i++)
+ {
+ // print position of ith tet vertex
+ fprintf(mesh_file,"%.17lg %.17lg %.17lg 1\n",
+ (double)V(i,0),
+ (double)V(i,1),
+ (double)V(i,2));
+ }
+ verbose("WARNING: save_mesh() assumes that vertices have"
+ " same indices in surface as volume...\n");
+ // print faces
+ fprintf(mesh_file,"Triangles\n");
+ // print number of triangles
+ int number_of_triangles = F.rows();
+ fprintf(mesh_file,"%d\n",number_of_triangles);
+ // loop over faces
+ for(int i = 0;i<number_of_triangles;i++)
+ {
+ // loop over vertices in face
+ fprintf(mesh_file,"%d %d %d 1\n",
+ (int)F(i,0)+1,
+ (int)F(i,1)+1,
+ (int)F(i,2)+1);
+ }
+ // print tetrahedra
+ fprintf(mesh_file,"Tetrahedra\n");
+ int number_of_tetrahedra = T.rows();
+ // print number of tetrahedra
+ fprintf(mesh_file,"%d\n",number_of_tetrahedra);
+ // loop over tetrahedra
+ for(int i = 0; i < number_of_tetrahedra;i++)
+ {
+ // mesh standard uses 1-based indexing
+ fprintf(mesh_file, "%d %d %d %d 1\n",
+ (int)T(i,0)+1,
+ (int)T(i,1)+1,
+ (int)T(i,2)+1,
+ (int)T(i,3)+1);
+ }
+ fclose(mesh_file);
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::writeMESH<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeMESH<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeMESH<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeMESH<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&);
+//template bool igl::writeMESH<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeMESH<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+
+template bool igl::writeMESH<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeMESH<double, int>(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::vector<std::vector<double, std::allocator<double> >, std::allocator<std::vector<double, std::allocator<double> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&, std::vector<std::vector<int, std::allocator<int> >, std::allocator<std::vector<int, std::allocator<int> > > > const&);
+#endif
diff --git a/xs/src/igl/writeMESH.h b/xs/src/igl/writeMESH.h
new file mode 100644
index 000000000..4bb51418e
--- /dev/null
+++ b/xs/src/igl/writeMESH.h
@@ -0,0 +1,58 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITEMESH_H
+#define IGL_WRITEMESH_H
+#include "igl_inline.h"
+
+#include <string>
+#include <vector>
+#include <Eigen/Core>
+
+namespace igl
+{
+ // save a tetrahedral volume mesh to a .mesh file
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be cast as double)
+ // Index type for indices (will be cast to int)
+ // Input:
+ // mesh_file_name path of .mesh file
+ // V double matrix of vertex positions #V by 3
+ // T #T list of tet indices into vertex positions
+ // F #F list of face indices into vertex positions
+ //
+ // Known bugs: Holes and regions are not supported
+ template <typename Scalar, typename Index>
+ IGL_INLINE bool writeMESH(
+ const std::string mesh_file_name,
+ const std::vector<std::vector<Scalar > > & V,
+ const std::vector<std::vector<Index > > & T,
+ const std::vector<std::vector<Index > > & F);
+
+ // Templates:
+ // DerivedV real-value: i.e. from MatrixXd
+ // DerivedT integer-value: i.e. from MatrixXi
+ // DerivedF integer-value: i.e. from MatrixXi
+ // Input:
+ // mesh_file_name path of .mesh file
+ // V eigen double matrix #V by 3
+ // T eigen int matrix #T by 4
+ // F eigen int matrix #F by 3
+ template <typename DerivedV, typename DerivedT, typename DerivedF>
+ IGL_INLINE bool writeMESH(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedT> & T,
+ const Eigen::PlainObjectBase<DerivedF> & F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writeMESH.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/writeOBJ.cpp b/xs/src/igl/writeOBJ.cpp
new file mode 100644
index 000000000..286254174
--- /dev/null
+++ b/xs/src/igl/writeOBJ.cpp
@@ -0,0 +1,136 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeOBJ.h"
+
+#include <iostream>
+#include <limits>
+#include <iomanip>
+#include <fstream>
+#include <cstdio>
+#include <cassert>
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedCN,
+ typename DerivedFN,
+ typename DerivedTC,
+ typename DerivedFTC>
+IGL_INLINE bool igl::writeOBJ(
+ const std::string str,
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedCN>& CN,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ const Eigen::MatrixBase<DerivedTC>& TC,
+ const Eigen::MatrixBase<DerivedFTC>& FTC)
+{
+ FILE * obj_file = fopen(str.c_str(),"w");
+ if(NULL==obj_file)
+ {
+ printf("IOError: %s could not be opened for writing...",str.c_str());
+ return false;
+ }
+ // Loop over V
+ for(int i = 0;i<(int)V.rows();i++)
+ {
+ fprintf(obj_file,"v");
+ for(int j = 0;j<(int)V.cols();++j)
+ {
+ fprintf(obj_file," %0.17g", V(i,j));
+ }
+ fprintf(obj_file,"\n");
+ }
+ bool write_N = CN.rows() >0;
+
+ if(write_N)
+ {
+ for(int i = 0;i<(int)CN.rows();i++)
+ {
+ fprintf(obj_file,"vn %0.17g %0.17g %0.17g\n",
+ CN(i,0),
+ CN(i,1),
+ CN(i,2)
+ );
+ }
+ fprintf(obj_file,"\n");
+ }
+
+ bool write_texture_coords = TC.rows() >0;
+
+ if(write_texture_coords)
+ {
+ for(int i = 0;i<(int)TC.rows();i++)
+ {
+ fprintf(obj_file, "vt %0.17g %0.17g\n",TC(i,0),TC(i,1));
+ }
+ fprintf(obj_file,"\n");
+ }
+
+ // loop over F
+ for(int i = 0;i<(int)F.rows();++i)
+ {
+ fprintf(obj_file,"f");
+ for(int j = 0; j<(int)F.cols();++j)
+ {
+ // OBJ is 1-indexed
+ fprintf(obj_file," %u",F(i,j)+1);
+
+ if(write_texture_coords)
+ fprintf(obj_file,"/%u",FTC(i,j)+1);
+ if(write_N)
+ {
+ if (write_texture_coords)
+ fprintf(obj_file,"/%u",FN(i,j)+1);
+ else
+ fprintf(obj_file,"//%u",FN(i,j)+1);
+ }
+ }
+ fprintf(obj_file,"\n");
+ }
+ fclose(obj_file);
+ return true;
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::writeOBJ(
+ const std::string str,
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(V.cols() == 3 && "V should have 3 columns");
+ ofstream s(str);
+ if(!s.is_open())
+ {
+ fprintf(stderr,"IOError: writeOBJ() could not open %s\n",str.c_str());
+ return false;
+ }
+ s<<
+ V.format(IOFormat(FullPrecision,DontAlignCols," ","\n","v ","","","\n"))<<
+ (F.array()+1).format(IOFormat(FullPrecision,DontAlignCols," ","\n","f ","","","\n"));
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::writeOBJ<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeOBJ<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeOBJ<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeOBJ<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&);
+template bool igl::writeOBJ<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeOBJ<Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeOBJ<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 1, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 1, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeOBJ<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeOBJ<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/writeOBJ.h b/xs/src/igl/writeOBJ.h
new file mode 100644
index 000000000..d515796db
--- /dev/null
+++ b/xs/src/igl/writeOBJ.h
@@ -0,0 +1,59 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITEOBJ_H
+#define IGL_WRITEOBJ_H
+#include "igl_inline.h"
+// History:
+// return type changed from void to bool Alec 20 Sept 2011
+
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+ // Write a mesh in an ascii obj file
+ // Inputs:
+ // str path to outputfile
+ // V #V by 3 mesh vertex positions
+ // F #F by 3|4 mesh indices into V
+ // CN #CN by 3 normal vectors
+ // FN #F by 3|4 corner normal indices into CN
+ // TC #TC by 2|3 texture coordinates
+ // FTC #F by 3|4 corner texture coord indices into TC
+ // Returns true on success, false on error
+ //
+ // Known issues: Horrifyingly, this does not have the same order of
+ // parameters as readOBJ.
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedCN,
+ typename DerivedFN,
+ typename DerivedTC,
+ typename DerivedFTC>
+ IGL_INLINE bool writeOBJ(
+ const std::string str,
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F,
+ const Eigen::MatrixBase<DerivedCN>& CN,
+ const Eigen::MatrixBase<DerivedFN>& FN,
+ const Eigen::MatrixBase<DerivedTC>& TC,
+ const Eigen::MatrixBase<DerivedFTC>& FTC);
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool writeOBJ(
+ const std::string str,
+ const Eigen::MatrixBase<DerivedV>& V,
+ const Eigen::MatrixBase<DerivedF>& F);
+
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writeOBJ.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/writeOFF.cpp b/xs/src/igl/writeOFF.cpp
new file mode 100644
index 000000000..9222d76a0
--- /dev/null
+++ b/xs/src/igl/writeOFF.cpp
@@ -0,0 +1,94 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeOFF.h"
+#include <cstdio>
+#include <fstream>
+
+// write mesh to an ascii off file
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::writeOFF(
+ const std::string fname,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(V.cols() == 3 && "V should have 3 columns");
+ ofstream s(fname);
+ if(!s.is_open())
+ {
+ fprintf(stderr,"IOError: writeOFF() could not open %s\n",fname.c_str());
+ return false;
+ }
+
+ s<<
+ "OFF\n"<<V.rows()<<" "<<F.rows()<<" 0\n"<<
+ V.format(IOFormat(FullPrecision,DontAlignCols," ","\n","","","","\n"))<<
+ (F.array()).format(IOFormat(FullPrecision,DontAlignCols," ","\n","3 ","","","\n"));
+ return true;
+}
+
+// write mesh and colors-by-vertex to an ascii off file
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE bool igl::writeOFF(
+ const std::string fname,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedC>& C)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(V.cols() == 3 && "V should have 3 columns");
+ assert(C.cols() == 3 && "C should have 3 columns");
+
+ if(V.rows() != C.rows())
+ {
+ fprintf(stderr,"IOError: writeOFF() Only color per vertex supported. V and C should have same size.\n");
+ return false;
+ }
+
+ ofstream s(fname);
+ if(!s.is_open())
+ {
+ fprintf(stderr,"IOError: writeOFF() could not open %s\n",fname.c_str());
+ return false;
+ }
+
+ //Check if RGB values are in the range [0..1] or [0..255]
+ int rgbScale = (C.maxCoeff() <= 1.0)?255:1;
+ // Use RGB_Array instead of RGB because of clash with mingw macro
+ // (https://github.com/libigl/libigl/pull/679)
+ Eigen::MatrixXd RGB_Array = rgbScale * C;
+
+ s<< "COFF\n"<<V.rows()<<" "<<F.rows()<<" 0\n";
+ for (unsigned i=0; i< V.rows(); i++)
+ {
+ s <<V.row(i).format(IOFormat(FullPrecision,DontAlignCols," "," ","","",""," "));
+ s << unsigned(RGB_Array(i,0)) << " " << unsigned(RGB_Array(i,1)) << " " << unsigned(RGB_Array(i,2)) << " 255\n";
+ }
+
+ s<<(F.array()).format(IOFormat(FullPrecision,DontAlignCols," ","\n","3 ","","","\n"));
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::writeOFF<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeOFF<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeOFF<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeOFF<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&);
+template bool igl::writeOFF<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, -1, 1, -1, -1> > const&);
+template bool igl::writeOFF<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+template bool igl::writeOFF<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+template bool igl::writeOFF<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+template bool igl::writeOFF<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&);
+template bool igl::writeOFF<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3>, Eigen::Matrix<double, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<unsigned int, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&);
+#endif
diff --git a/xs/src/igl/writeOFF.h b/xs/src/igl/writeOFF.h
new file mode 100644
index 000000000..754c18a53
--- /dev/null
+++ b/xs/src/igl/writeOFF.h
@@ -0,0 +1,50 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITEOFF_H
+#define IGL_WRITEOFF_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+ //Export geometry and colors-by-vertex
+ // Export a mesh from an ascii OFF file, filling in vertex positions.
+ // Only triangle meshes are supported
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Inputs:
+ // str path to .off output file
+ // V #V by 3 mesh vertex positions
+ // F #F by 3 mesh indices into V
+ // C double matrix of rgb values per vertex #V by 3
+ // Outputs:
+ // Returns true on success, false on errors
+ template <typename DerivedV, typename DerivedF, typename DerivedC>
+ IGL_INLINE bool writeOFF(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const Eigen::PlainObjectBase<DerivedC>& C);
+
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool writeOFF(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writeOFF.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/writePLY.cpp b/xs/src/igl/writePLY.cpp
new file mode 100644
index 000000000..55c9b83fd
--- /dev/null
+++ b/xs/src/igl/writePLY.cpp
@@ -0,0 +1,182 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writePLY.h"
+#include <vector>
+
+#include <igl/ply.h>
+#include <vector>
+
+namespace
+{
+ template <typename Scalar> int ply_type();
+ template <> int ply_type<char>(){ return PLY_CHAR; }
+ template <> int ply_type<short>(){ return PLY_SHORT; }
+ template <> int ply_type<int>(){ return PLY_INT; }
+ template <> int ply_type<unsigned char>(){ return PLY_UCHAR; }
+ template <> int ply_type<unsigned short>(){ return PLY_SHORT; }
+ template <> int ply_type<unsigned int>(){ return PLY_UINT; }
+ template <> int ply_type<float>(){ return PLY_FLOAT; }
+ template <> int ply_type<double>(){ return PLY_DOUBLE; }
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedUV>
+IGL_INLINE bool igl::writePLY(
+ const std::string & filename,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedN> & N,
+ const Eigen::MatrixBase<DerivedUV> & UV,
+ const bool ascii)
+{
+ // Largely based on obj2ply.c
+ typedef typename DerivedV::Scalar VScalar;
+ typedef typename DerivedN::Scalar NScalar;
+ typedef typename DerivedUV::Scalar UVScalar;
+ typedef typename DerivedF::Scalar FScalar;
+
+ typedef struct Vertex
+ {
+ VScalar x,y,z,w; /* position */
+ NScalar nx,ny,nz; /* surface normal */
+ UVScalar s,t; /* texture coordinates */
+ } Vertex;
+
+ typedef struct Face
+ {
+ unsigned char nverts; /* number of vertex indices in list */
+ FScalar *verts; /* vertex index list */
+ } Face;
+
+ igl::ply::PlyProperty vert_props[] =
+ { /* list of property information for a vertex */
+ {"x", ply_type<VScalar>(), ply_type<VScalar>(),offsetof(Vertex,x),0,0,0,0},
+ {"y", ply_type<VScalar>(), ply_type<VScalar>(),offsetof(Vertex,y),0,0,0,0},
+ {"z", ply_type<VScalar>(), ply_type<VScalar>(),offsetof(Vertex,z),0,0,0,0},
+ {"nx",ply_type<NScalar>(), ply_type<NScalar>(),offsetof(Vertex,nx),0,0,0,0},
+ {"ny",ply_type<NScalar>(), ply_type<NScalar>(),offsetof(Vertex,ny),0,0,0,0},
+ {"nz",ply_type<NScalar>(), ply_type<NScalar>(),offsetof(Vertex,nz),0,0,0,0},
+ {"s", ply_type<UVScalar>(),ply_type<UVScalar>(),offsetof(Vertex,s),0,0,0,0},
+ {"t", ply_type<UVScalar>(),ply_type<UVScalar>(),offsetof(Vertex,t),0,0,0,0},
+ };
+
+ igl::ply::PlyProperty face_props[] =
+ { /* list of property information for a face */
+ {"vertex_indices", ply_type<FScalar>(), ply_type<FScalar>(),
+ offsetof(Face,verts), 1, PLY_UCHAR, PLY_UCHAR, offsetof(Face,nverts)},
+ };
+ const bool has_normals = N.rows() > 0;
+ const bool has_texture_coords = UV.rows() > 0;
+ std::vector<Vertex> vlist(V.rows());
+ std::vector<Face> flist(F.rows());
+ for(size_t i = 0;i<(size_t)V.rows();i++)
+ {
+ vlist[i].x = V(i,0);
+ vlist[i].y = V(i,1);
+ vlist[i].z = V(i,2);
+ if(has_normals)
+ {
+ vlist[i].nx = N(i,0);
+ vlist[i].ny = N(i,1);
+ vlist[i].nz = N(i,2);
+ }
+ if(has_texture_coords)
+ {
+ vlist[i].s = UV(i,0);
+ vlist[i].t = UV(i,1);
+ }
+ }
+ for(size_t i = 0;i<(size_t)F.rows();i++)
+ {
+ flist[i].nverts = F.cols();
+ flist[i].verts = new FScalar[F.cols()];
+ for(size_t c = 0;c<(size_t)F.cols();c++)
+ {
+ flist[i].verts[c] = F(i,c);
+ }
+ }
+
+ const char * elem_names[] = {"vertex","face"};
+ FILE * fp = fopen(filename.c_str(),"w");
+ if(fp==NULL)
+ {
+ return false;
+ }
+ igl::ply::PlyFile * ply = igl::ply::ply_write(fp, 2,elem_names,
+ (ascii ? PLY_ASCII : PLY_BINARY_LE));
+ if(ply==NULL)
+ {
+ return false;
+ }
+
+ std::vector<igl::ply::PlyProperty> plist;
+ plist.push_back(vert_props[0]);
+ plist.push_back(vert_props[1]);
+ plist.push_back(vert_props[2]);
+ if (has_normals)
+ {
+ plist.push_back(vert_props[3]);
+ plist.push_back(vert_props[4]);
+ plist.push_back(vert_props[5]);
+ }
+ if (has_texture_coords)
+ {
+ plist.push_back(vert_props[6]);
+ plist.push_back(vert_props[7]);
+ }
+ ply_describe_element(ply, "vertex", V.rows(),plist.size(),
+ &plist[0]);
+
+ ply_describe_element(ply, "face", F.rows(),1,&face_props[0]);
+ ply_header_complete(ply);
+ int native_binary_type = igl::ply::get_native_binary_type2();
+ ply_put_element_setup(ply, "vertex");
+ for(const auto v : vlist)
+ {
+ ply_put_element(ply, (void *) &v, &native_binary_type);
+ }
+ ply_put_element_setup(ply, "face");
+ for(const auto f : flist)
+ {
+ ply_put_element(ply, (void *) &f, &native_binary_type);
+ }
+
+ ply_close(ply);
+ for(size_t i = 0;i<(size_t)F.rows();i++)
+ {
+ delete[] flist[i].verts;
+ }
+ return true;
+}
+
+template <
+ typename DerivedV,
+ typename DerivedF>
+IGL_INLINE bool igl::writePLY(
+ const std::string & filename,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const bool ascii)
+{
+ Eigen::Matrix<typename DerivedV::Scalar,Eigen::Dynamic,Eigen::Dynamic> N,UV;
+ return writePLY(filename,V,F,N,UV,ascii);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::writePLY<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
+// generated by autoexplicit.sh
+template bool igl::writePLY<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, bool);
+template bool igl::writePLY<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool);
+template bool igl::writePLY<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, bool);
+template bool igl::writePLY<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::MatrixBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::MatrixBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
+#endif
diff --git a/xs/src/igl/writePLY.h b/xs/src/igl/writePLY.h
new file mode 100644
index 000000000..8b99ea1d0
--- /dev/null
+++ b/xs/src/igl/writePLY.h
@@ -0,0 +1,49 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITEPLY_H
+#define IGL_WRITEPLY_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+ // Write a mesh to a .ply file.
+ //
+ // Inputs:
+ // filename path to .ply file
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // N #V by 3 list of vertex normals
+ // UV #V by 2 list of vertex texture coordinates
+ // Returns true iff success
+ template <
+ typename DerivedV,
+ typename DerivedF,
+ typename DerivedN,
+ typename DerivedUV>
+ IGL_INLINE bool writePLY(
+ const std::string & filename,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const Eigen::MatrixBase<DerivedN> & N,
+ const Eigen::MatrixBase<DerivedUV> & UV,
+ const bool ascii = true);
+ template <
+ typename DerivedV,
+ typename DerivedF>
+ IGL_INLINE bool writePLY(
+ const std::string & filename,
+ const Eigen::MatrixBase<DerivedV> & V,
+ const Eigen::MatrixBase<DerivedF> & F,
+ const bool ascii = true);
+}
+#ifndef IGL_STATIC_LIBRARY
+# include "writePLY.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/writeSTL.cpp b/xs/src/igl/writeSTL.cpp
new file mode 100644
index 000000000..d95f2a8d7
--- /dev/null
+++ b/xs/src/igl/writeSTL.cpp
@@ -0,0 +1,121 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeSTL.h"
+#include <iostream>
+
+template <typename DerivedV, typename DerivedF, typename DerivedN>
+IGL_INLINE bool igl::writeSTL(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const bool ascii)
+{
+ using namespace std;
+ assert(N.rows() == 0 || F.rows() == N.rows());
+ if(ascii)
+ {
+ FILE * stl_file = fopen(filename.c_str(),"w");
+ if(stl_file == NULL)
+ {
+ cerr<<"IOError: "<<filename<<" could not be opened for writing."<<endl;
+ return false;
+ }
+ fprintf(stl_file,"solid %s\n",filename.c_str());
+ for(int f = 0;f<F.rows();f++)
+ {
+ fprintf(stl_file,"facet normal ");
+ if(N.rows()>0)
+ {
+ fprintf(stl_file,"%e %e %e\n",
+ (float)N(f,0),
+ (float)N(f,1),
+ (float)N(f,2));
+ }else
+ {
+ fprintf(stl_file,"0 0 0\n");
+ }
+ fprintf(stl_file,"outer loop\n");
+ for(int c = 0;c<F.cols();c++)
+ {
+ fprintf(stl_file,"vertex %e %e %e\n",
+ (float)V(F(f,c),0),
+ (float)V(F(f,c),1),
+ (float)V(F(f,c),2));
+ }
+ fprintf(stl_file,"endloop\n");
+ fprintf(stl_file,"endfacet\n");
+ }
+ fprintf(stl_file,"endsolid %s\n",filename.c_str());
+ fclose(stl_file);
+ return true;
+ }else
+ {
+ FILE * stl_file = fopen(filename.c_str(),"wb");
+ if(stl_file == NULL)
+ {
+ cerr<<"IOError: "<<filename<<" could not be opened for writing."<<endl;
+ return false;
+ }
+ // Write unused 80-char header
+ for(char h = 0;h<80;h++)
+ {
+ fwrite(&h,sizeof(char),1,stl_file);
+ }
+ // Write number of triangles
+ unsigned int num_tri = F.rows();
+ fwrite(&num_tri,sizeof(unsigned int),1,stl_file);
+ assert(F.cols() == 3);
+ // Write each triangle
+ for(int f = 0;f<F.rows();f++)
+ {
+ vector<float> n(3,0);
+ if(N.rows() > 0)
+ {
+ n[0] = N(f,0);
+ n[1] = N(f,1);
+ n[2] = N(f,2);
+ }
+ fwrite(&n[0],sizeof(float),3,stl_file);
+ for(int c = 0;c<3;c++)
+ {
+ vector<float> v(3);
+ v[0] = V(F(f,c),0);
+ v[1] = V(F(f,c),1);
+ v[2] = V(F(f,c),2);
+ fwrite(&v[0],sizeof(float),3,stl_file);
+ }
+ unsigned short att_count = 0;
+ fwrite(&att_count,sizeof(unsigned short),1,stl_file);
+ }
+ fclose(stl_file);
+ return true;
+ }
+}
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::writeSTL(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const bool ascii)
+{
+ return writeSTL(filename,V,F, DerivedV(), ascii);
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::writeSTL<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
+// generated by autoexplicit.sh
+template bool igl::writeSTL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
+// generated by autoexplicit.sh
+template bool igl::writeSTL<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, bool);
+template bool igl::writeSTL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, bool);
+template bool igl::writeSTL<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, bool);
+#endif
diff --git a/xs/src/igl/writeSTL.h b/xs/src/igl/writeSTL.h
new file mode 100644
index 000000000..1ffd20281
--- /dev/null
+++ b/xs/src/igl/writeSTL.h
@@ -0,0 +1,52 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITESTL_H
+#define IGL_WRITESTL_H
+#include "igl_inline.h"
+
+#ifndef IGL_NO_EIGEN
+# include <Eigen/Core>
+#endif
+#include <string>
+#include <vector>
+
+namespace igl
+{
+ // Write a mesh to an stl file.
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Inputs:
+ // filename path to .obj file
+ // V double matrix of vertex positions #F*3 by 3
+ // F index matrix of triangle indices #F by 3
+ // N double matrix of vertex positions #F by 3
+ // asci write ascii file {true}
+ // Returns true on success, false on errors
+ //
+ template <typename DerivedV, typename DerivedF, typename DerivedN>
+ IGL_INLINE bool writeSTL(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedN> & N,
+ const bool ascii=true);
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool writeSTL(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const bool ascii=true);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writeSTL.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/writeTGF.cpp b/xs/src/igl/writeTGF.cpp
new file mode 100644
index 000000000..65c8fc6a4
--- /dev/null
+++ b/xs/src/igl/writeTGF.cpp
@@ -0,0 +1,73 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeTGF.h"
+#include <cstdio>
+
+IGL_INLINE bool igl::writeTGF(
+ const std::string tgf_filename,
+ const std::vector<std::vector<double> > & C,
+ const std::vector<std::vector<int> > & E)
+{
+ FILE * tgf_file = fopen(tgf_filename.c_str(),"w");
+ if(NULL==tgf_file)
+ {
+ printf("IOError: %s could not be opened\n",tgf_filename.c_str());
+ return false;
+ }
+ // Loop over vertices
+ for(int i = 0; i<(int)C.size();i++)
+ {
+ assert(C[i].size() == 3);
+ // print a line with vertex number then "description"
+ // Where "description" in our case is the 3d position in space
+ //
+ fprintf(tgf_file,
+ "%4d "
+ "%10.17g %10.17g %10.17g " // current location
+ // All others are not needed for this legacy support
+ "\n",
+ i+1,
+ C[i][0], C[i][1], C[i][2]);
+ }
+
+ // print a comment to separate vertices and edges
+ fprintf(tgf_file,"#\n");
+
+ // loop over edges
+ for(int i = 0;i<(int)E.size();i++)
+ {
+ assert(E[i].size()==2);
+ fprintf(tgf_file,"%4d %4d\n",
+ E[i][0]+1,
+ E[i][1]+1);
+ }
+
+ // print a comment to separate edges and faces
+ fprintf(tgf_file,"#\n");
+
+ fclose(tgf_file);
+
+ return true;
+}
+
+#ifndef IGL_NO_EIGEN
+#include "matrix_to_list.h"
+
+IGL_INLINE bool igl::writeTGF(
+ const std::string tgf_filename,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & E)
+{
+ using namespace std;
+ vector<vector<double> > vC;
+ vector<vector<int> > vE;
+ matrix_to_list(C,vC);
+ matrix_to_list(E,vE);
+ return writeTGF(tgf_filename,vC,vE);
+}
+#endif
diff --git a/xs/src/igl/writeTGF.h b/xs/src/igl/writeTGF.h
new file mode 100644
index 000000000..999584463
--- /dev/null
+++ b/xs/src/igl/writeTGF.h
@@ -0,0 +1,48 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITETGF_H
+#define IGL_WRITETGF_H
+#include "igl_inline.h"
+
+#include <vector>
+#include <string>
+#ifndef IGL_NO_EIGEN
+#include <Eigen/Dense>
+#endif
+
+namespace igl
+{
+ // WRITETGF
+ //
+ // Write a graph to a .tgf file
+ //
+ // Input:
+ // filename .tgf file name
+ // V # vertices by 3 list of vertex positions
+ // E # edges by 2 list of edge indices
+ //
+ // Assumes that graph vertices are 3 dimensional
+ IGL_INLINE bool writeTGF(
+ const std::string tgf_filename,
+ const std::vector<std::vector<double> > & C,
+ const std::vector<std::vector<int> > & E);
+
+ #ifndef IGL_NO_EIGEN
+ IGL_INLINE bool writeTGF(
+ const std::string tgf_filename,
+ const Eigen::MatrixXd & C,
+ const Eigen::MatrixXi & E);
+ #endif
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "writeTGF.cpp"
+#endif
+
+#endif
+
diff --git a/xs/src/igl/writeWRL.cpp b/xs/src/igl/writeWRL.cpp
new file mode 100644
index 000000000..2740d1c2f
--- /dev/null
+++ b/xs/src/igl/writeWRL.cpp
@@ -0,0 +1,126 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeWRL.h"
+#include <iostream>
+#include <fstream>
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::writeWRL(
+ const std::string & str,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(V.cols() == 3 && "V should have 3 columns");
+ assert(F.cols() == 3 && "F should have 3 columns");
+ ofstream s(str);
+ if(!s.is_open())
+ {
+ cerr<<"IOError: writeWRL() could not open "<<str<<endl;
+ return false;
+ }
+ // Append column of -1 to F
+ Matrix<typename DerivedF::Scalar,Dynamic,4> FF(F.rows(),4);
+ FF.leftCols(3) = F;
+ FF.col(3).setConstant(-1);
+
+ s<<R"(#VRML V2.0 utf8
+DEF default Transform {
+translation 0 0 0
+children [
+Shape {
+geometry DEF default-FACES IndexedFaceSet {
+ccw TRUE
+)"<<
+ V.format(
+ IOFormat(
+ FullPrecision,
+ DontAlignCols,
+ " ",",\n","","",
+ "coord DEF default-COORD Coordinate { point [ \n","]\n}\n"))<<
+ FF.format(
+ IOFormat(
+ FullPrecision,
+ DontAlignCols,
+ ",","\n","","",
+ "coordIndex [ \n"," ]\n"))<<
+ "}\n}\n]\n}\n";
+ return true;
+}
+
+// write mesh and colors-by-vertex to an ascii off file
+template <typename DerivedV, typename DerivedF, typename DerivedC>
+IGL_INLINE bool igl::writeWRL(
+ const std::string & str,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedC> & C)
+{
+ using namespace std;
+ using namespace Eigen;
+ assert(V.cols() == 3 && "V should have 3 columns");
+ assert(F.cols() == 3 && "F should have 3 columns");
+ ofstream s(str);
+ if(!s.is_open())
+ {
+ cerr<<"IOError: writeWRL() could not open "<<str<<endl;
+ return false;
+ }
+ // Append column of -1 to F
+ Matrix<typename DerivedF::Scalar,Dynamic,4> FF(F.rows(),4);
+ FF.leftCols(3) = F;
+ FF.col(3).setConstant(-1);
+
+
+ //Check if RGB values are in the range [0..1] or [0..255]
+ double rgbScale = (C.maxCoeff() <= 1.0)?1.0:1.0/255.0;
+ Eigen::MatrixXd RGB = rgbScale * C;
+
+ s<<R"(#VRML V2.0 utf8
+DEF default Transform {
+translation 0 0 0
+children [
+Shape {
+geometry DEF default-FACES IndexedFaceSet {
+ccw TRUE
+)"<<
+ V.format(
+ IOFormat(
+ FullPrecision,
+ DontAlignCols,
+ " ",",\n","","",
+ "coord DEF default-COORD Coordinate { point [ \n","]\n}\n"))<<
+ FF.format(
+ IOFormat(
+ FullPrecision,
+ DontAlignCols,
+ ",","\n","","",
+ "coordIndex [ \n"," ]\n"))<<
+ RGB.format(
+ IOFormat(
+ FullPrecision,
+ DontAlignCols,
+ ",","\n","","",
+ "colorPerVertex TRUE\ncolor Color { color [ \n"," ] }\n"))<<
+ "}\n}\n]\n}\n";
+ return true;
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::writeWRL<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeWRL<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeWRL<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&);
+// generated by autoexplicit.sh
+template bool igl::writeWRL<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&);
+template bool igl::writeWRL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&);
+template bool igl::writeWRL<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&);
+#endif
diff --git a/xs/src/igl/writeWRL.h b/xs/src/igl/writeWRL.h
new file mode 100644
index 000000000..5ff6a25ed
--- /dev/null
+++ b/xs/src/igl/writeWRL.h
@@ -0,0 +1,46 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2015 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITE_WRL_H
+#define IGL_WRITE_WRL_H
+#include "igl_inline.h"
+#include <Eigen/Core>
+#include <string>
+namespace igl
+{
+ // Write mesh to a .wrl file
+ //
+ // Inputs:
+ // str path to .wrl file
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // Returns true iff succes
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool writeWRL(
+ const std::string & str,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F);
+
+ // Write mesh to a .wrl file
+ //
+ // Inputs:
+ // str path to .wrl file
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of triangle indices
+ // C double matrix of rgb values per vertex #V by 3
+ // Returns true iff succes
+ template <typename DerivedV, typename DerivedF, typename DerivedC>
+ IGL_INLINE bool writeWRL(
+ const std::string & str,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F,
+ const Eigen::PlainObjectBase<DerivedC> & C);
+}
+#ifndef IGL_STATIC_LIBRARY
+#include "writeWRL.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/write_triangle_mesh.cpp b/xs/src/igl/write_triangle_mesh.cpp
new file mode 100644
index 000000000..3699009f5
--- /dev/null
+++ b/xs/src/igl/write_triangle_mesh.cpp
@@ -0,0 +1,70 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "write_triangle_mesh.h"
+#include "pathinfo.h"
+#include "writeMESH.h"
+#include "writeOBJ.h"
+#include "writeOFF.h"
+#include "writePLY.h"
+#include "writeSTL.h"
+#include "writeWRL.h"
+
+#include <iostream>
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::write_triangle_mesh(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const bool force_ascii)
+{
+ using namespace std;
+ // dirname, basename, extension and filename
+ string d,b,e,f;
+ pathinfo(str,d,b,e,f);
+ // Convert extension to lower case
+ std::transform(e.begin(), e.end(), e.begin(), ::tolower);
+ if(e == "mesh")
+ {
+ Eigen::MatrixXi _1;
+ return writeMESH(str,V,_1,F);
+ }else if(e == "obj")
+ {
+ return writeOBJ(str,V,F);
+ }else if(e == "off")
+ {
+ return writeOFF(str,V,F);
+ }else if(e == "ply")
+ {
+ return writePLY(str,V,F,force_ascii);
+ }else if(e == "stl")
+ {
+ return writeSTL(str,V,F,force_ascii);
+ }else if(e == "wrl")
+ {
+ return writeWRL(str,V,F);
+ }else
+ {
+ assert("Unsupported file format");
+ cerr<<"Unsupported file format: ."<<e<<endl;
+ return false;
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+// generated by autoexplicit.sh
+template bool igl::write_triangle_mesh<Eigen::Matrix<double, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
+// generated by autoexplicit.sh
+template bool igl::write_triangle_mesh<Eigen::Matrix<float, -1, 3, 1, -1, 3>, Eigen::Matrix<int, -1, 3, 1, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<float, -1, 3, 1, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 1, -1, 3> > const&, bool);
+// generated by autoexplicit.sh
+template bool igl::write_triangle_mesh<Eigen::Matrix<double, -1, 3, 0, -1, 3>, Eigen::Matrix<int, -1, 3, 0, -1, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 3, 0, -1, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 3, 0, -1, 3> > const&, bool);
+// generated by autoexplicit.sh
+template bool igl::write_triangle_mesh<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, -1, 0, -1, -1> > const&, const bool);
+template bool igl::write_triangle_mesh<Eigen::Matrix<double, 8, 3, 0, 8, 3>, Eigen::Matrix<int, 12, 3, 0, 12, 3> >(std::basic_string<char, std::char_traits<char>, std::allocator<char> >, Eigen::PlainObjectBase<Eigen::Matrix<double, 8, 3, 0, 8, 3> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, 12, 3, 0, 12, 3> > const&, bool);
+#endif
diff --git a/xs/src/igl/write_triangle_mesh.h b/xs/src/igl/write_triangle_mesh.h
new file mode 100644
index 000000000..6a7241628
--- /dev/null
+++ b/xs/src/igl/write_triangle_mesh.h
@@ -0,0 +1,42 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_WRITE_TRIANGLE_MESH_H
+#define IGL_WRITE_TRIANGLE_MESH_H
+#include "igl_inline.h"
+
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+ // write mesh to a file with automatic detection of file format. supported:
+ // obj, off, stl, wrl, ply, mesh).
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Inputs:
+ // str path to file
+ // V eigen double matrix #V by 3
+ // F eigen int matrix #F by 3
+ // force_ascii force ascii format even if binary is available
+ // Returns true iff success
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool write_triangle_mesh(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const bool force_ascii = true);
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "write_triangle_mesh.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/xml/ReAntTweakBarXMLSerialization.h b/xs/src/igl/xml/ReAntTweakBarXMLSerialization.h
new file mode 100644
index 000000000..c43af0c80
--- /dev/null
+++ b/xs/src/igl/xml/ReAntTweakBarXMLSerialization.h
@@ -0,0 +1,269 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_XML_REANTTWEAKBAR_XML_SERIALIZATION_H
+#define IGL_XML_REANTTWEAKBAR_XML_SERIALIZATION_H
+#include "../igl_inline.h"
+#include "serialize_xml.h"
+
+#undef IGL_HEADER_ONLY
+#include "../anttweakbar/ReAntTweakBar.h"
+
+// Forward declarations
+namespace igl
+{
+ namespace anttweakbar
+ {
+ class ReTwBar;
+ }
+};
+namespace tinyxml2
+{
+ class XMLDocument;
+};
+
+namespace igl
+{
+ namespace xml
+ {
+
+// namespace
+// {
+
+// IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char* file_name);
+// IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc);
+// IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char *file_name);
+// IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc);
+
+
+ IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char* file_name)
+ {
+ const char * name_chars = TwGetBarName(bar->bar);
+ std::string name = std::string(name_chars) + "_AntTweakBar";
+
+ const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
+ for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+ {
+ std::string val = bar->get_value_as_string(it->var,it->type);
+ //::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+ ::igl::serialize_xml(val,it->name,file_name,false,false);
+ }
+
+ char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
+ // Print all CB variables
+ const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
+ for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+ {
+ TwType type = it->type;
+ //TwSetVarCallback setCallback = it->setCallback;
+ TwGetVarCallback getCallback = it->getCallback;
+ void * clientData = it->clientData;
+ // I'm not sure how to do what I want to do. getCallback needs to be sure
+ // that it can write to var. So var needs to point to a valid and big
+ // enough chunk of memory
+ getCallback(var,clientData);
+
+ std::string val = bar->get_value_as_string(var,type);
+ //::igl::XMLSerializer::SaveObject(val,it->name,name,file_name,false);
+ ::igl::serialize_xml(val,it->name,file_name,false,false);
+ }
+
+ return true;
+ }
+
+ /*IGL_INLINE bool save_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+ {
+ std::vector<char**> buffer;
+
+ const char * name_chars = TwGetBarName(bar->bar);
+ std::string name = std::string(name_chars) + "_AntTweakBar";
+ ::igl::XMLSerializer* s = new ::igl::XMLSerializer(name);
+
+ const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
+ for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+ {
+ std::string val = bar->get_value_as_string(it->var,it->type);
+ char** cval = new char*; // create char* on heap
+ *cval = new char[val.size()+1];
+ buffer.push_back(cval);
+ strcpy(*cval,val.c_str());
+ s->Add(*cval,it->name);
+ }
+
+ char var[REANTTWEAKBAR_MAX_CB_VAR_SIZE];
+ // Print all CB variables
+ const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
+ for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+ {
+ TwType type = it->type;
+ //TwSetVarCallback setCallback = it->setCallback;
+ TwGetVarCallback getCallback = it->getCallback;
+ void * clientData = it->clientData;
+ // I'm not sure how to do what I want to do. getCallback needs to be sure
+ // that it can write to var. So var needs to point to a valid and big
+ // enough chunk of memory
+ getCallback(var,clientData);
+
+ std::string val = bar->get_value_as_string(var,type);
+ char** cval = new char*; // create char* on heap
+ *cval = new char[val.size()+1];
+ buffer.push_back(cval);
+ strcpy(*cval,val.c_str());
+ s->Add(*cval,it->name);
+ }
+
+ s->SaveToXMLDoc(name,doc);
+
+ // delete pointer buffers
+ for(unsigned int i=0;i<buffer.size();i++)
+ {
+ delete[] *buffer[i];
+ delete buffer[i];
+ }
+
+ delete s;
+
+ return true;
+ }*/
+
+ IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, const char *file_name)
+ {
+ char type_str[REANTTWEAKBAR_MAX_WORD];
+ char value_str[REANTTWEAKBAR_MAX_WORD];
+ TwType type;
+
+ const char * name_chars = TwGetBarName(bar->bar);
+ std::string name = std::string(name_chars) + "_AntTweakBar";
+
+ const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
+ for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+ {
+ char* val;
+ //::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+ ::igl::deserialize_xml(val,it->name,file_name);
+ sscanf(val,"%s %[^\n]",type_str,value_str);
+
+ if(!bar->type_from_string(type_str,type))
+ {
+ printf("ERROR: %s type not found... Skipping...\n",type_str);
+ continue;
+ }
+
+ bar->set_value_from_string(it->name.c_str(),type,value_str);
+ delete[] val;
+ }
+
+ const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
+ for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+ {
+ char* val;
+ //::igl::XMLSerializer::LoadObject(val,it->name,name,file_name);
+ ::igl::deserialize_xml(val,it->name,file_name);
+ sscanf(val,"%s %[^\n]",type_str,value_str);
+
+ if(!bar->type_from_string(type_str,type))
+ {
+ printf("ERROR: %s type not found... Skipping...\n",type_str);
+ continue;
+ }
+
+ bar->set_value_from_string(it->name.c_str(),type,value_str);
+ delete[] val;
+ }
+
+ return true;
+ }
+
+ /*IGL_INLINE bool load_ReAntTweakBar(::igl::anttweakbar::ReTwBar* bar, tinyxml2::XMLDocument* doc)
+ {
+ std::map<std::string,char*> variables;
+ std::map<std::string,char*> cbVariables;
+
+ const char * name_chars = TwGetBarName(bar->bar);
+ std::string name = std::string(name_chars) + "_AntTweakBar";
+ ::igl::XMLSerializer* s = new ::igl::XMLSerializer(name);
+
+ std::map<std::string,char*>::iterator iter;
+ const std::vector< ::igl::anttweakbar::ReTwRWItem>& rw_items = bar->get_rw_items();
+ for(std::vector< ::igl::anttweakbar::ReTwRWItem>::const_iterator it = rw_items.begin(); it != rw_items.end(); it++)
+ {
+ variables[it->name] = NULL;
+ iter = variables.find(it->name);
+ s->Add(iter->second,iter->first);
+ }
+
+ // Add all CB variables
+ const std::vector< ::igl::anttweakbar::ReTwCBItem>& cb_items = bar->get_cb_items();
+ for(std::vector< ::igl::anttweakbar::ReTwCBItem>::const_iterator it = cb_items.begin(); it != cb_items.end(); it++)
+ {
+ cbVariables[it->name] = NULL;
+ iter = cbVariables.find(it->name);
+ s->Add(iter->second,iter->first);
+ }
+
+ s->LoadFromXMLDoc(doc);
+
+ // Set loaded values
+ char type_str[REANTTWEAKBAR_MAX_WORD];
+ char value_str[REANTTWEAKBAR_MAX_WORD];
+ TwType type;
+
+ for(iter = variables.begin(); iter != variables.end(); iter++)
+ {
+ if(iter->second == NULL)
+ {
+ printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str());
+ continue;
+ }
+
+ sscanf(iter->second,"%s %[^\n]",type_str,value_str);
+
+ if(!bar->type_from_string(type_str,type))
+ {
+ printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str());
+ continue;
+ }
+
+ bar->set_value_from_string(iter->first.c_str(),type,value_str);
+ }
+
+ for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
+ {
+ if(iter->second == NULL)
+ {
+ printf("ERROR: '%s' entry not found... Skipping...\n",iter->first.c_str());
+ continue;
+ }
+
+ sscanf(iter->second,"%s %[^\n]",type_str,value_str);
+
+ if(!bar->type_from_string(type_str,type))
+ {
+ printf("ERROR: Type '%s' of '%s' not found... Skipping...\n",type_str,iter->first.c_str());
+ continue;
+ }
+
+ bar->set_value_from_string(iter->first.c_str(),type,value_str);
+ }
+
+ // delete buffers
+ for(iter = variables.begin(); iter != variables.end(); iter++)
+ delete[] iter->second;
+
+ for(iter = cbVariables.begin(); iter != cbVariables.end(); iter++)
+ delete[] iter->second;
+
+ delete s;
+
+ return true;
+ }*/
+
+// }
+ }
+}
+
+#endif
diff --git a/xs/src/igl/xml/XMLSerializable.h b/xs/src/igl/xml/XMLSerializable.h
new file mode 100644
index 000000000..610559643
--- /dev/null
+++ b/xs/src/igl/xml/XMLSerializable.h
@@ -0,0 +1,225 @@
+#ifndef IGL_XML_XMLSERIALIZABLE_H
+#define IGL_XML_XMLSERIALIZABLE_H
+
+#include "serialize_xml.h"
+#include "../igl_inline.h"
+#include "../serialize.h"
+
+#include <tinyxml2.h>
+
+
+// Interface for xml-serializable class see serialize_xml.h
+
+// Pretty sure all of these IGL_INLINE should be inline
+
+namespace igl
+{
+ namespace xml
+ {
+ // interface for user defined types
+ struct XMLSerializableBase : public SerializableBase
+ {
+ virtual void Serialize(std::vector<char>& buffer) const = 0;
+ virtual void Deserialize(const std::vector<char>& buffer) = 0;
+ virtual void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const = 0;
+ virtual void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) = 0;
+ };
+
+ // Convenient interface for user defined types
+ class XMLSerializable: public XMLSerializableBase
+ {
+ private:
+
+ template <typename T>
+ struct XMLSerializationObject: public XMLSerializableBase
+ {
+ bool Binary;
+ std::string Name;
+ T* Object;
+
+ void Serialize(std::vector<char>& buffer) const {
+ serialize(*Object,Name,buffer);
+ }
+
+ void Deserialize(const std::vector<char>& buffer) {
+ deserialize(*Object,Name,buffer);
+ }
+
+ void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const {
+ serialize_xml(*Object,Name,doc,element,Binary);
+ }
+
+ void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element) {
+ deserialize_xml(*Object,Name,doc,element);
+ }
+ };
+
+ mutable bool initialized;
+ mutable std::vector<XMLSerializableBase*> objects;
+
+ public:
+
+ // Override this function to add your member variables which should be serialized
+ IGL_INLINE virtual void InitSerialization() = 0;
+
+ // Following functions can be overridden to handle the specific events.
+ // Return false to prevent the de-/serialization of an object.
+ IGL_INLINE virtual bool PreSerialization() const;
+ IGL_INLINE virtual void PostSerialization() const;
+ IGL_INLINE virtual bool PreDeserialization();
+ IGL_INLINE virtual void PostDeserialization();
+
+ // Default implementation of XMLSerializableBase interface
+ IGL_INLINE void Serialize(std::vector<char>& buffer) const;
+ IGL_INLINE void Deserialize(const std::vector<char>& buffer);
+ IGL_INLINE void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const;
+ IGL_INLINE void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
+
+ // Default constructor, destructor, assignment and copy constructor
+ IGL_INLINE XMLSerializable();
+ IGL_INLINE XMLSerializable(const XMLSerializable& obj);
+ IGL_INLINE ~XMLSerializable();
+ IGL_INLINE XMLSerializable& operator=(const XMLSerializable& obj);
+
+ // Use this function to add your variables which should be serialized
+ template <typename T>
+ IGL_INLINE void Add(T& obj,std::string name,bool binary = false);
+ };
+
+ // IMPLEMENTATION
+
+ IGL_INLINE bool XMLSerializable::PreSerialization() const
+ {
+ return true;
+ }
+
+ IGL_INLINE void XMLSerializable::PostSerialization() const
+ {
+ }
+
+ IGL_INLINE bool XMLSerializable::PreDeserialization()
+ {
+ return true;
+ }
+
+ IGL_INLINE void XMLSerializable::PostDeserialization()
+ {
+ }
+
+ IGL_INLINE void XMLSerializable::Serialize(std::vector<char>& buffer) const
+ {
+ if(this->PreSerialization())
+ {
+ if(initialized == false)
+ {
+ objects.clear();
+ (const_cast<XMLSerializable*>(this))->InitSerialization();
+ initialized = true;
+ }
+
+ for(unsigned int i=0;i<objects.size();i++)
+ objects[i]->Serialize(buffer);
+
+ this->PostSerialization();
+ }
+ }
+
+ IGL_INLINE void XMLSerializable::Deserialize(const std::vector<char>& buffer)
+ {
+ if(this->PreDeserialization())
+ {
+ if(initialized == false)
+ {
+ objects.clear();
+ (const_cast<XMLSerializable*>(this))->InitSerialization();
+ initialized = true;
+ }
+
+ for(unsigned int i=0;i<objects.size();i++)
+ objects[i]->Deserialize(buffer);
+
+ this->PostDeserialization();
+ }
+ }
+
+ IGL_INLINE void XMLSerializable::Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const
+ {
+ if(this->PreSerialization())
+ {
+ if(initialized == false)
+ {
+ objects.clear();
+ (const_cast<XMLSerializable*>(this))->InitSerialization();
+ initialized = true;
+ }
+
+ for(unsigned int i=0;i<objects.size();i++)
+ objects[i]->Serialize(doc,element);
+
+ this->PostSerialization();
+ }
+ }
+
+ IGL_INLINE void XMLSerializable::Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+ {
+ if(this->PreDeserialization())
+ {
+ if(initialized == false)
+ {
+ objects.clear();
+ (const_cast<XMLSerializable*>(this))->InitSerialization();
+ initialized = true;
+ }
+
+ for(unsigned int i=0;i<objects.size();i++)
+ objects[i]->Deserialize(doc,element);
+
+ this->PostDeserialization();
+ }
+ }
+
+ IGL_INLINE XMLSerializable::XMLSerializable()
+ {
+ initialized = false;
+ }
+
+ IGL_INLINE XMLSerializable::XMLSerializable(const XMLSerializable& obj)
+ {
+ initialized = false;
+ objects.clear();
+ }
+
+ IGL_INLINE XMLSerializable::~XMLSerializable()
+ {
+ initialized = false;
+ objects.clear();
+ }
+
+
+ IGL_INLINE XMLSerializable& XMLSerializable::operator=(const XMLSerializable& obj)
+ {
+ if(this != &obj)
+ {
+ if(initialized)
+ {
+ initialized = false;
+ objects.clear();
+ }
+ }
+ return *this;
+ }
+
+ template <typename T>
+ IGL_INLINE void XMLSerializable::Add(T& obj,std::string name,bool binary)
+ {
+ XMLSerializationObject<T>* object = new XMLSerializationObject<T>();
+ object->Binary = binary;
+ object->Name = name;
+ object->Object = &obj;
+
+ objects.push_back(object);
+ }
+
+ }
+}
+#endif
diff --git a/xs/src/igl/xml/serialization_test.skip b/xs/src/igl/xml/serialization_test.skip
new file mode 100644
index 000000000..5888075c4
--- /dev/null
+++ b/xs/src/igl/xml/serialization_test.skip
@@ -0,0 +1,489 @@
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+//#ifndef IGL_SERIALIZATION_TEST_H
+//#define IGL_SERIALIZATION_TEST_H
+
+//#include <igl/Timer.h>
+#include "serialize_xml.h"
+#include "XMLSerializable.h"
+
+namespace igl
+{
+ namespace xml
+ {
+
+ struct Test1111
+ {
+ };
+
+ struct Test1 : public XMLSerializable
+ {
+ std::string ts;
+ std::vector<Test1*> tvt;
+ Test1* tt;
+
+ Test1()
+ {
+ tt = NULL;
+ }
+
+ void InitSerialization()
+ {
+ Add(ts,"ts",false);
+ Add(tvt,"tvt");
+ Add(tt,"tt");
+ }
+ };
+
+ struct Test2: public XMLSerializableBase
+ {
+ char tc;
+ int* ti;
+ std::vector<short> tvb;
+ float tf;
+
+ Test2()
+ {
+ tc = '1';
+ ti = NULL;
+ tf = 1.0004;
+ tvb.push_back(2);
+ tvb.push_back(3);
+ }
+
+ void Serialize(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element) const
+ {
+ serialize_xml(tc,"tc",doc,element);
+ serialize_xml(ti,"ti",doc,element);
+ serialize_xml(tvb,"tvb",doc,element);
+ }
+ void Deserialize(const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+ {
+ deserialize_xml(tc,"tc",doc,element);
+ deserialize_xml(ti,"ti",doc,element);
+ deserialize_xml(tvb,"tvb",doc,element);
+ }
+ void Serialize(std::vector<char>& buffer) const
+ {
+ serialize(tc,"tc",buffer);
+ serialize(ti,"ti",buffer);
+ serialize(tvb,"tvb",buffer);
+ serialize(tf,"tf",buffer);
+ }
+ void Deserialize(const std::vector<char>& buffer)
+ {
+ deserialize(tc,"tc",buffer);
+ deserialize(ti,"ti",buffer);
+ deserialize(tvb,"tvb",buffer);
+ deserialize(tf,"tf",buffer);
+ }
+ };
+
+ void serialization_test()
+ {
+ std::string file("test");
+
+ bool tbIn = true,tbOut;
+ char tcIn = 't',tcOut;
+ unsigned char tucIn = 'u',tucOut;
+ short tsIn = 6,tsOut;
+ int tiIn = -10,tiOut;
+ unsigned int tuiIn = 10,tuiOut;
+ float tfIn = 1.0005,tfOut;
+ double tdIn = 1.000000005,tdOut;
+
+ int* tinpIn = NULL,*tinpOut = NULL;
+ float* tfpIn = new float,*tfpOut = NULL;
+ *tfpIn = 1.11101;
+
+ std::string tstrIn("test12345"),tstrOut;
+
+ Test2 tObjIn,tObjOut;
+ int ti = 2;
+ tObjIn.ti = &ti;
+
+
+ Test1 test1,test2,test3;
+ test1.ts = "100";
+ test2.ts = "200";
+ test3.ts = "300";
+
+ Test1 testA, testC;
+ testA.tt = &test1;
+ testA.ts = "test123";
+ testA.tvt.push_back(&test2);
+ testA.tvt.push_back(&test3);
+
+ Test1 testB = testA;
+ testB.ts = "400";
+ testB.tvt.pop_back();
+
+ std::pair<int,bool> tPairIn(10,true);
+ std::pair<int,bool> tPairOut;
+
+ std::vector<int> tVector1In ={1,2,3,4,5};
+ std::vector<int> tVector1Out;
+
+ std::pair<int,bool> p1(10,1);
+ std::pair<int,bool> p2(1,0);
+ std::pair<int,bool> p3(10000,1);
+ std::vector<std::pair<int,bool> > tVector2In ={p1,p2,p3};
+ std::vector<std::pair<int,bool> > tVector2Out;
+
+ std::set<std::pair<int,bool> > tSetIn ={p1,p2,p3};
+ std::set<std::pair<int,bool> > tSetOut;
+
+ std::map<int,bool> tMapIn ={p1,p2,p3};
+ std::map<int,bool> tMapOut;
+
+ Eigen::Matrix<float,3,3> tDenseMatrixIn;
+ tDenseMatrixIn << Eigen::Matrix<float,3,3>::Random();
+ tDenseMatrixIn.coeffRef(0,0) = 1.00001;
+ Eigen::Matrix<float,3,3> tDenseMatrixOut;
+
+ Eigen::Matrix<float,3,3,Eigen::RowMajor> tDenseRowMatrixIn;
+ tDenseRowMatrixIn << Eigen::Matrix<float,3,3,Eigen::RowMajor>::Random();
+ Eigen::Matrix<float,3,3,Eigen::RowMajor> tDenseRowMatrixOut;
+
+ Eigen::SparseMatrix<double> tSparseMatrixIn;
+ tSparseMatrixIn.resize(3,3);
+ tSparseMatrixIn.insert(0,0) = 1.3;
+ tSparseMatrixIn.insert(1,1) = 10.2;
+ tSparseMatrixIn.insert(2,2) = 100.1;
+ tSparseMatrixIn.finalize();
+ Eigen::SparseMatrix<double> tSparseMatrixOut;
+
+ // binary serialization
+
+ serialize(tbIn,file);
+ deserialize(tbOut,file);
+ assert(tbIn == tbOut);
+
+ serialize(tcIn,file);
+ deserialize(tcOut,file);
+ assert(tcIn == tcOut);
+
+ serialize(tucIn,file);
+ deserialize(tucOut,file);
+ assert(tucIn == tucOut);
+
+ serialize(tsIn,file);
+ deserialize(tsOut,file);
+ assert(tsIn == tsOut);
+
+ serialize(tiIn,file);
+ deserialize(tiOut,file);
+ assert(tiIn == tiOut);
+
+ serialize(tuiIn,file);
+ deserialize(tuiOut,file);
+ assert(tuiIn == tuiOut);
+
+ serialize(tfIn,file);
+ deserialize(tfOut,file);
+ assert(tfIn == tfOut);
+
+ serialize(tdIn,file);
+ deserialize(tdOut,file);
+ assert(tdIn == tdOut);
+
+ serialize(tinpIn,file);
+ deserialize(tinpOut,file);
+ assert(tinpIn == tinpOut);
+
+ serialize(tfpIn,file);
+ deserialize(tfpOut,file);
+ assert(*tfpIn == *tfpOut);
+ tfpOut = NULL;
+
+ serialize(tstrIn,file);
+ deserialize(tstrOut,file);
+ assert(tstrIn == tstrOut);
+
+ // updating
+ serialize(tbIn,"tb",file,true);
+ serialize(tcIn,"tc",file);
+ serialize(tiIn,"ti",file);
+ tiIn++;
+ serialize(tiIn,"ti",file);
+ tiIn++;
+ serialize(tiIn,"ti",file);
+ deserialize(tbOut,"tb",file);
+ deserialize(tcOut,"tc",file);
+ deserialize(tiOut,"ti",file);
+ assert(tbIn == tbOut);
+ assert(tcIn == tcOut);
+ assert(tiIn == tiOut);
+
+ serialize(tsIn,"tsIn",file,true);
+ serialize(tVector1In,"tVector1In",file);
+ serialize(tVector2In,"tsIn",file);
+ deserialize(tVector2Out,"tsIn",file);
+ for(unsigned int i=0;i<tVector2In.size();i++)
+ {
+ assert(tVector2In[i].first == tVector2Out[i].first);
+ assert(tVector2In[i].second == tVector2Out[i].second);
+ }
+ tVector2Out.clear();
+
+ serialize(tObjIn,file);
+ deserialize(tObjOut,file);
+ assert(tObjIn.tc == tObjOut.tc);
+ assert(*tObjIn.ti == *tObjOut.ti);
+ for(unsigned int i=0;i<tObjIn.tvb.size();i++)
+ assert(tObjIn.tvb[i] == tObjOut.tvb[i]);
+ tObjOut.ti = NULL;
+
+ serialize(tPairIn,file);
+ deserialize(tPairOut,file);
+ assert(tPairIn.first == tPairOut.first);
+ assert(tPairIn.second == tPairOut.second);
+
+ serialize(tVector1In,file);
+ deserialize(tVector1Out,file);
+ for(unsigned int i=0;i<tVector1In.size();i++)
+ assert(tVector1In[i] == tVector1Out[i]);
+
+ serialize(tVector2In,file);
+ deserialize(tVector2Out,file);
+ for(unsigned int i=0;i<tVector2In.size();i++)
+ {
+ assert(tVector2In[i].first == tVector2Out[i].first);
+ assert(tVector2In[i].second == tVector2Out[i].second);
+ }
+
+ serialize(tSetIn,file);
+ deserialize(tSetOut,file);
+ assert(tSetIn.size() == tSetOut.size());
+
+ serialize(tMapIn,file);
+ deserialize(tMapOut,file);
+ assert(tMapIn.size() == tMapOut.size());
+
+ serialize(tDenseMatrixIn,file);
+ deserialize(tDenseMatrixOut,file);
+ assert((tDenseMatrixIn - tDenseMatrixOut).sum() == 0);
+
+ serialize(tDenseRowMatrixIn,file);
+ deserialize(tDenseRowMatrixOut,file);
+ assert((tDenseRowMatrixIn - tDenseRowMatrixOut).sum() == 0);
+
+ serialize(tSparseMatrixIn,file);
+ deserialize(tSparseMatrixOut,file);
+ assert((tSparseMatrixIn - tSparseMatrixOut).sum() == 0);
+
+ serialize(testB,file);
+ deserialize(testC,file);
+ assert(testB.ts == testC.ts);
+ assert(testB.tvt.size() == testC.tvt.size());
+ for(unsigned int i=0;i<testB.tvt.size();i++)
+ {
+ assert(testB.tvt[i]->ts == testC.tvt[i]->ts);
+ assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size());
+ assert(testB.tvt[i]->tt == testC.tvt[i]->tt);
+ }
+ assert(testB.tt->ts == testC.tt->ts);
+ assert(testB.tt->tvt.size() == testC.tt->tvt.size());
+ assert(testB.tt->tt == testC.tt->tt);
+ testC = Test1();
+
+ // big data test
+ /*std::vector<std::vector<float> > bigDataIn,bigDataOut;
+ for(unsigned int i=0;i<10000;i++)
+ {
+ std::vector<float> v;
+ for(unsigned int j=0;j<10000;j++)
+ {
+ v.push_back(j);
+ }
+ bigDataIn.push_back(v);
+ }
+
+ Timer timer;
+ timer.start();
+ serialize(bigDataIn,file);
+ timer.stop();
+ std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl;
+
+ timer.start();
+ deserialize(bigDataOut,file);
+ timer.stop();
+ std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl;
+ char c;
+ std::cin >> c; */
+
+ // xml serialization
+
+ serialize_xml(tbIn,file);
+ deserialize_xml(tbOut,file);
+ assert(tbIn == tbOut);
+
+ serialize_xml(tcIn,file);
+ deserialize_xml(tcOut,file);
+ assert(tcIn == tcOut);
+
+ serialize_xml(tucIn,file);
+ deserialize_xml(tucOut,file);
+ assert(tucIn == tucOut);
+
+ serialize_xml(tsIn,file);
+ deserialize_xml(tsOut,file);
+ assert(tsIn == tsOut);
+
+ serialize_xml(tiIn,file);
+ deserialize_xml(tiOut,file);
+ assert(tiIn == tiOut);
+
+ serialize_xml(tuiIn,file);
+ deserialize_xml(tuiOut,file);
+ assert(tuiIn == tuiOut);
+
+ serialize_xml(tfIn,file);
+ deserialize_xml(tfOut,file);
+ assert(tfIn == tfOut);
+
+ serialize_xml(tdIn,file);
+ deserialize_xml(tdOut,file);
+ assert(tdIn == tdOut);
+
+ serialize_xml(tinpIn,file);
+ deserialize_xml(tinpOut,file);
+ assert(tinpIn == tinpOut);
+
+ serialize_xml(tfpIn,file);
+ deserialize_xml(tfpOut,file);
+ assert(*tfpIn == *tfpOut);
+
+ serialize_xml(tstrIn,file);
+ deserialize_xml(tstrOut,file);
+ assert(tstrIn == tstrOut);
+
+ // updating
+ serialize_xml(tbIn,"tb",file,false,true);
+ serialize_xml(tcIn,"tc",file);
+ serialize_xml(tiIn,"ti",file);
+ tiIn++;
+ serialize_xml(tiIn,"ti",file);
+ tiIn++;
+ serialize_xml(tiIn,"ti",file);
+ deserialize_xml(tbOut,"tb",file);
+ deserialize_xml(tcOut,"tc",file);
+ deserialize_xml(tiOut,"ti",file);
+ assert(tbIn == tbOut);
+ assert(tcIn == tcOut);
+ assert(tiIn == tiOut);
+
+ serialize_xml(tsIn,"tsIn",file,false,true);
+ serialize_xml(tVector1In,"tVector1In",file);
+ serialize_xml(tVector2In,"tsIn",file);
+ deserialize_xml(tVector2Out,"tsIn",file);
+ for(unsigned int i=0;i<tVector2In.size();i++)
+ {
+ assert(tVector2In[i].first == tVector2Out[i].first);
+ assert(tVector2In[i].second == tVector2Out[i].second);
+ }
+ tVector2Out.clear();
+
+ // binarization
+ serialize_xml(tVector2In,"tVector2In",file,true);
+ deserialize_xml(tVector2Out,"tVector2In",file);
+ for(unsigned int i=0;i<tVector2In.size();i++)
+ {
+ assert(tVector2In[i].first == tVector2Out[i].first);
+ assert(tVector2In[i].second == tVector2Out[i].second);
+ }
+
+ serialize_xml(tObjIn,file);
+ deserialize_xml(tObjOut,file);
+ assert(tObjIn.tc == tObjOut.tc);
+ assert(*tObjIn.ti == *tObjOut.ti);
+ for(unsigned int i=0;i<tObjIn.tvb.size();i++)
+ assert(tObjIn.tvb[i] == tObjOut.tvb[i]);
+
+ serialize_xml(tPairIn,file);
+ deserialize_xml(tPairOut,file);
+ assert(tPairIn.first == tPairOut.first);
+ assert(tPairIn.second == tPairOut.second);
+
+ serialize_xml(tVector1In,file);
+ deserialize_xml(tVector1Out,file);
+ for(unsigned int i=0;i<tVector1In.size();i++)
+ assert(tVector1In[i] == tVector1Out[i]);
+
+ serialize_xml(tVector2In,file);
+ deserialize_xml(tVector2Out,file);
+ for(unsigned int i=0;i<tVector2In.size();i++)
+ {
+ assert(tVector2In[i].first == tVector2Out[i].first);
+ assert(tVector2In[i].second == tVector2Out[i].second);
+ }
+
+ serialize_xml(tSetIn,file);
+ deserialize_xml(tSetOut,file);
+ assert(tSetIn.size() == tSetOut.size());
+
+ serialize_xml(tMapIn,file);
+ deserialize_xml(tMapOut,file);
+ assert(tMapIn.size() == tMapOut.size());
+
+ serialize_xml(tDenseMatrixIn,file);
+ deserialize_xml(tDenseMatrixOut,file);
+ assert((tDenseMatrixIn - tDenseMatrixOut).sum() == 0);
+
+ serialize_xml(tDenseRowMatrixIn,file);
+ deserialize_xml(tDenseRowMatrixOut,file);
+ assert((tDenseRowMatrixIn - tDenseRowMatrixOut).sum() == 0);
+
+ serialize_xml(tSparseMatrixIn,file);
+ deserialize_xml(tSparseMatrixOut,file);
+ assert((tSparseMatrixIn - tSparseMatrixOut).sum() == 0);
+
+ serialize_xml(testB,file);
+ deserialize_xml(testC,file);
+ assert(testB.ts == testC.ts);
+ assert(testB.tvt.size() == testC.tvt.size());
+ for(unsigned int i=0;i<testB.tvt.size();i++)
+ {
+ assert(testB.tvt[i]->ts == testC.tvt[i]->ts);
+ assert(testB.tvt[i]->tvt.size() == testC.tvt[i]->tvt.size());
+ assert(testB.tvt[i]->tt == testC.tvt[i]->tt);
+ }
+ assert(testB.tt->ts == testC.tt->ts);
+ assert(testB.tt->tvt.size() == testC.tt->tvt.size());
+ assert(testB.tt->tt == testC.tt->tt);
+
+ // big data test
+ /*std::vector<std::vector<float> > bigDataIn,bigDataOut;
+ for(unsigned int i=0;i<10000;i++)
+ {
+ std::vector<float> v;
+ for(unsigned int j=0;j<10000;j++)
+ {
+ v.push_back(j);
+ }
+ bigDataIn.push_back(v);
+ }
+
+ Timer timer;
+ timer.start();
+ serialize_xml(bigDataIn,"bigDataIn",file,seRIALIZE_BINARY);
+ timer.stop();
+ std::cout << "ser: " << timer.getElapsedTimeInMilliSec() << std::endl;
+
+ timer.start();
+ deserialize_xml(bigDataOut,"bigDataIn",file);
+ timer.stop();
+ std::cout << "des: " << timer.getElapsedTimeInMilliSec() << std::endl;
+ char c;
+ std::cin >> c;*/
+
+ std::cout << "All tests run successfully!\n";
+ }
+ }
+}
+
+//#endif
diff --git a/xs/src/igl/xml/serialize_xml.cpp b/xs/src/igl/xml/serialize_xml.cpp
new file mode 100644
index 000000000..ee6ea11bc
--- /dev/null
+++ b/xs/src/igl/xml/serialize_xml.cpp
@@ -0,0 +1,912 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2014 Christian Schüller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+
+#include "serialize_xml.h"
+#include "../STR.h"
+#include "../serialize.h"
+#include "XMLSerializable.h"
+
+#include <iterator>
+#include <limits>
+#include <iomanip>
+
+namespace igl
+{
+ namespace xml
+ {
+ template <typename T>
+ IGL_INLINE void serialize_xml(
+ const T& obj,
+ const std::string& filename)
+ {
+ serialize_xml(obj,"object",filename,false,true);
+ }
+
+ template <typename T>
+ IGL_INLINE void serialize_xml(
+ const T& obj,
+ const std::string& objectName,
+ const std::string& filename,
+ bool binary,
+ bool overwrite)
+ {
+ tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+
+ if(overwrite == false)
+ {
+ // Check if file exists
+ tinyxml2::XMLError error = doc->LoadFile(filename.c_str());
+ if(error != tinyxml2::XML_SUCCESS)
+ {
+ doc->Clear();
+ }
+ }
+
+ tinyxml2::XMLElement* element = doc->FirstChildElement("serialization");
+ if(element == NULL)
+ {
+ element = doc->NewElement("serialization");
+ doc->InsertEndChild(element);
+ }
+
+ serialize_xml(obj,objectName,doc,element,binary);
+
+ // Save
+ tinyxml2::XMLError error = doc->SaveFile(filename.c_str());
+ if(error != tinyxml2::XML_SUCCESS)
+ {
+ doc->PrintError();
+ }
+
+ delete doc;
+ }
+
+ template <typename T>
+ IGL_INLINE void serialize_xml(
+ const T& obj,
+ const std::string& objectName,
+ tinyxml2::XMLDocument* doc,
+ tinyxml2::XMLElement* element,
+ bool binary)
+ {
+ static_assert(
+ serialization_xml::is_serializable<T>::value,
+ "'igl::xml::serialize_xml': type is not serializable");
+
+ std::string name(objectName);
+ serialization_xml::encodeXMLElementName(name);
+
+ tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+
+ if(child != NULL)
+ element->DeleteChild(child);
+
+ child = doc->NewElement(name.c_str());
+ element->InsertEndChild(child);
+
+ if(binary)
+ {
+ std::vector<char> buffer;
+ serialize(obj,name,buffer);
+ std::string data =
+ serialization_xml::base64_encode(
+ reinterpret_cast<const unsigned char*>(
+ buffer.data()),buffer.size());
+
+ child->SetAttribute("binary",true);
+
+ serialization_xml::serialize(data,doc,element,name);
+ }
+ else
+ {
+ serialization_xml::serialize(obj,doc,element,name);
+ }
+ }
+
+ template <typename T>
+ IGL_INLINE void deserialize_xml(T& obj,const std::string& filename)
+ {
+ deserialize_xml(obj,"object",filename);
+ }
+
+ template <typename T>
+ IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename)
+ {
+ tinyxml2::XMLDocument* doc = new tinyxml2::XMLDocument();
+
+ tinyxml2::XMLError error = doc->LoadFile(filename.c_str());
+ if(error != tinyxml2::XML_SUCCESS)
+ {
+ std::cerr << "File not found!" << std::endl;
+ doc->PrintError();
+ doc = NULL;
+ }
+ else
+ {
+ tinyxml2::XMLElement* element = doc->FirstChildElement("serialization");
+ if(element == NULL)
+ {
+ std::cerr << "Name of object not found! Initialized with default value." << std::endl;
+ obj = T();
+ }
+ else
+ {
+ deserialize_xml(obj,objectName,doc,element);
+ }
+
+ delete doc;
+ }
+ }
+
+ template <typename T>
+ IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element)
+ {
+ static_assert(serialization::is_serializable<T>::value,"'igl::xml::deserialize_xml': type is not deserializable");
+
+ std::string name(objectName);
+ serialization_xml::encodeXMLElementName(name);
+
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ bool isBinary = false;
+ const tinyxml2::XMLAttribute* attr = child->FindAttribute("binary");
+ if(attr != NULL)
+ {
+ std::string code;
+ serialization_xml::deserialize(code,doc,element,name);
+ std::string decoded = serialization_xml::base64_decode(code);
+
+ std::vector<char> buffer;
+ std::copy(decoded.c_str(),decoded.c_str()+decoded.length(),std::back_inserter(buffer));
+
+ deserialize(obj,name,buffer);
+ }
+ else
+ {
+ serialization_xml::deserialize(obj,doc,element,name);
+ }
+ }
+ }
+
+ namespace serialization_xml
+ {
+ // fundamental types
+
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* child = getElement(doc,element,name.c_str());
+ child->SetAttribute("val",obj);
+ }
+
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ getAttribute(child->Attribute("val"),obj);
+ }
+ else
+ {
+ obj = T();
+ }
+ }
+
+ // std::string
+
+ IGL_INLINE void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* child = getElement(doc,element,name.c_str());
+ child->SetAttribute("val",obj.c_str());
+ }
+
+ IGL_INLINE void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ getAttribute(child->Attribute("val"),obj);
+ }
+ else
+ {
+ obj = std::string("");
+ }
+ }
+
+ // Serializable
+
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ // Serialize object implementing Serializable interface
+ const XMLSerializableBase& object = dynamic_cast<const XMLSerializableBase&>(obj);
+
+ tinyxml2::XMLElement* child = getElement(doc,element,name.c_str());
+ object.Serialize(doc,child);
+ }
+
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+
+ if(child != NULL)
+ {
+ obj.Deserialize(doc,child);
+ }
+ else
+ {
+ obj = T();
+ }
+ }
+
+ // STL containers
+
+ template <typename T1,typename T2>
+ IGL_INLINE void serialize(const std::pair<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* pair = getElement(doc,element,name.c_str());
+ serialize(obj.first,doc,pair,"first");
+ serialize(obj.second,doc,pair,"second");
+ }
+
+ template <typename T1,typename T2>
+ IGL_INLINE void deserialize(std::pair<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ deserialize(obj.first,doc,child,"first");
+ deserialize(obj.second,doc,child,"second");
+ }
+ else
+ {
+ obj.first = T1();
+ obj.second = T2();
+ }
+ }
+
+ template <typename T1,typename T2>
+ IGL_INLINE void serialize(const std::vector<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* vector = getElement(doc,element,name.c_str());
+ vector->SetAttribute("size",(unsigned int)obj.size());
+
+ std::stringstream num;
+ for(unsigned int i=0;i<obj.size();i++)
+ {
+ num.str("");
+ num << "value" << i;
+ serialize(obj[i],doc,vector,num.str());
+ }
+ }
+
+ template <typename T1,typename T2>
+ IGL_INLINE void deserialize(std::vector<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ obj.clear();
+
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ unsigned int size = child->UnsignedAttribute("size");
+ obj.resize(size);
+
+ std::stringstream num;
+ for(unsigned int i=0;i<size;i++)
+ {
+ num.str("");
+ num << "value" << i;
+
+ deserialize(obj[i],doc,child,num.str());
+ }
+ }
+ else
+ {
+ obj.clear();
+ }
+ }
+
+ template <typename T>
+ IGL_INLINE void serialize(const std::set<T>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* set = getElement(doc,element,name.c_str());
+ set->SetAttribute("size",(unsigned int)obj.size());
+
+ std::stringstream num;
+ typename std::set<T>::iterator iter = obj.begin();
+ for(int i=0;iter!=obj.end();iter++,i++)
+ {
+ num.str("");
+ num << "value" << i;
+ serialize((T)*iter,doc,set,num.str());
+ }
+ }
+
+ template <typename T>
+ IGL_INLINE void deserialize(std::set<T>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ obj.clear();
+
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ unsigned int size = child->UnsignedAttribute("size");
+
+ std::stringstream num;
+ typename std::set<T>::iterator iter = obj.begin();
+ for(int i=0;i<size;i++)
+ {
+ num.str("");
+ num << "value" << i;
+
+ T val;
+ deserialize(val,doc,child,num.str());
+ obj.insert(val);
+ }
+ }
+ else
+ {
+ obj.clear();
+ }
+ }
+
+ template <typename T1,typename T2>
+ IGL_INLINE void serialize(const std::map<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* map = getElement(doc,element,name.c_str());
+ map->SetAttribute("size",(unsigned int)obj.size());
+
+ std::stringstream num;
+ typename std::map<T1,T2>::const_iterator iter = obj.cbegin();
+ for(int i=0;iter!=obj.end();iter++,i++)
+ {
+ num.str("");
+ num << "value" << i;
+ serialize((std::pair<T1,T2>)*iter,doc,map,num.str());
+ }
+ }
+
+ template <typename T1,typename T2>
+ IGL_INLINE void deserialize(std::map<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ obj.clear();
+
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ unsigned int size = child->UnsignedAttribute("size");
+
+ std::stringstream num;
+ typename std::map<T1,T2>::iterator iter = obj.begin();
+ for(int i=0;i<size;i++)
+ {
+ num.str("");
+ num << "value" << i;
+
+ std::pair<T1,T2> pair;
+ deserialize(pair,doc,child,num.str());
+ obj.insert(pair);
+ }
+ }
+ else
+ {
+ obj.clear();
+ }
+ }
+
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void serialize(
+ const Eigen::Matrix<T,R,C,P,MR,MC>& obj,
+ const std::string& name,
+ const std::function<std::string(const T &) >& to_string,
+ tinyxml2::XMLDocument* doc,
+ tinyxml2::XMLElement* element)
+ {
+ tinyxml2::XMLElement* matrix = getElement(doc,element,name.c_str());
+
+ const unsigned int rows = obj.rows();
+ const unsigned int cols = obj.cols();
+
+ matrix->SetAttribute("rows",rows);
+ matrix->SetAttribute("cols",cols);
+
+ std::stringstream ms;
+ ms << "\n";
+ for(unsigned int r=0;r<rows;r++)
+ {
+ for(unsigned int c=0;c<cols;c++)
+ {
+ ms << to_string(obj(r,c)) << ",";
+ }
+ ms << "\n";
+ }
+
+ std::string mString = ms.str();
+ if(mString.size() > 1)
+ mString[mString.size()-2] = '\0';
+
+ matrix->SetAttribute("matrix",mString.c_str());
+ }
+
+ // Eigen types
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void serialize(
+ const Eigen::Matrix<T,R,C,P,MR,MC>& obj,
+ tinyxml2::XMLDocument* doc,
+ tinyxml2::XMLElement* element,
+ const std::string& name)
+ {
+ const std::function<std::string(const T &) > to_string =
+ [](const T & v)->std::string
+ {
+ return
+ STR(std::setprecision(std::numeric_limits<double>::digits10+2)<<v);
+ };
+ serialize(obj,name,to_string,doc,element);
+ }
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void deserialize(
+ const tinyxml2::XMLDocument* doc,
+ const tinyxml2::XMLElement* element,
+ const std::string& name,
+ const std::function<void(const std::string &,T &)> & from_string,
+ Eigen::Matrix<T,R,C,P,MR,MC>& obj)
+ {
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ bool initialized = false;
+ if(child != NULL)
+ {
+ const unsigned int rows = child->UnsignedAttribute("rows");
+ const unsigned int cols = child->UnsignedAttribute("cols");
+
+ if(rows > 0 && cols > 0)
+ {
+ obj.resize(rows,cols);
+
+ const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix");
+ if(attribute != NULL)
+ {
+ std::string matTemp;
+ getAttribute(attribute->Value(),matTemp);
+
+ std::string line,srows,scols;
+ std::stringstream mats;
+ mats << matTemp;
+
+ int r=0;
+ std::string val;
+ // for each line
+ getline(mats,line);
+ while(getline(mats,line))
+ {
+ // get current line
+ std::stringstream liness(line);
+
+ for(unsigned int c=0;c<cols-1;c++)
+ {
+ // split line
+ getline(liness,val,',');
+
+ // push pack the data if any
+ if(!val.empty())
+ {
+ from_string(val,obj.coeffRef(r,c));
+ }
+ }
+
+ getline(liness,val);
+ from_string(val,obj.coeffRef(r,cols-1));
+
+ r++;
+ }
+ initialized = true;
+ }
+ }
+ }
+
+ if(!initialized)
+ {
+ obj = Eigen::Matrix<T,R,C,P,MR,MC>();
+ }
+ }
+
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void deserialize(
+ Eigen::Matrix<T,R,C,P,MR,MC>& obj,
+ const tinyxml2::XMLDocument* doc,
+ const tinyxml2::XMLElement* element,
+ const std::string& name)
+ {
+ const std::function<void(const std::string &,T &)> & from_string =
+ [](const std::string & s,T & v)
+ {
+ getAttribute(s.c_str(),v);
+ };
+ deserialize(doc,element,name,from_string,obj);
+ }
+
+ template<typename T,int P,typename I>
+ IGL_INLINE void serialize(const Eigen::SparseMatrix<T,P,I>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* matrix = getElement(doc,element,name.c_str());
+
+ const unsigned int rows = obj.rows();
+ const unsigned int cols = obj.cols();
+
+ matrix->SetAttribute("rows",rows);
+ matrix->SetAttribute("cols",cols);
+
+ char buffer[200];
+ std::stringstream ms;
+ ms << "\n";
+ for(int k=0;k<obj.outerSize();++k)
+ {
+ for(typename Eigen::SparseMatrix<T,P,I>::InnerIterator it(obj,k);it;++it)
+ {
+ tinyxml2::XMLUtil::ToStr(it.value(),buffer,200);
+ ms << it.row() << "," << it.col() << "," << buffer << "\n";
+ }
+ }
+
+ std::string mString = ms.str();
+ if(mString.size() > 0)
+ mString[mString.size()-1] = '\0';
+
+ matrix->SetAttribute("matrix",mString.c_str());
+ }
+
+ template<typename T,int P,typename I>
+ IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ bool initialized = false;
+ if(child != NULL)
+ {
+ const unsigned int rows = child->UnsignedAttribute("rows");
+ const unsigned int cols = child->UnsignedAttribute("cols");
+
+ if(rows > 0 && cols > 0)
+ {
+ obj.resize(rows,cols);
+ obj.setZero();
+
+ const tinyxml2::XMLAttribute* attribute = child->FindAttribute("matrix");
+ if(attribute != NULL)
+ {
+ std::string matTemp;
+ getAttribute(attribute->Value(),matTemp);
+
+ std::string line,srows,scols;
+ std::stringstream mats;
+ mats << matTemp;
+
+ std::vector<Eigen::Triplet<T,I> > triplets;
+ int r=0;
+ std::string val;
+
+ // for each line
+ getline(mats,line);
+ while(getline(mats,line))
+ {
+ // get current line
+ std::stringstream liness(line);
+
+ // row
+ getline(liness,val,',');
+ int row = atoi(val.c_str());
+ // col
+ getline(liness,val,',');
+ int col = atoi(val.c_str());
+ // val
+ getline(liness,val);
+ T value;
+ getAttribute(val.c_str(),value);
+
+ triplets.push_back(Eigen::Triplet<T,I>(row,col,value));
+
+ r++;
+ }
+
+ obj.setFromTriplets(triplets.begin(),triplets.end());
+ initialized = true;
+ }
+ }
+ }
+
+ if(!initialized)
+ {
+ obj = Eigen::SparseMatrix<T,P,I>();
+ }
+ }
+
+ // pointers
+
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* pointer = getElement(doc,element,name.c_str());
+
+ bool isNullPtr = (obj == NULL);
+
+ pointer->SetAttribute("isNullPtr",isNullPtr);
+
+ if(isNullPtr == false)
+ serialization_xml::serialize(*obj,doc,element,name);
+ }
+
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name)
+ {
+ const tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child != NULL)
+ {
+ bool isNullPtr = child->BoolAttribute("isNullPtr");
+
+ if(isNullPtr)
+ {
+ if(obj != NULL)
+ {
+ std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
+ obj = NULL;
+ }
+ }
+ else
+ {
+ if(obj != NULL)
+ std::cout << "deserialization: possible memory leak for '" << typeid(obj).name() << "'" << std::endl;
+
+ obj = new typename std::remove_pointer<T>::type();
+
+ serialization_xml::deserialize(*obj,doc,element,name);
+ }
+ }
+ }
+
+ // helper functions
+
+ IGL_INLINE tinyxml2::XMLElement* getElement(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name)
+ {
+ tinyxml2::XMLElement* child = element->FirstChildElement(name.c_str());
+ if(child == NULL)
+ {
+ child = doc->NewElement(name.c_str());
+ element->InsertEndChild(child);
+ }
+ return child;
+ }
+
+ IGL_INLINE void getAttribute(const char* src,bool& dest)
+ {
+ tinyxml2::XMLUtil::ToBool(src,&dest);
+ }
+
+ IGL_INLINE void getAttribute(const char* src,char& dest)
+ {
+ dest = (char)atoi(src);
+ }
+
+ IGL_INLINE void getAttribute(const char* src,std::string& dest)
+ {
+ dest = src;
+ }
+
+ IGL_INLINE void getAttribute(const char* src,float& dest)
+ {
+ tinyxml2::XMLUtil::ToFloat(src,&dest);
+ }
+
+ IGL_INLINE void getAttribute(const char* src,double& dest)
+ {
+ tinyxml2::XMLUtil::ToDouble(src,&dest);
+ }
+
+ template<typename T>
+ IGL_INLINE typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest)
+ {
+ unsigned int val;
+ tinyxml2::XMLUtil::ToUnsigned(src,&val);
+ dest = (T)val;
+ }
+
+ template<typename T>
+ IGL_INLINE typename std::enable_if<std::is_integral<T>::value && !std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest)
+ {
+ int val;
+ tinyxml2::XMLUtil::ToInt(src,&val);
+ dest = (T)val;
+ }
+
+ // tinyXML2 related stuff
+ static const int numForbiddenChars = 8;
+ static const char forbiddenChars[] ={' ','/','~','#','&','>','<','='};
+
+ IGL_INLINE void replaceSubString(std::string& str,const std::string& search,const std::string& replace)
+ {
+ size_t pos = 0;
+ while((pos = str.find(search,pos)) != std::string::npos)
+ {
+ str.replace(pos,search.length(),replace);
+ pos += replace.length();
+ }
+ }
+
+ IGL_INLINE void encodeXMLElementName(std::string& name)
+ {
+ // must not start with a digit
+ if(isdigit(*name.begin()))
+ {
+ name = ":::" + name;
+ }
+
+ std::stringstream stream;
+ for(int i=0;i<numForbiddenChars;i++)
+ {
+ std::string search;
+ search = forbiddenChars[i];
+ std::stringstream replaces;
+ replaces << ":" << (int)forbiddenChars[i];
+ std::string replace = replaces.str();
+
+ replaceSubString(name,search,replace);
+ }
+ }
+
+ IGL_INLINE void decodeXMLElementName(std::string& name)
+ {
+ if(name.find("::",0) == 0)
+ name.replace(0,3,"");
+
+ for(auto chr : forbiddenChars)
+ {
+ std::stringstream searchs;
+ searchs << ":" << (int)chr;
+ std::string search = searchs.str();
+ std::string replace;
+ replace = chr;
+
+ replaceSubString(name,search,replace);
+ }
+ }
+
+ /* Copyright(C) 2004-2008 Ren� Nyffenegger
+
+ This source code is provided 'as-is',without any express or implied
+ warranty.In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications,and to alter it and redistribute it
+ freely,subject to the following restrictions:
+
+ 1. The origin of this source code must not be misrepresented; you must not
+ claim that you wrote the original source code.If you use this source code
+ in a product,an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such,and must not be
+ misrepresented as being the original source code.
+
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Ren� Nyffenegger rene.nyffenegger@adp-gmbh.ch
+ */
+
+ static const std::string base64_chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+ static inline bool is_base64(unsigned char c) {
+ return (isalnum(c) || (c == '+') || (c == '/'));
+ }
+
+ std::string base64_encode(unsigned char const* bytes_to_encode,unsigned int in_len)
+ {
+ std::string ret;
+ int i = 0;
+ int j = 0;
+ unsigned char char_array_3[3];
+ unsigned char char_array_4[4];
+
+ while(in_len--) {
+ char_array_3[i++] = *(bytes_to_encode++);
+ if(i == 3) {
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for(i = 0; (i <4) ; i++)
+ ret += base64_chars[char_array_4[i]];
+
+ i = 0;
+ }
+ }
+
+ if(i)
+ {
+ for(j = i; j < 3; j++)
+ char_array_3[j] = '\0';
+
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for(j = 0; (j < i + 1); j++)
+ ret += base64_chars[char_array_4[j]];
+
+ while((i++ < 3))
+ ret += '=';
+ }
+
+ return ret;
+ }
+
+ std::string base64_decode(std::string const& encoded_string)
+ {
+ int in_len = encoded_string.size();
+ int i = 0;
+ int j = 0;
+ int in_ = 0;
+ unsigned char char_array_4[4],char_array_3[3];
+ std::string ret;
+
+ // construct fast lookup table
+ // added by Christian Sch�ller (schuellc@inf.ethz.ch)
+ int charLookup[200];
+ for(int i=0;i<(int)(base64_chars.length());i++)
+ charLookup[(int)base64_chars[i]] = i;
+
+ while(in_len-- && (encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+ char_array_4[i++] = encoded_string[in_]; in_++;
+ if(i ==4) {
+ for(i = 0; i <4; i++)
+ char_array_4[i] = charLookup[char_array_4[i]]; // new fast lookup
+ //char_array_4[i] = base64_chars.find(char_array_4[i]); // original version
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for(i = 0; (i < 3); i++)
+ ret += char_array_3[i];
+
+ i = 0;
+ }
+ }
+
+ if(i) {
+ for(j = i; j <4; j++)
+ char_array_4[j] = 0;
+
+ for(j = 0; j <4; j++)
+ char_array_4[j] = base64_chars.find(char_array_4[j]);
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for(j = 0; (j < i - 1);
+ j++) ret += char_array_3[j];
+ }
+
+ return ret;
+ }
+ }
+ }
+}
+
+#ifdef IGL_STATIC_LIBRARY
+// Explicit template instantiation
+template void igl::xml::serialize_xml<std::vector<float, std::allocator<float> > >(std::vector<float, std::allocator<float> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, bool, bool);
+template void igl::xml::deserialize_xml<std::vector<float, std::allocator<float> > >(std::vector<float, std::allocator<float> >&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&, std::basic_string<char, std::char_traits<char>, std::allocator<char> > const&);
+#endif
diff --git a/xs/src/igl/xml/serialize_xml.h b/xs/src/igl/xml/serialize_xml.h
new file mode 100644
index 000000000..2190f676a
--- /dev/null
+++ b/xs/src/igl/xml/serialize_xml.h
@@ -0,0 +1,247 @@
+//
+// Copyright (C) 2014 Christian Sch�ller <schuellchr@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_XML_SERIALIZABLE_XML_H
+#define IGL_XML_SERIALIZABLE_XML_H
+// -----------------------------------------------------------------------------
+// Functions to save and load a serialization of fundamental c++ data types to
+// and from a xml file. STL containers, Eigen matrix types and nested data
+// structures are also supported. To serialize a user defined class implement
+// the interface XMLSerializable or XMLSerializableBase.
+//
+// See also: serialize.h
+// -----------------------------------------------------------------------------
+
+#include "../igl_inline.h"
+
+
+#include <Eigen/Dense>
+#include <Eigen/Sparse>
+#include <tinyxml2.h>
+
+#include <type_traits>
+#include <functional>
+#include <iostream>
+#include <vector>
+#include <set>
+#include <map>
+#include <memory>
+
+//#define SERIALIZE_XML(x) igl::xml::serialize_xml(x,#x,doc,element);
+//#define DESERIALIZE_XML(x) igl::xml::deserialize_xml(x,#x,,doc,element);
+
+namespace igl
+{
+ namespace xml
+ {
+ struct XMLSerializableBase;
+ // serializes the given object either to a xml file or to the provided doc data
+ //
+ // Templates:
+ // T type of the object to serialize
+ // Inputs:
+ // obj object to serialize
+ // objectName unique object name,used for the identification
+ // filename name of the file containing the serialization
+ // binary set to true to serialize the object in binary format (faster for big data)
+ // overwrite set to true to overwrite an existing xml file
+ // element tinyxml2 virtual representation of the current xml node
+ // Outputs:
+ // doc contains current tinyxml2 virtual representation of the xml data
+ //
+ template <typename T>
+ IGL_INLINE void serialize_xml(const T& obj,const std::string& filename);
+ template <typename T>
+ IGL_INLINE void serialize_xml(
+ const T& obj,
+ const std::string& objectName,
+ const std::string& filename,
+ bool binary = false,
+ bool overwrite = false);
+ template <typename T>
+ IGL_INLINE void serialize_xml(
+ const T& obj,
+ const std::string& objectName,
+ tinyxml2::XMLDocument* doc,
+ tinyxml2::XMLElement* element,
+ bool binary = false);
+
+ // deserializes the given data from a xml file or doc data back to the provided object
+ //
+ // Templates:
+ // T type of the object to serialize
+ // Inputs:
+ //
+ // objectName unique object name,used for the identification
+ // filename name of the file containing the serialization
+ // binary set to true to serialize the object in binary format (faster for big data)
+ // overwrite set to true to overwrite an existing xml file
+ // doc contains current tinyxml2 virtual representation of the xml data
+ // element tinyxml2 virtual representation of the current xml node
+ // Outputs:
+ // obj object to load back serialization to
+ //
+ template <typename T>
+ IGL_INLINE void deserialize_xml(T& obj,const std::string& filename);
+ template <typename T>
+ IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const std::string& filename);
+ template <typename T>
+ IGL_INLINE void deserialize_xml(T& obj,const std::string& objectName,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element);
+
+ // internal functions
+ namespace serialization_xml
+ {
+ // fundamental types
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_fundamental<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ // std::string
+ IGL_INLINE void serialize(const std::string& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ IGL_INLINE void deserialize(std::string& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ // XMLSerializableBase
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_base_of<XMLSerializableBase,T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ // STL containers
+ template <typename T1, typename T2>
+ IGL_INLINE void serialize(const std::pair<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template <typename T1,typename T2>
+ IGL_INLINE void deserialize(std::pair<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ template <typename T1,typename T2>
+ IGL_INLINE void serialize(const std::vector<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template <typename T1,typename T2>
+ IGL_INLINE void deserialize(std::vector<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ template <typename T>
+ IGL_INLINE void serialize(const std::set<T>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template <typename T>
+ IGL_INLINE void deserialize(std::set<T>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ template <typename T1,typename T2>
+ IGL_INLINE void serialize(const std::map<T1,T2>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template <typename T1,typename T2>
+ IGL_INLINE void deserialize(std::map<T1,T2>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ // Eigen types
+
+ // Serialize a Dense Eigen Matrix to xml (in the matrix= attribute,
+ // awkward...)
+ //
+ // Inputs:
+ // obj MR by MC matrix of T types
+ // name name of matrix
+ // to_string function converting T to string
+ // Outputs:
+ // doc pointer to xml document
+ // element pointer to xml element
+ //
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void serialize(
+ const Eigen::Matrix<T,R,C,P,MR,MC>& obj,
+ const std::string& name,
+ const std::function<std::string(const T &) >& to_string,
+ tinyxml2::XMLDocument* doc,
+ tinyxml2::XMLElement* element);
+ // De-Serialize a Dense Eigen Matrix from xml (in the matrix= attribute,
+ // awkward...)
+ //
+ // Inputs:
+ // doc pointer to xml document
+ // element pointer to xml element
+ // name name of matrix
+ // from_string function string to T
+ // Outputs:
+ // obj MR by MC matrix of T types
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void deserialize(
+ const tinyxml2::XMLDocument* doc,
+ const tinyxml2::XMLElement* element,
+ const std::string& name,
+ const std::function<void(const std::string &,T &)> & from_string,
+ Eigen::Matrix<T,R,C,P,MR,MC>& obj);
+
+ // Legacy APIs
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void serialize(
+ const Eigen::Matrix<T,R,C,P,MR,MC>& obj,
+ tinyxml2::XMLDocument* doc,
+ tinyxml2::XMLElement* element,
+ const std::string& name);
+ template<typename T,int R,int C,int P,int MR,int MC>
+ IGL_INLINE void deserialize(
+ Eigen::Matrix<T,R,C,P,MR,MC>& obj,
+ const tinyxml2::XMLDocument* doc,
+ const tinyxml2::XMLElement* element,
+ const std::string& name);
+
+ template<typename T,int P,typename I>
+ IGL_INLINE void serialize(const Eigen::SparseMatrix<T,P,I>& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template<typename T,int P,typename I>
+ IGL_INLINE void deserialize(Eigen::SparseMatrix<T,P,I>& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ // raw pointers
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type serialize(const T& obj,tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ template <typename T>
+ IGL_INLINE typename std::enable_if<std::is_pointer<T>::value>::type deserialize(T& obj,const tinyxml2::XMLDocument* doc,const tinyxml2::XMLElement* element,const std::string& name);
+
+ // helper functions
+ tinyxml2::XMLElement* getElement(tinyxml2::XMLDocument* doc,tinyxml2::XMLElement* element,const std::string& name);
+ IGL_INLINE void getAttribute(const char* src,bool& dest);
+ IGL_INLINE void getAttribute(const char* scr,char& dest);
+ IGL_INLINE void getAttribute(const char* src,std::string& dest);
+ IGL_INLINE void getAttribute(const char* src,float& dest);
+ IGL_INLINE void getAttribute(const char* src,double& dest);
+ template<typename T>
+ IGL_INLINE typename std::enable_if<std::is_integral<T>::value && std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest);
+ template<typename T>
+ IGL_INLINE typename std::enable_if<std::is_integral<T>::value && !std::is_unsigned<T>::value>::type getAttribute(const char* src,T& dest);
+ IGL_INLINE void replaceSubString(std::string& str,const std::string& search,const std::string& replace);
+ IGL_INLINE void encodeXMLElementName(std::string& name);
+ IGL_INLINE void decodeXMLElementName(std::string& name);
+ IGL_INLINE std::string base64_encode(unsigned char const* bytes_to_encode,unsigned int in_len);
+ IGL_INLINE std::string base64_decode(std::string const& encoded_string);
+
+ // compile time type serializable check
+ template <typename T>
+ struct is_stl_container { static const bool value = false; };
+ template <typename T1,typename T2>
+ struct is_stl_container<std::pair<T1,T2> > { static const bool value = true; };
+ template <typename T1,typename T2>
+ struct is_stl_container<std::vector<T1,T2> > { static const bool value = true; };
+ template <typename T>
+ struct is_stl_container<std::set<T> > { static const bool value = true; };
+ template <typename T1,typename T2>
+ struct is_stl_container<std::map<T1,T2> > { static const bool value = true; };
+
+ template <typename T>
+ struct is_eigen_type { static const bool value = false; };
+ template <typename T,int R,int C,int P,int MR,int MC>
+ struct is_eigen_type<Eigen::Matrix<T,R,C,P,MR,MC> > { static const bool value = true; };
+ template <typename T,int P,typename I>
+ struct is_eigen_type<Eigen::SparseMatrix<T,P,I> > { static const bool value = true; };
+
+ template <typename T>
+ struct is_serializable {
+ using T0 = typename std::remove_pointer<T>::type;
+ static const bool value = std::is_fundamental<T0>::value || std::is_same<std::string,T0>::value || std::is_base_of<XMLSerializableBase,T0>::value
+ || is_stl_container<T0>::value || is_eigen_type<T0>::value;
+ };
+ }
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+ #include "serialize_xml.cpp"
+#endif
+
+#endif
diff --git a/xs/src/igl/xml/writeDAE.cpp b/xs/src/igl/xml/writeDAE.cpp
new file mode 100644
index 000000000..2c2bb4301
--- /dev/null
+++ b/xs/src/igl/xml/writeDAE.cpp
@@ -0,0 +1,138 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "writeDAE.h"
+#include "../STR.h"
+#include <tinyxml2.h>
+#include <map>
+#include <list>
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::xml::writeDAE(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F)
+{
+ using namespace std;
+ using namespace Eigen;
+ using namespace tinyxml2;
+
+ XMLDocument* doc = new XMLDocument();
+
+ const auto & ele = [&doc](
+ const std::string tag,
+ // Can't just use `{}` as the default argument because of a clang-bug
+ // http://stackoverflow.com/questions/17264067/
+ const std::map<std::string,std::string> attribs =
+ std::map<std::string,std::string>(),
+ const std::string text="",
+ const std::list<XMLElement *> children =
+ std::list<XMLElement *>()
+ )->XMLElement *
+ {
+ XMLElement * element = doc->NewElement(tag.c_str());
+ for(const auto & key_value : attribs)
+ {
+ element->SetAttribute(key_value.first.c_str(),key_value.second.c_str());
+ }
+ if(!text.empty())
+ {
+ element->InsertEndChild(doc->NewText(text.c_str()));
+ }
+ for(auto & child : children)
+ {
+ element->InsertEndChild(child);
+ }
+ return element;
+ };
+
+ Eigen::IOFormat row_format(Eigen::FullPrecision,0," "," ","","","");
+ doc->InsertEndChild(
+ ele("COLLADA",
+ {
+ {"xmlns","http://www.collada.org/2005/11/COLLADASchema"},
+ {"version","1.4.1"}
+ },
+ "",
+ {
+ ele("asset",{},"",
+ {
+ ele("unit",{{"meter","0.0254000"},{"name","inch"}}),
+ ele("up_axis",{},"Y_UP")
+ }),
+ ele("library_visual_scenes",{},"",
+ {
+ ele("visual_scene",{{"id","ID2"}},"",
+ {
+ ele("node",{{"name","SketchUp"}},"",
+ {
+ ele("node",{{"id","ID3"},{"name","group_0"}},"",
+ {
+ ele("matrix",{},"1 0 0 0 0 1 0 0 0 0 1 0 0 0 0 1"),
+ ele("instance_geometry",{{"url","#ID4"}},"",
+ {
+ ele("bind_material",{},"",{ele("technique_common")}),
+ }),
+ }),
+ }),
+ }),
+ }),
+ ele("library_geometries",{},"",
+ {
+ ele("geometry",{{"id","ID4"}},"",
+ {
+ ele("mesh",{},"",
+ {
+ ele("source",{{"id","ID7"}},"",
+ {
+ ele(
+ "float_array",
+ {{"count",STR(V.size())},{"id","ID10"}},
+ STR(V.format(row_format))),
+ ele("technique_common",{},"",
+ {
+ ele(
+ "accessor",
+ {{"count",STR(V.rows())},{"source","#ID8"},{"stride","3"}},
+ "",
+ {
+ ele("param",{{"name","X"},{"type","float"}}),
+ ele("param",{{"name","Y"},{"type","float"}}),
+ ele("param",{{"name","Z"},{"type","float"}}),
+ })
+ })
+ }),
+ ele(
+ "vertices",
+ {{"id","ID9"}},
+ "",
+ {ele("input",{{"semantic","POSITION"},{"source","#ID7"}})}),
+ ele(
+ "triangles",
+ {{"count",STR(F.rows())}},
+ "",
+ {
+ ele("input",{{"semantic","VERTEX"},{"source","#ID9"}}),
+ ele("p",{},STR(F.format(row_format))),
+ })
+ })
+ })
+ }),
+ ele("scene",{},"",{ele("instance_visual_scene",{{"url","#ID2"}})}),
+ }));
+ // tinyxml2 seems **not** to print the <?xml ...?> header by default, but it
+ // also seems that that's OK
+ XMLError error = doc->SaveFile(filename.c_str());
+ bool ret = true;
+ if(error != XML_NO_ERROR)
+ {
+ doc->PrintError();
+ ret = false;
+ }
+ delete doc;
+ return ret;
+}
diff --git a/xs/src/igl/xml/writeDAE.h b/xs/src/igl/xml/writeDAE.h
new file mode 100644
index 000000000..731fe7255
--- /dev/null
+++ b/xs/src/igl/xml/writeDAE.h
@@ -0,0 +1,38 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_XML_WRITEDAE_H
+#define IGL_XML_WRITEDAE_H
+#include "../igl_inline.h"
+#include <string>
+#include <Eigen/Core>
+namespace igl
+{
+ namespace xml
+ {
+ // Write a mesh to a Collada .dae scene file. The resulting scene contains
+ // a single "geometry" suitable for solid operaions (boolean union,
+ // intersection, etc.) in SketchUp.
+ //
+ // Inputs:
+ // filename path to .dae file
+ // V #V by 3 list of vertex positions
+ // F #F by 3 list of face indices
+ // Returns true iff success
+ //
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool writeDAE(
+ const std::string & filename,
+ const Eigen::PlainObjectBase<DerivedV> & V,
+ const Eigen::PlainObjectBase<DerivedF> & F);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+#include "writeDAE.cpp"
+#endif
+#endif
diff --git a/xs/src/igl/xml/write_triangle_mesh.cpp b/xs/src/igl/xml/write_triangle_mesh.cpp
new file mode 100644
index 000000000..1f3d54b8d
--- /dev/null
+++ b/xs/src/igl/xml/write_triangle_mesh.cpp
@@ -0,0 +1,33 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#include "write_triangle_mesh.h"
+#include "../write_triangle_mesh.h"
+#include "../pathinfo.h"
+#include "writeDAE.h"
+
+template <typename DerivedV, typename DerivedF>
+IGL_INLINE bool igl::xml::write_triangle_mesh(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const bool ascii)
+{
+ using namespace std;
+ // dirname, basename, extension and filename
+ string d,b,e,f;
+ pathinfo(str,d,b,e,f);
+ // Convert extension to lower case
+ std::transform(e.begin(), e.end(), e.begin(), ::tolower);
+ if(e == "dae")
+ {
+ return writeDAE(str,V,F);
+ }else
+ {
+ return igl::write_triangle_mesh(str,V,F,ascii);
+ }
+}
diff --git a/xs/src/igl/xml/write_triangle_mesh.h b/xs/src/igl/xml/write_triangle_mesh.h
new file mode 100644
index 000000000..a5f8dad69
--- /dev/null
+++ b/xs/src/igl/xml/write_triangle_mesh.h
@@ -0,0 +1,45 @@
+// This file is part of libigl, a simple c++ geometry processing library.
+//
+// Copyright (C) 2016 Alec Jacobson <alecjacobson@gmail.com>
+//
+// This Source Code Form is subject to the terms of the Mozilla Public License
+// v. 2.0. If a copy of the MPL was not distributed with this file, You can
+// obtain one at http://mozilla.org/MPL/2.0/.
+#ifndef IGL_XML_WRITE_TRIANGLE_MESH_H
+#define IGL_XML_WRITE_TRIANGLE_MESH_H
+#include "../igl_inline.h"
+
+#include <Eigen/Core>
+#include <string>
+
+namespace igl
+{
+ namespace xml
+ {
+ // write mesh to a file with automatic detection of file format. supported:
+ // dae, or any of the formats supported by igl::write_triangle_mesh
+ //
+ // Templates:
+ // Scalar type for positions and vectors (will be read as double and cast
+ // to Scalar)
+ // Index type for indices (will be read as int and cast to Index)
+ // Inputs:
+ // str path to file
+ // V eigen double matrix #V by 3
+ // F eigen int matrix #F by 3
+ // Returns true iff success
+ template <typename DerivedV, typename DerivedF>
+ IGL_INLINE bool write_triangle_mesh(
+ const std::string str,
+ const Eigen::PlainObjectBase<DerivedV>& V,
+ const Eigen::PlainObjectBase<DerivedF>& F,
+ const bool ascii = true);
+ }
+}
+
+#ifndef IGL_STATIC_LIBRARY
+# include "write_triangle_mesh.cpp"
+#endif
+
+#endif
+