├── .clang-format ├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .gitattributes ├── .github ├── FUNDING.yml ├── ISSUE_TEMPLATE │ ├── bug_report.md │ ├── feature_request.md │ └── question.md ├── pull_request_template.md └── workflows │ ├── clang-format-check.yml │ ├── continuous.yml │ ├── coverage.yml │ ├── cuda.yml │ ├── docs.yml │ ├── pypi.yml │ └── python.yml ├── .gitignore ├── .pre-commit-config.yaml ├── CMakeLists.txt ├── CMakePresets.json ├── IPCToolkitOptions.cmake.sample ├── LICENSE ├── MANIFEST.in ├── README.md ├── cmake ├── find │ └── FindSIMD.cmake ├── ipc_toolkit │ ├── ipc_toolkit_cpm_cache.cmake │ ├── ipc_toolkit_filter_flags.cmake │ ├── ipc_toolkit_tests_data.cmake │ ├── ipc_toolkit_use_colors.cmake │ └── ipc_toolkit_warnings.cmake └── recipes │ ├── CPM.cmake │ ├── abseil.cmake │ ├── catch2.cmake │ ├── ccd_query_io.cmake │ ├── eigen.cmake │ ├── evouga_ccd.cmake │ ├── filib.cmake │ ├── finite_diff.cmake │ ├── json.cmake │ ├── libigl.cmake │ ├── onetbb.cmake │ ├── pybind11.cmake │ ├── rational_cpp.cmake │ ├── robin_map.cmake │ ├── scalable_ccd.cmake │ ├── simple_bvh.cmake │ ├── spdlog.cmake │ └── tight_inclusion.cmake ├── codecov.yml ├── docs ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── Makefile ├── PYPI_README.md ├── make.bat ├── requirements.txt └── source │ ├── Doxyfile │ ├── _static │ ├── css │ │ └── custom.css │ ├── favicon.ico │ ├── hammer-wrench.svg │ ├── logo.png │ └── versions.json │ ├── _templates │ └── 404.html │ ├── changelog.rst │ ├── code_of_conduct.rst │ ├── conf.py │ ├── contributing.rst │ ├── cpp-api │ ├── adhesion.rst │ ├── barrier.rst │ ├── broad_phase.rst │ ├── candidates.rst │ ├── ccd.rst │ ├── collision_mesh.rst │ ├── distance.rst │ ├── friction.rst │ ├── intersections.rst │ ├── interval.rst │ ├── normal_collisions.rst │ ├── potentials.rst │ ├── tangent.rst │ ├── tangential_collisions.rst │ └── utils.rst │ ├── cpp.rst │ ├── index.rst │ ├── license.rst │ ├── python-api │ ├── adhesion.rst │ ├── barrier.rst │ ├── broad_phase.rst │ ├── candidates.rst │ ├── ccd.rst │ ├── collision_mesh.rst │ ├── distance.rst │ ├── friction.rst │ ├── intersections.rst │ ├── interval.rst │ ├── normal_collisions.rst │ ├── potentials.rst │ ├── tangent.rst │ ├── tangential_collisions.rst │ └── utils.rst │ ├── python.rst │ ├── references.bib │ ├── style_guide.rst │ └── tutorial │ ├── adhesion.rst │ ├── convergent.rst │ ├── faq.rst │ ├── getting_started.rst │ ├── misc.rst │ ├── nonlinear_ccd.rst │ ├── references.rst │ └── simulation.rst ├── notebooks ├── adhesion.ipynb ├── area_weights.ipynb ├── closest_point_grad.ipynb ├── distances.ipynb ├── ee_mollifier_shape_derivative.ipynb ├── find_ipctk.py ├── generate_cpp_code.py ├── improved_max_approximator.ipynb ├── nonlinear_trajectories.ipynb ├── parula.py ├── physical_barrier.ipynb ├── tangent_basis_grad.ipynb └── utils.py ├── pyproject.toml ├── python ├── .clang-format ├── CMakeLists.txt ├── README.md ├── example.ipynb ├── src │ ├── CMakeLists.txt │ ├── adhesion │ │ ├── CMakeLists.txt │ │ ├── adhesion.cpp │ │ └── bindings.hpp │ ├── barrier │ │ ├── CMakeLists.txt │ │ ├── adaptive_stiffness.cpp │ │ ├── barrier.cpp │ │ ├── barrier_force_magnitude.cpp │ │ └── bindings.hpp │ ├── bindings.cpp │ ├── bindings.hpp │ ├── broad_phase │ │ ├── CMakeLists.txt │ │ ├── aabb.cpp │ │ ├── bindings.hpp │ │ ├── broad_phase.cpp │ │ ├── brute_force.cpp │ │ ├── bvh.cpp │ │ ├── hash_grid.cpp │ │ ├── spatial_hash.cpp │ │ ├── sweep_and_prune.cpp │ │ ├── sweep_and_tiniest_queue.cpp │ │ └── voxel_size_heuristic.cpp │ ├── candidates │ │ ├── CMakeLists.txt │ │ ├── bindings.hpp │ │ ├── candidates.cpp │ │ ├── collision_stencil.cpp │ │ ├── edge_edge.cpp │ │ ├── edge_face.cpp │ │ ├── edge_vertex.cpp │ │ ├── face_face.cpp │ │ ├── face_vertex.cpp │ │ └── vertex_vertex.cpp │ ├── ccd │ │ ├── CMakeLists.txt │ │ ├── aabb.cpp │ │ ├── additive_ccd.cpp │ │ ├── bindings.hpp │ │ ├── check_initial_distance.cpp │ │ ├── inexact_ccd.cpp │ │ ├── inexact_point_edge.cpp │ │ ├── narrow_phase_ccd.cpp │ │ ├── nonlinear_ccd.cpp │ │ ├── point_static_plane.cpp │ │ └── tight_inclusion_ccd.cpp │ ├── collision_mesh.cpp │ ├── collisions │ │ ├── CMakeLists.txt │ │ ├── bindings.hpp │ │ ├── normal │ │ │ ├── CMakeLists.txt │ │ │ ├── bindings.hpp │ │ │ ├── edge_edge.cpp │ │ │ ├── edge_vertex.cpp │ │ │ ├── face_vertex.cpp │ │ │ ├── normal_collision.cpp │ │ │ ├── normal_collisions.cpp │ │ │ ├── plane_vertex.cpp │ │ │ └── vertex_vertex.cpp │ │ └── tangential │ │ │ ├── CMakeLists.txt │ │ │ ├── bindings.hpp │ │ │ ├── edge_edge.cpp │ │ │ ├── edge_vertex.cpp │ │ │ ├── face_vertex.cpp │ │ │ ├── tangential_collision.cpp │ │ │ ├── tangential_collisions.cpp │ │ │ └── vertex_vertex.cpp │ ├── common.hpp │ ├── distance │ │ ├── CMakeLists.txt │ │ ├── bindings.hpp │ │ ├── distance_type.cpp │ │ ├── edge_edge.cpp │ │ ├── edge_edge_mollifier.cpp │ │ ├── line_line.cpp │ │ ├── point_edge.cpp │ │ ├── point_line.cpp │ │ ├── point_plane.cpp │ │ ├── point_point.cpp │ │ └── point_triangle.cpp │ ├── friction │ │ ├── CMakeLists.txt │ │ ├── bindings.hpp │ │ └── smooth_friction_mollifier.cpp │ ├── implicits │ │ ├── CMakeLists.txt │ │ ├── bindings.hpp │ │ └── plane.cpp │ ├── ipc.cpp │ ├── potentials │ │ ├── CMakeLists.txt │ │ ├── barrier_potential.cpp │ │ ├── bindings.hpp │ │ ├── friction_potential.cpp │ │ ├── normal_adhesion_potential.cpp │ │ ├── normal_potential.cpp │ │ ├── potential.hpp │ │ ├── tangential_adhesion_potential.cpp │ │ └── tangential_potential.cpp │ ├── tangent │ │ ├── CMakeLists.txt │ │ ├── bindings.hpp │ │ ├── closest_point.cpp │ │ ├── relative_velocity.cpp │ │ └── tangent_basis.cpp │ └── utils │ │ ├── CMakeLists.txt │ │ ├── area_gradient.cpp │ │ ├── bindings.hpp │ │ ├── eigen_ext.cpp │ │ ├── intersection.cpp │ │ ├── interval.cpp │ │ ├── logger.cpp │ │ ├── thread_limiter.cpp │ │ ├── vertex_to_min_edge.cpp │ │ └── world_bbox_diagonal_length.cpp └── tests │ ├── find_ipctk.py │ ├── requirements.txt │ ├── test_candidates.py │ ├── test_ccd.py │ ├── test_collision_mesh.py │ ├── test_constraints.py │ ├── test_intersections.py │ ├── test_interval.py │ ├── test_ipc.py │ └── utils.py ├── setup.py ├── src └── ipc │ ├── CMakeLists.txt │ ├── adhesion │ ├── CMakeLists.txt │ ├── adhesion.cpp │ └── adhesion.hpp │ ├── barrier │ ├── CMakeLists.txt │ ├── adaptive_stiffness.cpp │ ├── adaptive_stiffness.hpp │ ├── barrier.cpp │ ├── barrier.hpp │ ├── barrier_force_magnitude.cpp │ └── barrier_force_magnitude.hpp │ ├── broad_phase │ ├── CMakeLists.txt │ ├── aabb.cpp │ ├── aabb.hpp │ ├── broad_phase.cpp │ ├── broad_phase.hpp │ ├── brute_force.cpp │ ├── brute_force.hpp │ ├── bvh.cpp │ ├── bvh.hpp │ ├── default_broad_phase.hpp │ ├── hash_grid.cpp │ ├── hash_grid.hpp │ ├── spatial_hash.cpp │ ├── spatial_hash.hpp │ ├── sweep_and_prune.cpp │ ├── sweep_and_prune.hpp │ ├── sweep_and_tiniest_queue.cpp │ ├── sweep_and_tiniest_queue.hpp │ ├── voxel_size_heuristic.cpp │ └── voxel_size_heuristic.hpp │ ├── candidates │ ├── CMakeLists.txt │ ├── candidates.cpp │ ├── candidates.hpp │ ├── collision_stencil.cpp │ ├── collision_stencil.hpp │ ├── edge_edge.cpp │ ├── edge_edge.hpp │ ├── edge_face.cpp │ ├── edge_face.hpp │ ├── edge_vertex.cpp │ ├── edge_vertex.hpp │ ├── face_face.cpp │ ├── face_face.hpp │ ├── face_vertex.cpp │ ├── face_vertex.hpp │ ├── vertex_vertex.cpp │ └── vertex_vertex.hpp │ ├── ccd │ ├── CMakeLists.txt │ ├── aabb.cpp │ ├── aabb.hpp │ ├── additive_ccd.cpp │ ├── additive_ccd.hpp │ ├── check_initial_distance.hpp │ ├── default_narrow_phase_ccd.cpp │ ├── default_narrow_phase_ccd.hpp │ ├── inexact_ccd.cpp │ ├── inexact_ccd.hpp │ ├── inexact_point_edge.cpp │ ├── inexact_point_edge.hpp │ ├── narrow_phase_ccd.hpp │ ├── nonlinear_ccd.cpp │ ├── nonlinear_ccd.hpp │ ├── point_static_plane.cpp │ ├── point_static_plane.hpp │ ├── tight_inclusion_ccd.cpp │ └── tight_inclusion_ccd.hpp │ ├── collision_mesh.cpp │ ├── collision_mesh.hpp │ ├── collisions │ ├── CMakeLists.txt │ ├── normal │ │ ├── CMakeLists.txt │ │ ├── edge_edge.cpp │ │ ├── edge_edge.hpp │ │ ├── edge_vertex.hpp │ │ ├── face_vertex.hpp │ │ ├── normal_collision.cpp │ │ ├── normal_collision.hpp │ │ ├── normal_collisions.cpp │ │ ├── normal_collisions.hpp │ │ ├── normal_collisions_builder.cpp │ │ ├── normal_collisions_builder.hpp │ │ ├── plane_vertex.cpp │ │ ├── plane_vertex.hpp │ │ └── vertex_vertex.hpp │ └── tangential │ │ ├── CMakeLists.txt │ │ ├── edge_edge.cpp │ │ ├── edge_edge.hpp │ │ ├── edge_vertex.cpp │ │ ├── edge_vertex.hpp │ │ ├── face_vertex.cpp │ │ ├── face_vertex.hpp │ │ ├── tangential_collision.cpp │ │ ├── tangential_collision.hpp │ │ ├── tangential_collisions.cpp │ │ ├── tangential_collisions.hpp │ │ ├── vertex_vertex.cpp │ │ └── vertex_vertex.hpp │ ├── config.hpp.in │ ├── distance │ ├── CMakeLists.txt │ ├── distance_type.cpp │ ├── distance_type.hpp │ ├── edge_edge.cpp │ ├── edge_edge.hpp │ ├── edge_edge_mollifier.cpp │ ├── edge_edge_mollifier.hpp │ ├── line_line.cpp │ ├── line_line.hpp │ ├── point_edge.cpp │ ├── point_edge.hpp │ ├── point_line.cpp │ ├── point_line.hpp │ ├── point_plane.cpp │ ├── point_plane.hpp │ ├── point_point.cpp │ ├── point_point.hpp │ ├── point_triangle.cpp │ └── point_triangle.hpp │ ├── friction │ ├── CMakeLists.txt │ ├── smooth_friction_mollifier.cpp │ └── smooth_friction_mollifier.hpp │ ├── implicits │ ├── CMakeLists.txt │ ├── plane.cpp │ └── plane.hpp │ ├── ipc.cpp │ ├── ipc.hpp │ ├── potentials │ ├── CMakeLists.txt │ ├── barrier_potential.cpp │ ├── barrier_potential.hpp │ ├── friction_potential.cpp │ ├── friction_potential.hpp │ ├── normal_adhesion_potential.cpp │ ├── normal_adhesion_potential.hpp │ ├── normal_potential.cpp │ ├── normal_potential.hpp │ ├── potential.hpp │ ├── potential.tpp │ ├── tangential_adhesion_potential.cpp │ ├── tangential_adhesion_potential.hpp │ ├── tangential_potential.cpp │ └── tangential_potential.hpp │ ├── tangent │ ├── CMakeLists.txt │ ├── closest_point.cpp │ ├── closest_point.hpp │ ├── relative_velocity.cpp │ ├── relative_velocity.hpp │ ├── tangent_basis.cpp │ └── tangent_basis.hpp │ └── utils │ ├── CMakeLists.txt │ ├── area_gradient.cpp │ ├── area_gradient.hpp │ ├── eigen_ext.hpp │ ├── eigen_ext.tpp │ ├── intersection.cpp │ ├── intersection.hpp │ ├── interval.cpp │ ├── interval.hpp │ ├── local_to_global.hpp │ ├── logger.cpp │ ├── logger.hpp │ ├── merge_thread_local.hpp │ ├── save_obj.cpp │ ├── save_obj.hpp │ ├── unordered_map_and_set.cpp │ ├── unordered_map_and_set.hpp │ ├── vertex_to_min_edge.cpp │ ├── vertex_to_min_edge.hpp │ └── world_bbox_diagonal_length.hpp └── tests ├── .clang-format ├── CMakeLists.txt └── src └── tests ├── CMakeLists.txt ├── adhesion ├── CMakeLists.txt └── test_adhesion.cpp ├── barrier ├── CMakeLists.txt ├── test_adaptive_stiffness.cpp ├── test_barrier.cpp └── test_barrier_force_magnitude.cpp ├── benchmark_eigen.cpp ├── broad_phase ├── CMakeLists.txt ├── benchmark_broad_phase.cpp ├── brute_force_comparison.cpp ├── brute_force_comparison.hpp ├── test_aabb.cpp ├── test_broad_phase.cpp ├── test_spatial_hash.cpp ├── test_stq.cpp └── test_voxel_size_heuristic.cpp ├── candidates ├── CMakeLists.txt ├── test_candidates.cpp └── test_coefficients.cpp ├── ccd ├── CMakeLists.txt ├── benchmark_ccd.cpp ├── collision_generator.cpp ├── collision_generator.hpp ├── test_ccd.cpp ├── test_ccd_benchmark.cpp ├── test_edge_edge_ccd.cpp ├── test_gpu_ccd.cpp ├── test_nonlinear_ccd.cpp ├── test_point_edge_ccd.cpp ├── test_point_point_ccd.cpp └── test_point_triangle_ccd.cpp ├── collisions ├── CMakeLists.txt └── test_normal_collisions.cpp ├── config.hpp.in ├── distance ├── CMakeLists.txt ├── test_distance_type.cpp ├── test_edge_edge.cpp ├── test_edge_edge_mollifier.cpp ├── test_line_line.cpp ├── test_point_edge.cpp ├── test_point_line.cpp ├── test_point_plane.cpp ├── test_point_point.cpp └── test_point_triangle.cpp ├── friction ├── CMakeLists.txt ├── friction_data_generator.cpp ├── friction_data_generator.hpp ├── test_force_jacobian.cpp ├── test_friction.cpp └── test_smooth_friction_mollifier.cpp ├── main.cpp ├── potential ├── CMakeLists.txt ├── test_adhesion_potentials.cpp ├── test_barrier_potential.cpp └── test_friction_potential.cpp ├── tangent ├── CMakeLists.txt ├── test_closest_point.cpp ├── test_relative_velocity.cpp └── test_tangent_basis.cpp ├── test_cfl.cpp ├── test_collision_mesh.cpp ├── test_has_intersections.cpp ├── test_ipc.cpp ├── utils.cpp ├── utils.hpp └── utils ├── CMakeLists.txt ├── test_interval.cpp └── test_utils.cpp /.clang-format: -------------------------------------------------------------------------------- 1 | --- 2 | Language: Cpp 3 | BasedOnStyle: WebKit 4 | AlignAfterOpenBracket: AlwaysBreak 5 | AlignTrailingComments: 6 | Kind: Always 7 | OverEmptyLines: 0 8 | BinPackParameters: false 9 | BreakArrays: false 10 | BreakBeforeBinaryOperators: NonAssignment 11 | BreakStringLiterals: false 12 | ColumnLimit: 80 13 | CommentPragmas: '^@.+' 14 | FixNamespaceComments: true 15 | # Regroup includes with a priority system 16 | IncludeBlocks: Regroup 17 | IncludeCategories: 18 | # by default, the main header of a cpp will get priority 0 19 | # regex here are sorted by search pattern, not by sort priority 20 | - Regex: "^" # this libraries 21 | Priority: 2 # internal library group 22 | SortPriority: 2 23 | CaseSensitive: true 24 | - Regex: "^" # this libraries 25 | Priority: 2 # internal library group 26 | SortPriority: 3 27 | CaseSensitive: true 28 | - Regex: "^<(.*\\.h[px]*)|(Eigen\/.*)>" 29 | Priority: 4 # libraries (because they end in .h) 30 | SortPriority: 4 31 | CaseSensitive: false 32 | - Regex: "^<.*" 33 | Priority: 5 # system (without .h, because that is captured by the other group) 34 | SortPriority: 5 35 | CaseSensitive: false 36 | - Regex: ".*" # catch-all for internal files 37 | Priority: 1 # internal file group 38 | SortPriority: 1 39 | CaseSensitive: true 40 | PackConstructorInitializers: CurrentLine 41 | RemoveEmptyLinesInUnwrappedLines: true 42 | SortIncludes: CaseInsensitive 43 | ... 44 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # These files should be ignored from GitHub's language statistics. 2 | python/example.ipynb linguist-vendored 3 | notebooks/*.ipynb linguist-vendored -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [zfergus] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: bug 6 | assignees: zfergus 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Compile with '...' 16 | 2. Call function '...' 17 | 3. See error 18 | 19 | **Expected behavior** 20 | A clear and concise description of what you expected to happen. 21 | 22 | **Screenshots** 23 | If applicable, add screenshots to help explain your problem. 24 | 25 | **Environment (please complete the following information):** 26 | - OS and Version: [e.g. macOS, Linux, Windows] 27 | - Compiler and Version: [e.g. GCC, Clang, MSVC] 28 | 29 | **Additional context** 30 | Add any other context about the problem here. 31 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: '' 5 | labels: enhancement 6 | assignees: zfergus 7 | 8 | --- 9 | 10 | **Is your feature request related to a problem? Please describe.** 11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 12 | 13 | **Describe the solution you'd like** 14 | A clear and concise description of what you want to happen. 15 | 16 | **Describe alternatives you've considered** 17 | A clear and concise description of any alternative solutions or features you've considered. 18 | 19 | **Additional context** 20 | Add any other context or screenshots about the feature request here. 21 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/question.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Question 3 | about: Ask a question 4 | title: '' 5 | labels: question 6 | assignees: zfergus 7 | 8 | --- 9 | 10 | 11 | -------------------------------------------------------------------------------- /.github/pull_request_template.md: -------------------------------------------------------------------------------- 1 | # Description 2 | 3 | Please include a summary of the changes and the related issue. Please also include relevant motivation and context. List any dependencies that are required for this change. 4 | 5 | Fixes # (issue) 6 | 7 | ## Type of change 8 | 9 | Please delete options that are not relevant. 10 | 11 | - [ ] Bug fix (non-breaking change which fixes an issue) 12 | - [ ] Enhancement (non-breaking change which improves existing functionality) 13 | - [ ] New feature (non-breaking change which adds functionality) 14 | - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) 15 | - [ ] This change requires a documentation update 16 | 17 | # How Has This Been Tested? 18 | 19 | Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration 20 | 21 | - [ ] Test A 22 | - [ ] Test B 23 | 24 | **Test Configuration**: 25 | * OS and Version: 26 | * Compiler and Version: 27 | 28 | # Checklist 29 | 30 | - [ ] I have followed the project [style guide](https://ipctk.xyz/style_guide.html) 31 | - [ ] My code follows the clang-format style guidelines of this project 32 | - [ ] I have performed a self-review of my code 33 | - [ ] I have commented my code, particularly in hard-to-understand areas 34 | - [ ] I have made corresponding changes to the documentation 35 | - [ ] My changes generate no new warnings 36 | - [ ] I have added tests that prove my fix is effective or that my feature works 37 | - [ ] New and existing unit tests pass locally with my changes 38 | - [ ] Any dependent changes have been merged and published in downstream modules -------------------------------------------------------------------------------- /.github/workflows/clang-format-check.yml: -------------------------------------------------------------------------------- 1 | name: clang-format Check 2 | on: 3 | push: 4 | paths: 5 | - '.github/workflows/clang-format-check.yml' 6 | - '.clang-format' 7 | - 'src/**' 8 | - 'tests/src/**' 9 | - 'python/src/**' 10 | pull_request: 11 | paths: 12 | - '.github/workflows/clang-format-check.yml' 13 | - '.clang-format' 14 | - 'src/**' 15 | - 'tests/src/**' 16 | - 'python/src/**' 17 | jobs: 18 | formatting-check: 19 | name: Formatting Check 20 | runs-on: ubuntu-latest 21 | strategy: 22 | matrix: 23 | path: 24 | - 'src' 25 | - 'tests/src' 26 | - 'python/src' 27 | steps: 28 | - uses: actions/checkout@v4 29 | - name: clang-format style check 30 | uses: jidicula/clang-format-action@v4.15.0 31 | with: 32 | clang-format-version: '20' 33 | check-path: ${{ matrix.path }} -------------------------------------------------------------------------------- /.pre-commit-config.yaml: -------------------------------------------------------------------------------- 1 | repos: 2 | - repo: https://github.com/pre-commit/mirrors-clang-format 3 | rev: v14.0.0 4 | hooks: 5 | - id: clang-format 6 | name: clang-format 7 | description: "Use clang-format to format C/C++ code" 8 | entry: clang-format-18 9 | args: 10 | - --style=file 11 | - --verbose 12 | files: '\.(c|cc|cpp|h|hpp|tpp|cxx|hh|inl|ipp)$' 13 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 IPC-Sim 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | recursive-include src *.hpp *.cpp *.tpp CMakeLists.txt 2 | recursive-include python *.hpp *.cpp CMakeLists.txt 3 | recursive-include cmake *.cmake 4 | include LICENSE README.md pyproject.toml setup.py CMakeLists.txt -------------------------------------------------------------------------------- /cmake/ipc_toolkit/ipc_toolkit_cpm_cache.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2021 Adobe. All rights reserved. 3 | # This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. You may obtain a copy 5 | # of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed under 8 | # the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | # OF ANY KIND, either express or implied. See the License for the specific language 10 | # governing permissions and limitations under the License. 11 | # 12 | 13 | if(DEFINED ENV{CPM_SOURCE_CACHE}) 14 | set(CPM_SOURCE_CACHE_DEFAULT $ENV{CPM_SOURCE_CACHE}) 15 | else() 16 | # Set CPM cache folder if unset 17 | file(REAL_PATH "~/.cache/CPM" CPM_SOURCE_CACHE_DEFAULT EXPAND_TILDE) 18 | endif() 19 | 20 | set(CPM_SOURCE_CACHE 21 | ${CPM_SOURCE_CACHE_DEFAULT} 22 | CACHE PATH "Directory to download CPM dependencies" 23 | ) 24 | message(STATUS "Using CPM cache folder: ${CPM_SOURCE_CACHE}") -------------------------------------------------------------------------------- /cmake/ipc_toolkit/ipc_toolkit_filter_flags.cmake: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright 2021 Adobe. All rights reserved. 3 | # This file is licensed to you under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. You may obtain a copy 5 | # of the License at http://www.apache.org/licenses/LICENSE-2.0 6 | # 7 | # Unless required by applicable law or agreed to in writing, software distributed under 8 | # the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS 9 | # OF ANY KIND, either express or implied. See the License for the specific language 10 | # governing permissions and limitations under the License. 11 | # 12 | function(ipc_toolkit_filter_flags flags) 13 | include(CheckCXXCompilerFlag) 14 | set(output_flags) 15 | foreach(FLAG IN ITEMS ${${flags}}) 16 | string(REPLACE "=" "-" FLAG_VAR "${FLAG}") 17 | if(NOT DEFINED IS_SUPPORTED_${FLAG_VAR}) 18 | check_cxx_compiler_flag("${FLAG}" IS_SUPPORTED_${FLAG_VAR}) 19 | endif() 20 | if(IS_SUPPORTED_${FLAG_VAR}) 21 | list(APPEND output_flags $<$:${FLAG}>) 22 | endif() 23 | endforeach() 24 | set(${flags} ${output_flags} PARENT_SCOPE) 25 | endfunction() -------------------------------------------------------------------------------- /cmake/ipc_toolkit/ipc_toolkit_tests_data.cmake: -------------------------------------------------------------------------------- 1 | # ipc-toolkit-tests-data (https://github.com/ipc-sim/ipc-toolkit-tests-data) 2 | # License: MIT 3 | 4 | if(TARGET ipc_toolkit_test_data_download) 5 | return() 6 | endif() 7 | 8 | include(ExternalProject) 9 | include(FetchContent) 10 | 11 | set(IPC_TOOLKIT_TESTS_DATA_DIR "${PROJECT_SOURCE_DIR}/tests/data/" CACHE PATH "Where should we download the tests data?") 12 | option(IPC_TOOLKIT_USE_EXISTING_TESTS_DATA_DIR "Use an existing test data directory instead of downloading it" OFF) 13 | 14 | if(IPC_TOOLKIT_USE_EXISTING_TESTS_DATA_DIR) 15 | ExternalProject_Add( 16 | ipc_toolkit_test_data_download 17 | PREFIX "${FETCHCONTENT_BASE_DIR}/tests/data" 18 | SOURCE_DIR ${IPC_TOOLKIT_TESTS_DATA_DIR} 19 | 20 | # NOTE: No download step 21 | CONFIGURE_COMMAND "" 22 | BUILD_COMMAND "" 23 | INSTALL_COMMAND "" 24 | LOG_DOWNLOAD ON 25 | ) 26 | else() 27 | ExternalProject_Add( 28 | ipc_toolkit_test_data_download 29 | PREFIX "${FETCHCONTENT_BASE_DIR}/tests/data" 30 | SOURCE_DIR ${IPC_TOOLKIT_TESTS_DATA_DIR} 31 | 32 | GIT_REPOSITORY https://github.com/ipc-sim/ipc-toolkit-tests-data.git 33 | GIT_TAG 333aed25f87c5820bec8a7f82d7959ff87a9a502 34 | 35 | CONFIGURE_COMMAND "" 36 | BUILD_COMMAND "" 37 | INSTALL_COMMAND "" 38 | LOG_DOWNLOAD ON 39 | ) 40 | endif() -------------------------------------------------------------------------------- /cmake/recipes/CPM.cmake: -------------------------------------------------------------------------------- 1 | set(CPM_DOWNLOAD_VERSION 0.40.2) 2 | 3 | if(CPM_SOURCE_CACHE) 4 | set(CPM_DOWNLOAD_LOCATION "${CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 5 | elseif(DEFINED ENV{CPM_SOURCE_CACHE}) 6 | set(CPM_DOWNLOAD_LOCATION "$ENV{CPM_SOURCE_CACHE}/cpm/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 7 | else() 8 | set(CPM_DOWNLOAD_LOCATION "${CMAKE_BINARY_DIR}/cmake/CPM_${CPM_DOWNLOAD_VERSION}.cmake") 9 | endif() 10 | 11 | # Expand relative path. This is important if the provided path contains a tilde (~) 12 | get_filename_component(CPM_DOWNLOAD_LOCATION ${CPM_DOWNLOAD_LOCATION} ABSOLUTE) 13 | 14 | function(download_cpm) 15 | message(STATUS "Downloading CPM.cmake to ${CPM_DOWNLOAD_LOCATION}") 16 | file(DOWNLOAD 17 | https://github.com/cpm-cmake/CPM.cmake/releases/download/v${CPM_DOWNLOAD_VERSION}/CPM.cmake 18 | ${CPM_DOWNLOAD_LOCATION} 19 | ) 20 | endfunction() 21 | 22 | if(NOT (EXISTS ${CPM_DOWNLOAD_LOCATION})) 23 | download_cpm() 24 | else() 25 | # resume download if it previously failed 26 | file(READ ${CPM_DOWNLOAD_LOCATION} check) 27 | if("${check}" STREQUAL "") 28 | download_cpm() 29 | endif() 30 | unset(check) 31 | endif() 32 | 33 | include(${CPM_DOWNLOAD_LOCATION}) 34 | -------------------------------------------------------------------------------- /cmake/recipes/abseil.cmake: -------------------------------------------------------------------------------- 1 | # Abseil (https://github.com/abseil/abseil-cpp) 2 | # License: Apache 2.0 3 | if(TARGET absl::flat_hash_map) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'absl::flat_hash_map'") 8 | 9 | option(ABSL_PROPAGATE_CXX_STD "Use CMake C++ standard meta features (e.g. cxx_std_11) that propagate to targets that link to Abseil" ON) 10 | option(ABSL_USE_SYSTEM_INCLUDES "Silence warnings in Abseil headers by marking them as SYSTEM includes" ON) 11 | option(ABSL_BUILD_TESTING "If ON, Abseil will build all of Abseil's own tests." OFF) 12 | set(ABSL_IDE_FOLDER "ThirdParty/Abseil") 13 | 14 | include(CPM) 15 | CPMAddPackage("gh:abseil/abseil-cpp#20230125.3") -------------------------------------------------------------------------------- /cmake/recipes/catch2.cmake: -------------------------------------------------------------------------------- 1 | # Catch2 (https://github.com/catchorg/Catch2) 2 | # License: BSL-1.0 3 | if(TARGET Catch2::Catch2) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'Catch2::Catch2'") 8 | 9 | option(CATCH_CONFIG_CPP17_STRING_VIEW "Enable support for std::string_view" ON) 10 | option(CATCH_INSTALL_DOCS "Install documentation alongside library" OFF) 11 | option(CATCH_INSTALL_EXTRAS "Install extras alongside library" OFF) 12 | 13 | include(CPM) 14 | CPMAddPackage("gh:catchorg/Catch2@3.8.1") 15 | 16 | # Folder name for IDE 17 | set_target_properties(Catch2 PROPERTIES FOLDER "ThirdParty/Catch2") 18 | set_target_properties(Catch2WithMain PROPERTIES FOLDER "ThirdParty/Catch2") -------------------------------------------------------------------------------- /cmake/recipes/ccd_query_io.cmake: -------------------------------------------------------------------------------- 1 | # CCD Query IO (https://github.com/Continuous-Collision-Detection/CCD-Query-IO) 2 | # License: MIT 3 | if(TARGET ccd_io::ccd_io) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'ccd_io::ccd_io'") 8 | 9 | include(ipc_toolkit_tests_data) 10 | 11 | set(CCD_IO_DOWNLOAD_SAMPLE_QUERIES ON CACHE BOOL "Download sample CCD queries" FORCE) 12 | set(CCD_IO_SAMPLE_QUERIES_DIR "${IPC_TOOLKIT_TESTS_DATA_DIR}/ccd-queries/" CACHE PATH "Where should we download sample queries?") 13 | 14 | include(CPM) 15 | CPMAddPackage("gh:Continuous-Collision-Detection/CCD-Query-IO#36f6093af81a65acc27d9f05ad32d6b5729e8d15") -------------------------------------------------------------------------------- /cmake/recipes/evouga_ccd.cmake: -------------------------------------------------------------------------------- 1 | # Etienne Vouga's CCD Library (https://github.com/evouga/collisiondetection.git) 2 | # License: ??? 3 | if(TARGET evouga::ccd) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'evouga::ccd'") 8 | 9 | include(CPM) 10 | CPMAddPackage( 11 | NAME evccd 12 | GITHUB_REPOSITORY evouga/collisiondetection 13 | GIT_TAG e5fe5c9767207df5047e375fb20180a665ae186f 14 | DOWNLOAD_ONLY YES 15 | ) 16 | 17 | # file(GLOB EVOUGA_CCD_SOURCE_FILES "${evccd_SOURCE_DIR}/src/*.cpp") 18 | add_library(evouga_ccd 19 | "${evccd_SOURCE_DIR}/src/CTCD.cpp" 20 | ) 21 | add_library(evouga::ccd ALIAS evouga_ccd) 22 | 23 | target_include_directories(evouga_ccd PUBLIC "${evccd_SOURCE_DIR}/include") 24 | 25 | include(eigen) 26 | target_link_libraries(evouga_ccd PUBLIC Eigen3::Eigen) 27 | 28 | # Turn off floating point contraction for CCD robustness 29 | target_compile_options(evouga_ccd PRIVATE "-ffp-contract=off") 30 | 31 | # Folder name for IDE 32 | set_target_properties(evouga_ccd PROPERTIES FOLDER "ThirdParty") -------------------------------------------------------------------------------- /cmake/recipes/filib.cmake: -------------------------------------------------------------------------------- 1 | # filib (https://github.com/zfergus/filib.git) 2 | # License: LGPL-2.1 3 | if(TARGET filib::filib) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'filib::filib'") 8 | 9 | # NOTE: filib should be built as a shared library to avoid licensing IPC Toolkit under LGPL 10 | # However, Setting up proper linkage is a bit tricky, so we'll just use a static library by 11 | # default and provide instructions on how to build as a shared library in the README. 12 | option(FILIB_BUILD_SHARED_LIB "Build shared library" OFF) 13 | 14 | include(CPM) 15 | CPMAddPackage("gh:zfergus/filib#7cf13519b0db72df2493c9c8997a8bef9e372848") 16 | 17 | # Folder name for IDE 18 | set_target_properties(filib PROPERTIES FOLDER "ThirdParty") -------------------------------------------------------------------------------- /cmake/recipes/finite_diff.cmake: -------------------------------------------------------------------------------- 1 | # finite-diff (https://github.com/zfergus/finite-diff) 2 | # License: MIT 3 | if(TARGET finitediff::finitediff) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'finitediff::finitediff'") 8 | 9 | include(CPM) 10 | CPMAddPackage("gh:zfergus/finite-diff@1.0.1") 11 | 12 | # Folder name for IDE 13 | set_target_properties(finitediff_finitediff PROPERTIES FOLDER "ThirdParty") -------------------------------------------------------------------------------- /cmake/recipes/json.cmake: -------------------------------------------------------------------------------- 1 | # Nlohmann's JSON (https://github.com/nlohmann/json) 2 | # License: MIT 3 | if(TARGET nlohmann_json::nlohmann_json) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'nlohmann_json::nlohmann_json'") 8 | 9 | # nlohmann_json is a big repo for a single header, so we just download the release archive 10 | set(NLOHMANNJSON_VERSION "v3.11.2") 11 | 12 | include(CPM) 13 | CPMAddPackage( 14 | NAME nlohmann_json 15 | URL "https://github.com/nlohmann/json/releases/download/${NLOHMANNJSON_VERSION}/include.zip" 16 | URL_HASH SHA256=e5c7a9f49a16814be27e4ed0ee900ecd0092bfb7dbfca65b5a421b774dccaaed 17 | DOWNLOAD_ONLY YES 18 | ) 19 | 20 | add_library(nlohmann_json INTERFACE) 21 | add_library(nlohmann_json::nlohmann_json ALIAS nlohmann_json) 22 | 23 | include(GNUInstallDirs) 24 | target_include_directories(nlohmann_json SYSTEM INTERFACE 25 | "$/include" 26 | "$" 27 | ) 28 | 29 | # Install rules 30 | set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME nlohmann_json) 31 | install(DIRECTORY ${nlohmann_json_SOURCE_DIR}/include/nlohmann DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) 32 | install(TARGETS nlohmann_json EXPORT NlohmannJson_Targets) 33 | install(EXPORT NlohmannJson_Targets DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/nlohmann_json NAMESPACE nlohmann_json::) 34 | export(EXPORT NlohmannJson_Targets FILE "${CMAKE_CURRENT_BINARY_DIR}/NlohmannJsonTargets.cmake") -------------------------------------------------------------------------------- /cmake/recipes/libigl.cmake: -------------------------------------------------------------------------------- 1 | # libigl (https://github.com/libigl/libigl) 2 | # License: MPL-2.0 3 | if(TARGET igl::core) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'igl::core'") 8 | 9 | set(LIBIGL_PREDICATES ON CACHE BOOL "Use exact predicates" FORCE) 10 | 11 | include(eigen) 12 | 13 | include(CPM) 14 | CPMAddPackage("gh:libigl/libigl#89267b4a80b1904de3f6f2812a2053e5e9332b7e") 15 | 16 | # Folder name for IDE 17 | foreach(target_name IN ITEMS core predicates) 18 | set_target_properties(igl_${target_name} PROPERTIES FOLDER "ThirdParty/libigl") 19 | endforeach() 20 | -------------------------------------------------------------------------------- /cmake/recipes/pybind11.cmake: -------------------------------------------------------------------------------- 1 | # pybind11 (https://github.com/pybind/pybind11) 2 | # License: BSD-style 3 | if(TARGET pybind11::pybind11) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'pybind11::pybind11'") 8 | 9 | if (POLICY CMP0094) # https://cmake.org/cmake/help/latest/policy/CMP0094.html 10 | cmake_policy(SET CMP0094 NEW) # FindPython should return the first matching Python 11 | endif () 12 | 13 | # needed on GitHub Actions CI: actions/setup-python does not touch registry/frameworks on Windows/macOS 14 | # this mirrors PythonInterp behavior which did not consult registry/frameworks first 15 | if (NOT DEFINED Python_FIND_REGISTRY) 16 | set(Python_FIND_REGISTRY "LAST") 17 | endif () 18 | if (NOT DEFINED Python_FIND_FRAMEWORK) 19 | set(Python_FIND_FRAMEWORK "LAST") 20 | endif () 21 | 22 | include(CPM) 23 | CPMAddPackage("gh:pybind/pybind11@2.13.1") 24 | -------------------------------------------------------------------------------- /cmake/recipes/rational_cpp.cmake: -------------------------------------------------------------------------------- 1 | # rational-cpp (https://github.com/zfergus/rational-cpp) 2 | # License: MIT 3 | if(TARGET rational::rational) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'rational::rational'") 8 | 9 | include(CPM) 10 | CPMAddPackage("gh:zfergus/rational-cpp#687d4ea3436ada7231b8920f3cd5b02b438c21aa") -------------------------------------------------------------------------------- /cmake/recipes/robin_map.cmake: -------------------------------------------------------------------------------- 1 | # robin-map (https://github.com/Tessil/robin-map) 2 | # License: MIT 3 | if(TARGET tsl::robin_map) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'tsl::robin_map'") 8 | 9 | include(CPM) 10 | CPMAddPackage("gh:Tessil/robin-map@1.4.0") -------------------------------------------------------------------------------- /cmake/recipes/scalable_ccd.cmake: -------------------------------------------------------------------------------- 1 | # Scalable-CCD (https://github.com/continuous-collision-detection/scalable-ccd) 2 | # License: Apache 2.0 3 | if(TARGET scalable_ccd::scalable_ccd) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'scalable_ccd::scalable_ccd'") 8 | 9 | set(SCALABLE_CCD_WITH_CUDA ${IPC_TOOLKIT_WITH_CUDA} CACHE BOOL "Enable CUDA CCD" FORCE) 10 | 11 | include(CPM) 12 | CPMAddPackage("gh:continuous-collision-detection/scalable-ccd#2c82b9ca43fba30b85f7e9aa83283464b1bb7843") 13 | 14 | # Folder name for IDE 15 | set_target_properties(scalable_ccd PROPERTIES FOLDER "ThirdParty") -------------------------------------------------------------------------------- /cmake/recipes/simple_bvh.cmake: -------------------------------------------------------------------------------- 1 | # BVH (https://github.com/geometryprocessing/SimpleBVH) 2 | # License: MIT 3 | 4 | if(TARGET simple_bvh::simple_bvh) 5 | return() 6 | endif() 7 | 8 | message(STATUS "Third-party: creating target 'simple_bvh::simple_bvh'") 9 | 10 | include(CPM) 11 | CPMAddPackage("gh:geometryprocessing/SimpleBVH#e1a931337a9e07e8bd2d2e8bbdfd7e54bc850df5") 12 | 13 | # Folder name for IDE 14 | set_target_properties(simple_bvh PROPERTIES FOLDER "ThirdParty") -------------------------------------------------------------------------------- /cmake/recipes/spdlog.cmake: -------------------------------------------------------------------------------- 1 | # spdlog (https://github.com/gabime/spdlog) 2 | # License: MIT 3 | if(TARGET spdlog::spdlog) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'spdlog::spdlog'") 8 | 9 | option(SPDLOG_INSTALL "Generate the install target" ON) 10 | set(CMAKE_INSTALL_DEFAULT_COMPONENT_NAME "spdlog") 11 | 12 | include(CPM) 13 | CPMAddPackage("gh:gabime/spdlog@1.11.0") 14 | 15 | set_target_properties(spdlog PROPERTIES POSITION_INDEPENDENT_CODE ON) 16 | 17 | # Folder name for IDE 18 | set_target_properties(spdlog PROPERTIES FOLDER "ThirdParty") 19 | 20 | if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang" OR 21 | "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") 22 | target_compile_options(spdlog PRIVATE 23 | "-Wno-sign-conversion" 24 | ) 25 | endif() 26 | -------------------------------------------------------------------------------- /cmake/recipes/tight_inclusion.cmake: -------------------------------------------------------------------------------- 1 | # Tight Inclusion (https://github.com/Continuous-Collision-Detection/Tight-Inclusion) 2 | # License: MIT 3 | if(TARGET tight_inclusion::tight_inclusion) 4 | return() 5 | endif() 6 | 7 | message(STATUS "Third-party: creating target 'tight_inclusion::tight_inclusion'") 8 | 9 | include(CPM) 10 | CPMAddPackage("gh:Continuous-Collision-Detection/Tight-Inclusion@1.0.6") 11 | 12 | # Folder name for IDE 13 | set_target_properties(tight_inclusion PROPERTIES FOLDER "ThirdParty") -------------------------------------------------------------------------------- /codecov.yml: -------------------------------------------------------------------------------- 1 | coverage: 2 | status: 3 | project: 4 | default: 5 | target: auto 6 | threshold: 1% 7 | patch: 8 | default: 9 | target: 75% 10 | threshold: 5% 11 | only_pulls: true 12 | ignore: 13 | - "tests/*" 14 | -------------------------------------------------------------------------------- /docs/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are welcome, and they are greatly appreciated! Every 4 | little bit helps, and credit will always be given. 5 | 6 | ## Types of Contributions 7 | 8 | ### Report Bugs 9 | 10 | Report bugs at . 11 | 12 | If you are reporting a bug, please include: 13 | 14 | * Your operating system name and version. 15 | * Your compiler name and version. 16 | * Any details about your local setup that might be helpful in troubleshooting. 17 | * Detailed steps to reproduce the bug. 18 | 19 | ### Fix Bugs 20 | 21 | Look through the GitHub issues for bugs. Anything tagged with "bug" 22 | and "help wanted" is open to whoever wants to implement it. 23 | 24 | ### Implement Features 25 | 26 | Look through the GitHub issues for features. Anything tagged with "enhancement" 27 | and "help wanted" is open to whoever wants to implement it. Those that are 28 | tagged with "first-timers-only" is suitable for those getting started in open-source software. 29 | 30 | ### Write Documentation 31 | 32 | IPC Toolkit could always use more documentation, whether as part of the 33 | official docs, in code comments, or even on the web in blog posts, articles, 34 | and such. 35 | 36 | ### Submit Feedback 37 | 38 | The best way to send feedback is to file an issue at . 39 | 40 | If you are proposing a feature: 41 | 42 | * Explain in detail how it would work. 43 | * Keep the scope as narrow as possible, to make it easier to implement. 44 | * Remember that this is a volunteer-driven project, and that contributions 45 | are welcome :) 46 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile clean 16 | 17 | clean: 18 | rm -rf source/api/ 19 | @$(SPHINXBUILD) -M clean "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 20 | 21 | # Catch-all target: route all unknown targets to Sphinx using the new 22 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 23 | %: Makefile 24 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 25 | 26 | livehtml: 27 | sphinx-autobuild --host 0.0.0.0 "$(SOURCEDIR)" "$(BUILDDIR)/html" $(SPHINXOPTS) $(O) 28 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | if "%1" == "" goto help 14 | 15 | %SPHINXBUILD% >NUL 2>NUL 16 | if errorlevel 9009 ( 17 | echo. 18 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 19 | echo.installed, then set the SPHINXBUILD environment variable to point 20 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 21 | echo.may add the Sphinx directory to PATH. 22 | echo. 23 | echo.If you don't have Sphinx installed, grab it from 24 | echo.http://sphinx-doc.org/ 25 | exit /b 1 26 | ) 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | sphinx 2 | sphinx-sitemap 3 | sphinx-immaterial 4 | autoclasstoc 5 | # sphinx-autodoc-toolbox 6 | breathe 7 | nbsphinx 8 | pandoc 9 | myst_parser 10 | sphinxcontrib-bibtex 11 | sphinxemoji 12 | sphinx-last-updated-by-git 13 | sphinx-autobuild -------------------------------------------------------------------------------- /docs/source/_static/css/custom.css: -------------------------------------------------------------------------------- 1 | .md-grid { 2 | max-width: max(1250px, 75vw) !important; 3 | } 4 | 5 | span.colon { 6 | margin-left: -1em; 7 | } 8 | 9 | dl.cpp.objdesc, 10 | dl.py.objdesc { 11 | /* border: 0.05rem solid var(--md-primary-fg-color); */ 12 | border: 0.05rem solid rgb(68, 138, 255); 13 | box-shadow: var(--md-shadow-z1); 14 | border-radius: 0.4rem; 15 | overflow: hidden; 16 | } 17 | 18 | dl.cpp.objdesc>dt, 19 | dl.py.objdesc>dt { 20 | padding-left: 0.5rem; 21 | padding-right: 0.5rem; 22 | } 23 | 24 | dl.cpp.objdesc>dd, 25 | dl.py.objdesc>dd { 26 | margin: 0 1.875em; 27 | } 28 | 29 | dl.py.objdesc>dd>details.toggle-details { 30 | border: 0.05rem solid var(--md-primary-fg-color); 31 | box-shadow: var(--md-shadow-z1); 32 | border-radius: 0.4rem; 33 | overflow: hidden; 34 | } 35 | 36 | dl.py.objdesc>dd>details.toggle-details>summary { 37 | border: 0; 38 | font-size: 0.8rem; 39 | } 40 | 41 | dl.py.objdesc>dd>details.toggle-details>summary::before, 42 | dl.py.objdesc>dd>details.toggle-details>summary::after { 43 | background-color: var(--md-primary-fg-color--light); 44 | /* background-color: currentcolor; */ 45 | top: auto; 46 | } 47 | 48 | dl.py.objdesc>dd>details.toggle-details>summary>svg.tb-icon { 49 | display: none; 50 | } 51 | 52 | table.autosummary { 53 | font-size: 0.75rem !important; 54 | } 55 | 56 | /* .breatheparameterlist li tt + p { 57 | display: inline; 58 | } 59 | 60 | dd.field-odd { 61 | padding: 0 !important;; 62 | margin: 0 !important;; 63 | } 64 | 65 | dl.api-field { 66 | width: 100%; 67 | overflow: hidden; 68 | } 69 | 70 | dl.api-field > dt { 71 | float: left; 72 | width: 60%; 73 | padding: 0; 74 | margin: 10px; 75 | } 76 | 77 | dl.api-field > dd { 78 | float: left; 79 | width: calc(40%-10px); 80 | padding: 0 !important; 81 | margin: 0 !important; 82 | } 83 | 84 | dl.api-field > dd > p { 85 | padding: 0 !important; 86 | margin: 0 !important; 87 | } */ -------------------------------------------------------------------------------- /docs/source/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipc-sim/ipc-toolkit/3ce57050ed2570dba48301e5241ae0ad9ba88023/docs/source/_static/favicon.ico -------------------------------------------------------------------------------- /docs/source/_static/hammer-wrench.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/source/_static/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipc-sim/ipc-toolkit/3ce57050ed2570dba48301e5241ae0ad9ba88023/docs/source/_static/logo.png -------------------------------------------------------------------------------- /docs/source/_static/versions.json: -------------------------------------------------------------------------------- 1 | [{ 2 | "version": "https://ipctk.xyz", 3 | "title": "main", 4 | "aliases": ["latest", "head"] 5 | }, { 6 | "version": "https://ipctk.xyz/v1.3.1", 7 | "title": "v1.3.1", 8 | "aliases": ["stable"] 9 | }, { 10 | "version": "https://ipctk.xyz/v1.3.0", 11 | "title": "v1.3.0" 12 | }, { 13 | "version": "https://ipctk.xyz/v1.2.1", 14 | "title": "v1.2.1" 15 | }, { 16 | "version": "https://ipctk.xyz/v1.2.0", 17 | "title": "v1.2.0" 18 | }, { 19 | "version": "https://ipctk.xyz/v1.1.1", 20 | "title": "v1.1.1" 21 | }, { 22 | "version": "https://ipctk.xyz/v1.1.0", 23 | "title": "v1.1.0" 24 | }, { 25 | "version": "https://ipctk.xyz/v1.0.0", 26 | "title": "v1.0.0" 27 | }] -------------------------------------------------------------------------------- /docs/source/_templates/404.html: -------------------------------------------------------------------------------- 1 | {% extends '!layout.html' %} 2 | 3 | {% block content %} 4 |
5 |

404: File not found!

6 |
7 | {% endblock %} -------------------------------------------------------------------------------- /docs/source/code_of_conduct.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CODE_OF_CONDUCT.md 2 | :parser: myst_parser.sphinx_ -------------------------------------------------------------------------------- /docs/source/contributing.rst: -------------------------------------------------------------------------------- 1 | .. include:: ../CONTRIBUTING.md 2 | :parser: myst_parser.sphinx_ -------------------------------------------------------------------------------- /docs/source/cpp-api/adhesion.rst: -------------------------------------------------------------------------------- 1 | Adhesion 2 | ======== 3 | 4 | Normal Adhesion Potential 5 | ------------------------- 6 | 7 | .. doxygenfunction:: normal_adhesion_potential 8 | .. doxygenfunction:: normal_adhesion_potential_first_derivative 9 | .. doxygenfunction:: normal_adhesion_potential_second_derivative 10 | .. doxygenfunction:: max_normal_adhesion_force_magnitude 11 | 12 | Tangential Adhesion Potential 13 | ----------------------------- 14 | 15 | .. doxygenfunction:: tangential_adhesion_f0 16 | .. doxygenfunction:: tangential_adhesion_f1 17 | .. doxygenfunction:: tangential_adhesion_f2 18 | .. doxygenfunction:: tangential_adhesion_f1_over_x 19 | .. doxygenfunction:: tangential_adhesion_f2_x_minus_f1_over_x3 -------------------------------------------------------------------------------- /docs/source/cpp-api/barrier.rst: -------------------------------------------------------------------------------- 1 | Barrier 2 | ======= 3 | 4 | .. doxygenfunction:: barrier(const double, const double) 5 | .. doxygenfunction:: barrier_first_derivative 6 | .. doxygenfunction:: barrier_second_derivative 7 | 8 | Barrier Force Magnitude 9 | ----------------------- 10 | 11 | .. doxygenfunction:: barrier_force_magnitude 12 | .. doxygenfunction:: barrier_force_magnitude_gradient 13 | 14 | Adaptive Barrier Stiffness 15 | -------------------------- 16 | 17 | .. doxygenfunction:: ipc::initial_barrier_stiffness 18 | .. doxygenfunction:: ipc::update_barrier_stiffness 19 | 20 | Semi-Implicit Stiffness 21 | ~~~~~~~~~~~~~~~~~~~~~~~ 22 | 23 | .. doxygenfunction:: ipc::semi_implicit_stiffness(const CollisionMesh&, const Eigen::MatrixXd&, const StencilsT&, const Eigen::VectorXd&, const Eigen::SparseMatrix&, const double) 24 | 25 | Barrier Class 26 | ------------- 27 | 28 | .. doxygenclass:: ipc::Barrier 29 | :allow-dot-graphs: 30 | 31 | Clamped Log Barrier 32 | ~~~~~~~~~~~~~~~~~~~ 33 | 34 | .. doxygenclass:: ipc::ClampedLogBarrier 35 | :allow-dot-graphs: 36 | 37 | Normalized Clamped Log Barrier 38 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 39 | 40 | .. doxygenclass:: ipc::NormalizedClampedLogBarrier 41 | :allow-dot-graphs: 42 | 43 | Clamped Log Squared Barrier 44 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 45 | 46 | .. doxygenclass:: ipc::ClampedLogSqBarrier 47 | :allow-dot-graphs: 48 | 49 | Cubic Barrier 50 | ~~~~~~~~~~~~~ 51 | 52 | .. doxygenclass:: ipc::CubicBarrier 53 | :allow-dot-graphs: -------------------------------------------------------------------------------- /docs/source/cpp-api/broad_phase.rst: -------------------------------------------------------------------------------- 1 | Broad Phase 2 | =========== 3 | 4 | Broad Phase 5 | ----------- 6 | 7 | .. doxygenclass:: ipc::BroadPhase 8 | :allow-dot-graphs: 9 | 10 | Brute Force 11 | ----------- 12 | 13 | .. doxygenclass:: ipc::BruteForce 14 | :allow-dot-graphs: 15 | 16 | Hash Grid 17 | --------- 18 | 19 | .. doxygenclass:: ipc::HashGrid 20 | :allow-dot-graphs: 21 | 22 | Spatial Hash 23 | ------------ 24 | 25 | .. doxygenclass:: ipc::SpatialHash 26 | :allow-dot-graphs: 27 | 28 | BVH 29 | --- 30 | 31 | .. doxygenclass:: ipc::BVH 32 | :allow-dot-graphs: 33 | 34 | Sweep and Prune 35 | ----------------------- 36 | 37 | .. doxygenclass:: ipc::SweepAndPrune 38 | :allow-dot-graphs: 39 | 40 | Sweep and Tiniest Queue 41 | ----------------------- 42 | 43 | .. .. doxygenclass:: ipc::SweepAndTiniestQueueGPU 44 | 45 | AABB 46 | ---- 47 | 48 | .. doxygenclass:: ipc::AABB 49 | :allow-dot-graphs: -------------------------------------------------------------------------------- /docs/source/cpp-api/candidates.rst: -------------------------------------------------------------------------------- 1 | Candidates 2 | ========== 3 | 4 | Candidates 5 | ---------- 6 | 7 | .. doxygenclass:: ipc::Candidates 8 | :allow-dot-graphs: 9 | 10 | Collision Stencil 11 | ----------------- 12 | 13 | .. doxygenclass:: ipc::CollisionStencil 14 | :allow-dot-graphs: 15 | 16 | 17 | Vertex-Vertex Candidate 18 | ----------------------- 19 | 20 | .. doxygenclass:: ipc::VertexVertexCandidate 21 | :allow-dot-graphs: 22 | 23 | 24 | Edge-Vertex Candidate 25 | --------------------- 26 | 27 | .. doxygenclass:: ipc::EdgeVertexCandidate 28 | :allow-dot-graphs: 29 | 30 | 31 | Edge-Edge Candidate 32 | ------------------- 33 | 34 | .. doxygenclass:: ipc::EdgeEdgeCandidate 35 | :allow-dot-graphs: 36 | 37 | 38 | Edge-Face Candidate 39 | ------------------- 40 | 41 | .. doxygenclass:: ipc::EdgeFaceCandidate 42 | :allow-dot-graphs: 43 | 44 | Face-Vertex Candidate 45 | --------------------- 46 | 47 | .. doxygenclass:: ipc::FaceVertexCandidate 48 | :allow-dot-graphs: -------------------------------------------------------------------------------- /docs/source/cpp-api/ccd.rst: -------------------------------------------------------------------------------- 1 | Continuous Collision Detection 2 | ============================== 3 | 4 | .. doxygenfunction:: ipc::is_step_collision_free 5 | 6 | .. doxygenfunction:: ipc::compute_collision_free_stepsize 7 | 8 | Narrow Phase CCD 9 | ---------------- 10 | 11 | .. doxygenclass:: ipc::NarrowPhaseCCD 12 | :allow-dot-graphs: 13 | 14 | Tight Inclusion CCD 15 | ^^^^^^^^^^^^^^^^^^^ 16 | 17 | .. doxygenclass:: ipc::TightInclusionCCD 18 | :allow-dot-graphs: 19 | 20 | Additive CCD 21 | ^^^^^^^^^^^^ 22 | 23 | .. doxygenclass:: ipc::AdditiveCCD 24 | :allow-dot-graphs: 25 | 26 | Inexact CCD 27 | ^^^^^^^^^^^ 28 | 29 | .. note:: 30 | This method is disabled by default. To enable it, set the 31 | ``IPC_TOOLKIT_WITH_INEXACT_CCD`` CMake option to ``ON``. 32 | 33 | .. .. doxygenclass:: ipc::InexactCCD 34 | .. :allow-dot-graphs: 35 | 36 | .. doxygenfunction:: ipc::inexact_point_edge_ccd_2D 37 | 38 | Nonlinear CCD 39 | ------------- 40 | 41 | .. doxygenclass:: ipc::NonlinearTrajectory 42 | :allow-dot-graphs: 43 | 44 | .. doxygenclass:: ipc::IntervalNonlinearTrajectory 45 | :allow-dot-graphs: 46 | 47 | 48 | .. doxygenfunction:: ipc::point_point_nonlinear_ccd 49 | .. doxygenfunction:: ipc::point_edge_nonlinear_ccd 50 | .. doxygenfunction:: ipc::edge_edge_nonlinear_ccd 51 | .. doxygenfunction:: ipc::point_triangle_nonlinear_ccd 52 | 53 | Generic Interface 54 | ^^^^^^^^^^^^^^^^^ 55 | 56 | .. doxygenfunction:: ipc::conservative_piecewise_linear_ccd 57 | 58 | Miscellaneous 59 | ------------- 60 | 61 | .. doxygenfunction:: ipc::point_static_plane_ccd -------------------------------------------------------------------------------- /docs/source/cpp-api/collision_mesh.rst: -------------------------------------------------------------------------------- 1 | Collision Mesh 2 | ============== 3 | 4 | .. doxygenclass:: ipc::CollisionMesh 5 | :allow-dot-graphs: -------------------------------------------------------------------------------- /docs/source/cpp-api/friction.rst: -------------------------------------------------------------------------------- 1 | Friction 2 | ======== 3 | 4 | Smooth Mollifier 5 | ---------------- 6 | 7 | .. doxygenfunction:: smooth_friction_f0 8 | .. doxygenfunction:: smooth_friction_f1 9 | .. doxygenfunction:: smooth_friction_f2 10 | .. doxygenfunction:: smooth_friction_f1_over_x 11 | .. doxygenfunction:: smooth_friction_f2_x_minus_f1_over_x3 -------------------------------------------------------------------------------- /docs/source/cpp-api/intersections.rst: -------------------------------------------------------------------------------- 1 | Intersections 2 | ============= 3 | 4 | .. doxygenfunction:: ipc::has_intersections 5 | .. doxygenfunction:: ipc::is_edge_intersecting_triangle -------------------------------------------------------------------------------- /docs/source/cpp-api/interval.rst: -------------------------------------------------------------------------------- 1 | Interval Arithmetic 2 | =================== 3 | 4 | For interval arithmetic, we use the `Filib `_ library. 5 | 6 | .. doxygenclass:: filib::Interval 7 | 8 | Helper Functions 9 | ---------------- 10 | 11 | .. doxygenfunction:: ipc::norm 12 | .. doxygenfunction:: ipc::squared_norm 13 | 14 | Type Definitions 15 | ---------------- 16 | 17 | .. doxygentypedef:: ipc::Vector2I 18 | .. doxygentypedef:: ipc::Vector3I 19 | .. doxygentypedef:: ipc::VectorXI 20 | 21 | .. doxygentypedef:: ipc::RowVector2I 22 | .. doxygentypedef:: ipc::RowVector3I 23 | .. doxygentypedef:: ipc::RowVectorXI 24 | 25 | .. doxygentypedef:: ipc::Matrix2I 26 | .. doxygentypedef:: ipc::Matrix3I 27 | .. doxygentypedef:: ipc::MatrixXI 28 | 29 | .. doxygentypedef:: ipc::VectorMax3I 30 | .. doxygentypedef:: ipc::RowVectorMax3I 31 | .. doxygentypedef:: ipc::MatrixMax3I -------------------------------------------------------------------------------- /docs/source/cpp-api/normal_collisions.rst: -------------------------------------------------------------------------------- 1 | Normal Collisions 2 | ================= 3 | 4 | Normal Collisions 5 | ----------------- 6 | 7 | .. doxygenclass:: ipc::NormalCollisions 8 | :allow-dot-graphs: 9 | 10 | Normal Collision 11 | ---------------- 12 | 13 | .. doxygenclass:: ipc::NormalCollision 14 | :allow-dot-graphs: 15 | 16 | Vertex-Vertex Normal Collision 17 | ------------------------------ 18 | 19 | .. doxygenclass:: ipc::VertexVertexNormalCollision 20 | :allow-dot-graphs: 21 | 22 | Edge-Vertex Normal Collision 23 | ---------------------------- 24 | 25 | .. doxygenclass:: ipc::EdgeVertexNormalCollision 26 | :allow-dot-graphs: 27 | 28 | Edge-Edge Normal Collision 29 | -------------------------- 30 | 31 | .. doxygenclass:: ipc::EdgeEdgeNormalCollision 32 | :allow-dot-graphs: 33 | 34 | Face-Vertex Normal Collision 35 | ---------------------------- 36 | 37 | .. doxygenclass:: ipc::FaceVertexNormalCollision 38 | :allow-dot-graphs: 39 | 40 | Plane-Vertex Normal Collision 41 | ----------------------------- 42 | 43 | .. doxygenclass:: ipc::PlaneVertexNormalCollision 44 | :allow-dot-graphs: -------------------------------------------------------------------------------- /docs/source/cpp-api/potentials.rst: -------------------------------------------------------------------------------- 1 | Potentials 2 | ========== 3 | 4 | Generic Potential 5 | ----------------- 6 | 7 | .. doxygenclass:: ipc::Potential 8 | :allow-dot-graphs: 9 | 10 | Normal Potentials 11 | ----------------- 12 | 13 | .. doxygenclass:: ipc::NormalPotential 14 | :allow-dot-graphs: 15 | 16 | Barrier Potential 17 | ^^^^^^^^^^^^^^^^^ 18 | 19 | .. doxygenclass:: ipc::BarrierPotential 20 | :allow-dot-graphs: 21 | 22 | Normal Adhesion Potential 23 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 24 | 25 | .. doxygenclass:: ipc::NormalAdhesionPotential 26 | :allow-dot-graphs: 27 | 28 | Tangential Potentials 29 | --------------------- 30 | 31 | .. doxygenclass:: ipc::TangentialPotential 32 | :allow-dot-graphs: 33 | 34 | Friction Potential 35 | ^^^^^^^^^^^^^^^^^^ 36 | 37 | .. doxygenclass:: ipc::FrictionPotential 38 | :allow-dot-graphs: 39 | 40 | Tangential Adhesion Potential 41 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 42 | 43 | .. doxygenclass:: ipc::TangentialAdhesionPotential 44 | :allow-dot-graphs: -------------------------------------------------------------------------------- /docs/source/cpp-api/tangential_collisions.rst: -------------------------------------------------------------------------------- 1 | Tangential Collisions 2 | ===================== 3 | 4 | .. doxygenclass:: ipc::TangentialCollisions 5 | :allow-dot-graphs: 6 | 7 | Tangential Collision 8 | -------------------- 9 | 10 | .. doxygenclass:: ipc::TangentialCollision 11 | :allow-dot-graphs: 12 | 13 | Vertex-Vertex Tangential Collision 14 | ---------------------------------- 15 | 16 | .. doxygenclass:: ipc::VertexVertexTangentialCollision 17 | :allow-dot-graphs: 18 | 19 | Edge-Vertex Tangential Collision 20 | -------------------------------- 21 | 22 | .. doxygenclass:: ipc::EdgeVertexTangentialCollision 23 | :allow-dot-graphs: 24 | 25 | Edge-Edge Tangential Collision 26 | ------------------------------ 27 | 28 | .. doxygenclass:: ipc::EdgeEdgeTangentialCollision 29 | :allow-dot-graphs: 30 | 31 | Face-Vertex Tangential Collision 32 | -------------------------------- 33 | 34 | .. doxygenclass:: ipc::FaceVertexTangentialCollision 35 | :allow-dot-graphs: -------------------------------------------------------------------------------- /docs/source/cpp-api/utils.rst: -------------------------------------------------------------------------------- 1 | Utils 2 | ===== 3 | 4 | Logger 5 | ------ 6 | 7 | .. doxygenfunction:: ipc::logger 8 | .. doxygenfunction:: ipc::set_logger 9 | 10 | Positive Semi-Definite Projection 11 | --------------------------------- 12 | 13 | .. doxygenfunction:: ipc::project_to_psd 14 | .. doxygenfunction:: ipc::project_to_pd 15 | 16 | .. doxygenenum:: ipc::PSDProjectionMethod -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | .. toctree:: 2 | :caption: General 3 | :hidden: 4 | 5 | Home 6 | changelog.rst 7 | license.rst 8 | 9 | .. toctree:: 10 | :caption: Tutorial 11 | :hidden: 12 | 13 | tutorial/getting_started.rst 14 | tutorial/convergent.rst 15 | tutorial/nonlinear_ccd.rst 16 | tutorial/adhesion.rst 17 | tutorial/simulation.rst 18 | tutorial/misc.rst 19 | tutorial/faq.rst 20 | tutorial/references.rst 21 | 22 | .. toctree:: 23 | :caption: C++ 24 | :hidden: 25 | 26 | Getting Started 27 | cpp-api/potentials.rst 28 | cpp-api/collision_mesh.rst 29 | cpp-api/candidates.rst 30 | cpp-api/normal_collisions.rst 31 | cpp-api/tangential_collisions.rst 32 | cpp-api/friction.rst 33 | cpp-api/broad_phase.rst 34 | cpp-api/ccd.rst 35 | cpp-api/distance.rst 36 | cpp-api/tangent.rst 37 | cpp-api/barrier.rst 38 | cpp-api/adhesion.rst 39 | cpp-api/intersections.rst 40 | cpp-api/interval.rst 41 | cpp-api/utils.rst 42 | 43 | .. toctree:: 44 | :caption: Python 45 | :hidden: 46 | 47 | Getting Started 48 | python-api/potentials.rst 49 | python-api/collision_mesh.rst 50 | python-api/candidates.rst 51 | python-api/normal_collisions.rst 52 | python-api/tangential_collisions.rst 53 | python-api/friction.rst 54 | python-api/broad_phase.rst 55 | python-api/ccd.rst 56 | python-api/distance.rst 57 | python-api/tangent.rst 58 | python-api/barrier.rst 59 | python-api/adhesion.rst 60 | python-api/intersections.rst 61 | python-api/interval.rst 62 | python-api/utils.rst 63 | 64 | .. toctree:: 65 | :caption: Developers 66 | :hidden: 67 | 68 | contributing 69 | style_guide 70 | Code of Conduct 71 | 72 | Home 73 | ==== 74 | 75 | .. image:: _static/logo.png 76 | :alt: IPC Toolkit 77 | 78 | .. include:: ../../README.md 79 | :parser: myst_parser.sphinx_ 80 | :start-line: 4 81 | -------------------------------------------------------------------------------- /docs/source/license.rst: -------------------------------------------------------------------------------- 1 | 2 | License 3 | ======= 4 | 5 | .. literalinclude:: ../../LICENSE 6 | :language: md -------------------------------------------------------------------------------- /docs/source/python-api/adhesion.rst: -------------------------------------------------------------------------------- 1 | Adhesion 2 | ======== 3 | 4 | Normal Adhesion Potential 5 | ------------------------- 6 | 7 | .. autofunction:: ipctk.normal_adhesion_potential 8 | .. autofunction:: ipctk.normal_adhesion_potential_first_derivative 9 | .. autofunction:: ipctk.normal_adhesion_potential_second_derivative 10 | .. autofunction:: ipctk.max_normal_adhesion_force_magnitude 11 | 12 | Tangential Adhesion Potential 13 | ----------------------------- 14 | 15 | .. autofunction:: ipctk.tangential_adhesion_f0 16 | .. autofunction:: ipctk.tangential_adhesion_f1 17 | .. autofunction:: ipctk.tangential_adhesion_f2 18 | .. autofunction:: ipctk.tangential_adhesion_f1_over_x 19 | .. autofunction:: ipctk.tangential_adhesion_f2_x_minus_f1_over_x3 -------------------------------------------------------------------------------- /docs/source/python-api/barrier.rst: -------------------------------------------------------------------------------- 1 | Barrier 2 | ======= 3 | 4 | .. autofunction:: ipctk.barrier 5 | .. autofunction:: ipctk.barrier_first_derivative 6 | .. autofunction:: ipctk.barrier_second_derivative 7 | 8 | Barrier Force Magnitude 9 | ----------------------- 10 | 11 | .. autofunction:: ipctk.barrier_force_magnitude 12 | .. autofunction:: ipctk.barrier_force_magnitude_gradient 13 | 14 | Adaptive Barrier Stiffness 15 | -------------------------- 16 | 17 | .. autofunction:: ipctk.initial_barrier_stiffness 18 | .. autofunction:: ipctk.update_barrier_stiffness 19 | 20 | 21 | Semi-Implicit Stiffness 22 | ~~~~~~~~~~~~~~~~~~~~~~~ 23 | 24 | .. autofunction:: ipctk.semi_implicit_stiffness 25 | 26 | Barrier Class 27 | ------------- 28 | 29 | .. autoclass:: ipctk.Barrier 30 | 31 | Clamped Log Barrier 32 | ~~~~~~~~~~~~~~~~~~~ 33 | 34 | .. autoclass:: ipctk.ClampedLogBarrier 35 | 36 | Normalized Clamped Log Barrier 37 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 38 | 39 | .. autoclass:: ipctk.NormalizedClampedLogBarrier 40 | 41 | Clamped Log Squared Barrier 42 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~ 43 | 44 | .. autoclass:: ipctk.ClampedLogSqBarrier 45 | 46 | Cubic Barrier 47 | ~~~~~~~~~~~~~ 48 | 49 | .. autoclass:: ipctk.CubicBarrier -------------------------------------------------------------------------------- /docs/source/python-api/broad_phase.rst: -------------------------------------------------------------------------------- 1 | Broad Phase 2 | =========== 3 | 4 | Broad Phase 5 | ----------- 6 | 7 | .. autoclass:: ipctk.BroadPhase 8 | 9 | .. autoclasstoc:: 10 | 11 | Brute Force 12 | ----------- 13 | 14 | .. autoclass:: ipctk.BruteForce 15 | 16 | .. autoclasstoc:: 17 | 18 | Hash Grid 19 | --------- 20 | 21 | .. autoclass:: ipctk.HashGrid 22 | 23 | .. autoclasstoc:: 24 | 25 | Spatial Hash 26 | ------------ 27 | 28 | .. autoclass:: ipctk.SpatialHash 29 | 30 | .. autoclasstoc:: 31 | 32 | BVH 33 | --- 34 | 35 | .. autoclass:: ipctk.BVH 36 | 37 | .. autoclasstoc:: 38 | 39 | Sweep and Prune 40 | --------------- 41 | 42 | .. autoclass:: ipctk.SweepAndPrune 43 | 44 | .. autoclasstoc:: 45 | 46 | Sweep and Tiniest Queue 47 | ----------------------- 48 | 49 | .. .. autoclass:: ipctk.SweepAndTiniestQueueGPU 50 | .. :members: 51 | 52 | AABB 53 | ---- 54 | 55 | .. autoclass:: ipctk.AABB 56 | 57 | .. autoclasstoc:: -------------------------------------------------------------------------------- /docs/source/python-api/candidates.rst: -------------------------------------------------------------------------------- 1 | Candidates 2 | ========== 3 | 4 | Candidates 5 | ---------- 6 | 7 | .. autoclass:: ipctk.Candidates 8 | 9 | .. autoclasstoc:: 10 | 11 | Collision Stencil 12 | ----------------- 13 | 14 | .. error:: 15 | This ``autoclass`` is not working. I don't know why. I have to investigate. 16 | 17 | .. .. autoclass:: ipctk.CollisionStencil 18 | 19 | Vertex-Vertex Candidate 20 | ----------------------- 21 | 22 | .. autoclass:: ipctk.VertexVertexCandidate 23 | 24 | .. autoclasstoc:: 25 | 26 | Edge-Vertex Candidate 27 | --------------------- 28 | 29 | .. autoclass:: ipctk.EdgeVertexCandidate 30 | 31 | .. autoclasstoc:: 32 | 33 | Edge-Edge Candidate 34 | ------------------- 35 | 36 | .. autoclass:: ipctk.EdgeEdgeCandidate 37 | 38 | .. autoclasstoc:: 39 | 40 | Edge-Face Candidate 41 | ------------------- 42 | 43 | .. autoclass:: ipctk.EdgeFaceCandidate 44 | 45 | .. autoclasstoc:: 46 | 47 | Face-Vertex Candidate 48 | --------------------- 49 | 50 | .. autoclass:: ipctk.FaceVertexCandidate 51 | 52 | .. autoclasstoc:: -------------------------------------------------------------------------------- /docs/source/python-api/ccd.rst: -------------------------------------------------------------------------------- 1 | Continuous Collision Detection 2 | ============================== 3 | 4 | .. autofunction:: ipctk.is_step_collision_free 5 | 6 | .. autofunction:: ipctk.compute_collision_free_stepsize 7 | 8 | Narrow Phase CCD 9 | ---------------- 10 | 11 | .. autoclass:: ipctk.NarrowPhaseCCD 12 | 13 | .. autoclasstoc:: 14 | 15 | Tight Inclusion CCD 16 | ^^^^^^^^^^^^^^^^^^^ 17 | 18 | .. autoclass:: ipctk.TightInclusionCCD 19 | 20 | .. autoclasstoc:: 21 | 22 | Additive CCD 23 | ^^^^^^^^^^^^ 24 | 25 | .. autoclass:: ipctk.AdditiveCCD 26 | 27 | .. autoclasstoc:: 28 | 29 | Inexact CCD 30 | ^^^^^^^^^^^ 31 | 32 | .. note:: 33 | This method is disabled by default. To enable it, set the 34 | ``IPC_TOOLKIT_WITH_INEXACT_CCD`` CMake option to ``ON``. 35 | 36 | .. .. autoclass:: ipctk.InexactCCD 37 | 38 | .. autofunction:: ipctk.inexact_point_edge_ccd_2D 39 | 40 | Nonlinear CCD 41 | ------------- 42 | 43 | .. autoclass:: ipctk.NonlinearTrajectory 44 | 45 | .. autoclasstoc:: 46 | 47 | .. autoclass:: ipctk.IntervalNonlinearTrajectory 48 | 49 | .. autoclasstoc:: 50 | 51 | .. autofunction:: ipctk.point_point_nonlinear_ccd 52 | .. autofunction:: ipctk.point_edge_nonlinear_ccd 53 | .. autofunction:: ipctk.edge_edge_nonlinear_ccd 54 | .. autofunction:: ipctk.point_triangle_nonlinear_ccd 55 | 56 | Miscellaneous 57 | ------------- 58 | 59 | .. autofunction:: ipctk.point_static_plane_ccd -------------------------------------------------------------------------------- /docs/source/python-api/collision_mesh.rst: -------------------------------------------------------------------------------- 1 | Collision Mesh 2 | ============== 3 | 4 | .. autoclass:: ipctk.CollisionMesh 5 | 6 | .. autoclasstoc:: -------------------------------------------------------------------------------- /docs/source/python-api/friction.rst: -------------------------------------------------------------------------------- 1 | Friction 2 | ======== 3 | 4 | Smooth Mollifier 5 | ---------------- 6 | 7 | .. autofunction:: ipctk.smooth_friction_f0 8 | .. autofunction:: ipctk.smooth_friction_f1 9 | .. autofunction:: ipctk.smooth_friction_f2 10 | .. autofunction:: ipctk.smooth_friction_f1_over_x 11 | .. autofunction:: ipctk.smooth_friction_f2_x_minus_f1_over_x3 -------------------------------------------------------------------------------- /docs/source/python-api/intersections.rst: -------------------------------------------------------------------------------- 1 | Intersections 2 | ============= 3 | 4 | .. autofunction:: ipctk.has_intersections 5 | .. autofunction:: ipctk.is_edge_intersecting_triangle 6 | .. autofunction:: ipctk.segment_segment_intersect -------------------------------------------------------------------------------- /docs/source/python-api/interval.rst: -------------------------------------------------------------------------------- 1 | Interval Arithmetic 2 | =================== 3 | 4 | .. automodule:: ipctk.filib 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | :inherited-members: -------------------------------------------------------------------------------- /docs/source/python-api/normal_collisions.rst: -------------------------------------------------------------------------------- 1 | Normal Collisions 2 | ================= 3 | 4 | Normal Collisions 5 | ----------------- 6 | 7 | .. autoclass:: ipctk.NormalCollisions 8 | 9 | .. autoclasstoc:: 10 | 11 | Normal Collision 12 | ---------------- 13 | 14 | .. autoclass:: ipctk.NormalCollision 15 | 16 | .. autoclasstoc:: 17 | 18 | Vertex-Vertex Normal Collision 19 | ----------------------------- 20 | 21 | .. autoclass:: ipctk.VertexVertexNormalCollision 22 | 23 | .. autoclasstoc:: 24 | 25 | Edge-Vertex Normal Collision 26 | ----------------------------- 27 | 28 | .. autoclass:: ipctk.EdgeVertexNormalCollision 29 | 30 | .. autoclasstoc:: 31 | 32 | Edge-Edge Normal Collision 33 | ----------------------------- 34 | 35 | .. autoclass:: ipctk.EdgeEdgeNormalCollision 36 | 37 | .. autoclasstoc:: 38 | 39 | Face-Vertex Normal Collision 40 | ----------------------------- 41 | 42 | .. autoclass:: ipctk.FaceVertexNormalCollision 43 | 44 | .. autoclasstoc:: 45 | 46 | Plane-Vertex Normal Collision 47 | ----------------------------- 48 | 49 | .. autoclass:: ipctk.PlaneVertexNormalCollision 50 | 51 | .. autoclasstoc:: -------------------------------------------------------------------------------- /docs/source/python-api/potentials.rst: -------------------------------------------------------------------------------- 1 | Potentials 2 | ========== 3 | 4 | Normal Potentials 5 | ----------------- 6 | 7 | .. autoclass:: ipctk.NormalPotential 8 | 9 | .. autoclasstoc:: 10 | 11 | Barrier Potential 12 | ^^^^^^^^^^^^^^^^^ 13 | 14 | .. autoclass:: ipctk.BarrierPotential 15 | 16 | .. autoclasstoc:: 17 | 18 | Normal Adhesion Potential 19 | ^^^^^^^^^^^^^^^^^^^^^^^^^ 20 | 21 | .. autoclass:: ipctk.NormalAdhesionPotential 22 | 23 | .. autoclasstoc:: 24 | 25 | Tangential Potentials 26 | --------------------- 27 | 28 | .. autoclass:: ipctk.TangentialPotential 29 | 30 | .. autoclasstoc:: 31 | 32 | Friction Potential 33 | ^^^^^^^^^^^^^^^^^^ 34 | 35 | .. autoclass:: ipctk.FrictionPotential 36 | 37 | .. autoclasstoc:: 38 | 39 | Tangential Adhesion Potential 40 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 41 | 42 | .. autoclass:: ipctk.TangentialAdhesionPotential 43 | 44 | .. autoclasstoc:: -------------------------------------------------------------------------------- /docs/source/python-api/tangential_collisions.rst: -------------------------------------------------------------------------------- 1 | Tangential Collisions 2 | ===================== 3 | 4 | .. autoclass:: ipctk.TangentialCollisions 5 | 6 | .. autoclasstoc:: 7 | 8 | Tangential Collision 9 | -------------------- 10 | 11 | .. autoclass:: ipctk.TangentialCollision 12 | 13 | .. autoclasstoc:: 14 | 15 | Vertex-Vertex Tangential Collision 16 | ---------------------------------- 17 | 18 | .. autoclass:: ipctk.VertexVertexTangentialCollision 19 | 20 | .. autoclasstoc:: 21 | 22 | Edge-Vertex Tangential Collision 23 | -------------------------------- 24 | 25 | .. autoclass:: ipctk.EdgeVertexTangentialCollision 26 | 27 | .. autoclasstoc:: 28 | 29 | Edge-Edge Tangential Collision 30 | ------------------------------ 31 | 32 | .. autoclass:: ipctk.EdgeEdgeTangentialCollision 33 | 34 | .. autoclasstoc:: 35 | 36 | Face-Vertex Tangential Collision 37 | -------------------------------- 38 | 39 | .. autoclass:: ipctk.FaceVertexTangentialCollision 40 | 41 | .. autoclasstoc:: -------------------------------------------------------------------------------- /docs/source/python-api/utils.rst: -------------------------------------------------------------------------------- 1 | Utils 2 | ===== 3 | 4 | Logger 5 | ------ 6 | 7 | .. autoclass:: ipctk.LoggerLevel 8 | .. autofunction:: ipctk.set_logger_level 9 | 10 | Multi-Threading 11 | --------------- 12 | 13 | .. autofunction:: ipctk.get_num_threads 14 | .. autofunction:: ipctk.set_num_threads 15 | 16 | Positive Semi-Definite Projection 17 | --------------------------------- 18 | 19 | .. autofunction:: ipctk.project_to_psd 20 | .. autofunction:: ipctk.project_to_pd 21 | .. autoclass:: ipctk.PSDProjectionMethod -------------------------------------------------------------------------------- /docs/source/python.rst: -------------------------------------------------------------------------------- 1 | Python 2 | ====== 3 | 4 | .. include:: ../../python/README.md 5 | :parser: myst_parser.sphinx_ 6 | :start-line: 2 7 | -------------------------------------------------------------------------------- /docs/source/style_guide.rst: -------------------------------------------------------------------------------- 1 | Style Guide 2 | =========== 3 | 4 | This document provides a guide to the style used in this project. 5 | 6 | Code Formatting 7 | --------------- 8 | 9 | We utilize `ClangFormat `_ to automate code formatting. Please format your code before pushing and/or creating a pull request. 10 | 11 | Additionally, ensure that your code adheres to the project's linting rules. Use the provided linting tools to check for any issues before committing your changes. 12 | 13 | Naming conventions 14 | ------------------ 15 | 16 | General 17 | ^^^^^^^ 18 | 19 | In general, we stick to the following naming conventions: 20 | 21 | * ``snake_case`` for variables, functions, and filenames 22 | * ``PascalCase`` for classes and structs 23 | * ``ALL_CAPS`` for constants and enum members 24 | * ``m_`` prefix for class member variables (if the member is not public) 25 | * ``member()`` to get a class member variable (if the member is not public) 26 | * ``set_member()`` to set a class member variable (if the member is not public) 27 | 28 | Specific 29 | ^^^^^^^^ 30 | 31 | * Vertex positions: ``vertices`` or ``positions`` 32 | * Vertex displacements: ``displacements`` 33 | * Vertex rest positions/material coordinates: ``rest_positions`` 34 | * Vertex velocities: ``velocities`` 35 | * Mesh edge matrix: ``edges`` 36 | * Mesh face matrix: ``faces`` 37 | * Element vertices: Use a numeral suffix (e.g., ``e0`` and ``e1`` for the end-points of an edge). 38 | * Edge-edge pairings: Use suffixes ``a`` and ``b``. 39 | * Continuous collision detection pairs: Use the suffix ``_t0`` for starting values and ``_t1`` for end values. 40 | * Favor the term "collision" over "contact" (but this is not a hard rule). 41 | * Prefer the term "potential" over "constraint" when referring to collisions and friction. 42 | 43 | Documentation 44 | ------------- 45 | 46 | We use `Doxygen `_ to generate documentation. Please document your code before pushing and/or creating a pull request. -------------------------------------------------------------------------------- /docs/source/tutorial/faq.rst: -------------------------------------------------------------------------------- 1 | .. _faq: 2 | 3 | Frequently Asked Questions 4 | ========================== 5 | 6 | .. role:: cpp(code) 7 | :language: c++ 8 | .. role:: cmake(code) 9 | :language: cmake 10 | .. role:: python(code) 11 | :language: python 12 | 13 | How do I include IPC Toolkit in my project? 14 | ------------------------------------------- 15 | 16 | If you are using CMake, the public include directory is added to the :cmake:`ipc::toolkit` cmake target which means that any lib/bin that includes :cmake:`ipc::toolkit` as a dependency also adds those include directories too. 17 | 18 | If you are not using CMake, the include path is ``src``. 19 | 20 | Files are included with the prefix :cpp:`#include ` in C++ and :python:`import ipctk` in Python. 21 | 22 | How do I determine which edges intersect? 23 | ----------------------------------------- 24 | 25 | We do not provide an edge-edge intersection function in 3D, but you can approximate it by computing the distance between the two edges and checking if it is less than a threshold. 26 | 27 | Inside any :cpp:`BroadPhase` classes, the function :cpp:`detect_edge_edge_candidates` determines which edges intersect based on their bounding boxes. You can then use :cpp:`edge_edge_distance` to check if they approximatly intersect by computing the distance. 28 | 29 | How do I build the edge matrix from the face matrix? 30 | ---------------------------------------------------- 31 | 32 | To build the edge matrix you can use :cpp:`igl::edges(faces, edges);` in C++ or :python:`ipctk.edges(faces)` in Python. 33 | 34 | My question is not answered here. What should I do? 35 | --------------------------------------------------- 36 | 37 | Please open an issue on `GitHub `_ and we will do our best to help you. -------------------------------------------------------------------------------- /docs/source/tutorial/references.rst: -------------------------------------------------------------------------------- 1 | References 2 | ========== 3 | 4 | .. bibliography:: -------------------------------------------------------------------------------- /notebooks/find_ipctk.py: -------------------------------------------------------------------------------- 1 | try: 2 | import ipctk # Try to import the built module 3 | except ImportError: 4 | import sys 5 | import pathlib 6 | repo_root = pathlib.Path(__file__).parents[1] 7 | possible_paths = [ 8 | pathlib.Path("python").resolve(), 9 | repo_root / "build" / "python", 10 | repo_root / "build" / "release" / "python", 11 | repo_root / "build" / "debug" / "python", 12 | ] 13 | for path in possible_paths: 14 | if path.exists() and len(list(path.glob("ipctk.*"))) > 0: 15 | sys.path.append(str(path)) 16 | break 17 | else: 18 | raise ImportError("Could not find the ipctk module") 19 | print(f"Using found ipctk module at {path}") 20 | import ipctk # Try again 21 | -------------------------------------------------------------------------------- /notebooks/utils.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | import sympy 3 | 4 | 5 | def sq_norm(x): 6 | """Compute the squared norm of a vector x.""" 7 | return x.dot(x) 8 | 9 | 10 | def norm(x): 11 | """Compute the norm of a vector x.""" 12 | return sympy.sqrt(sq_norm(x)) 13 | 14 | 15 | def normalize(x): 16 | """Normalize a vector x.""" 17 | return x / norm(x) 18 | 19 | 20 | def jacobian(F, x): 21 | J = np.empty((x.size * F.shape[0], F.shape[1]), dtype=object) 22 | for xi in range(x.size): 23 | for Fi in range(F.shape[0]): 24 | for Fj in range(F.shape[1]): 25 | J[xi * F.shape[0] + Fi, Fj] = F[Fi, Fj].diff(x[xi]) 26 | return J 27 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = [ 3 | "setuptools>=42", 4 | "wheel", 5 | "ninja", 6 | # "cmake>=3.14", 7 | ] 8 | build-backend = "setuptools.build_meta" 9 | 10 | [project] 11 | name = "ipctk" 12 | version = "1.4.0" 13 | authors = [{ name = "Zachary Ferguson", email = "zy.fergus@gmail.com" }] 14 | description = "A set of reusable functions to integrate Incremental Potential Contact (IPC) into a simulation." 15 | readme = "docs/PYPI_README.md" 16 | license = { file = "LICENSE" } 17 | classifiers = [ 18 | "Programming Language :: C++", 19 | "Programming Language :: Python :: 3", 20 | "Topic :: Games/Entertainment :: Simulation", 21 | "Topic :: Scientific/Engineering :: Physics", 22 | "License :: OSI Approved :: MIT License", 23 | "Operating System :: OS Independent", 24 | "Intended Audience :: Science/Research", 25 | ] 26 | requires-python = ">=3.6" 27 | dependencies = ["numpy", "scipy"] 28 | keywords = ["IPC", "simulation", "physics", "science", "research"] 29 | 30 | [project.urls] 31 | "Homepage" = "https://ipctk.xyz" 32 | "Bug Tracker" = "https://github.com/ipc-sim/ipc-toolkit/issues" 33 | "Source Code" = "https://github.com/ipc-sim/ipc-toolkit" 34 | 35 | [tools.cibuildwheel] 36 | build-frontend = "build" 37 | -------------------------------------------------------------------------------- /python/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: InheritParentConfig 2 | SortIncludes: false -------------------------------------------------------------------------------- /python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Create Python module for IPC Toolkit 3 | include(pybind11) 4 | 5 | pybind11_add_module(ipctk) 6 | 7 | add_subdirectory(src) # Add sources to ipctk 8 | target_include_directories(ipctk PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src") 9 | 10 | target_link_libraries(ipctk PRIVATE ipc::toolkit) 11 | 12 | if (FILIB_BUILD_SHARED_LIB AND WIN32) 13 | # Copy DLLs to the output directory 14 | add_custom_command( 15 | TARGET ipctk POST_BUILD 16 | COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $ 17 | COMMAND_EXPAND_LISTS 18 | ) 19 | endif() 20 | 21 | # Extra warnings 22 | # target_link_libraries(ipctk PRIVATE IPCToolkit::warnings) 23 | 24 | # Folder name for IDE 25 | set_target_properties(ipctk PROPERTIES FOLDER "SRC") 26 | get_target_property(IPCTK_SOURCES ipctk SOURCES) 27 | source_group(TREE "${PROJECT_SOURCE_DIR}/python" FILES ${IPCTK_SOURCES}) -------------------------------------------------------------------------------- /python/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | bindings.cpp 3 | collision_mesh.cpp 4 | ipc.cpp 5 | ) 6 | 7 | target_sources(ipctk PRIVATE ${SOURCES}) 8 | 9 | ################################################################################ 10 | # Subfolders 11 | ################################################################################ 12 | 13 | add_subdirectory(adhesion) 14 | add_subdirectory(barrier) 15 | add_subdirectory(broad_phase) 16 | add_subdirectory(candidates) 17 | add_subdirectory(ccd) 18 | add_subdirectory(collisions) 19 | add_subdirectory(distance) 20 | add_subdirectory(friction) 21 | add_subdirectory(implicits) 22 | add_subdirectory(potentials) 23 | add_subdirectory(tangent) 24 | add_subdirectory(utils) -------------------------------------------------------------------------------- /python/src/adhesion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | adhesion.cpp 3 | ) 4 | 5 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/adhesion/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | 7 | void define_adhesion(py::module_& m); -------------------------------------------------------------------------------- /python/src/barrier/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | adaptive_stiffness.cpp 3 | barrier_force_magnitude.cpp 4 | barrier.cpp 5 | ) 6 | 7 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/barrier/barrier_force_magnitude.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_barrier_force_magnitude(py::module_& m) 9 | { 10 | m.def( 11 | "barrier_force_magnitude", &barrier_force_magnitude, 12 | R"ipc_Qu8mg5v7( 13 | Compute the magnitude of the force due to a barrier. 14 | 15 | Parameters: 16 | distance_squared: The squared distance between elements. 17 | barrier: The barrier function. 18 | dhat: The activation distance of the barrier. 19 | barrier_stiffness: The stiffness of the barrier. 20 | dmin: The minimum distance offset to the barrier. 21 | 22 | Returns: 23 | The magnitude of the force. 24 | )ipc_Qu8mg5v7", 25 | py::arg("distance_squared"), py::arg("barrier"), py::arg("dhat"), 26 | py::arg("barrier_stiffness"), py::arg("dmin") = 0); 27 | 28 | m.def( 29 | "barrier_force_magnitude_gradient", &barrier_force_magnitude_gradient, 30 | R"ipc_Qu8mg5v7( 31 | Compute the gradient of the magnitude of the force due to a barrier. 32 | 33 | Parameters: 34 | distance_squared: The squared distance between elements. 35 | distance_squared_gradient: The gradient of the squared distance. 36 | barrier: The barrier function. 37 | dhat: The activation distance of the barrier. 38 | barrier_stiffness: The stiffness of the barrier. 39 | dmin: The minimum distance offset to the barrier. 40 | 41 | Returns: 42 | The gradient of the force. 43 | )ipc_Qu8mg5v7", 44 | py::arg("distance_squared"), py::arg("distance_squared_gradient"), 45 | py::arg("barrier"), py::arg("dhat"), py::arg("barrier_stiffness"), 46 | py::arg("dmin") = 0); 47 | } 48 | -------------------------------------------------------------------------------- /python/src/barrier/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | 7 | void define_adaptive_stiffness(py::module_& m); 8 | void define_barrier_force_magnitude(py::module_& m); 9 | void define_barrier(py::module_& m); -------------------------------------------------------------------------------- /python/src/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | 18 | namespace py = pybind11; 19 | 20 | void define_collision_mesh(py::module_& m); 21 | void define_ipc(py::module_& m); -------------------------------------------------------------------------------- /python/src/broad_phase/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | aabb.cpp 3 | broad_phase.cpp 4 | brute_force.cpp 5 | bvh.cpp 6 | hash_grid.cpp 7 | spatial_hash.cpp 8 | sweep_and_prune.cpp 9 | sweep_and_tiniest_queue.cpp 10 | voxel_size_heuristic.cpp 11 | ) 12 | 13 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/broad_phase/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | 7 | void define_aabb(py::module_& m); 8 | void define_broad_phase(py::module_& m); 9 | void define_brute_force(py::module_& m); 10 | void define_bvh(py::module_& m); 11 | void define_hash_grid(py::module_& m); 12 | void define_spatial_hash(py::module_& m); 13 | void define_sweep_and_prune(py::module_& m); 14 | void define_sweep_and_tiniest_queue(py::module_& m); 15 | void define_voxel_size_heuristic(py::module_& m); 16 | -------------------------------------------------------------------------------- /python/src/broad_phase/brute_force.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_brute_force(py::module_& m) 9 | { 10 | py::class_>( 11 | m, "BruteForce") 12 | .def(py::init()); 13 | } 14 | -------------------------------------------------------------------------------- /python/src/broad_phase/bvh.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_bvh(py::module_& m) 9 | { 10 | py::class_>(m, "BVH").def(py::init()); 11 | } 12 | -------------------------------------------------------------------------------- /python/src/broad_phase/hash_grid.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_hash_grid(py::module_& m) 9 | { 10 | py::class_(m, "HashItem") 11 | .def( 12 | py::init(), 13 | "Construct a hash item as a (key, value) pair.", py::arg("key"), 14 | py::arg("id")) 15 | .def( 16 | "__lt__", &HashItem::operator<, 17 | "Compare HashItems by their keys for sorting.", py::arg("other")) 18 | .def_readwrite("key", &HashItem::key, "The key of the item.") 19 | .def_readwrite("id", &HashItem::id, "The value of the item."); 20 | 21 | py::class_>(m, "HashGrid") 22 | .def(py::init()) 23 | .def_property_readonly("cell_size", &HashGrid::cell_size) 24 | .def_property_readonly( 25 | "grid_size", &HashGrid::grid_size, 26 | py::return_value_policy::reference) 27 | .def_property_readonly( 28 | "domain_min", &HashGrid::domain_min, 29 | py::return_value_policy::reference) 30 | .def_property_readonly( 31 | "domain_max", &HashGrid::domain_max, 32 | py::return_value_policy::reference); 33 | } 34 | -------------------------------------------------------------------------------- /python/src/broad_phase/sweep_and_prune.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_sweep_and_prune(py::module_& m) 9 | { 10 | py::class_>( 11 | m, "SweepAndPrune") 12 | .def(py::init()); 13 | } 14 | -------------------------------------------------------------------------------- /python/src/broad_phase/sweep_and_tiniest_queue.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | #ifdef IPC_TOOLKIT_WITH_CUDA 7 | using namespace ipc; // not defined if IPC_TOOLKIT_WITH_CUDA is not defined 8 | #endif 9 | 10 | void define_sweep_and_tiniest_queue(py::module_& m) 11 | { 12 | #ifdef IPC_TOOLKIT_WITH_CUDA 13 | py::class_< 14 | SweepAndTiniestQueue, BroadPhase, 15 | std::shared_ptr>(m, "SweepAndTiniestQueue") 16 | .def(py::init()); 17 | #endif 18 | } 19 | -------------------------------------------------------------------------------- /python/src/candidates/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | collision_stencil.cpp 3 | edge_edge.cpp 4 | edge_face.cpp 5 | edge_vertex.cpp 6 | face_face.cpp 7 | face_vertex.cpp 8 | vertex_vertex.cpp 9 | candidates.cpp 10 | ) 11 | 12 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/candidates/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // candidates 6 | void define_candidates(py::module_& m); 7 | void define_collision_stencil(py::module_& m); 8 | void define_edge_edge_candidate(py::module_& m); 9 | void define_edge_face_candidate(py::module_& m); 10 | void define_edge_vertex_candidate(py::module_& m); 11 | void define_face_face_candidate(py::module_& m); 12 | void define_face_vertex_candidate(py::module_& m); 13 | void define_vertex_vertex_candidate(py::module_& m); -------------------------------------------------------------------------------- /python/src/candidates/edge_edge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_edge_edge_candidate(py::module_& m) 9 | { 10 | py::class_(m, "EdgeEdgeCandidate") 11 | .def( 12 | py::init(), py::arg("edge0_id"), 13 | py::arg("edge1_id")) 14 | .def( 15 | py::init([](std::tuple edge_ids) { 16 | return std::make_unique( 17 | std::get<0>(edge_ids), std::get<1>(edge_ids)); 18 | }), 19 | py::arg("edge_ids")) 20 | .def("known_dtype", &EdgeEdgeCandidate::known_dtype) 21 | .def( 22 | "__str__", 23 | [](const EdgeEdgeCandidate& ee) { 24 | return fmt::format("[{:d}, {:d}]", ee.edge0_id, ee.edge1_id); 25 | }) 26 | .def( 27 | "__repr__", 28 | [](const EdgeEdgeCandidate& ee) { 29 | return fmt::format( 30 | "EdgeEdgeCandidate({:d}, {:d})", ee.edge0_id, ee.edge1_id); 31 | }) 32 | .def("__eq__", &EdgeEdgeCandidate::operator==, py::arg("other")) 33 | .def("__ne__", &EdgeEdgeCandidate::operator!=, py::arg("other")) 34 | .def( 35 | "__lt__", &EdgeEdgeCandidate::operator<, 36 | "Compare EdgeEdgeCandidates for sorting.", py::arg("other")) 37 | .def_readwrite( 38 | "edge0_id", &EdgeEdgeCandidate::edge0_id, "ID of the first edge.") 39 | .def_readwrite( 40 | "edge1_id", &EdgeEdgeCandidate::edge1_id, "ID of the second edge."); 41 | 42 | py::implicitly_convertible< 43 | std::tuple, EdgeEdgeCandidate>(); 44 | } 45 | -------------------------------------------------------------------------------- /python/src/candidates/edge_face.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace py = pybind11; 7 | using namespace ipc; 8 | 9 | void define_edge_face_candidate(py::module_& m) 10 | { 11 | py::class_(m, "EdgeFaceCandidate") 12 | .def( 13 | py::init(), py::arg("edge_id"), 14 | py::arg("face_id")) 15 | .def( 16 | py::init([](std::tuple edge_and_face_id) { 17 | return std::make_unique( 18 | std::get<0>(edge_and_face_id), 19 | std::get<1>(edge_and_face_id)); 20 | }), 21 | py::arg("edge_and_face_id")) 22 | .def( 23 | "__str__", 24 | [](const EdgeFaceCandidate& ev) { 25 | return fmt::format("[{:d}, {:d}]", ev.edge_id, ev.face_id); 26 | }) 27 | .def( 28 | "__repr__", 29 | [](const EdgeFaceCandidate& ev) { 30 | return fmt::format( 31 | "EdgeFaceCandidate({:d}, {:d})", ev.edge_id, ev.face_id); 32 | }) 33 | .def("__eq__", &EdgeFaceCandidate::operator==, py::arg("other")) 34 | .def("__ne__", &EdgeFaceCandidate::operator!=, py::arg("other")) 35 | .def( 36 | "__lt__", &EdgeFaceCandidate::operator<, 37 | "Compare EdgeFaceCandidate for sorting.", py::arg("other")) 38 | .def_readwrite("edge_id", &EdgeFaceCandidate::edge_id, "ID of the edge") 39 | .def_readwrite( 40 | "face_id", &EdgeFaceCandidate::face_id, "ID of the face"); 41 | 42 | py::implicitly_convertible< 43 | std::tuple, EdgeFaceCandidate>(); 44 | } 45 | -------------------------------------------------------------------------------- /python/src/candidates/edge_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_edge_vertex_candidate(py::module_& m) 9 | { 10 | py::class_(m, "EdgeVertexCandidate") 11 | .def( 12 | py::init(), py::arg("edge_id"), 13 | py::arg("vertex_id")) 14 | .def( 15 | py::init([](std::tuple edge_and_vertex_id) { 16 | return std::make_unique( 17 | std::get<0>(edge_and_vertex_id), 18 | std::get<1>(edge_and_vertex_id)); 19 | }), 20 | py::arg("edge_and_vertex_id")) 21 | .def("known_dtype", &EdgeVertexCandidate::known_dtype) 22 | .def( 23 | "__str__", 24 | [](const EdgeVertexCandidate& ev) { 25 | return fmt::format("[{:d}, {:d}]", ev.edge_id, ev.vertex_id); 26 | }) 27 | .def( 28 | "__repr__", 29 | [](const EdgeVertexCandidate& ev) { 30 | return fmt::format( 31 | "EdgeVertexCandidate({:d}, {:d})", ev.edge_id, 32 | ev.vertex_id); 33 | }) 34 | .def("__eq__", &EdgeVertexCandidate::operator==, py::arg("other")) 35 | .def("__ne__", &EdgeVertexCandidate::operator!=, py::arg("other")) 36 | .def( 37 | "__lt__", &EdgeVertexCandidate::operator<, 38 | "Compare EdgeVertexCandidates for sorting.", py::arg("other")) 39 | .def_readwrite( 40 | "edge_id", &EdgeVertexCandidate::edge_id, "ID of the edge") 41 | .def_readwrite( 42 | "vertex_id", &EdgeVertexCandidate::vertex_id, "ID of the vertex"); 43 | 44 | py::implicitly_convertible< 45 | std::tuple, EdgeVertexCandidate>(); 46 | } 47 | -------------------------------------------------------------------------------- /python/src/candidates/face_face.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace py = pybind11; 7 | using namespace ipc; 8 | 9 | void define_face_face_candidate(py::module_& m) 10 | { 11 | py::class_(m, "FaceFaceCandidate") 12 | .def( 13 | py::init(), py::arg("face0_id"), 14 | py::arg("face1_id")) 15 | .def( 16 | py::init([](std::tuple face_ids) { 17 | return std::make_unique( 18 | std::get<0>(face_ids), std::get<1>(face_ids)); 19 | }), 20 | py::arg("face_ids")) 21 | .def( 22 | "__str__", 23 | [](const FaceFaceCandidate& ff) { 24 | return fmt::format("[{:d}, {:d}]", ff.face0_id, ff.face1_id); 25 | }) 26 | .def( 27 | "__repr__", 28 | [](const FaceFaceCandidate& ff) { 29 | return fmt::format( 30 | "FaceFaceCandidate({:d}, {:d})", ff.face0_id, ff.face1_id); 31 | }) 32 | .def("__eq__", &FaceFaceCandidate::operator==, py::arg("other")) 33 | .def("__ne__", &FaceFaceCandidate::operator!=, py::arg("other")) 34 | .def( 35 | "__lt__", &FaceFaceCandidate::operator<, 36 | "Compare FaceFaceCandidate for sorting.", py::arg("other")) 37 | .def_readwrite( 38 | "face0_id", &FaceFaceCandidate::face0_id, "ID of the first face.") 39 | .def_readwrite( 40 | "face1_id", &FaceFaceCandidate::face1_id, "ID of the second face."); 41 | 42 | py::implicitly_convertible< 43 | std::tuple, FaceFaceCandidate>(); 44 | } 45 | -------------------------------------------------------------------------------- /python/src/candidates/face_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_face_vertex_candidate(py::module_& m) 9 | { 10 | py::class_(m, "FaceVertexCandidate") 11 | .def( 12 | py::init(), py::arg("face_id"), 13 | py::arg("vertex_id")) 14 | .def( 15 | py::init([](std::tuple face_and_vertex_id) { 16 | return std::make_unique( 17 | std::get<0>(face_and_vertex_id), 18 | std::get<1>(face_and_vertex_id)); 19 | }), 20 | py::arg("face_and_vertex_id")) 21 | .def("known_dtype", &FaceVertexCandidate::known_dtype) 22 | .def( 23 | "__str__", 24 | [](const FaceVertexCandidate& ev) { 25 | return fmt::format("[{:d}, {:d}]", ev.face_id, ev.vertex_id); 26 | }) 27 | .def( 28 | "__repr__", 29 | [](const FaceVertexCandidate& ev) { 30 | return fmt::format( 31 | "FaceVertexCandidate({:d}, {:d})", ev.face_id, 32 | ev.vertex_id); 33 | }) 34 | .def("__eq__", &FaceVertexCandidate::operator==, py::arg("other")) 35 | .def("__ne__", &FaceVertexCandidate::operator!=, py::arg("other")) 36 | .def( 37 | "__lt__", &FaceVertexCandidate::operator<, 38 | "Compare FaceVertexCandidate for sorting.", py::arg("other")) 39 | .def_readwrite( 40 | "face_id", &FaceVertexCandidate::face_id, "ID of the face") 41 | .def_readwrite( 42 | "vertex_id", &FaceVertexCandidate::vertex_id, "ID of the vertex"); 43 | 44 | py::implicitly_convertible< 45 | std::tuple, FaceVertexCandidate>(); 46 | } 47 | -------------------------------------------------------------------------------- /python/src/candidates/vertex_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_vertex_vertex_candidate(py::module_& m) 9 | { 10 | py::class_( 11 | m, "VertexVertexCandidate") 12 | .def( 13 | py::init(), py::arg("vertex0_id"), 14 | py::arg("vertex1_id")) 15 | .def( 16 | py::init([](std::tuple vertex_ids) { 17 | return std::make_unique( 18 | std::get<0>(vertex_ids), std::get<1>(vertex_ids)); 19 | }), 20 | py::arg("vertex_ids")) 21 | .def( 22 | "__str__", 23 | [](const VertexVertexCandidate& ev) { 24 | return fmt::format( 25 | "[{:d}, {:d}]", ev.vertex0_id, ev.vertex1_id); 26 | }) 27 | .def( 28 | "__repr__", 29 | [](const VertexVertexCandidate& ev) { 30 | return fmt::format( 31 | "VertexVertexCandidate({:d}, {:d})", ev.vertex0_id, 32 | ev.vertex1_id); 33 | }) 34 | .def("__eq__", &VertexVertexCandidate::operator==, py::arg("other")) 35 | .def("__ne__", &VertexVertexCandidate::operator!=, py::arg("other")) 36 | .def( 37 | "__lt__", &VertexVertexCandidate::operator<, 38 | "Compare EdgeVertexCandidates for sorting.", py::arg("other")) 39 | .def_readwrite( 40 | "vertex0_id", &VertexVertexCandidate::vertex0_id, 41 | "ID of the first vertex") 42 | .def_readwrite( 43 | "vertex1_id", &VertexVertexCandidate::vertex1_id, 44 | "ID of the second vertex"); 45 | 46 | py::implicitly_convertible< 47 | std::tuple, VertexVertexCandidate>(); 48 | } 49 | -------------------------------------------------------------------------------- /python/src/ccd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | aabb.cpp 3 | additive_ccd.cpp 4 | check_initial_distance.cpp 5 | inexact_ccd.cpp 6 | inexact_point_edge.cpp 7 | narrow_phase_ccd.cpp 8 | nonlinear_ccd.cpp 9 | point_static_plane.cpp 10 | tight_inclusion_ccd.cpp 11 | ) 12 | 13 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/ccd/aabb.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_ccd_aabb(py::module_& m) 9 | { 10 | m.def( 11 | "point_edge_aabb_cd", &point_edge_aabb_cd, py::arg("p"), py::arg("e0"), 12 | py::arg("e1"), py::arg("dist")); 13 | 14 | m.def( 15 | "edge_edge_aabb_cd", &edge_edge_aabb_cd, py::arg("ea0"), py::arg("ea1"), 16 | py::arg("eb0"), py::arg("eb1"), py::arg("dist")); 17 | 18 | m.def( 19 | "point_triangle_aabb_cd", &point_triangle_aabb_cd, py::arg("p"), 20 | py::arg("t0"), py::arg("t1"), py::arg("t2"), py::arg("dist")); 21 | 22 | m.def( 23 | "edge_triangle_aabb_cd", &edge_triangle_aabb_cd, py::arg("e0"), 24 | py::arg("e1"), py::arg("t0"), py::arg("t1"), py::arg("t2"), 25 | py::arg("dist")); 26 | 27 | m.def( 28 | "point_edge_aabb_ccd", &point_edge_aabb_ccd, py::arg("p_t0"), 29 | py::arg("e0_t0"), py::arg("e1_t0"), py::arg("p_t1"), py::arg("e0_t1"), 30 | py::arg("e1_t1"), py::arg("dist")); 31 | 32 | m.def( 33 | "edge_edge_aabb_ccd", &edge_edge_aabb_ccd, py::arg("ea0_t0"), 34 | py::arg("ea1_t0"), py::arg("eb0_t0"), py::arg("eb1_t0"), 35 | py::arg("ea0_t1"), py::arg("ea1_t1"), py::arg("eb0_t1"), 36 | py::arg("eb1_t1"), py::arg("dist")); 37 | 38 | m.def( 39 | "point_triangle_aabb_ccd", &point_triangle_aabb_ccd, py::arg("p_t0"), 40 | py::arg("t0_t0"), py::arg("t1_t0"), py::arg("t2_t0"), py::arg("p_t1"), 41 | py::arg("t0_t1"), py::arg("t1_t1"), py::arg("t2_t1"), py::arg("dist")); 42 | } 43 | -------------------------------------------------------------------------------- /python/src/ccd/additive_ccd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_additive_ccd(py::module_& m) 9 | { 10 | py::class_(m, "AdditiveCCD") 11 | .def( 12 | py::init(), 13 | R"ipc_Qu8mg5v7( 14 | Construct a new AdditiveCCD object. 15 | 16 | Parameters: 17 | conservative_rescaling: The conservative rescaling of the time of impact. 18 | )ipc_Qu8mg5v7", 19 | py::arg("max_iterations") = AdditiveCCD::DEFAULT_MAX_ITERATIONS, 20 | py::arg("conservative_rescaling") = 21 | AdditiveCCD::DEFAULT_CONSERVATIVE_RESCALING) 22 | .def_readonly_static( 23 | "DEFAULT_CONSERVATIVE_RESCALING", 24 | &AdditiveCCD::DEFAULT_CONSERVATIVE_RESCALING, 25 | "The default conservative rescaling value used to avoid taking steps exactly to impact. Value choosen to based on [Li et al. 2021].") 26 | .def_readwrite( 27 | "conservative_rescaling", &AdditiveCCD::conservative_rescaling, 28 | "The conservative rescaling value used to avoid taking steps exactly to impact."); 29 | } 30 | -------------------------------------------------------------------------------- /python/src/ccd/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_ccd_aabb(py::module_& m); 7 | void define_additive_ccd(py::module_& m); 8 | void define_check_initial_distance(py::module_& m); 9 | void define_inexact_ccd(py::module_& m); 10 | void define_inexact_point_edge(py::module_& m); 11 | void define_narrow_phase_ccd(py::module_& m); 12 | void define_nonlinear_ccd(py::module_& m); 13 | void define_point_static_plane(py::module_& m); 14 | void define_tight_inclusion_ccd(py::module_& m); -------------------------------------------------------------------------------- /python/src/ccd/check_initial_distance.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_check_initial_distance(py::module_& m) 9 | { 10 | m.def( 11 | "check_initial_distance", 12 | [](const double initial_distance, const double min_distance) { 13 | double toi; 14 | bool r = 15 | check_initial_distance(initial_distance, min_distance, toi); 16 | return std::make_tuple(r, toi); 17 | }, 18 | py::arg("initial_distance"), py::arg("min_distance")); 19 | } 20 | -------------------------------------------------------------------------------- /python/src/ccd/inexact_ccd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace py = pybind11; 8 | 9 | void define_inexact_ccd(py::module_& m) 10 | { 11 | #ifdef IPC_TOOLKIT_WITH_INEXACT_CCD 12 | using namespace ipc; 13 | 14 | py::class_(m, "InexactCCD") 15 | .def( 16 | py::init(), 17 | R"ipc_Qu8mg5v7( 18 | Construct a new AdditiveCCD object. 19 | 20 | Parameters: 21 | conservative_rescaling: The conservative rescaling of the time of impact. 22 | )ipc_Qu8mg5v7", 23 | py::arg("conservative_rescaling") = 24 | InexactCCD::DEFAULT_CONSERVATIVE_RESCALING) 25 | .def_readonly_static( 26 | "DEFAULT_CONSERVATIVE_RESCALING", 27 | &InexactCCD::DEFAULT_CONSERVATIVE_RESCALING, 28 | "The default conservative rescaling value used to avoid taking steps exactly to impact.") 29 | .def_readonly_static( 30 | "SMALL_TOI", &InexactCCD::SMALL_TOI, 31 | "Tolerance for small time of impact which triggers rerunning CCD without a minimum separation.") 32 | .def_readwrite( 33 | "conservative_rescaling", &InexactCCD::conservative_rescaling, 34 | "Conservative rescaling of the time of impact."); 35 | #endif 36 | } 37 | -------------------------------------------------------------------------------- /python/src/ccd/inexact_point_edge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_inexact_point_edge(py::module_& m) 9 | { 10 | m.def( 11 | "inexact_point_edge_ccd_2D", 12 | [](Eigen::ConstRef p_t0, 13 | Eigen::ConstRef e0_t0, 14 | Eigen::ConstRef e1_t0, 15 | Eigen::ConstRef p_t1, 16 | Eigen::ConstRef e0_t1, 17 | Eigen::ConstRef e1_t1, 18 | const double conservative_rescaling) { 19 | double toi; 20 | bool r = inexact_point_edge_ccd_2D( 21 | p_t0, e0_t0, e1_t0, p_t1, e0_t1, e1_t1, toi, 22 | conservative_rescaling); 23 | return std::make_tuple(r, toi); 24 | }, 25 | R"ipc_Qu8mg5v7( 26 | Inexact continuous collision detection between a point and an edge in 2D. 27 | 28 | Parameters: 29 | p_t0: Initial position of the point 30 | e0_t0: Initial position of the first endpoint of the edge 31 | e1_t0: Initial position of the second endpoint of the edge 32 | p_t1: Final position of the point 33 | e0_t1: Final position of the first endpoint of the edge 34 | e1_t1: Final position of the second endpoint of the edge 35 | conservative_rescaling: Conservative rescaling of the time of impact 36 | 37 | Returns: 38 | Tuple of: 39 | True if a collision was detected, false otherwise. 40 | Output time of impact 41 | )ipc_Qu8mg5v7", 42 | py::arg("p_t0"), py::arg("e0_t0"), py::arg("e1_t0"), py::arg("p_t1"), 43 | py::arg("e0_t1"), py::arg("e1_t1"), py::arg("conservative_rescaling")); 44 | } 45 | -------------------------------------------------------------------------------- /python/src/ccd/point_static_plane.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_point_static_plane(py::module_& m) 9 | { 10 | m.def( 11 | "point_static_plane_ccd", 12 | [](Eigen::ConstRef p_t0, Eigen::ConstRef p_t1, 13 | Eigen::ConstRef plane_origin, 14 | Eigen::ConstRef plane_normal, 15 | const double conservative_rescaling) { 16 | double toi; 17 | bool r = point_static_plane_ccd( 18 | p_t0, p_t1, plane_origin, plane_normal, toi, 19 | conservative_rescaling); 20 | return std::make_tuple(r, toi); 21 | }, 22 | R"ipc_Qu8mg5v7( 23 | Compute the time of impact between a point and a static plane in 3D using continuous collision detection. 24 | 25 | Parameters: 26 | p_t0: The initial position of the point. 27 | p_t1: The final position of the point. 28 | plane_origin: The origin of the plane. 29 | plane_normal: The normal of the plane. 30 | conservative_rescaling: Conservative rescaling of the time of impact. 31 | 32 | Returns: 33 | Tuple of: 34 | True if a collision was detected, false otherwise. 35 | Output time of impact 36 | )ipc_Qu8mg5v7", 37 | py::arg("p_t0"), py::arg("p_t1"), py::arg("plane_origin"), 38 | py::arg("plane_normal"), 39 | py::arg("conservative_rescaling") = 40 | TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); 41 | } 42 | -------------------------------------------------------------------------------- /python/src/collisions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set(SOURCES) 2 | 3 | # target_sources(ipc_toolkit PRIVATE ${SOURCES}) 4 | 5 | ################################################################################ 6 | # Subfolders 7 | ################################################################################ 8 | 9 | add_subdirectory(normal) 10 | add_subdirectory(tangential) -------------------------------------------------------------------------------- /python/src/collisions/bindings.hpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include -------------------------------------------------------------------------------- /python/src/collisions/normal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | edge_edge.cpp 3 | edge_vertex.cpp 4 | face_vertex.cpp 5 | normal_collision.cpp 6 | normal_collisions.cpp 7 | plane_vertex.cpp 8 | vertex_vertex.cpp 9 | ) 10 | 11 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/collisions/normal/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_normal_collision(py::module_& m); 7 | void define_normal_collisions(py::module_& m); 8 | void define_edge_edge_normal_collision(py::module_& m); 9 | void define_edge_vertex_normal_collision(py::module_& m); 10 | void define_face_vertex_normal_collision(py::module_& m); 11 | void define_plane_vertex_normal_collision(py::module_& m); 12 | void define_vertex_vertex_normal_collision(py::module_& m); -------------------------------------------------------------------------------- /python/src/collisions/normal/edge_edge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_edge_edge_normal_collision(py::module_& m) 9 | { 10 | py::class_( 11 | m, "EdgeEdgeNormalCollision") 12 | .def( 13 | py::init< 14 | const index_t, const index_t, const double, 15 | const EdgeEdgeDistanceType>(), 16 | py::arg("edge0_id"), py::arg("edge1_id"), py::arg("eps_x"), 17 | py::arg("dtype") = EdgeEdgeDistanceType::AUTO) 18 | .def( 19 | py::init< 20 | const EdgeEdgeCandidate&, const double, 21 | const EdgeEdgeDistanceType>(), 22 | py::arg("candidate"), py::arg("eps_x"), 23 | py::arg("dtype") = EdgeEdgeDistanceType::AUTO) 24 | // .def( 25 | // py::init< 26 | // const index_t, const index_t, const double, const double, 27 | // const Eigen::SparseVector&, 28 | // const EdgeEdgeDistanceType>(), 29 | // py::arg("edge0_id"), py::arg("edge1_id"), py::arg("eps_x"), 30 | // py::arg("weight"), py::arg("weight_gradient"), 31 | // py::arg("dtype") = EdgeEdgeDistanceType::AUTO) 32 | .def("__eq__", &EdgeEdgeNormalCollision::operator==, py::arg("other")) 33 | .def("__ne__", &EdgeEdgeNormalCollision::operator!=, py::arg("other")) 34 | .def("__lt__", &EdgeEdgeNormalCollision::operator<, py::arg("other")) 35 | .def_readwrite( 36 | "eps_x", &EdgeEdgeNormalCollision::eps_x, 37 | "Mollifier activation threshold.") 38 | .def_readwrite( 39 | "dtype", &EdgeEdgeNormalCollision::dtype, 40 | R"ipc_Qu8mg5v7( 41 | Cached distance type. 42 | 43 | Some EE collisions are mollified EV or VV collisions. 44 | )ipc_Qu8mg5v7"); 45 | } 46 | -------------------------------------------------------------------------------- /python/src/collisions/normal/edge_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_edge_vertex_normal_collision(py::module_& m) 9 | { 10 | py::class_( 11 | m, "EdgeVertexNormalCollision") 12 | .def( 13 | py::init(), py::arg("edge_id"), 14 | py::arg("vertex_id")) 15 | .def(py::init(), py::arg("candidate")); 16 | // .def( 17 | // py::init< 18 | // const index_t, const index_t, const double, 19 | // const Eigen::SparseVector&>(), 20 | // py::arg("edge_id"), py::arg("vertex_id"), py::arg("weight"), 21 | // py::arg("weight_gradient")); 22 | } 23 | -------------------------------------------------------------------------------- /python/src/collisions/normal/face_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_face_vertex_normal_collision(py::module_& m) 9 | { 10 | py::class_( 11 | m, "FaceVertexNormalCollision") 12 | .def( 13 | py::init(), "", py::arg("face_id"), 14 | py::arg("vertex_id")) 15 | .def(py::init(), py::arg("candidate")); 16 | // .def( 17 | // py::init< 18 | // const index_t, const index_t, const double, 19 | // const Eigen::SparseVector&>(), 20 | // py::arg("face_id"), py::arg("vertex_id"), py::arg("weight"), 21 | // py::arg("weight_gradient")); 22 | } 23 | -------------------------------------------------------------------------------- /python/src/collisions/normal/plane_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_plane_vertex_normal_collision(py::module_& m) 9 | { 10 | py::class_( 11 | m, "PlaneVertexNormalCollision") 12 | .def( 13 | py::init< 14 | Eigen::ConstRef, Eigen::ConstRef, 15 | const index_t>(), 16 | py::arg("plane_origin"), py::arg("plane_normal"), 17 | py::arg("vertex_id")) 18 | .def_readwrite( 19 | "plane_origin", &PlaneVertexNormalCollision::plane_origin, 20 | "The plane's origin.") 21 | .def_readwrite( 22 | "plane_normal", &PlaneVertexNormalCollision::plane_normal, 23 | "The plane's normal.") 24 | .def_readwrite( 25 | "vertex_id", &PlaneVertexNormalCollision::vertex_id, 26 | "The vertex's id."); 27 | } 28 | -------------------------------------------------------------------------------- /python/src/collisions/normal/vertex_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_vertex_vertex_normal_collision(py::module_& m) 9 | { 10 | py::class_< 11 | VertexVertexNormalCollision, VertexVertexCandidate, NormalCollision>( 12 | m, "VertexVertexNormalCollision") 13 | .def( 14 | py::init(), "", py::arg("vertex0_id"), 15 | py::arg("vertex1_id")) 16 | .def(py::init(), py::arg("vv_candidate")); 17 | // .def( 18 | // py::init< 19 | // const index_t, const index_t, const double, 20 | // const Eigen::SparseVector&>(), 21 | // py::arg("vertex0_id"), py::arg("vertex1_id"), py::arg("weight"), 22 | // py::arg("weight_gradient")); 23 | } 24 | -------------------------------------------------------------------------------- /python/src/collisions/tangential/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | edge_edge.cpp 3 | edge_vertex.cpp 4 | face_vertex.cpp 5 | tangential_collision.cpp 6 | tangential_collisions.cpp 7 | vertex_vertex.cpp 8 | ) 9 | 10 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/collisions/tangential/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_tangential_collision(py::module_& m); 7 | void define_tangential_collisions(py::module_& m); 8 | void define_edge_edge_tangential_collision(py::module_& m); 9 | void define_edge_vertex_tangential_collision(py::module_& m); 10 | void define_face_vertex_tangential_collision(py::module_& m); 11 | void define_vertex_vertex_tangential_collision(py::module_& m); -------------------------------------------------------------------------------- /python/src/collisions/tangential/edge_edge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_edge_edge_tangential_collision(py::module_& m) 9 | { 10 | py::class_< 11 | EdgeEdgeTangentialCollision, EdgeEdgeCandidate, TangentialCollision>( 12 | m, "EdgeEdgeTangentialCollision") 13 | .def(py::init(), py::arg("collision")) 14 | .def( 15 | py::init< 16 | const EdgeEdgeNormalCollision&, Eigen::ConstRef, 17 | const NormalPotential&, const double>(), 18 | py::arg("collision"), py::arg("positions"), 19 | py::arg("normal_potential"), py::arg("normal_stiffness")); 20 | } 21 | -------------------------------------------------------------------------------- /python/src/collisions/tangential/edge_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_edge_vertex_tangential_collision(py::module_& m) 9 | { 10 | py::class_< 11 | EdgeVertexTangentialCollision, EdgeVertexCandidate, 12 | TangentialCollision>(m, "EdgeVertexTangentialCollision") 13 | .def(py::init(), py::arg("collision")) 14 | .def( 15 | py::init< 16 | const EdgeVertexNormalCollision&, Eigen::ConstRef, 17 | const NormalPotential&, const double>(), 18 | py::arg("collision"), py::arg("positions"), 19 | py::arg("normal_potential"), py::arg("normal_stiffness")); 20 | } 21 | -------------------------------------------------------------------------------- /python/src/collisions/tangential/face_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_face_vertex_tangential_collision(py::module_& m) 9 | { 10 | py::class_< 11 | FaceVertexTangentialCollision, FaceVertexCandidate, 12 | TangentialCollision>(m, "FaceVertexTangentialCollision") 13 | .def(py::init(), py::arg("collision")) 14 | .def( 15 | py::init< 16 | const FaceVertexNormalCollision&, Eigen::ConstRef, 17 | const NormalPotential&, const double>(), 18 | py::arg("collision"), py::arg("positions"), 19 | py::arg("normal_potential"), py::arg("normal_stiffness")); 20 | } 21 | -------------------------------------------------------------------------------- /python/src/collisions/tangential/vertex_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_vertex_vertex_tangential_collision(py::module_& m) 9 | { 10 | py::class_< 11 | VertexVertexTangentialCollision, VertexVertexCandidate, 12 | TangentialCollision>(m, "VertexVertexTangentialCollision") 13 | .def( 14 | py::init(), 15 | py::arg("collision")) 16 | .def( 17 | py::init< 18 | const VertexVertexNormalCollision&, 19 | Eigen::ConstRef, const NormalPotential&, 20 | const double>(), 21 | py::arg("collision"), py::arg("positions"), 22 | py::arg("normal_potential"), py::arg("normal_stiffness")); 23 | } 24 | -------------------------------------------------------------------------------- /python/src/distance/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | distance_type.cpp 3 | edge_edge_mollifier.cpp 4 | edge_edge.cpp 5 | line_line.cpp 6 | point_edge.cpp 7 | point_line.cpp 8 | point_plane.cpp 9 | point_point.cpp 10 | point_triangle.cpp 11 | ) 12 | 13 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/distance/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_distance_type(py::module_& m); 7 | void define_edge_edge_mollifier(py::module_& m); 8 | void define_edge_edge_distance(py::module_& m); 9 | void define_line_line_distance(py::module_& m); 10 | void define_point_edge_distance(py::module_& m); 11 | void define_point_line_distance(py::module_& m); 12 | void define_point_point_distance(py::module_& m); 13 | void define_point_plane_distance(py::module_& m); 14 | void define_point_triangle_distance(py::module_& m); -------------------------------------------------------------------------------- /python/src/distance/point_point.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace py = pybind11; 7 | using namespace ipc; 8 | 9 | void define_point_point_distance(py::module_& m) 10 | { 11 | m.def( 12 | "point_point_distance", &point_point_distance, 13 | R"ipc_Qu8mg5v7( 14 | Compute the distance between two points. 15 | 16 | Note: 17 | The distance is actually squared distance. 18 | 19 | Parameters: 20 | p0: The first point. 21 | p1: The second point. 22 | 23 | Returns: 24 | The distance between p0 and p1. 25 | )ipc_Qu8mg5v7", 26 | py::arg("p0"), py::arg("p1")); 27 | 28 | m.def( 29 | "point_point_distance_gradient", &point_point_distance_gradient, 30 | R"ipc_Qu8mg5v7( 31 | Compute the gradient of the distance between two points. 32 | 33 | Note: 34 | The distance is actually squared distance. 35 | 36 | Parameters: 37 | p0: The first point. 38 | p1: The second point. 39 | 40 | Returns: 41 | The computed gradient. 42 | )ipc_Qu8mg5v7", 43 | py::arg("p0"), py::arg("p1")); 44 | 45 | m.def( 46 | "point_point_distance_hessian", &point_point_distance_hessian, 47 | R"ipc_Qu8mg5v7( 48 | Compute the hessian of the distance between two points. 49 | 50 | Note: 51 | The distance is actually squared distance. 52 | 53 | Parameters: 54 | p0: The first point. 55 | p1: The second point. 56 | 57 | Returns: 58 | The computed hessian. 59 | )ipc_Qu8mg5v7", 60 | py::arg("p0"), py::arg("p1")); 61 | } 62 | -------------------------------------------------------------------------------- /python/src/friction/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | smooth_friction_mollifier.cpp 3 | ) 4 | 5 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/friction/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_smooth_friction_mollifier(py::module_& m); -------------------------------------------------------------------------------- /python/src/implicits/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | plane.cpp 3 | ) 4 | 5 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/implicits/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_plane_implicit(py::module_& m); -------------------------------------------------------------------------------- /python/src/potentials/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | barrier_potential.cpp 3 | friction_potential.cpp 4 | normal_adhesion_potential.cpp 5 | normal_potential.cpp 6 | tangential_adhesion_potential.cpp 7 | tangential_potential.cpp 8 | ) 9 | 10 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/potentials/barrier_potential.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_barrier_potential(py::module_& m) 9 | { 10 | py::class_(m, "BarrierPotential") 11 | .def( 12 | py::init(), 13 | R"ipc_Qu8mg5v7( 14 | Construct a barrier potential. 15 | 16 | Parameters: 17 | dhat: The activation distance of the barrier. 18 | )ipc_Qu8mg5v7", 19 | py::arg("dhat"), py::arg("use_physical_barrier") = false) 20 | .def( 21 | py::init< 22 | const std::shared_ptr, const double, const bool>(), 23 | R"ipc_Qu8mg5v7( 24 | Construct a barrier potential. 25 | 26 | Parameters: 27 | barrier: The barrier function. 28 | dhat: The activation distance of the barrier. 29 | )ipc_Qu8mg5v7", 30 | py::arg("barrier"), py::arg("dhat"), 31 | py::arg("use_physical_barrier") = false) 32 | .def_property( 33 | "dhat", &BarrierPotential::dhat, &BarrierPotential::set_dhat, 34 | "Barrier activation distance.") 35 | .def_property( 36 | "barrier", 37 | py::cpp_function( 38 | &BarrierPotential::barrier, py::return_value_policy::reference), 39 | &BarrierPotential::set_barrier, 40 | "Barrier function used to compute the potential."); 41 | } 42 | -------------------------------------------------------------------------------- /python/src/potentials/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_barrier_potential(py::module_& m); 7 | void define_friction_potential(py::module_& m); 8 | void define_normal_adhesion_potential(py::module_& m); 9 | void define_normal_potential(py::module_& m); 10 | void define_tangential_adhesion_potential(py::module_& m); 11 | void define_tangential_potential(py::module_& m); -------------------------------------------------------------------------------- /python/src/potentials/friction_potential.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_friction_potential(py::module_& m) 9 | { 10 | py::class_(m, "FrictionPotential") 11 | .def( 12 | py::init(), 13 | R"ipc_Qu8mg5v7( 14 | Construct a friction potential. 15 | 16 | Parameters: 17 | eps_v: The smooth friction mollifier parameter :math:`\\epsilon_{v}`. 18 | )ipc_Qu8mg5v7", 19 | py::arg("eps_v")) 20 | .def_property( 21 | "eps_v", &FrictionPotential::eps_v, &FrictionPotential::set_eps_v, 22 | "The smooth friction mollifier parameter :math:`\\epsilon_{v}`."); 23 | } 24 | -------------------------------------------------------------------------------- /python/src/potentials/normal_adhesion_potential.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_normal_adhesion_potential(py::module_& m) 9 | { 10 | py::class_( 11 | m, "NormalAdhesionPotential") 12 | .def( 13 | py::init(), 14 | py::arg("dhat_p"), py::arg("dhat_a"), py::arg("Y"), 15 | py::arg("eps_c")) 16 | .def_readwrite( 17 | "dhat_p", &NormalAdhesionPotential::dhat_p, 18 | "The distance of largest adhesion force (:math:`\\hat{d}_{p}`) (:math:`0 < \\hat{d}_{p} < \\hat{d}_{a}`).") 19 | .def_readwrite( 20 | "dhat_a", &NormalAdhesionPotential::dhat_a, 21 | "The adhesion activation distance (:math:`\\hat{d}_{a}`.") 22 | .def_readwrite( 23 | "Y", &NormalAdhesionPotential::Y, 24 | "The Young's modulus (:math:`Y`)).") 25 | .def_readwrite( 26 | "eps_c", &NormalAdhesionPotential::eps_c, 27 | "The critical strain (:math:`\\varepsilon_{c}`))."); 28 | } 29 | -------------------------------------------------------------------------------- /python/src/potentials/tangential_adhesion_potential.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_tangential_adhesion_potential(py::module_& m) 9 | { 10 | py::class_( 11 | m, "TangentialAdhesionPotential") 12 | .def( 13 | py::init(), 14 | R"ipc_Qu8mg5v7( 15 | Construct a tangential adhesion potential. 16 | 17 | Parameters: 18 | eps_a: The tangential adhesion mollifier parameter :math:`\epsilon_a`. 19 | )ipc_Qu8mg5v7", 20 | py::arg("eps_a")) 21 | .def_property( 22 | "eps_a", &TangentialAdhesionPotential::eps_a, 23 | &TangentialAdhesionPotential::set_eps_a, 24 | "Get the tangential adhesion mollifier parameter :math:`\epsilon_a`."); 25 | } 26 | -------------------------------------------------------------------------------- /python/src/tangent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | closest_point.cpp 3 | relative_velocity.cpp 4 | tangent_basis.cpp 5 | ) 6 | 7 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/tangent/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_closest_point(py::module_& m); 7 | void define_relative_velocity(py::module_& m); 8 | void define_tangent_basis(py::module_& m); -------------------------------------------------------------------------------- /python/src/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | area_gradient.cpp 3 | eigen_ext.cpp 4 | intersection.cpp 5 | interval.cpp 6 | logger.cpp 7 | thread_limiter.cpp 8 | vertex_to_min_edge.cpp 9 | world_bbox_diagonal_length.cpp 10 | ) 11 | 12 | target_sources(ipctk PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /python/src/utils/area_gradient.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | namespace py = pybind11; 7 | using namespace ipc; 8 | 9 | void define_area_gradient(py::module_& m) 10 | { 11 | m.def( 12 | "edge_length_gradient", &edge_length_gradient, 13 | R"ipc_Qu8mg5v7( 14 | Compute the gradient of an edge's length. 15 | 16 | Parameters: 17 | e0: The first vertex of the edge. 18 | e1: The second vertex of the edge. 19 | 20 | Returns: 21 | The gradient of the edge's length wrt e0, and e1. 22 | )ipc_Qu8mg5v7", 23 | py::arg("e0"), py::arg("e1")); 24 | 25 | m.def( 26 | "triangle_area_gradient", &triangle_area_gradient, 27 | R"ipc_Qu8mg5v7( 28 | Compute the gradient of the area of a triangle. 29 | 30 | Parameters: 31 | t0: The first vertex of the triangle. 32 | t1: The second vertex of the triangle. 33 | t2: The third vertex of the triangle. 34 | 35 | Returns: 36 | The gradient of the triangle's area t0, t1, and t2. 37 | )ipc_Qu8mg5v7", 38 | py::arg("t0"), py::arg("t1"), py::arg("t2")); 39 | } 40 | -------------------------------------------------------------------------------- /python/src/utils/bindings.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | namespace py = pybind11; 5 | 6 | void define_area_gradient(py::module_& m); 7 | void define_eigen_ext(py::module_& m); 8 | void define_interval(py::module_& m); 9 | void define_intersection(py::module_& m); 10 | void define_logger(py::module_& m); 11 | void define_thread_limiter(py::module_& m); 12 | void define_vertex_to_min_edge(py::module_& m); 13 | void define_world_bbox_diagonal_length(py::module_& m); -------------------------------------------------------------------------------- /python/src/utils/eigen_ext.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_eigen_ext(py::module_& m) 9 | { 10 | m.def( 11 | "project_to_pd", 12 | // clang-format off 13 | &project_to_pd< 14 | double, Eigen::Dynamic, Eigen::Dynamic, 15 | Eigen::ColMajor | Eigen::AutoAlign, Eigen::Dynamic, Eigen::Dynamic>, 16 | // clang-format on 17 | R"ipc_Qu8mg5v7( 18 | Matrix projection onto positive definite cone 19 | 20 | Parameters: 21 | A: Symmetric matrix to project 22 | 23 | Returns: 24 | Projected matrix 25 | )ipc_Qu8mg5v7", 26 | py::arg("A"), py::arg("eps") = 1e-8); 27 | 28 | py::enum_( 29 | m, "PSDProjectionMethod", 30 | "Enumeration of implemented PSD projection methods.") 31 | .value("NONE", PSDProjectionMethod::NONE, "No PSD projection") 32 | .value( 33 | "CLAMP", PSDProjectionMethod::CLAMP, 34 | "Clamp negative eigenvalues to zero") 35 | .value("ABS", PSDProjectionMethod::ABS, "Flip negative eigenvalues") 36 | .export_values(); 37 | 38 | m.def( 39 | "project_to_psd", 40 | // clang-format off 41 | &project_to_psd< 42 | double, Eigen::Dynamic, Eigen::Dynamic, 43 | Eigen::ColMajor | Eigen::AutoAlign, Eigen::Dynamic, Eigen::Dynamic>, 44 | // clang-format on 45 | R"ipc_Qu8mg5v7( 46 | Matrix projection onto positive semi-definite cone 47 | 48 | Parameters: 49 | A: Symmetric matrix to project 50 | method: PSD projection method 51 | 52 | Returns: 53 | Projected matrix 54 | )ipc_Qu8mg5v7", 55 | py::arg("A"), py::arg("method") = PSDProjectionMethod::CLAMP); 56 | } 57 | -------------------------------------------------------------------------------- /python/src/utils/intersection.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace py = pybind11; 8 | using namespace ipc; 9 | 10 | void define_intersection(py::module_& m) 11 | { 12 | m.def( 13 | "is_edge_intersecting_triangle", &is_edge_intersecting_triangle, 14 | py::arg("e0"), py::arg("e1"), py::arg("t0"), py::arg("t1"), 15 | py::arg("t2")); 16 | 17 | m.def( 18 | "segment_segment_intersect", 19 | [](Eigen::ConstRef A, 20 | Eigen::ConstRef B, 21 | Eigen::ConstRef C, 22 | Eigen::ConstRef D) -> bool { 23 | igl::predicates::exactinit(); 24 | return igl::predicates::segment_segment_intersect(A, B, C, D); 25 | }, 26 | R"ipc_Qu8mg5v7( 27 | Given two segments in 2d test whether they intersect each other using predicates orient2d 28 | 29 | Parameters: 30 | A: 1st endpoint of segment 1 31 | B: 2st endpoint of segment 1 32 | C: 1st endpoint of segment 2 33 | D: 2st endpoint of segment 2 34 | 35 | Returns: 36 | true if they intersect 37 | )ipc_Qu8mg5v7", 38 | py::arg("A"), py::arg("B"), py::arg("C"), py::arg("D")); 39 | } 40 | -------------------------------------------------------------------------------- /python/src/utils/logger.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_logger(py::module_& m) 9 | { 10 | py::enum_( 11 | m, "LoggerLevel", "Enumeration of log levels") 12 | .value("trace", spdlog::level::level_enum::trace, "Trace level") 13 | .value("debug", spdlog::level::level_enum::debug, "Debug level") 14 | .value("info", spdlog::level::level_enum::info, "Info level") 15 | .value("warn", spdlog::level::level_enum::warn, "Warning level") 16 | .value("error", spdlog::level::level_enum::err, "Error level") 17 | .value( 18 | "critical", spdlog::level::level_enum::critical, "Critical level") 19 | .value("off", spdlog::level::level_enum::off, "Off level") 20 | .export_values(); 21 | 22 | m.def( 23 | "set_logger_level", 24 | [](const spdlog::level::level_enum& level) { 25 | logger().set_level(level); 26 | }, 27 | "Set log level", py::arg("level")); 28 | } 29 | -------------------------------------------------------------------------------- /python/src/utils/thread_limiter.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | 6 | #include 7 | #include 8 | 9 | #include 10 | 11 | namespace py = pybind11; 12 | using namespace ipc; 13 | 14 | static std::shared_ptr thread_limiter; 15 | 16 | int get_num_threads() 17 | { 18 | return tbb::global_control::active_value( 19 | tbb::global_control::max_allowed_parallelism); 20 | } 21 | 22 | void set_num_threads(int nthreads) 23 | { 24 | if (nthreads <= 0) { 25 | nthreads = tbb::info::default_concurrency(); 26 | } else if (nthreads > tbb::info::default_concurrency()) { 27 | logger().warn( 28 | "Attempting to use more threads than available ({:d} > {:d})!", 29 | nthreads, tbb::info::default_concurrency()); 30 | nthreads = tbb::info::default_concurrency(); 31 | } 32 | thread_limiter = std::make_shared( 33 | tbb::global_control::max_allowed_parallelism, nthreads); 34 | } 35 | 36 | void define_thread_limiter(py::module_& m) 37 | { 38 | m.def( 39 | "get_num_threads", &get_num_threads, 40 | "get maximum number of threads to use"); 41 | m.def( 42 | "set_num_threads", &set_num_threads, 43 | "set maximum number of threads to use", py::arg("nthreads")); 44 | 45 | std::atexit([]() { thread_limiter.reset(); }); 46 | } 47 | -------------------------------------------------------------------------------- /python/src/utils/vertex_to_min_edge.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_vertex_to_min_edge(py::module_& m) 9 | { 10 | m.def( 11 | "vertex_to_min_edge", &vertex_to_min_edge, py::arg("num_vertices"), 12 | py::arg("edges")); 13 | } 14 | -------------------------------------------------------------------------------- /python/src/utils/world_bbox_diagonal_length.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | namespace py = pybind11; 6 | using namespace ipc; 7 | 8 | void define_world_bbox_diagonal_length(py::module_& m) 9 | { 10 | m.def( 11 | "world_bbox_diagonal_length", &world_bbox_diagonal_length, 12 | R"ipc_Qu8mg5v7( 13 | Compute the diagonal length of the world bounding box. 14 | 15 | Parameters: 16 | vertices: Vertex positions 17 | 18 | Returns: 19 | The diagonal length of the world bounding box. 20 | )ipc_Qu8mg5v7", 21 | py::arg("vertices")); 22 | } 23 | -------------------------------------------------------------------------------- /python/tests/find_ipctk.py: -------------------------------------------------------------------------------- 1 | try: 2 | import ipctk # Try to import the built module 3 | except ImportError: 4 | import sys 5 | import pathlib 6 | repo_root = pathlib.Path(__file__).parents[2] 7 | possible_paths = [ 8 | pathlib.Path("python").resolve(), 9 | repo_root / "build" / "python", 10 | repo_root / "build" / "release" / "python", 11 | repo_root / "build" / "debug" / "python", 12 | ] 13 | for path in possible_paths: 14 | if path.exists() and len(list(path.glob("ipctk.*"))) > 0: 15 | sys.path.append(str(path)) 16 | break 17 | else: 18 | raise ImportError("Could not find the ipctk module") 19 | print(f"Using found ipctk module at {path}") 20 | import ipctk # Try again 21 | -------------------------------------------------------------------------------- /python/tests/requirements.txt: -------------------------------------------------------------------------------- 1 | nose2 2 | meshio -------------------------------------------------------------------------------- /python/tests/test_candidates.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from find_ipctk import ipctk 4 | from ipctk.filib import Interval 5 | 6 | from utils import load_mesh 7 | 8 | 9 | def test_candidates(): 10 | V0, E, F = load_mesh("two-cubes-close.ply") 11 | V1, E, F = load_mesh("two-cubes-intersecting.ply") 12 | 13 | mesh = ipctk.CollisionMesh(V0, E, F) 14 | 15 | candidates = ipctk.Candidates() 16 | candidates.build(mesh, V0, V1) 17 | 18 | assert len(candidates) > 0, "No candidates generated." -------------------------------------------------------------------------------- /python/tests/test_constraints.py: -------------------------------------------------------------------------------- 1 | from find_ipctk import ipctk 2 | 3 | 4 | def test_collisions(): 5 | c = ipctk.VertexVertexNormalCollision(0, 1) 6 | c.weight = 10 7 | assert c.weight == 10 8 | 9 | cs = ipctk.Candidates() 10 | num_candidates = 20 11 | cs.ev_candidates = [ 12 | ipctk.EdgeVertexCandidate(i, i+1) for i in range(num_candidates)] 13 | assert len(cs) == num_candidates 14 | 15 | assert ipctk.EdgeVertexCandidate(0, 1) == ipctk.EdgeVertexCandidate(0, 1) 16 | -------------------------------------------------------------------------------- /python/tests/test_intersections.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | 3 | from find_ipctk import ipctk 4 | 5 | 6 | def test_segment_segment_intersect(): 7 | assert ipctk.segment_segment_intersect( 8 | np.array([-1, 0]), np.array([1, 0]), np.array([0, -1]), np.array([0, 1])) 9 | -------------------------------------------------------------------------------- /python/tests/utils.py: -------------------------------------------------------------------------------- 1 | import pathlib 2 | import numpy as np 3 | import meshio 4 | 5 | from find_ipctk import ipctk 6 | 7 | 8 | def download_test_data_if_needed(directory): 9 | if directory.exists(): 10 | return 11 | 12 | # Clone the test data repository 13 | print(f"Downloading test data to {directory}") 14 | import subprocess 15 | subprocess.run([ 16 | 'git', 'clone', 'https://github.com/ipc-sim/ipc-toolkit-tests-data', 17 | str(directory) 18 | ]) 19 | 20 | 21 | def test_data_dir(): 22 | _test_data_dir = pathlib.Path(__file__).parents[2] / 'tests' / 'data' 23 | download_test_data_if_needed(_test_data_dir) 24 | return _test_data_dir 25 | 26 | 27 | def load_mesh(mesh_name): 28 | mesh = meshio.read(test_data_dir() / mesh_name) 29 | return mesh.points, ipctk.edges(mesh.cells_dict['triangle']), mesh.cells_dict['triangle'] 30 | 31 | 32 | def broad_phases(): 33 | yield ipctk.BruteForce() 34 | yield ipctk.HashGrid() 35 | yield ipctk.SpatialHash() 36 | yield ipctk.BVH() 37 | yield ipctk.SweepAndPrune() 38 | 39 | 40 | def finite_jacobian(x, f, h=1e-8): 41 | external_coeffs = [1, -1] 42 | internal_coeffs = [1, -1] 43 | assert len(external_coeffs) == len(internal_coeffs) 44 | inner_steps = len(internal_coeffs) 45 | denom = 2 * h 46 | 47 | jac = np.zeros((f(x).shape[0], x.shape[0])) 48 | 49 | x_mutable = x.copy() 50 | for i in range(x.shape[0]): 51 | for ci in range(inner_steps): 52 | x_mutable[i] += internal_coeffs[ci] * h 53 | jac[:, i] += external_coeffs[ci] * f(x_mutable) 54 | x_mutable[i] = x[i] 55 | jac[:, i] /= denom 56 | 57 | return jac 58 | 59 | 60 | def finite_gradient(x, f, h=1e-8): 61 | return finite_jacobian(x, lambda x: np.array([f(x)]), h) 62 | -------------------------------------------------------------------------------- /src/ipc/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | collision_mesh.cpp 3 | collision_mesh.hpp 4 | ipc.hpp 5 | ipc.cpp 6 | ) 7 | 8 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) 9 | 10 | ################################################################################ 11 | # Subfolders 12 | ################################################################################ 13 | 14 | add_subdirectory(adhesion) 15 | add_subdirectory(barrier) 16 | add_subdirectory(broad_phase) 17 | add_subdirectory(candidates) 18 | add_subdirectory(ccd) 19 | add_subdirectory(collisions) 20 | add_subdirectory(distance) 21 | add_subdirectory(friction) 22 | add_subdirectory(implicits) 23 | add_subdirectory(potentials) 24 | add_subdirectory(tangent) 25 | add_subdirectory(utils) -------------------------------------------------------------------------------- /src/ipc/adhesion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | adhesion.cpp 3 | adhesion.hpp 4 | ) 5 | 6 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/barrier/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | adaptive_stiffness.cpp 3 | adaptive_stiffness.hpp 4 | barrier_force_magnitude.cpp 5 | barrier_force_magnitude.hpp 6 | barrier.cpp 7 | barrier.hpp 8 | ) 9 | 10 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/barrier/barrier_force_magnitude.cpp: -------------------------------------------------------------------------------- 1 | #include "barrier_force_magnitude.hpp" 2 | 3 | namespace ipc { 4 | 5 | double barrier_force_magnitude( 6 | const double distance_squared, 7 | const Barrier& barrier, 8 | const double dhat, 9 | const double barrier_stiffness, 10 | const double dmin) 11 | { 12 | double grad_b = barrier.first_derivative( 13 | distance_squared - dmin * dmin, (2 * dmin + dhat) * dhat); 14 | return -barrier_stiffness * grad_b * 2 * sqrt(distance_squared); 15 | } 16 | 17 | VectorMax12d barrier_force_magnitude_gradient( 18 | const double distance_squared, 19 | Eigen::ConstRef distance_squared_gradient, 20 | const Barrier& barrier, 21 | const double dhat, 22 | const double barrier_stiffness, 23 | const double dmin) 24 | { 25 | double arg_d = distance_squared - dmin * dmin; 26 | double arg_dhat = (2 * dmin + dhat) * dhat; 27 | double distance = sqrt(distance_squared); 28 | assert(distance > 0); 29 | 30 | // ∇ₓ -κ * b'(d²(x)) * 2 * d(x) 31 | // = -κ * ∇ₓb'(d²(x)) * 2 * d(x) - κ * b'(d²(x)) * 2 * ∇ₓd(x) 32 | // = -κ * (b"(d²(x)) * 2 * d(x) + b'(d²(x)) / d(x)) * ∇ₓd(x) 33 | return -barrier_stiffness 34 | * (barrier.second_derivative(arg_d, arg_dhat) * 2 * distance 35 | + barrier.first_derivative(arg_d, arg_dhat) / distance) 36 | * distance_squared_gradient; 37 | } 38 | 39 | } // namespace ipc 40 | -------------------------------------------------------------------------------- /src/ipc/barrier/barrier_force_magnitude.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace ipc { 7 | 8 | /// @brief Compute the magnitude of the force due to a barrier. 9 | /// @param distance_squared The squared distance between elements. 10 | /// @param barrier The barrier function. 11 | /// @param dhat The activation distance of the barrier. 12 | /// @param barrier_stiffness The stiffness of the barrier. 13 | /// @param dmin The minimum distance offset to the barrier. 14 | /// @return The magnitude of the force. 15 | double barrier_force_magnitude( 16 | const double distance_squared, 17 | const Barrier& barrier, 18 | const double dhat, 19 | const double barrier_stiffness, 20 | const double dmin = 0); 21 | 22 | /// @brief Compute the gradient of the magnitude of the force due to a barrier. 23 | /// @param distance_squared The squared distance between elements. 24 | /// @param distance_squared_gradient The gradient of the squared distance. 25 | /// @param barrier The barrier function. 26 | /// @param dhat The activation distance of the barrier. 27 | /// @param barrier_stiffness The stiffness of the barrier. 28 | /// @param dmin The minimum distance offset to the barrier. 29 | /// @return The gradient of the force. 30 | VectorMax12d barrier_force_magnitude_gradient( 31 | const double distance_squared, 32 | Eigen::ConstRef distance_squared_gradient, 33 | const Barrier& barrier, 34 | const double dhat, 35 | const double barrier_stiffness, 36 | const double dmin = 0); 37 | 38 | } // namespace ipc 39 | -------------------------------------------------------------------------------- /src/ipc/broad_phase/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | aabb.cpp 3 | aabb.hpp 4 | broad_phase.cpp 5 | broad_phase.hpp 6 | brute_force.cpp 7 | brute_force.hpp 8 | bvh.cpp 9 | bvh.hpp 10 | default_broad_phase.hpp 11 | hash_grid.cpp 12 | hash_grid.hpp 13 | spatial_hash.cpp 14 | spatial_hash.hpp 15 | sweep_and_prune.cpp 16 | sweep_and_prune.hpp 17 | sweep_and_tiniest_queue.cpp 18 | sweep_and_tiniest_queue.hpp 19 | voxel_size_heuristic.cpp 20 | voxel_size_heuristic.hpp 21 | ) 22 | 23 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/broad_phase/default_broad_phase.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | inline std::shared_ptr make_default_broad_phase() 8 | { 9 | return std::make_shared(); 10 | } 11 | 12 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/broad_phase/voxel_size_heuristic.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | double suggest_good_voxel_size( 8 | Eigen::ConstRef vertices, 9 | Eigen::ConstRef edges, 10 | const double inflation_radius = 0); 11 | 12 | double suggest_good_voxel_size( 13 | Eigen::ConstRef vertices_t0, 14 | Eigen::ConstRef vertices_t1, 15 | Eigen::ConstRef edges, 16 | const double inflation_radius = 0); 17 | 18 | /// @brief Compute the average edge length of a mesh. 19 | double mean_edge_length( 20 | Eigen::ConstRef vertices_t0, 21 | Eigen::ConstRef vertices_t1, 22 | Eigen::ConstRef edges, 23 | double& std_deviation); 24 | 25 | /// @brief Compute the average displacement length. 26 | double mean_displacement_length( 27 | Eigen::ConstRef displacements, double& std_deviation); 28 | 29 | /// @brief Compute the median edge length of a mesh. 30 | double median_edge_length( 31 | Eigen::ConstRef vertices_t0, 32 | Eigen::ConstRef vertices_t1, 33 | Eigen::ConstRef edges); 34 | 35 | /// @brief Compute the median displacement length. 36 | double 37 | median_displacement_length(Eigen::ConstRef displacements); 38 | 39 | /// @brief Compute the maximum edge length of a mesh. 40 | double max_edge_length( 41 | Eigen::ConstRef vertices_t0, 42 | Eigen::ConstRef vertices_t1, 43 | Eigen::ConstRef edges); 44 | 45 | /// @brief Compute the maximum displacement length. 46 | double max_displacement_length(Eigen::ConstRef displacements); 47 | 48 | } // namespace ipc 49 | -------------------------------------------------------------------------------- /src/ipc/candidates/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | candidates.cpp 3 | candidates.hpp 4 | collision_stencil.cpp 5 | collision_stencil.hpp 6 | edge_edge.cpp 7 | edge_edge.hpp 8 | edge_face.cpp 9 | edge_face.hpp 10 | edge_vertex.cpp 11 | edge_vertex.hpp 12 | face_face.cpp 13 | face_face.hpp 14 | face_vertex.cpp 15 | face_vertex.hpp 16 | # plane_vertex.cpp 17 | # plane_vertex.hpp 18 | vertex_vertex.cpp 19 | vertex_vertex.hpp 20 | ) 21 | 22 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/candidates/collision_stencil.cpp: -------------------------------------------------------------------------------- 1 | #include "collision_stencil.hpp" 2 | 3 | namespace ipc { 4 | 5 | std::ostream& CollisionStencil::write_ccd_query( 6 | std::ostream& out, 7 | Eigen::ConstRef vertices_t0, 8 | Eigen::ConstRef vertices_t1) const 9 | { 10 | assert(vertices_t0.size() == vertices_t1.size()); 11 | 12 | const int dim = vertices_t0.size() / num_vertices(); 13 | assert(vertices_t0.size() % num_vertices() == 0); 14 | 15 | for (int i = 0; i < num_vertices(); i++) { 16 | out << vertices_t0.segment(dim * i, dim) 17 | .transpose() 18 | .format(OBJ_VERTEX_FORMAT); 19 | } 20 | 21 | for (int i = 0; i < num_vertices(); i++) { 22 | out << vertices_t1.segment(dim * i, dim) 23 | .transpose() 24 | .format(OBJ_VERTEX_FORMAT); 25 | } 26 | 27 | return out; 28 | } 29 | 30 | } // namespace ipc 31 | -------------------------------------------------------------------------------- /src/ipc/candidates/edge_face.cpp: -------------------------------------------------------------------------------- 1 | #include "edge_face.hpp" 2 | 3 | namespace ipc { 4 | 5 | EdgeFaceCandidate::EdgeFaceCandidate(index_t _edge_id, index_t _face_id) 6 | : edge_id(_edge_id) 7 | , face_id(_face_id) 8 | { 9 | } 10 | 11 | bool EdgeFaceCandidate::operator==(const EdgeFaceCandidate& other) const 12 | { 13 | return edge_id == other.edge_id && face_id == other.face_id; 14 | } 15 | 16 | bool EdgeFaceCandidate::operator!=(const EdgeFaceCandidate& other) const 17 | { 18 | return !(*this == other); 19 | } 20 | 21 | bool EdgeFaceCandidate::operator<(const EdgeFaceCandidate& other) const 22 | { 23 | if (edge_id == other.edge_id) { 24 | return face_id < other.face_id; 25 | } 26 | return edge_id < other.edge_id; 27 | } 28 | 29 | } // namespace ipc 30 | -------------------------------------------------------------------------------- /src/ipc/candidates/edge_face.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace ipc { 8 | 9 | /// @brief Candidate for intersection between edge and face. 10 | /// 11 | /// Not included in Candidates because it is not a collision candidate. 12 | class EdgeFaceCandidate { 13 | public: 14 | EdgeFaceCandidate(index_t edge_id, index_t face_id); 15 | 16 | bool operator==(const EdgeFaceCandidate& other) const; 17 | bool operator!=(const EdgeFaceCandidate& other) const; 18 | /// @brief Compare EdgeFaceCandidate for sorting. 19 | bool operator<(const EdgeFaceCandidate& other) const; 20 | 21 | template 22 | friend H AbslHashValue(H h, const EdgeFaceCandidate& fv) 23 | { 24 | return H::combine(std::move(h), fv.edge_id, fv.face_id); 25 | } 26 | 27 | /// @brief ID of the edge 28 | index_t edge_id; 29 | /// @brief ID of the face 30 | index_t face_id; 31 | }; 32 | 33 | } // namespace ipc 34 | -------------------------------------------------------------------------------- /src/ipc/candidates/face_face.cpp: -------------------------------------------------------------------------------- 1 | #include "face_face.hpp" 2 | 3 | namespace ipc { 4 | 5 | FaceFaceCandidate::FaceFaceCandidate(index_t _face0_id, index_t _face1_id) 6 | : face0_id(_face0_id) 7 | , face1_id(_face1_id) 8 | { 9 | } 10 | 11 | bool FaceFaceCandidate::operator==(const FaceFaceCandidate& other) const 12 | { 13 | // (i, j) == (i, j) || (i, j) == (j, i) 14 | return (this->face0_id == other.face0_id 15 | && this->face1_id == other.face1_id) 16 | || (this->face0_id == other.face1_id 17 | && this->face1_id == other.face0_id); 18 | } 19 | 20 | bool FaceFaceCandidate::operator!=(const FaceFaceCandidate& other) const 21 | { 22 | return !(*this == other); 23 | } 24 | 25 | bool FaceFaceCandidate::operator<(const FaceFaceCandidate& other) const 26 | { 27 | index_t this_min = std::min(this->face0_id, this->face1_id); 28 | index_t other_min = std::min(other.face0_id, other.face1_id); 29 | if (this_min == other_min) { 30 | return std::max(this->face0_id, this->face1_id) 31 | < std::max(other.face0_id, other.face1_id); 32 | } 33 | return this_min < other_min; 34 | } 35 | 36 | } // namespace ipc 37 | -------------------------------------------------------------------------------- /src/ipc/candidates/face_face.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace ipc { 8 | 9 | /// @brief Candidate for collision between two faces. 10 | /// @note This collision candidate is not needed for flat triangles because face-vertex and edge-edge collisions are sufficient. 11 | /// @note This may be useful for nonlinear triangles in the future. 12 | class FaceFaceCandidate { 13 | public: 14 | FaceFaceCandidate(index_t face0_id, index_t face1_id); 15 | 16 | bool operator==(const FaceFaceCandidate& other) const; 17 | bool operator!=(const FaceFaceCandidate& other) const; 18 | /// @brief Compare FaceFaceCandidate for sorting. 19 | bool operator<(const FaceFaceCandidate& other) const; 20 | 21 | template 22 | friend H AbslHashValue(H h, const FaceFaceCandidate& ff) 23 | { 24 | index_t min_fi = std::min(ff.face0_id, ff.face1_id); 25 | index_t max_fi = std::max(ff.face0_id, ff.face1_id); 26 | return H::combine(std::move(h), min_fi, max_fi); 27 | } 28 | 29 | /// @brief ID of the first face. 30 | index_t face0_id; 31 | /// @brief ID of the second face. 32 | index_t face1_id; 33 | }; 34 | 35 | } // namespace ipc 36 | -------------------------------------------------------------------------------- /src/ipc/ccd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | aabb.cpp 3 | aabb.hpp 4 | additive_ccd.cpp 5 | additive_ccd.hpp 6 | check_initial_distance.hpp 7 | default_narrow_phase_ccd.cpp 8 | default_narrow_phase_ccd.hpp 9 | inexact_ccd.cpp 10 | inexact_ccd.hpp 11 | inexact_point_edge.cpp 12 | inexact_point_edge.hpp 13 | nonlinear_ccd.cpp 14 | nonlinear_ccd.hpp 15 | point_static_plane.cpp 16 | point_static_plane.hpp 17 | tight_inclusion_ccd.cpp 18 | tight_inclusion_ccd.hpp 19 | ) 20 | 21 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/ccd/check_initial_distance.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | inline bool check_initial_distance( 8 | const double initial_distance, const double min_distance, double& toi) 9 | { 10 | if (initial_distance > min_distance) { 11 | return false; 12 | } 13 | 14 | logger().warn( 15 | "Initial distance {} ≤ d_min={}, returning toi=0!", initial_distance, 16 | min_distance); 17 | 18 | toi = 0; // Initially touching 19 | 20 | return true; 21 | } 22 | 23 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/ccd/default_narrow_phase_ccd.cpp: -------------------------------------------------------------------------------- 1 | #include "default_narrow_phase_ccd.hpp" 2 | 3 | namespace ipc { 4 | const TightInclusionCCD DEFAULT_NARROW_PHASE_CCD; 5 | } -------------------------------------------------------------------------------- /src/ipc/ccd/default_narrow_phase_ccd.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | extern const TightInclusionCCD DEFAULT_NARROW_PHASE_CCD; 7 | } -------------------------------------------------------------------------------- /src/ipc/ccd/inexact_point_edge.hpp: -------------------------------------------------------------------------------- 1 | // 2 | // NOTE: This method is provided for reference comparison and is not utilized by 3 | // the high-level functionality. In compairson to Tight Inclusion CCD, this CCD 4 | // method is not provably conservative and so can potentially produce false 5 | // negatives (i.e., miss collisions) due to floating-point rounding error. 6 | // 7 | 8 | #pragma once 9 | 10 | #include 11 | 12 | namespace ipc { 13 | 14 | /// @brief Inexact continuous collision detection between a point and an edge in 2D. 15 | /// @param[in] p_t0 The initial position of the point. 16 | /// @param[in] e0_t0 The initial position of the first endpoint of the edge. 17 | /// @param[in] e1_t0 The initial position of the second endpoint of the edge. 18 | /// @param[in] p_t1 The final position of the point. 19 | /// @param[in] e0_t1 The final position of the first endpoint of the edge. 20 | /// @param[in] e1_t1 The final position of the second endpoint of the edge. 21 | /// @param[out] toi Output time of impact. 22 | /// @param[in] conservative_rescaling The conservative rescaling of the time of impact. 23 | /// @return True if a collision was detected, false otherwise. 24 | bool inexact_point_edge_ccd_2D( 25 | Eigen::ConstRef p_t0, 26 | Eigen::ConstRef e0_t0, 27 | Eigen::ConstRef e1_t0, 28 | Eigen::ConstRef p_t1, 29 | Eigen::ConstRef e0_t1, 30 | Eigen::ConstRef e1_t1, 31 | double& toi, 32 | const double conservative_rescaling); 33 | 34 | } // namespace ipc 35 | -------------------------------------------------------------------------------- /src/ipc/ccd/point_static_plane.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief Computes the time of impact between a point and a static plane in 3D using continuous collision detection. 8 | /// @param[in] p_t0 The initial position of the point. 9 | /// @param[in] p_t1 The final position of the point. 10 | /// @param[in] plane_origin The origin of the plane. 11 | /// @param[in] plane_normal The normal of the plane. 12 | /// @param[out] toi Output time of impact. 13 | /// @param[in] conservative_rescaling Conservative rescaling of the time of impact. 14 | /// @return True if a collision was detected, false otherwise. 15 | bool point_static_plane_ccd( 16 | Eigen::ConstRef p_t0, 17 | Eigen::ConstRef p_t1, 18 | Eigen::ConstRef plane_origin, 19 | Eigen::ConstRef plane_normal, 20 | double& toi, 21 | const double conservative_rescaling = 22 | TightInclusionCCD::DEFAULT_CONSERVATIVE_RESCALING); 23 | 24 | } // namespace ipc 25 | -------------------------------------------------------------------------------- /src/ipc/collisions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # set(SOURCES) 2 | 3 | # target_sources(ipc_toolkit PRIVATE ${SOURCES}) 4 | 5 | ################################################################################ 6 | # Subfolders 7 | ################################################################################ 8 | 9 | add_subdirectory(normal) 10 | add_subdirectory(tangential) -------------------------------------------------------------------------------- /src/ipc/collisions/normal/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | edge_edge.cpp 3 | edge_edge.hpp 4 | edge_vertex.hpp 5 | face_vertex.hpp 6 | normal_collision.cpp 7 | normal_collision.hpp 8 | normal_collisions_builder.cpp 9 | normal_collisions_builder.hpp 10 | normal_collisions.cpp 11 | normal_collisions.hpp 12 | plane_vertex.cpp 13 | plane_vertex.hpp 14 | vertex_vertex.hpp 15 | ) 16 | 17 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/collisions/normal/edge_vertex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace ipc { 7 | 8 | class EdgeVertexNormalCollision : public EdgeVertexCandidate, 9 | public NormalCollision { 10 | public: 11 | using EdgeVertexCandidate::EdgeVertexCandidate; 12 | 13 | EdgeVertexNormalCollision(const EdgeVertexCandidate& candidate) 14 | : EdgeVertexCandidate(candidate) 15 | { 16 | } 17 | 18 | EdgeVertexNormalCollision( 19 | const index_t _edge_id, 20 | const index_t _vertex_id, 21 | const double _weight, 22 | const Eigen::SparseVector& _weight_gradient) 23 | : EdgeVertexCandidate(_edge_id, _vertex_id) 24 | , NormalCollision(_weight, _weight_gradient) 25 | { 26 | } 27 | 28 | PointEdgeDistanceType known_dtype() const override 29 | { 30 | // The distance type is known because of NormalCollisions::build() 31 | return PointEdgeDistanceType::P_E; 32 | } 33 | 34 | template 35 | friend H AbslHashValue(H h, const EdgeVertexNormalCollision& ev) 36 | { 37 | return AbslHashValue( 38 | std::move(h), static_cast(ev)); 39 | } 40 | }; 41 | 42 | } // namespace ipc 43 | -------------------------------------------------------------------------------- /src/ipc/collisions/normal/face_vertex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | namespace ipc { 7 | 8 | class FaceVertexNormalCollision : public FaceVertexCandidate, 9 | public NormalCollision { 10 | public: 11 | using FaceVertexCandidate::FaceVertexCandidate; 12 | 13 | FaceVertexNormalCollision(const FaceVertexCandidate& candidate) 14 | : FaceVertexCandidate(candidate) 15 | { 16 | } 17 | 18 | FaceVertexNormalCollision( 19 | const index_t _face_id, 20 | const index_t _vertex_id, 21 | const double _weight, 22 | const Eigen::SparseVector& _weight_gradient) 23 | : FaceVertexCandidate(_face_id, _vertex_id) 24 | , NormalCollision(_weight, _weight_gradient) 25 | { 26 | } 27 | 28 | PointTriangleDistanceType known_dtype() const override 29 | { 30 | // The distance type is known because of NormalCollisions::build() 31 | return PointTriangleDistanceType::P_T; 32 | } 33 | 34 | template 35 | friend H AbslHashValue(H h, const FaceVertexNormalCollision& fv) 36 | { 37 | return AbslHashValue( 38 | std::move(h), static_cast(fv)); 39 | } 40 | }; 41 | 42 | } // namespace ipc 43 | -------------------------------------------------------------------------------- /src/ipc/collisions/normal/normal_collision.cpp: -------------------------------------------------------------------------------- 1 | #include "normal_collision.hpp" 2 | 3 | namespace ipc { 4 | 5 | NormalCollision::NormalCollision( 6 | const double _weight, const Eigen::SparseVector& _weight_gradient) 7 | : weight(_weight) 8 | , weight_gradient(_weight_gradient) 9 | { 10 | } 11 | 12 | double NormalCollision::mollifier(Eigen::ConstRef positions) const 13 | { 14 | return 1.0; 15 | } 16 | 17 | double NormalCollision::mollifier( 18 | Eigen::ConstRef positions, double eps_x) const 19 | { 20 | return 1.0; 21 | } 22 | 23 | VectorMax12d NormalCollision::mollifier_gradient( 24 | Eigen::ConstRef positions) const 25 | { 26 | return VectorMax12d::Zero(positions.size()); 27 | } 28 | 29 | VectorMax12d NormalCollision::mollifier_gradient( 30 | Eigen::ConstRef positions, double eps_x) const 31 | { 32 | return VectorMax12d::Zero(positions.size()); 33 | } 34 | 35 | MatrixMax12d NormalCollision::mollifier_hessian( 36 | Eigen::ConstRef positions) const 37 | { 38 | return MatrixMax12d::Zero(positions.size(), positions.size()); 39 | } 40 | 41 | MatrixMax12d NormalCollision::mollifier_hessian( 42 | Eigen::ConstRef positions, double eps_x) const 43 | { 44 | return MatrixMax12d::Zero(positions.size(), positions.size()); 45 | } 46 | 47 | Vector12d NormalCollision::mollifier_gradient_wrt_x( 48 | Eigen::ConstRef rest_positions, 49 | Eigen::ConstRef positions) const 50 | { 51 | return Vector12d::Zero(rest_positions.size()); 52 | } 53 | 54 | Matrix12d NormalCollision::mollifier_gradient_jacobian_wrt_x( 55 | Eigen::ConstRef rest_positions, 56 | Eigen::ConstRef positions) const 57 | { 58 | return Matrix12d::Zero(rest_positions.size(), positions.size()); 59 | } 60 | 61 | } // namespace ipc 62 | -------------------------------------------------------------------------------- /src/ipc/collisions/normal/plane_vertex.cpp: -------------------------------------------------------------------------------- 1 | #include "plane_vertex.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace ipc { 7 | 8 | PlaneVertexNormalCollision::PlaneVertexNormalCollision( 9 | Eigen::ConstRef _plane_origin, 10 | Eigen::ConstRef _plane_normal, 11 | const index_t _vertex_id) 12 | : plane_origin(_plane_origin) 13 | , plane_normal(_plane_normal) 14 | , vertex_id(_vertex_id) 15 | { 16 | } 17 | 18 | double PlaneVertexNormalCollision::compute_distance( 19 | Eigen::ConstRef point) const 20 | { 21 | assert(point.size() == plane_origin.size()); 22 | return point_plane_distance(point, plane_origin, plane_normal); 23 | } 24 | 25 | VectorMax12d PlaneVertexNormalCollision::compute_distance_gradient( 26 | Eigen::ConstRef point) const 27 | { 28 | assert(point.size() == plane_origin.size()); 29 | return point_plane_distance_gradient(point, plane_origin, plane_normal); 30 | } 31 | 32 | MatrixMax12d PlaneVertexNormalCollision::compute_distance_hessian( 33 | Eigen::ConstRef point) const 34 | { 35 | assert(point.size() == plane_origin.size()); 36 | return point_plane_distance_hessian(point, plane_origin, plane_normal); 37 | } 38 | 39 | VectorMax4d PlaneVertexNormalCollision::compute_coefficients( 40 | Eigen::ConstRef positions) const 41 | { 42 | VectorMax4d coeffs(1); 43 | coeffs << 1.0; 44 | return coeffs; 45 | } 46 | 47 | bool PlaneVertexNormalCollision::ccd( 48 | Eigen::ConstRef vertices_t0, 49 | Eigen::ConstRef vertices_t1, 50 | double& toi, 51 | const double min_distance, 52 | const double tmax, 53 | const NarrowPhaseCCD& narrow_phase_ccd) const 54 | { 55 | assert(min_distance == 0 && "Not implemented"); 56 | return point_static_plane_ccd( 57 | vertices_t0, vertices_t1, plane_origin, plane_normal, toi); 58 | } 59 | 60 | } // namespace ipc 61 | -------------------------------------------------------------------------------- /src/ipc/collisions/normal/vertex_vertex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ipc { 8 | 9 | class VertexVertexNormalCollision : public VertexVertexCandidate, 10 | public NormalCollision { 11 | public: 12 | using VertexVertexCandidate::VertexVertexCandidate; 13 | 14 | VertexVertexNormalCollision(const VertexVertexCandidate& candidate) 15 | : VertexVertexCandidate(candidate) 16 | { 17 | } 18 | 19 | VertexVertexNormalCollision( 20 | const index_t _vertex0_id, 21 | const index_t _vertex1_id, 22 | const double _weight, 23 | const Eigen::SparseVector& _weight_gradient) 24 | : VertexVertexCandidate(_vertex0_id, _vertex1_id) 25 | , NormalCollision(_weight, _weight_gradient) 26 | { 27 | } 28 | 29 | template 30 | friend H AbslHashValue(H h, const VertexVertexNormalCollision& vv) 31 | { 32 | return AbslHashValue( 33 | std::move(h), static_cast(vv)); 34 | } 35 | }; 36 | 37 | } // namespace ipc 38 | -------------------------------------------------------------------------------- /src/ipc/collisions/tangential/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | edge_edge.cpp 3 | edge_edge.hpp 4 | edge_vertex.cpp 5 | edge_vertex.hpp 6 | face_vertex.cpp 7 | face_vertex.hpp 8 | tangential_collision.cpp 9 | tangential_collision.hpp 10 | tangential_collisions.cpp 11 | tangential_collisions.hpp 12 | vertex_vertex.cpp 13 | vertex_vertex.hpp 14 | ) 15 | 16 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/collisions/tangential/edge_edge.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ipc { 8 | 9 | class EdgeEdgeTangentialCollision : public EdgeEdgeCandidate, 10 | public TangentialCollision { 11 | public: 12 | using EdgeEdgeCandidate::EdgeEdgeCandidate; 13 | 14 | EdgeEdgeTangentialCollision(const EdgeEdgeNormalCollision& collision); 15 | 16 | EdgeEdgeTangentialCollision( 17 | const EdgeEdgeNormalCollision& collision, 18 | Eigen::ConstRef positions, 19 | const NormalPotential& normal_potential, 20 | const double normal_stiffness); 21 | 22 | protected: 23 | EdgeEdgeDistanceType known_dtype() const override 24 | { 25 | // The distance type is known because mollified PP and PE were skipped. 26 | return EdgeEdgeDistanceType::EA_EB; 27 | } 28 | 29 | MatrixMax compute_tangent_basis( 30 | Eigen::ConstRef positions) const override; 31 | 32 | MatrixMax compute_tangent_basis_jacobian( 33 | Eigen::ConstRef positions) const override; 34 | 35 | VectorMax2d compute_closest_point( 36 | Eigen::ConstRef positions) const override; 37 | 38 | MatrixMax compute_closest_point_jacobian( 39 | Eigen::ConstRef positions) const override; 40 | 41 | VectorMax3d 42 | relative_velocity(Eigen::ConstRef velocities) const override; 43 | 44 | using TangentialCollision::relative_velocity_matrix; 45 | 46 | MatrixMax relative_velocity_matrix( 47 | Eigen::ConstRef closest_point) const override; 48 | 49 | MatrixMax relative_velocity_matrix_jacobian( 50 | Eigen::ConstRef closest_point) const override; 51 | }; 52 | 53 | } // namespace ipc 54 | -------------------------------------------------------------------------------- /src/ipc/collisions/tangential/edge_vertex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ipc { 8 | 9 | class EdgeVertexTangentialCollision : public EdgeVertexCandidate, 10 | public TangentialCollision { 11 | public: 12 | using EdgeVertexCandidate::EdgeVertexCandidate; 13 | 14 | EdgeVertexTangentialCollision(const EdgeVertexNormalCollision& collision); 15 | 16 | EdgeVertexTangentialCollision( 17 | const EdgeVertexNormalCollision& collision, 18 | Eigen::ConstRef positions, 19 | const NormalPotential& normal_potential, 20 | const double normal_stiffness); 21 | 22 | protected: 23 | MatrixMax compute_tangent_basis( 24 | Eigen::ConstRef positions) const override; 25 | 26 | MatrixMax compute_tangent_basis_jacobian( 27 | Eigen::ConstRef positions) const override; 28 | 29 | VectorMax2d compute_closest_point( 30 | Eigen::ConstRef positions) const override; 31 | 32 | MatrixMax compute_closest_point_jacobian( 33 | Eigen::ConstRef positions) const override; 34 | 35 | VectorMax3d 36 | relative_velocity(Eigen::ConstRef velocities) const override; 37 | 38 | using TangentialCollision::relative_velocity_matrix; 39 | 40 | MatrixMax relative_velocity_matrix( 41 | Eigen::ConstRef closest_point) const override; 42 | 43 | MatrixMax relative_velocity_matrix_jacobian( 44 | Eigen::ConstRef closest_point) const override; 45 | }; 46 | 47 | } // namespace ipc 48 | -------------------------------------------------------------------------------- /src/ipc/collisions/tangential/face_vertex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ipc { 8 | 9 | class FaceVertexTangentialCollision : public FaceVertexCandidate, 10 | public TangentialCollision { 11 | public: 12 | using FaceVertexCandidate::FaceVertexCandidate; 13 | 14 | FaceVertexTangentialCollision(const FaceVertexNormalCollision& collision); 15 | 16 | FaceVertexTangentialCollision( 17 | const FaceVertexNormalCollision& collision, 18 | Eigen::ConstRef positions, 19 | const NormalPotential& normal_potential, 20 | const double normal_stiffness); 21 | 22 | protected: 23 | MatrixMax compute_tangent_basis( 24 | Eigen::ConstRef positions) const override; 25 | 26 | MatrixMax compute_tangent_basis_jacobian( 27 | Eigen::ConstRef positions) const override; 28 | 29 | VectorMax2d compute_closest_point( 30 | Eigen::ConstRef positions) const override; 31 | 32 | MatrixMax compute_closest_point_jacobian( 33 | Eigen::ConstRef positions) const override; 34 | 35 | VectorMax3d 36 | relative_velocity(Eigen::ConstRef velocities) const override; 37 | 38 | using TangentialCollision::relative_velocity_matrix; 39 | 40 | MatrixMax relative_velocity_matrix( 41 | Eigen::ConstRef closest_point) const override; 42 | 43 | MatrixMax relative_velocity_matrix_jacobian( 44 | Eigen::ConstRef closest_point) const override; 45 | }; 46 | 47 | } // namespace ipc 48 | -------------------------------------------------------------------------------- /src/ipc/collisions/tangential/tangential_collision.cpp: -------------------------------------------------------------------------------- 1 | #include "tangential_collision.hpp" 2 | 3 | #include 4 | 5 | #include // std::out_of_range 6 | 7 | namespace ipc { 8 | 9 | void TangentialCollision::init( 10 | const NormalCollision& collision, 11 | Eigen::ConstRef positions, 12 | const NormalPotential& normal_potential, 13 | const double normal_stiffness) 14 | { 15 | // do this to initialize dim() 16 | const int dim = collision.dim(positions.size()); 17 | tangent_basis.resize(dim, dim - 1); 18 | 19 | closest_point = compute_closest_point(positions); 20 | tangent_basis = compute_tangent_basis(positions); 21 | normal_force_magnitude = normal_potential.force_magnitude( 22 | compute_distance(positions), collision.dmin, normal_stiffness); 23 | } 24 | 25 | } // namespace ipc 26 | -------------------------------------------------------------------------------- /src/ipc/collisions/tangential/vertex_vertex.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | 7 | namespace ipc { 8 | 9 | class VertexVertexTangentialCollision : public VertexVertexCandidate, 10 | public TangentialCollision { 11 | public: 12 | using VertexVertexCandidate::VertexVertexCandidate; 13 | 14 | VertexVertexTangentialCollision( 15 | const VertexVertexNormalCollision& collision); 16 | 17 | VertexVertexTangentialCollision( 18 | const VertexVertexNormalCollision& collision, 19 | Eigen::ConstRef positions, 20 | const NormalPotential& normal_potential, 21 | const double normal_stiffness); 22 | 23 | protected: 24 | MatrixMax compute_tangent_basis( 25 | Eigen::ConstRef positions) const override; 26 | 27 | MatrixMax compute_tangent_basis_jacobian( 28 | Eigen::ConstRef positions) const override; 29 | 30 | VectorMax2d compute_closest_point( 31 | Eigen::ConstRef positions) const override; 32 | 33 | MatrixMax compute_closest_point_jacobian( 34 | Eigen::ConstRef positions) const override; 35 | 36 | VectorMax3d 37 | relative_velocity(Eigen::ConstRef velocities) const override; 38 | 39 | using TangentialCollision::relative_velocity_matrix; 40 | 41 | MatrixMax relative_velocity_matrix( 42 | Eigen::ConstRef closest_point) const override; 43 | 44 | MatrixMax relative_velocity_matrix_jacobian( 45 | Eigen::ConstRef closest_point) const override; 46 | }; 47 | 48 | } // namespace ipc 49 | -------------------------------------------------------------------------------- /src/ipc/config.hpp.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | // WARNING: Do not modify config.hpp directly. Instead, modify config.hpp.in. 6 | 7 | #define IPC_TOOLKIT_NAME "@PROJECT_NAME@" 8 | #define IPC_TOOLKIT_VER "@PROJECT_VERSION@" 9 | #define IPC_TOOLKIT_VER_MAJOR "@PROJECT_VERSION_MAJOR@" 10 | #define IPC_TOOLKIT_VER_MINOR "@PROJECT_VERSION_MINOR@" 11 | #define IPC_TOOLKIT_VER_PATCH "@PROJECT_VERSION_PATCH@" 12 | 13 | #cmakedefine IPC_TOOLKIT_WITH_INEXACT_CCD 14 | #cmakedefine IPC_TOOLKIT_WITH_RATIONAL_INTERSECTION 15 | #cmakedefine IPC_TOOLKIT_WITH_CUDA 16 | #cmakedefine IPC_TOOLKIT_WITH_ROBIN_MAP 17 | #cmakedefine IPC_TOOLKIT_WITH_ABSEIL 18 | #cmakedefine IPC_TOOLKIT_WITH_FILIB 19 | 20 | namespace ipc { 21 | 22 | // Type definitions 23 | using index_t = int32_t; 24 | // using scalar_t = double; 25 | 26 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/distance/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | distance_type.cpp 3 | distance_type.hpp 4 | edge_edge.cpp 5 | edge_edge.hpp 6 | edge_edge_mollifier.cpp 7 | edge_edge_mollifier.hpp 8 | line_line.cpp 9 | line_line.hpp 10 | point_edge.cpp 11 | point_edge.hpp 12 | point_line.cpp 13 | point_line.hpp 14 | point_plane.cpp 15 | point_plane.hpp 16 | point_point.cpp 17 | point_point.hpp 18 | point_triangle.cpp 19 | point_triangle.hpp 20 | ) 21 | 22 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/distance/point_edge.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief Compute the distance between a point and edge in 2D or 3D. 8 | /// @note The distance is actually squared distance. 9 | /// @param p The point. 10 | /// @param e0 The first vertex of the edge. 11 | /// @param e1 The second vertex of the edge. 12 | /// @param dtype The point edge distance type to compute. 13 | /// @return The distance between the point and edge. 14 | double point_edge_distance( 15 | Eigen::ConstRef p, 16 | Eigen::ConstRef e0, 17 | Eigen::ConstRef e1, 18 | PointEdgeDistanceType dtype = PointEdgeDistanceType::AUTO); 19 | 20 | /// @brief Compute the gradient of the distance between a point and edge. 21 | /// @note The distance is actually squared distance. 22 | /// @param p The point. 23 | /// @param e0 The first vertex of the edge. 24 | /// @param e1 The second vertex of the edge. 25 | /// @param dtype The point edge distance type to compute. 26 | /// @return grad The gradient of the distance wrt p, e0, and e1. 27 | VectorMax9d point_edge_distance_gradient( 28 | Eigen::ConstRef p, 29 | Eigen::ConstRef e0, 30 | Eigen::ConstRef e1, 31 | PointEdgeDistanceType dtype = PointEdgeDistanceType::AUTO); 32 | 33 | /// @brief Compute the hessian of the distance between a point and edge. 34 | /// @note The distance is actually squared distance. 35 | /// @param p The point. 36 | /// @param e0 The first vertex of the edge. 37 | /// @param e1 The second vertex of the edge. 38 | /// @param dtype The point edge distance type to compute. 39 | /// @return hess The hessian of the distance wrt p, e0, and e1. 40 | MatrixMax9d point_edge_distance_hessian( 41 | Eigen::ConstRef p, 42 | Eigen::ConstRef e0, 43 | Eigen::ConstRef e1, 44 | PointEdgeDistanceType dtype = PointEdgeDistanceType::AUTO); 45 | 46 | } // namespace ipc 47 | -------------------------------------------------------------------------------- /src/ipc/distance/point_point.cpp: -------------------------------------------------------------------------------- 1 | #include "point_point.hpp" 2 | 3 | namespace ipc { 4 | 5 | double point_point_distance( 6 | Eigen::ConstRef p0, Eigen::ConstRef p1) 7 | { 8 | return (p1 - p0).squaredNorm(); 9 | } 10 | 11 | VectorMax6d point_point_distance_gradient( 12 | Eigen::ConstRef p0, Eigen::ConstRef p1) 13 | { 14 | int dim = p0.size(); 15 | assert(p1.size() == dim); 16 | 17 | VectorMax6d grad(2 * dim); 18 | 19 | grad.head(dim) = 2.0 * (p0 - p1); 20 | grad.tail(dim) = -grad.head(dim); 21 | 22 | return grad; 23 | } 24 | 25 | MatrixMax6d point_point_distance_hessian( 26 | Eigen::ConstRef p0, Eigen::ConstRef p1) 27 | { 28 | int dim = p0.size(); 29 | assert(p1.size() == dim); 30 | 31 | MatrixMax6d hess(2 * dim, 2 * dim); 32 | 33 | hess.setZero(); 34 | hess.diagonal().setConstant(2.0); 35 | for (int i = 0; i < dim; i++) { 36 | hess(i, i + dim) = hess(i + dim, i) = -2; 37 | } 38 | 39 | return hess; 40 | } 41 | 42 | } // namespace ipc 43 | -------------------------------------------------------------------------------- /src/ipc/distance/point_point.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief Compute the distance between two points. 8 | /// @note The distance is actually squared distance. 9 | /// @param p0 The first point. 10 | /// @param p1 The second point. 11 | /// @return The distance between p0 and p1. 12 | double point_point_distance( 13 | Eigen::ConstRef p0, Eigen::ConstRef p1); 14 | 15 | /// @brief Compute the gradient of the distance between two points. 16 | /// @note The distance is actually squared distance. 17 | /// @param p0 The first point. 18 | /// @param p1 The second point. 19 | /// @return The computed gradient. 20 | VectorMax6d point_point_distance_gradient( 21 | Eigen::ConstRef p0, Eigen::ConstRef p1); 22 | 23 | /// @brief Compute the hessian of the distance between two points. 24 | /// @note The distance is actually squared distance. 25 | /// @param p0 The first point. 26 | /// @param p1 The second point. 27 | /// @return The computed hessian. 28 | MatrixMax6d point_point_distance_hessian( 29 | Eigen::ConstRef p0, Eigen::ConstRef p1); 30 | 31 | } // namespace ipc 32 | -------------------------------------------------------------------------------- /src/ipc/friction/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | smooth_friction_mollifier.cpp 3 | smooth_friction_mollifier.hpp 4 | ) 5 | 6 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/friction/smooth_friction_mollifier.cpp: -------------------------------------------------------------------------------- 1 | #include "smooth_friction_mollifier.hpp" 2 | 3 | #include 4 | #include 5 | 6 | namespace ipc { 7 | 8 | double smooth_friction_f0(const double y, const double eps_v) 9 | { 10 | assert(eps_v > 0); 11 | if (std::abs(y) >= eps_v) { 12 | return y; 13 | } 14 | return y * y * (1 - y / (3 * eps_v)) / eps_v + eps_v / 3; 15 | } 16 | 17 | double smooth_friction_f1(const double y, const double eps_v) 18 | { 19 | assert(eps_v > 0); 20 | if (std::abs(y) >= eps_v) { 21 | return 1; 22 | } 23 | return y * (2 - y / eps_v) / eps_v; 24 | } 25 | 26 | double smooth_friction_f2(const double y, const double eps_v) 27 | { 28 | assert(eps_v > 0); 29 | if (std::abs(y) >= eps_v) { 30 | return 0; 31 | } 32 | return (2 - 2 * y / eps_v) / eps_v; 33 | } 34 | 35 | double smooth_friction_f1_over_x(const double y, const double eps_v) 36 | { 37 | assert(eps_v > 0); 38 | if (std::abs(y) >= eps_v) { 39 | return 1 / y; 40 | } 41 | return (2 - y / eps_v) / eps_v; 42 | } 43 | 44 | double smooth_friction_f2_x_minus_f1_over_x3(const double y, const double eps_v) 45 | { 46 | assert(eps_v > 0); 47 | if (std::abs(y) >= eps_v) { 48 | return -1 / (y * y * y); 49 | } 50 | return -1 / (y * eps_v * eps_v); 51 | } 52 | 53 | } // namespace ipc 54 | -------------------------------------------------------------------------------- /src/ipc/implicits/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | plane.cpp 3 | plane.hpp 4 | ) 5 | 6 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/potentials/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | barrier_potential.cpp 3 | barrier_potential.hpp 4 | friction_potential.cpp 5 | friction_potential.hpp 6 | normal_adhesion_potential.cpp 7 | normal_adhesion_potential.hpp 8 | normal_potential.cpp 9 | normal_potential.hpp 10 | potential.hpp 11 | potential.tpp 12 | tangential_adhesion_potential.cpp 13 | tangential_adhesion_potential.hpp 14 | tangential_potential.cpp 15 | tangential_potential.hpp 16 | ) 17 | 18 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/potentials/friction_potential.cpp: -------------------------------------------------------------------------------- 1 | #include "friction_potential.hpp" 2 | 3 | namespace ipc { 4 | 5 | FrictionPotential::FrictionPotential(const double eps_v) : Super() 6 | { 7 | set_eps_v(eps_v); 8 | } 9 | 10 | double FrictionPotential::f0(const double x) const 11 | { 12 | return smooth_friction_f0(x, eps_v()); 13 | } 14 | 15 | double FrictionPotential::f1_over_x(const double x) const 16 | { 17 | return smooth_friction_f1_over_x(x, eps_v()); 18 | } 19 | 20 | double FrictionPotential::f2_x_minus_f1_over_x3(const double x) const 21 | { 22 | return smooth_friction_f2_x_minus_f1_over_x3(x, eps_v()); 23 | } 24 | 25 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/potentials/friction_potential.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief The friction dissipative potential. 8 | class FrictionPotential : public TangentialPotential { 9 | using Super = TangentialPotential; 10 | 11 | public: 12 | /// @brief Construct a friction potential. 13 | /// @param eps_v The smooth friction mollifier parameter \f$\epsilon_v\f$. 14 | explicit FrictionPotential(const double eps_v); 15 | 16 | /// @brief Get the smooth friction mollifier parameter \f$\epsilon_v\f$. 17 | double eps_v() const { return m_eps_v; } 18 | 19 | /// @brief Set the smooth friction mollifier parameter \f$\epsilon_v\f$. 20 | /// @param eps_v The smooth friction mollifier parameter \f$\epsilon_v\f$. 21 | void set_eps_v(const double eps_v) 22 | { 23 | assert(eps_v > 0); 24 | m_eps_v = eps_v; 25 | } 26 | 27 | protected: 28 | double f0(const double x) const override; 29 | double f1_over_x(const double x) const override; 30 | double f2_x_minus_f1_over_x3(const double x) const override; 31 | 32 | bool is_dynamic(const double speed) const override 33 | { 34 | return speed > eps_v(); 35 | } 36 | 37 | /// @brief The smooth friction mollifier parameter \f$\epsilon_v\f$. 38 | double m_eps_v; 39 | }; 40 | 41 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/potentials/tangential_adhesion_potential.cpp: -------------------------------------------------------------------------------- 1 | #include "tangential_adhesion_potential.hpp" 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | TangentialAdhesionPotential::TangentialAdhesionPotential(const double eps_a) 8 | : Super() 9 | { 10 | set_eps_a(eps_a); 11 | } 12 | 13 | double TangentialAdhesionPotential::f0(const double x) const 14 | { 15 | return tangential_adhesion_f0(x, eps_a()); 16 | } 17 | 18 | double TangentialAdhesionPotential::f1_over_x(const double x) const 19 | { 20 | return tangential_adhesion_f1_over_x(x, eps_a()); 21 | } 22 | 23 | double TangentialAdhesionPotential::f2_x_minus_f1_over_x3(const double x) const 24 | { 25 | return tangential_adhesion_f2_x_minus_f1_over_x3(x, eps_a()); 26 | } 27 | 28 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/potentials/tangential_adhesion_potential.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief The tangential adhesion potential. 8 | class TangentialAdhesionPotential : public TangentialPotential { 9 | using Super = TangentialPotential; 10 | 11 | public: 12 | /// @brief Construct a tangential adhesion potential. 13 | /// @param eps_a The tangential adhesion mollifier parameter \f$\epsilon_a\f$. 14 | explicit TangentialAdhesionPotential(const double eps_a); 15 | 16 | /// @brief Get the tangential adhesion mollifier parameter \f$\epsilon_a\f$. 17 | double eps_a() const { return m_eps_a; } 18 | 19 | /// @brief Set the tangential adhesion mollifier parameter \f$\epsilon_v\f$. 20 | /// @param eps_a The tangential adhesion mollifier parameter \f$\epsilon_v\f$. 21 | void set_eps_a(const double eps_a) 22 | { 23 | assert(eps_a > 0); 24 | m_eps_a = eps_a; 25 | } 26 | 27 | protected: 28 | double f0(const double x) const override; 29 | double f1_over_x(const double x) const override; 30 | double f2_x_minus_f1_over_x3(const double x) const override; 31 | 32 | bool is_dynamic(const double speed) const override 33 | { 34 | return speed > eps_a(); 35 | } 36 | 37 | /// @brief The tangential adhesion mollifier parameter \f$\epsilon_a\f$. 38 | double m_eps_a; 39 | }; 40 | 41 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/tangent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | closest_point.cpp 3 | closest_point.hpp 4 | relative_velocity.cpp 5 | relative_velocity.hpp 6 | tangent_basis.cpp 7 | tangent_basis.hpp 8 | ) 9 | 10 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) 11 | 12 | ################################################################################ 13 | # Subfolders 14 | ################################################################################ -------------------------------------------------------------------------------- /src/ipc/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | area_gradient.cpp 3 | area_gradient.hpp 4 | eigen_ext.hpp 5 | eigen_ext.tpp 6 | intersection.cpp 7 | intersection.hpp 8 | interval.cpp 9 | interval.hpp 10 | local_to_global.hpp 11 | logger.cpp 12 | logger.hpp 13 | merge_thread_local.hpp 14 | save_obj.cpp 15 | save_obj.hpp 16 | unordered_map_and_set.cpp 17 | unordered_map_and_set.hpp 18 | vertex_to_min_edge.cpp 19 | vertex_to_min_edge.hpp 20 | world_bbox_diagonal_length.hpp 21 | ) 22 | 23 | target_sources(ipc_toolkit PRIVATE ${SOURCES}) -------------------------------------------------------------------------------- /src/ipc/utils/area_gradient.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief Compute the gradient of an edge's length. 8 | /// @param e0 The first vertex of the edge. 9 | /// @param e1 The second vertex of the edge. 10 | /// @return The gradient of the edge's length wrt e0, and e1. 11 | VectorMax6d edge_length_gradient( 12 | Eigen::ConstRef e0, Eigen::ConstRef e1); 13 | 14 | /// @brief Compute the gradient of the area of a triangle. 15 | /// @param t0 The first vertex of the triangle. 16 | /// @param t1 The second vertex of the triangle. 17 | /// @param t2 The third vertex of the triangle. 18 | /// @return The gradient of the triangle's area t0, t1, and t2. 19 | Vector9d triangle_area_gradient( 20 | Eigen::ConstRef t0, 21 | Eigen::ConstRef t1, 22 | Eigen::ConstRef t2); 23 | 24 | namespace autogen { 25 | 26 | // dA is (9×1) flattened in column-major order 27 | void triangle_area_gradient( 28 | double t0_x, 29 | double t0_y, 30 | double t0_z, 31 | double t1_x, 32 | double t1_y, 33 | double t1_z, 34 | double t2_x, 35 | double t2_y, 36 | double t2_z, 37 | double dA[9]); 38 | 39 | } // namespace autogen 40 | 41 | } // namespace ipc 42 | -------------------------------------------------------------------------------- /src/ipc/utils/intersection.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief Check if an edge intersects a triangle. 8 | /// @param e0 Edge start point. 9 | /// @param e1 Edge end point. 10 | /// @param t0 Triangle vertex 0. 11 | /// @param t1 Triangle vertex 1. 12 | /// @param t2 Triangle vertex 2. 13 | /// @return True if the edge intersects the triangle. 14 | bool is_edge_intersecting_triangle( 15 | Eigen::ConstRef e0, 16 | Eigen::ConstRef e1, 17 | Eigen::ConstRef t0, 18 | Eigen::ConstRef t1, 19 | Eigen::ConstRef t2); 20 | 21 | } // namespace ipc 22 | -------------------------------------------------------------------------------- /src/ipc/utils/interval.cpp: -------------------------------------------------------------------------------- 1 | #include "interval.hpp" 2 | 3 | #ifdef IPC_TOOLKIT_WITH_FILIB 4 | 5 | namespace ipc { 6 | 7 | filib::Interval squared_norm(Eigen::ConstRef x) 8 | { 9 | filib::Interval sqr_norm(0); 10 | for (int i = 0; i < x.size(); i++) { 11 | sqr_norm += sqr(x[i]); 12 | } 13 | return sqr_norm; 14 | } 15 | 16 | filib::Interval norm(Eigen::ConstRef x) 17 | { 18 | return sqrt(squared_norm(x)); 19 | } 20 | 21 | } // namespace ipc 22 | #endif -------------------------------------------------------------------------------- /src/ipc/utils/logger.cpp: -------------------------------------------------------------------------------- 1 | #include "logger.hpp" 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace ipc { 8 | 9 | namespace { 10 | 11 | // Custom logger instance defined by the user, if any 12 | std::shared_ptr& get_shared_logger() 13 | { 14 | static std::shared_ptr logger; 15 | return logger; 16 | } 17 | 18 | } // namespace 19 | 20 | // Retrieve current logger 21 | spdlog::logger& logger() 22 | { 23 | if (get_shared_logger()) { 24 | return *get_shared_logger(); 25 | } else { 26 | // When using factory methods provided by spdlog (_st and _mt 27 | // functions), names must be unique, since the logger is registered 28 | // globally. Otherwise, you will need to create the logger manually. See 29 | // https://github.com/gabime/spdlog/wiki/2.-Creating-loggers 30 | static auto default_logger = spdlog::stdout_color_mt("ipctk"); 31 | return *default_logger; 32 | } 33 | } 34 | 35 | // Use a custom logger 36 | void set_logger(std::shared_ptr x) 37 | { 38 | get_shared_logger() = std::move(x); 39 | } 40 | 41 | void log_and_throw_error(const std::string& msg) 42 | { 43 | logger().error(msg); 44 | throw std::runtime_error(msg); 45 | } 46 | 47 | } // namespace ipc 48 | -------------------------------------------------------------------------------- /src/ipc/utils/logger.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // clang-format off 4 | #include 5 | #include 6 | #include 7 | // clang-format on 8 | 9 | namespace ipc { 10 | 11 | /// Retrieves the current logger. 12 | /// @return A const reference to the logger object. 13 | spdlog::logger& logger(); 14 | 15 | /// Setup a logger object. Calling this function with other function is not 16 | /// thread-safe. 17 | /// @param logger New logger object to be used. 18 | void set_logger(std::shared_ptr logger); 19 | 20 | [[noreturn]] void log_and_throw_error(const std::string& msg); 21 | 22 | template 23 | [[noreturn]] void 24 | log_and_throw_error(const std::string& msg, const Args&... args) 25 | { 26 | log_and_throw_error(fmt::format(msg, args...)); 27 | } 28 | 29 | } // namespace ipc 30 | -------------------------------------------------------------------------------- /src/ipc/utils/merge_thread_local.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace ipc { 8 | 9 | template 10 | void merge_thread_local_vectors( 11 | const tbb::enumerable_thread_specific>& vectors, 12 | std::vector& out) 13 | { 14 | // size up the items 15 | size_t size = out.size(); 16 | for (const auto& vector : vectors) { 17 | size += vector.size(); 18 | } 19 | // serial merge! 20 | out.reserve(size); 21 | for (const auto& vector : vectors) { 22 | out.insert(out.end(), vector.begin(), vector.end()); 23 | } 24 | } 25 | 26 | template 27 | void merge_thread_local_unordered_sets( 28 | const tbb::enumerable_thread_specific>& sets, 29 | unordered_set& out) 30 | { 31 | // size up the items 32 | size_t size = out.size(); 33 | for (const auto& set : sets) { 34 | size += set.size(); 35 | } 36 | // serial merge! 37 | out.reserve(size); 38 | for (const auto& set : sets) { 39 | out.insert(set.begin(), set.end()); 40 | } 41 | } 42 | 43 | } // namespace ipc -------------------------------------------------------------------------------- /src/ipc/utils/save_obj.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | namespace ipc { 10 | 11 | template 12 | void save_obj( 13 | std::ostream& out, 14 | Eigen::ConstRef V, 15 | Eigen::ConstRef E, 16 | Eigen::ConstRef F, 17 | const std::vector& candidates, 18 | const int v_offset = 0); 19 | 20 | template 21 | bool save_obj( 22 | const std::string& filename, 23 | Eigen::ConstRef V, 24 | Eigen::ConstRef E, 25 | Eigen::ConstRef F, 26 | const std::vector& candidates) 27 | { 28 | std::ofstream obj(filename); 29 | if (!obj.is_open()) { 30 | return false; 31 | } 32 | save_obj(obj, V, E, F, candidates); 33 | return true; 34 | } 35 | 36 | } // namespace ipc 37 | -------------------------------------------------------------------------------- /src/ipc/utils/unordered_map_and_set.cpp: -------------------------------------------------------------------------------- 1 | #include "unordered_map_and_set.hpp" 2 | 3 | #ifndef IPC_TOOLKIT_WITH_ABSEIL 4 | 5 | #include // std::pair 6 | 7 | namespace ipc { 8 | 9 | template <> 10 | Hash> 11 | AbslHashValue(Hash> h, const std::pair p) 12 | { 13 | return Hash>::combine(std::move(h), p.first, p.second); 14 | } 15 | 16 | template <> Hash AbslHashValue(Hash h, const int i) 17 | { 18 | return Hash::combine(std::move(h), i); 19 | } 20 | 21 | template <> 22 | Hash> AbslHashValue( 23 | Hash> h, const std::pair p) 24 | { 25 | return Hash>::combine( 26 | std::move(h), p.first, p.second); 27 | } 28 | 29 | template <> Hash AbslHashValue(Hash h, const size_t i) 30 | { 31 | return Hash::combine(std::move(h), i); 32 | } 33 | 34 | } // namespace ipc 35 | 36 | #endif 37 | -------------------------------------------------------------------------------- /src/ipc/utils/vertex_to_min_edge.cpp: -------------------------------------------------------------------------------- 1 | #include "vertex_to_min_edge.hpp" 2 | 3 | #include // std::min/max 4 | 5 | namespace ipc { 6 | 7 | std::vector 8 | vertex_to_min_edge(size_t num_vertices, Eigen::ConstRef edges) 9 | { 10 | std::vector V2E(num_vertices, edges.rows() + 1); 11 | // Column first because colmajor 12 | for (size_t ej = 0; ej < edges.cols(); ej++) { 13 | for (size_t ei = 0; ei < edges.rows(); ei++) { 14 | const size_t& vi = edges(ei, ej); 15 | V2E[vi] = std::min(V2E[vi], ei); 16 | } 17 | } 18 | return V2E; 19 | } 20 | 21 | } // namespace ipc 22 | -------------------------------------------------------------------------------- /src/ipc/utils/vertex_to_min_edge.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | namespace ipc { 8 | 9 | std::vector 10 | vertex_to_min_edge(size_t num_vertices, Eigen::ConstRef edges); 11 | 12 | } // namespace ipc 13 | -------------------------------------------------------------------------------- /src/ipc/utils/world_bbox_diagonal_length.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | namespace ipc { 6 | 7 | /// @brief Compute the diagonal length of the world bounding box. 8 | /// @param vertices Vertex positions 9 | /// @return The diagonal length of the world bounding box. 10 | inline double 11 | world_bbox_diagonal_length(Eigen::ConstRef vertices) 12 | { 13 | return (vertices.colwise().maxCoeff() - vertices.colwise().minCoeff()) 14 | .norm(); 15 | } 16 | 17 | } // namespace ipc 18 | -------------------------------------------------------------------------------- /tests/.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: InheritParentConfig 2 | SortIncludes: false -------------------------------------------------------------------------------- /tests/src/tests/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | main.cpp 3 | config.hpp 4 | 5 | # Tests 6 | test_cfl.cpp 7 | test_collision_mesh.cpp 8 | test_has_intersections.cpp 9 | test_ipc.cpp 10 | 11 | # Benchmarks 12 | benchmark_eigen.cpp 13 | 14 | # Utilities 15 | utils.cpp 16 | utils.hpp 17 | ) 18 | 19 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 20 | 21 | ################################################################################ 22 | # Subfolders 23 | ################################################################################ 24 | 25 | add_subdirectory(adhesion) 26 | add_subdirectory(barrier) 27 | add_subdirectory(broad_phase) 28 | add_subdirectory(candidates) 29 | add_subdirectory(ccd) 30 | add_subdirectory(collisions) 31 | add_subdirectory(distance) 32 | add_subdirectory(friction) 33 | add_subdirectory(potential) 34 | add_subdirectory(tangent) 35 | add_subdirectory(utils) -------------------------------------------------------------------------------- /tests/src/tests/adhesion/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_adhesion.cpp 4 | 5 | # Benchmarks 6 | 7 | # Utilities 8 | ) 9 | 10 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 11 | 12 | ################################################################################ 13 | # Subfolders 14 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/barrier/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_adaptive_stiffness.cpp 4 | test_barrier.cpp 5 | 6 | # Benchmarks 7 | 8 | # Utilities 9 | ) 10 | 11 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 12 | 13 | ################################################################################ 14 | # Subfolders 15 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/broad_phase/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_aabb.cpp 4 | test_broad_phase.cpp 5 | test_spatial_hash.cpp 6 | test_stq.cpp 7 | test_voxel_size_heuristic.cpp 8 | 9 | # Benchmarks 10 | benchmark_broad_phase.cpp 11 | 12 | # Utilities 13 | brute_force_comparison.cpp 14 | brute_force_comparison.hpp 15 | ) 16 | 17 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 18 | 19 | ################################################################################ 20 | # Subfolders 21 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/broad_phase/brute_force_comparison.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | void brute_force_comparison( 7 | const ipc::CollisionMesh& mesh, 8 | const Eigen::MatrixXd& V0, 9 | const Eigen::MatrixXd& V1, 10 | ipc::Candidates& candidates, 11 | const double inflation_radius, 12 | const std::string& cached_bf_candidates = ""); 13 | 14 | template 15 | void brute_force_comparison( 16 | const ipc::CollisionMesh& mesh, 17 | const Eigen::MatrixXd& V0, 18 | const Eigen::MatrixXd& V1, 19 | std::vector& candidates, 20 | std::vector& bf_candidates); 21 | -------------------------------------------------------------------------------- /tests/src/tests/broad_phase/test_spatial_hash.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | #include 7 | 8 | using namespace ipc; 9 | 10 | TEST_CASE("Build SpatialHash", "[broad_phase][spatial_hash][build]") 11 | { 12 | #ifndef NDEBUG 13 | SKIP("'Build SpatialHash' test is skipped in debug mode"); 14 | #endif 15 | 16 | Eigen::MatrixXd V0, V1; 17 | Eigen::MatrixXi E, F; 18 | 19 | REQUIRE(tests::load_mesh("cloth_ball92.ply", V0, E, F)); 20 | REQUIRE(tests::load_mesh("cloth_ball93.ply", V1, E, F)); 21 | 22 | double inflation_radius = 0; 23 | 24 | SpatialHash sh; 25 | sh.build(V0, V1, E, F, inflation_radius); 26 | 27 | Candidates candidates; 28 | sh.detect_collision_candidates(V0.cols(), candidates); 29 | 30 | CHECK(candidates.size() == 6'852'873); 31 | CHECK(candidates.vv_candidates.size() == 0); 32 | CHECK(candidates.ev_candidates.size() == 0); 33 | CHECK(candidates.ee_candidates.size() == 5'197'332); 34 | CHECK(candidates.fv_candidates.size() == 1'655'541); 35 | 36 | sh.clear(); 37 | } 38 | -------------------------------------------------------------------------------- /tests/src/tests/candidates/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_candidates.cpp 4 | test_coefficients.cpp 5 | 6 | # Benchmarks 7 | 8 | # Utilities 9 | ) 10 | 11 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 12 | 13 | ################################################################################ 14 | # Subfolders 15 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/ccd/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_ccd.cpp 4 | test_gpu_ccd.cpp 5 | test_ccd_benchmark.cpp 6 | test_edge_edge_ccd.cpp 7 | test_nonlinear_ccd.cpp 8 | test_point_edge_ccd.cpp 9 | test_point_point_ccd.cpp 10 | test_point_triangle_ccd.cpp 11 | 12 | # Benchmarks 13 | benchmark_ccd.cpp 14 | 15 | # Utilities 16 | collision_generator.cpp 17 | collision_generator.hpp 18 | ) 19 | 20 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 21 | 22 | ################################################################################ 23 | # Subfolders 24 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/ccd/benchmark_ccd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | #include 6 | 7 | #include 8 | #include 9 | 10 | using namespace ipc; 11 | 12 | TEST_CASE("Benchmark earliest toi", "[!benchmark][ccd][earliest_toi]") 13 | { 14 | Eigen::MatrixXd V0, V1; 15 | Eigen::MatrixXi E, F; 16 | 17 | std::string mesh_name_t0, mesh_name_t1; 18 | SECTION("Data 0") 19 | { 20 | mesh_name_t0 = "private/slow-broadphase-ccd/0.ply"; 21 | mesh_name_t1 = "private/slow-broadphase-ccd/1.ply"; 22 | } 23 | SECTION("Data 1") 24 | { 25 | mesh_name_t0 = "private/slow-broadphase-ccd/s0.ply"; 26 | mesh_name_t1 = "private/slow-broadphase-ccd/s1.ply"; 27 | } 28 | SECTION("Cloth-ball") 29 | { 30 | mesh_name_t0 = "cloth_ball92.ply"; 31 | mesh_name_t1 = "cloth_ball93.ply"; 32 | } 33 | // SECTION("Squishy-Ball") 34 | // { 35 | // mesh_name_t0 = "private/puffer-ball/20.ply"; 36 | // mesh_name_t1 = "private/puffer-ball/21.ply"; 37 | // } 38 | 39 | if (!tests::load_mesh(mesh_name_t0, V0, E, F) 40 | || !tests::load_mesh(mesh_name_t1, V1, E, F)) { 41 | SKIP("Slow broadphase CCD meshes are private"); 42 | } 43 | 44 | CollisionMesh mesh = CollisionMesh::build_from_full_mesh(V0, E, F); 45 | // Discard codimensional/internal vertices 46 | V0 = mesh.vertices(V0); 47 | V1 = mesh.vertices(V1); 48 | 49 | TightInclusionCCD ccd(/*tolerance=*/1e-6, /*max_iterations=*/1e7); 50 | 51 | Candidates candidates; 52 | candidates.build(mesh, V0, V1); 53 | 54 | double toi; 55 | BENCHMARK("Earliest ToI Narrow-Phase") 56 | { 57 | toi = candidates.compute_collision_free_stepsize( 58 | mesh, V0, V1, /*min_distance=*/0, ccd); 59 | }; 60 | } 61 | -------------------------------------------------------------------------------- /tests/src/tests/ccd/collision_generator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | struct TestImpact { 8 | Eigen::Vector2d p_t0, e0_t0, e1_t0; 9 | Eigen::Vector2d dp, de0, de1; 10 | double toi; 11 | }; 12 | 13 | TestImpact generate_random_impact(const bool rigid); 14 | 15 | class TestImpactGenerator : public Catch::Generators::IGenerator { 16 | protected: 17 | TestImpact current; 18 | bool rigid; 19 | size_t current_i, max_i; 20 | 21 | public: 22 | TestImpactGenerator(size_t value, bool rigid); 23 | 24 | bool next() override; 25 | 26 | TestImpact const& get() const override; 27 | }; 28 | 29 | Catch::Generators::GeneratorWrapper 30 | random_impacts(size_t value, bool rigid); 31 | -------------------------------------------------------------------------------- /tests/src/tests/ccd/test_gpu_ccd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | #include 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace ipc; 13 | 14 | #ifdef IPC_TOOLKIT_WITH_CUDA 15 | 16 | TEST_CASE("GPU CCD", "[ccd][gpu]") 17 | { 18 | Eigen::MatrixXd V0, V1; 19 | Eigen::MatrixXi E, F; 20 | 21 | std::string mesh_name_t0, mesh_name_t1; 22 | SECTION("Cloth-Ball") 23 | { 24 | mesh_name_t0 = "cloth_ball92.ply"; 25 | mesh_name_t1 = "cloth_ball93.ply"; 26 | } 27 | // SECTION("Squishy-Ball") 28 | // { 29 | // mesh_name_t0 = "private/puffer-ball/20.ply"; 30 | // mesh_name_t1 = "private/puffer-ball/21.ply"; 31 | // } 32 | 33 | if (!tests::load_mesh(mesh_name_t0, V0, E, F) 34 | || !tests::load_mesh(mesh_name_t1, V1, E, F)) { 35 | SKIP("Puffer-ball meshes are not available"); 36 | } 37 | 38 | CollisionMesh mesh = CollisionMesh::build_from_full_mesh(V0, E, F); 39 | // Discard codimensional/internal vertices 40 | V0 = mesh.vertices(V0); 41 | V1 = mesh.vertices(V1); 42 | 43 | const double tolerance = 1e-6; 44 | const int max_iterations = 1e7; 45 | const double min_distance = 0; 46 | 47 | const double toi_cpu = compute_collision_free_stepsize( 48 | mesh, V0, V1, min_distance, std::make_shared(), 49 | TightInclusionCCD(tolerance, max_iterations)); 50 | 51 | // Got this value from running the code 52 | CHECK(toi_cpu == Catch::Approx(4.76837158203125000e-06)); 53 | 54 | const double toi_gpu = compute_collision_free_stepsize( 55 | mesh, V0, V1, min_distance, std::make_shared(), 56 | TightInclusionCCD(tolerance, max_iterations)); 57 | 58 | // Got this value from running the code 59 | CHECK(toi_gpu == Catch::Approx(3.05175781250000017e-6)); 60 | } 61 | 62 | #endif -------------------------------------------------------------------------------- /tests/src/tests/ccd/test_point_point_ccd.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace ipc; 10 | 11 | TEST_CASE("Point-point CCD", "[ccd][point-point]") 12 | { 13 | const int dim = GENERATE(2, 3); 14 | const Eigen::Vector3d p0_t0_3D(0.0, 0.0, 0.0), p0_t1_3D(1.0, 1.0, 1.0); 15 | const Eigen::Vector3d p1_t0_3D(1.0, 1.0, 0.0), p1_t1_3D(0.0, 0.0, 1.0); 16 | const VectorMax3d p0_t0 = p0_t0_3D.head(dim), p0_t1 = p0_t1_3D.head(dim); 17 | const VectorMax3d p1_t0 = p1_t0_3D.head(dim), p1_t1 = p1_t1_3D.head(dim); 18 | 19 | const double min_distance = GENERATE(0, 1e-6, 1e-4, 1e-2); 20 | 21 | double toi; 22 | 23 | const TightInclusionCCD tight_inclusion_ccd; 24 | bool is_colliding = tight_inclusion_ccd.point_point_ccd( 25 | p0_t0, p1_t0, p0_t1, p1_t1, toi, min_distance); 26 | 27 | // Check the results 28 | CHECK(is_colliding); 29 | CHECK(toi == Catch::Approx(0.5).margin(1e-3)); 30 | 31 | const AdditiveCCD additive_ccd( 32 | AdditiveCCD::UNLIMITTED_ITERATIONS, /*conservative_rescaling=*/0.999); 33 | is_colliding = additive_ccd.point_point_ccd( 34 | p0_t0, p1_t0, p0_t1, p1_t1, toi, min_distance); 35 | 36 | // Check the results 37 | CHECK(is_colliding); 38 | CHECK(toi == Catch::Approx(0.5).margin(1e-3)); 39 | } -------------------------------------------------------------------------------- /tests/src/tests/collisions/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_normal_collisions.cpp 4 | 5 | # Benchmarks 6 | 7 | # Utilities 8 | ) 9 | 10 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 11 | 12 | ################################################################################ 13 | # Subfolders 14 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/config.hpp.in: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // WARNING: Do not modify config.hpp directly. Instead, modify config.hpp.in. 4 | 5 | #include 6 | 7 | #include 8 | 9 | #cmakedefine IPC_TOOLKIT_TESTS_CCD_BENCHMARK 10 | 11 | namespace ipc::tests { 12 | 13 | #ifdef IPC_TOOLKIT_TESTS_CCD_BENCHMARK 14 | static const std::filesystem::path 15 | CCD_BENCHMARK_DIR("@IPC_TOOLKIT_TESTS_CCD_BENCHMARK_DIR@"); 16 | static const std::filesystem::path 17 | NEW_CCD_BENCHMARK_DIR("@IPC_TOOLKIT_TESTS_NEW_CCD_BENCHMARK_DIR@"); 18 | #endif 19 | 20 | static const std::filesystem::path DATA_DIR("@IPC_TOOLKIT_TESTS_DATA_DIR@"); 21 | 22 | } // namespace ipc::tests -------------------------------------------------------------------------------- /tests/src/tests/distance/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_distance_type.cpp 4 | test_edge_edge_mollifier.cpp 5 | test_edge_edge.cpp 6 | test_line_line.cpp 7 | test_point_edge.cpp 8 | test_point_line.cpp 9 | test_point_plane.cpp 10 | test_point_point.cpp 11 | test_point_triangle.cpp 12 | 13 | # Benchmarks 14 | 15 | # Utilities 16 | ) 17 | 18 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 19 | 20 | ################################################################################ 21 | # Subfolders 22 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/friction/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_force_jacobian.cpp 4 | test_friction.cpp 5 | test_smooth_friction_mollifier.cpp 6 | 7 | # Benchmarks 8 | 9 | # Utilities 10 | friction_data_generator.cpp 11 | friction_data_generator.hpp 12 | ) 13 | 14 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 15 | 16 | ################################################################################ 17 | # Subfolders 18 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/friction/friction_data_generator.hpp: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #include 6 | 7 | struct FrictionData { 8 | Eigen::MatrixXd V0; 9 | Eigen::MatrixXd V1; 10 | Eigen::MatrixXi E; 11 | Eigen::MatrixXi F; 12 | ipc::NormalCollisions collisions; 13 | double mu; 14 | double epsv_times_h; 15 | double p; 16 | double barrier_stiffness; 17 | }; 18 | 19 | Eigen::VectorXd LogSpaced(int num, double start, double stop, double base = 10); 20 | Eigen::VectorXd GeomSpaced(int num, double start, double stop); 21 | 22 | FrictionData friction_data_generator(); -------------------------------------------------------------------------------- /tests/src/tests/potential/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_adhesion_potentials.cpp 4 | test_barrier_potential.cpp 5 | test_friction_potential.cpp 6 | 7 | # Benchmarks 8 | 9 | # Utilities 10 | ) 11 | 12 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 13 | 14 | ################################################################################ 15 | # Subfolders 16 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/potential/test_friction_potential.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #include 6 | 7 | #include 8 | #include 9 | #include 10 | 11 | #include 12 | 13 | using namespace ipc; 14 | 15 | TEST_CASE("Friction gradient and hessian", "[friction][gradient][hessian]") 16 | { 17 | FrictionData data = friction_data_generator(); 18 | const auto& [V0, V1, E, F, collisions, mu, epsv_times_h, dhat, barrier_stiffness] = 19 | data; 20 | 21 | const Eigen::MatrixXd U = V1 - V0; 22 | 23 | const CollisionMesh mesh(V0, E, F); 24 | 25 | TangentialCollisions tangential_collisions; 26 | tangential_collisions.build( 27 | mesh, V0, collisions, BarrierPotential(dhat), barrier_stiffness, mu); 28 | 29 | const FrictionPotential D(epsv_times_h); 30 | 31 | const Eigen::VectorXd grad = D.gradient(tangential_collisions, mesh, U); 32 | 33 | // Compute the gradient using finite differences 34 | auto f = [&](const Eigen::VectorXd& x) { 35 | const Eigen::MatrixXd fd_U = fd::unflatten(x, data.V1.cols()) - data.V0; 36 | return D(tangential_collisions, mesh, fd_U); 37 | }; 38 | Eigen::VectorXd fgrad; 39 | fd::finite_gradient(fd::flatten(V1), f, fgrad); 40 | CHECK(fd::compare_gradient(grad, fgrad)); 41 | 42 | const Eigen::MatrixXd hess = D.hessian(tangential_collisions, mesh, U); 43 | Eigen::MatrixXd fhess; 44 | fd::finite_hessian(fd::flatten(V1), f, fhess); 45 | CHECK(fd::compare_hessian(hess, fhess, 1e-3)); 46 | } -------------------------------------------------------------------------------- /tests/src/tests/tangent/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_closest_point.cpp 4 | test_relative_velocity.cpp 5 | test_tangent_basis.cpp 6 | 7 | # Benchmarks 8 | 9 | # Utilities 10 | ) 11 | 12 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 13 | 14 | ################################################################################ 15 | # Subfolders 16 | ################################################################################ -------------------------------------------------------------------------------- /tests/src/tests/test_cfl.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace ipc; 8 | 9 | TEST_CASE("Compute CFL stepsize", "[ccd][cfl]") 10 | { 11 | const double dhat = GENERATE(1e-6, 1e-3, 1e-1); 12 | 13 | Eigen::MatrixXd V0, V1; 14 | Eigen::MatrixXi E, F; 15 | SECTION("Cube-Cube") 16 | { 17 | Eigen::MatrixXi E1, F1; 18 | const bool success = tests::load_mesh("two-cubes-close.ply", V0, E, F) 19 | && tests::load_mesh("two-cubes-intersecting.ply", V1, E1, F1); 20 | REQUIRE(success); 21 | } 22 | #ifdef NDEBUG 23 | SECTION("Cloth-Ball") 24 | { 25 | const bool success = tests::load_mesh("cloth_ball92.ply", V0, E, F) 26 | && tests::load_mesh("cloth_ball93.ply", V1, E, F); 27 | REQUIRE(success); 28 | } 29 | #endif 30 | 31 | CollisionMesh mesh(V0, E, F); 32 | 33 | Candidates candidates; 34 | candidates.build(mesh, V0, dhat / 2); 35 | 36 | const double cfl_step_size = 37 | candidates.compute_cfl_stepsize(mesh, V0, V1, dhat); 38 | 39 | const double ccd_step_size = 40 | ipc::compute_collision_free_stepsize(mesh, V0, V1); 41 | 42 | CHECK(cfl_step_size <= ccd_step_size); 43 | } 44 | -------------------------------------------------------------------------------- /tests/src/tests/test_ipc.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | 5 | #include 6 | 7 | using namespace ipc; 8 | 9 | TEST_CASE("Is step collision free", "[is_step_collision_free]") 10 | { 11 | Eigen::MatrixXd V0, V1; 12 | Eigen::MatrixXi E, F; 13 | REQUIRE(tests::load_mesh("two-cubes-close.ply", V0, E, F)); 14 | REQUIRE(tests::load_mesh("two-cubes-intersecting.ply", V1, E, F)); 15 | 16 | CollisionMesh mesh(V0, E, F); 17 | 18 | CHECK(is_step_collision_free(mesh, V0, V0)); 19 | CHECK(!is_step_collision_free(mesh, V0, V1)); 20 | } -------------------------------------------------------------------------------- /tests/src/tests/utils/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set(SOURCES 2 | # Tests 3 | test_interval.cpp 4 | test_utils.cpp 5 | 6 | # Benchmarks 7 | 8 | # Utilities 9 | ) 10 | 11 | target_sources(ipc_toolkit_tests PRIVATE ${SOURCES}) 12 | 13 | ################################################################################ 14 | # Subfolders 15 | ################################################################################ --------------------------------------------------------------------------------