├── .github
├── FUNDING.yml
└── workflows
│ └── parry-ci-build.yml
├── .gitignore
├── ARCHITECTURE.md
├── CHANGELOG.md
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Cargo.toml
├── LICENSE
├── README.md
├── assets
└── tests
│ ├── bar.obj
│ ├── center_cylinder.obj
│ ├── low_poly_bunny.obj
│ ├── offset_cylinder.obj
│ ├── poly_cylinder.obj
│ └── stairs.obj
├── crates
├── parry2d-f64
│ └── Cargo.toml
├── parry2d
│ ├── Cargo.toml
│ ├── examples
│ │ ├── aabb2d.rs
│ │ ├── ball2d.rs
│ │ ├── bounding_sphere2d.rs
│ │ ├── common_macroquad2d.rs
│ │ ├── contact_query2d.rs
│ │ ├── convex2d.rs
│ │ ├── convex_hull2d.rs
│ │ ├── convex_try_new2d.rs
│ │ ├── cuboid2d.rs
│ │ ├── distance_query2d.rs
│ │ ├── plane2d.rs
│ │ ├── point_in_poly2d.rs
│ │ ├── polygons_intersection2d.rs
│ │ ├── polyline2d.rs
│ │ ├── project_point2d.rs
│ │ ├── proximity_query2d.rs
│ │ ├── raycasts_animated.rs
│ │ ├── solid_point_query2d.rs
│ │ ├── solid_ray_cast2d.rs
│ │ └── time_of_impact_query2d.rs
│ └── tests
│ │ ├── geometry
│ │ ├── aabb_scale.rs
│ │ ├── ball_ball_toi.rs
│ │ ├── ball_cuboid_contact.rs
│ │ ├── convex_polygons_intersection.rs
│ │ ├── epa2.rs
│ │ ├── epa_convergence.rs
│ │ ├── mod.rs
│ │ ├── ray_cast.rs
│ │ └── time_of_impact2.rs
│ │ ├── lib.rs
│ │ └── query
│ │ ├── mod.rs
│ │ ├── point_composite_shape.rs
│ │ └── point_triangle.rs
├── parry3d-f64
│ └── Cargo.toml
└── parry3d
│ ├── Cargo.toml
│ ├── benches
│ ├── all.rs
│ ├── bounding_volume
│ │ └── mod.rs
│ ├── common
│ │ ├── default_gen.rs
│ │ ├── generators.rs
│ │ ├── macros.rs
│ │ ├── mod.rs
│ │ └── unref.rs
│ ├── query
│ │ ├── algorithm.rs
│ │ ├── contacts.rs
│ │ ├── mod.rs
│ │ └── ray.rs
│ └── support_map
│ │ └── mod.rs
│ ├── examples
│ ├── aabb3d.rs
│ ├── ball3d.rs
│ ├── bounding_sphere3d.rs
│ ├── capsule.rs
│ ├── common_macroquad3d.rs
│ ├── cone.rs
│ ├── contact_query3d.rs
│ ├── convex3d.rs
│ ├── convex_decomposition.rs
│ ├── convex_hull3d.rs
│ ├── convex_try_new3d.rs
│ ├── cuboid3d.rs
│ ├── cylinder.rs
│ ├── distance_query3d.rs
│ ├── getting_started.rs
│ ├── mesh3d.rs
│ ├── plane3d.rs
│ ├── plane_intersection.rs
│ ├── polyline3d.rs
│ ├── project_point3d.rs
│ ├── proximity_query3d.rs
│ ├── solid_point_query3d.rs
│ ├── solid_ray_cast3d.rs
│ └── time_of_impact_query3d.rs
│ └── tests
│ ├── geometry
│ ├── aabb_scale.rs
│ ├── ball_ball_toi.rs
│ ├── ball_triangle_toi.rs
│ ├── convex_hull.rs
│ ├── cuboid_ray_cast.rs
│ ├── cylinder_cuboid_contact.rs
│ ├── epa3.rs
│ ├── mod.rs
│ ├── still_objects_toi.rs
│ ├── time_of_impact3.rs
│ ├── trimesh_connected_components.rs
│ ├── trimesh_intersection.rs
│ └── trimesh_trimesh_toi.rs
│ └── lib.rs
├── publish.sh
├── rustfmt.toml
├── src
├── bounding_volume
│ ├── aabb.rs
│ ├── aabb_ball.rs
│ ├── aabb_capsule.rs
│ ├── aabb_convex_polygon.rs
│ ├── aabb_convex_polyhedron.rs
│ ├── aabb_cuboid.rs
│ ├── aabb_halfspace.rs
│ ├── aabb_heightfield.rs
│ ├── aabb_support_map.rs
│ ├── aabb_triangle.rs
│ ├── aabb_utils.rs
│ ├── aabb_voxels.rs
│ ├── bounding_sphere.rs
│ ├── bounding_sphere_ball.rs
│ ├── bounding_sphere_capsule.rs
│ ├── bounding_sphere_cone.rs
│ ├── bounding_sphere_convex.rs
│ ├── bounding_sphere_convex_polygon.rs
│ ├── bounding_sphere_cuboid.rs
│ ├── bounding_sphere_cylinder.rs
│ ├── bounding_sphere_halfspace.rs
│ ├── bounding_sphere_heightfield.rs
│ ├── bounding_sphere_polyline.rs
│ ├── bounding_sphere_segment.rs
│ ├── bounding_sphere_triangle.rs
│ ├── bounding_sphere_trimesh.rs
│ ├── bounding_sphere_utils.rs
│ ├── bounding_sphere_voxels.rs
│ ├── bounding_volume.rs
│ ├── mod.rs
│ └── simd_aabb.rs
├── lib.rs
├── mass_properties
│ ├── mass_properties.rs
│ ├── mass_properties_ball.rs
│ ├── mass_properties_capsule.rs
│ ├── mass_properties_compound.rs
│ ├── mass_properties_cone.rs
│ ├── mass_properties_convex_polygon.rs
│ ├── mass_properties_convex_polyhedron.rs
│ ├── mass_properties_cuboid.rs
│ ├── mass_properties_cylinder.rs
│ ├── mass_properties_triangle.rs
│ ├── mass_properties_trimesh2d.rs
│ ├── mass_properties_trimesh3d.rs
│ ├── mass_properties_voxels.rs
│ └── mod.rs
├── partitioning
│ ├── mod.rs
│ ├── qbvh
│ │ ├── build.rs
│ │ ├── mod.rs
│ │ ├── qbvh.rs
│ │ ├── traversal.rs
│ │ ├── update.rs
│ │ ├── update
│ │ │ └── tests.rs
│ │ └── utils.rs
│ └── visitor.rs
├── query
│ ├── clip
│ │ ├── clip_aabb_line.rs
│ │ ├── clip_aabb_polygon.rs
│ │ ├── clip_halfspace_polygon.rs
│ │ ├── clip_segment_segment.rs
│ │ └── mod.rs
│ ├── closest_points
│ │ ├── closest_points.rs
│ │ ├── closest_points_ball_ball.rs
│ │ ├── closest_points_ball_convex_polyhedron.rs
│ │ ├── closest_points_composite_shape_shape.rs
│ │ ├── closest_points_cuboid_cuboid.rs
│ │ ├── closest_points_cuboid_triangle.rs
│ │ ├── closest_points_halfspace_support_map.rs
│ │ ├── closest_points_line_line.rs
│ │ ├── closest_points_segment_segment.rs
│ │ ├── closest_points_shape_shape.rs
│ │ ├── closest_points_support_map_support_map.rs
│ │ └── mod.rs
│ ├── contact
│ │ ├── contact.rs
│ │ ├── contact_ball_ball.rs
│ │ ├── contact_ball_convex_polyhedron.rs
│ │ ├── contact_composite_shape_shape.rs
│ │ ├── contact_cuboid_cuboid.rs
│ │ ├── contact_halfspace_support_map.rs
│ │ ├── contact_shape_shape.rs
│ │ ├── contact_support_map_support_map.rs
│ │ └── mod.rs
│ ├── contact_manifolds
│ │ ├── contact_manifold.rs
│ │ ├── contact_manifolds_ball_ball.rs
│ │ ├── contact_manifolds_capsule_capsule.rs
│ │ ├── contact_manifolds_composite_shape_composite_shape.rs
│ │ ├── contact_manifolds_composite_shape_shape.rs
│ │ ├── contact_manifolds_convex_ball.rs
│ │ ├── contact_manifolds_cuboid_capsule.rs
│ │ ├── contact_manifolds_cuboid_cuboid.rs
│ │ ├── contact_manifolds_cuboid_triangle.rs
│ │ ├── contact_manifolds_halfspace_pfm.rs
│ │ ├── contact_manifolds_heightfield_composite_shape.rs
│ │ ├── contact_manifolds_heightfield_shape.rs
│ │ ├── contact_manifolds_pfm_pfm.rs
│ │ ├── contact_manifolds_trimesh_shape.rs
│ │ ├── contact_manifolds_voxels_ball.rs
│ │ ├── contact_manifolds_voxels_composite_shape.rs
│ │ ├── contact_manifolds_voxels_shape.rs
│ │ ├── contact_manifolds_voxels_voxels.rs
│ │ ├── contact_manifolds_workspace.rs
│ │ ├── mod.rs
│ │ ├── normals_constraint.rs
│ │ └── polygon_polygon_contact_generator.rs
│ ├── default_query_dispatcher.rs
│ ├── distance
│ │ ├── distance.rs
│ │ ├── distance_ball_ball.rs
│ │ ├── distance_ball_convex_polyhedron.rs
│ │ ├── distance_composite_shape_shape.rs
│ │ ├── distance_cuboid_cuboid.rs
│ │ ├── distance_halfspace_support_map.rs
│ │ ├── distance_segment_segment.rs
│ │ ├── distance_support_map_support_map.rs
│ │ └── mod.rs
│ ├── epa
│ │ ├── epa2.rs
│ │ ├── epa3.rs
│ │ └── mod.rs
│ ├── error.rs
│ ├── gjk
│ │ ├── cso_point.rs
│ │ ├── gjk.rs
│ │ ├── mod.rs
│ │ ├── special_support_maps.rs
│ │ ├── voronoi_simplex2.rs
│ │ └── voronoi_simplex3.rs
│ ├── intersection_test
│ │ ├── intersection_test.rs
│ │ ├── intersection_test_ball_ball.rs
│ │ ├── intersection_test_ball_point_query.rs
│ │ ├── intersection_test_composite_shape_shape.rs
│ │ ├── intersection_test_cuboid_cuboid.rs
│ │ ├── intersection_test_cuboid_segment.rs
│ │ ├── intersection_test_cuboid_triangle.rs
│ │ ├── intersection_test_halfspace_support_map.rs
│ │ ├── intersection_test_polygon_polygon.rs
│ │ ├── intersection_test_support_map_support_map.rs
│ │ ├── intersection_test_voxels_shape.rs
│ │ └── mod.rs
│ ├── mod.rs
│ ├── nonlinear_shape_cast
│ │ ├── mod.rs
│ │ ├── nonlinear_rigid_motion.rs
│ │ ├── nonlinear_shape_cast.rs
│ │ ├── nonlinear_shape_cast_composite_shape_shape.rs
│ │ ├── nonlinear_shape_cast_halfspace_support_map.rs
│ │ ├── nonlinear_shape_cast_support_map_support_map.rs
│ │ └── nonlinear_shape_cast_voxels_shape.rs
│ ├── point
│ │ ├── mod.rs
│ │ ├── point_aabb.rs
│ │ ├── point_ball.rs
│ │ ├── point_bounding_sphere.rs
│ │ ├── point_capsule.rs
│ │ ├── point_composite_shape.rs
│ │ ├── point_cone.rs
│ │ ├── point_cuboid.rs
│ │ ├── point_cylinder.rs
│ │ ├── point_halfspace.rs
│ │ ├── point_heightfield.rs
│ │ ├── point_query.rs
│ │ ├── point_round_shape.rs
│ │ ├── point_segment.rs
│ │ ├── point_support_map.rs
│ │ ├── point_tetrahedron.rs
│ │ ├── point_triangle.rs
│ │ └── point_voxels.rs
│ ├── query_dispatcher.rs
│ ├── ray
│ │ ├── mod.rs
│ │ ├── ray.rs
│ │ ├── ray_aabb.rs
│ │ ├── ray_ball.rs
│ │ ├── ray_bounding_sphere.rs
│ │ ├── ray_composite_shape.rs
│ │ ├── ray_cuboid.rs
│ │ ├── ray_halfspace.rs
│ │ ├── ray_heightfield.rs
│ │ ├── ray_round_shape.rs
│ │ ├── ray_support_map.rs
│ │ ├── ray_triangle.rs
│ │ ├── ray_trimesh.rs
│ │ ├── ray_voxels.rs
│ │ └── simd_ray.rs
│ ├── sat
│ │ ├── mod.rs
│ │ ├── sat_cuboid_cuboid.rs
│ │ ├── sat_cuboid_point.rs
│ │ ├── sat_cuboid_segment.rs
│ │ ├── sat_cuboid_support_map.rs
│ │ ├── sat_cuboid_triangle.rs
│ │ ├── sat_support_map_support_map.rs
│ │ └── sat_triangle_segment.rs
│ ├── shape_cast
│ │ ├── mod.rs
│ │ ├── shape_cast.rs
│ │ ├── shape_cast_ball_ball.rs
│ │ ├── shape_cast_composite_shape_shape.rs
│ │ ├── shape_cast_halfspace_support_map.rs
│ │ ├── shape_cast_heightfield_shape.rs
│ │ ├── shape_cast_support_map_support_map.rs
│ │ └── shape_cast_voxels_shape.rs
│ ├── split
│ │ ├── mod.rs
│ │ ├── split.rs
│ │ ├── split_aabb.rs
│ │ ├── split_segment.rs
│ │ └── split_trimesh.rs
│ └── visitors
│ │ ├── aabb_sets_interferences_collector.rs
│ │ ├── bounding_volume_intersections_simultaneous_visitor.rs
│ │ ├── bounding_volume_intersections_visitor.rs
│ │ ├── composite_closest_point_visitor.rs
│ │ ├── composite_point_containment_test.rs
│ │ ├── mod.rs
│ │ ├── point_intersections_visitor.rs
│ │ └── ray_intersections_visitor.rs
├── shape
│ ├── ball.rs
│ ├── capsule.rs
│ ├── composite_shape.rs
│ ├── compound.rs
│ ├── cone.rs
│ ├── convex_polygon.rs
│ ├── convex_polyhedron.rs
│ ├── cuboid.rs
│ ├── cylinder.rs
│ ├── feature_id.rs
│ ├── half_space.rs
│ ├── heightfield2.rs
│ ├── heightfield3.rs
│ ├── mod.rs
│ ├── polygon.rs
│ ├── polygonal_feature2d.rs
│ ├── polygonal_feature3d.rs
│ ├── polygonal_feature_map.rs
│ ├── polyline.rs
│ ├── round_shape.rs
│ ├── segment.rs
│ ├── shape.rs
│ ├── shared_shape.rs
│ ├── support_map.rs
│ ├── tetrahedron.rs
│ ├── triangle.rs
│ ├── triangle_pseudo_normals.rs
│ ├── trimesh.rs
│ └── voxels.rs
├── transformation
│ ├── convex_hull2.rs
│ ├── convex_hull3
│ │ ├── convex_hull.rs
│ │ ├── error.rs
│ │ ├── initial_mesh.rs
│ │ ├── mod.rs
│ │ ├── triangle_facet.rs
│ │ └── validation.rs
│ ├── convex_hull_utils.rs
│ ├── ear_clipping.rs
│ ├── hertel_mehlhorn.rs
│ ├── mesh_intersection
│ │ ├── mesh_intersection.rs
│ │ ├── mesh_intersection_error.rs
│ │ ├── mod.rs
│ │ └── triangle_triangle_intersection.rs
│ ├── mod.rs
│ ├── polygon_intersection.rs
│ ├── to_outline
│ │ ├── ball_to_outline.rs
│ │ ├── capsule_to_outline.rs
│ │ ├── cone_to_outline.rs
│ │ ├── convex_polyhedron_to_outline.rs
│ │ ├── cuboid_to_outline.rs
│ │ ├── cylinder_to_outline.rs
│ │ ├── heightfield_to_outline.rs
│ │ ├── mod.rs
│ │ ├── round_cone_to_outline.rs
│ │ ├── round_convex_polyhedron_to_outline.rs
│ │ ├── round_cuboid_to_outline.rs
│ │ ├── round_cylinder_to_outline.rs
│ │ ├── round_triangle_to_outline.rs
│ │ └── voxels_to_outline.rs
│ ├── to_polyline
│ │ ├── ball_to_polyline.rs
│ │ ├── capsule_to_polyline.rs
│ │ ├── cuboid_to_polyline.rs
│ │ ├── heightfield_to_polyline.rs
│ │ ├── mod.rs
│ │ ├── round_convex_polygon_to_polyline.rs
│ │ ├── round_cuboid_to_polyline.rs
│ │ └── voxels_to_polyline.rs
│ ├── to_trimesh
│ │ ├── ball_to_trimesh.rs
│ │ ├── capsule_to_trimesh.rs
│ │ ├── cone_to_trimesh.rs
│ │ ├── convex_polyhedron_to_trimesh.rs
│ │ ├── cuboid_to_trimesh.rs
│ │ ├── cylinder_to_trimesh.rs
│ │ ├── heightfield_to_trimesh.rs
│ │ ├── mod.rs
│ │ └── voxels_to_trimesh.rs
│ ├── utils.rs
│ ├── vhacd
│ │ ├── mod.rs
│ │ ├── parameters.rs
│ │ └── vhacd.rs
│ ├── voxelization
│ │ ├── mod.rs
│ │ ├── voxel_set.rs
│ │ └── voxelized_volume.rs
│ └── wavefront.rs
└── utils
│ ├── as_bytes.rs
│ ├── ccw_face_normal.rs
│ ├── center.rs
│ ├── cleanup.rs
│ ├── consts.rs
│ ├── cov.rs
│ ├── deterministic_state.rs
│ ├── fx_hasher.rs
│ ├── hashable_partial_eq.rs
│ ├── hashmap.rs
│ ├── hashset.rs
│ ├── interval.rs
│ ├── inv.rs
│ ├── isometry_ops.rs
│ ├── median.rs
│ ├── mod.rs
│ ├── obb.rs
│ ├── point_cloud_support_point.rs
│ ├── point_in_poly2d.rs
│ ├── point_in_triangle.rs
│ ├── sdp_matrix.rs
│ ├── segments_intersection.rs
│ ├── sort.rs
│ ├── sorted_pair.rs
│ ├── spade.rs
│ ├── weighted_value.rs
│ ├── wops.rs
│ └── z_order.rs
└── write_examples.sh
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [ "dimforge" ] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: # Replace with a single Patreon username
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: # Replace with a single Ko-fi username
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.swo
3 | *.html
4 | BENCH
5 | lib
6 | target
7 | private
8 | Cargo.lock
9 | Makefile
10 | .vscode
11 | .idea
--------------------------------------------------------------------------------
/ARCHITECTURE.md:
--------------------------------------------------------------------------------
1 | ## Repository architecture
2 |
3 | The architecture of this repository is a bit unusual because we are using some tricks to have both
4 | the 2D and 3D version of Parry share the same code-base. Here are the main folders:
5 | - **`crates/`**: contains one folder per Parry crate (for the 2D, 3D, `f32`, and `f64` versions). Each
6 | crate has its own `Cargo.toml` file that adjusts some cargo features, and reference the `src` folder.
7 | - **`src/`**: contains the actual `.rs` source code of the Parry geometric library.
8 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to Parry
2 |
3 | Thank you for wanting to contribute! Contribution can take many forms, including:
4 | - Reporting a bug.
5 | - Submitting a fix.
6 | - Fixing typos.
7 | - Improving the docs.
8 | - [Donations on GitHub Sponsors](https://github.com/sponsors/dimforge).
9 |
10 | It is strongly recommended to [open an issue](https://github.com/dimforge/parry/issues) or to discuss
11 | with us [on Discord][discord] before fixing complicated issues, or implementing new
12 | features.
13 |
14 |
15 | ## Contributing to the Rust code
16 | The Rust source code of the Parry geometric library is available on our `parry` repository
17 | [on GitHub](https://github.com/dimforge/parry.rs).
18 |
19 | 1. Fork our `parry` repository [on GitHub](https://github.com/dimforge/parry).
20 | 2. Clone the repository and make the necessary changes.
21 | 3. In order to debug your changes and check that it works, do the following:
22 | - Run the tests `cargo test`
23 | 4. Once you are satisfied with your changes, submit them by [opening a Pull Request](https://github.com/dimforge/parry/pulls) on GitHub.
24 | 5. If that Pull Request does something you need urgently, or if you think it has been forgotten, don't hesitate
25 | to ask **@sebcrozet** directly [on Discord][discord] for a review.
26 | 6. Iterate with the reviewer until the PR gets merged.
27 |
28 |
29 | [discord]: https://discord.gg/vt9DJSW
--------------------------------------------------------------------------------
/Cargo.toml:
--------------------------------------------------------------------------------
1 | [workspace]
2 | members = [
3 | "crates/parry2d",
4 | "crates/parry3d",
5 | "crates/parry2d-f64",
6 | "crates/parry3d-f64",
7 | ]
8 | resolver = "2"
9 |
10 | [workspace.lints]
11 | rust.unexpected_cfgs = { level = "warn", check-cfg = [
12 | 'cfg(feature, values("dim2", "dim3", "f32", "f64"))',
13 | # "wavefront" is only used for 3D crates.
14 | 'cfg(feature, values("wavefront"))',
15 | ] }
16 |
17 | [workspace.lints.clippy]
18 | alloc_instead_of_core = "warn"
19 | std_instead_of_alloc = "warn"
20 | std_instead_of_core = "warn"
21 |
22 | [patch.crates-io]
23 | parry2d = { path = "crates/parry2d" }
24 | parry3d = { path = "crates/parry3d" }
25 | parry2d-f64 = { path = "crates/parry2d-f64" }
26 | parry3d-f64 = { path = "crates/parry3d-f64" }
27 |
28 | #simba = { path = "../simba" }
29 | #simba = { git = "https://github.com/dimforge/simba", rev = "45a5266eb36ed9d25907e9bf9130cd4ac846a748" }
30 | #nalgebra = { git = "https://github.com/dimforge/nalgebra", rev = "0cf79aef0e6155befc3279a3145f1940822b8377" }
31 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | -----
17 |
18 |
19 |
20 | 2D Documentation | 3D Documentation | User Guide
21 |
22 |
23 |
24 | -----
25 |
26 | ## What is Parry?
27 |
28 | **Parry** is a set 2 and 3-dimensional geometric and collision detection libraries.
29 | These libraries are `parry2d`, `parry3d`, `parry2d-f64`, and `parry3d-f64`. They are written with the Rust
30 | programming language, by the [Dimforge](https://dimforge.com) organization. It is forever free
31 | and open-source! We regularly give updates about our progress on [our blog](https://www.dimforge.com/blog).
32 |
33 | ## Resources and discussions
34 | - [Dimforge](https://dimforge.com): See all the open-source projects we are working on! Follow our announcements
35 | on our [blog](https://www.dimforge.com/blog).
36 | - [User guide](https://www.parry.rs/docs/): (WIP) Learn to use Parry in your project by reading the official User Guide.
37 | - [Discord](https://discord.gg/vt9DJSW): Come chat with us, get help, suggest features, on Discord!
38 |
--------------------------------------------------------------------------------
/assets/tests/stairs.obj:
--------------------------------------------------------------------------------
1 | # Author: Camilo Talero
2 | # License: CC0
3 | v -1.000000 -1.000000 1.000000
4 | v -1.000000 1.000000 1.000000
5 | v -1.000000 -1.000000 -1.000000
6 | v -1.000000 1.000000 -1.000000
7 | v 1.000000 -1.000000 1.000000
8 | v 1.000000 1.000000 1.000000
9 | v 1.000000 -1.000000 -1.000000
10 | v 1.000000 1.000000 -1.000000
11 | v -1.000000 -1.000000 4.915915
12 | v -1.000000 1.000000 4.915915
13 | v 1.000000 1.000000 4.915915
14 | v 1.000000 -1.000000 4.915915
15 | v -1.000000 4.391501 1.000000
16 | v -1.000000 4.391501 -1.000000
17 | v 1.000000 4.391501 -1.000000
18 | v 1.000000 4.391501 1.000000
19 | v -1.000000 1.000000 -7.119346
20 | v 1.000000 1.000000 -7.119346
21 | v -1.000000 4.391501 -7.119346
22 | v 1.000000 4.391501 -7.119346
23 | v -1.000000 11.844163 -1.000000
24 | v 1.000000 11.844163 -1.000000
25 | v -1.000000 11.844163 -7.119346
26 | v 1.000000 11.844163 -7.119346
27 | s off
28 | f 2 3 1
29 | f 4 7 3
30 | f 8 5 7
31 | f 2 11 6
32 | f 7 1 3
33 | f 2 14 4
34 | f 11 9 12
35 | f 6 12 5
36 | f 1 10 2
37 | f 5 9 1
38 | f 14 16 15
39 | f 6 13 2
40 | f 4 18 8
41 | f 8 16 6
42 | f 17 20 18
43 | f 8 20 15
44 | f 14 17 4
45 | f 14 23 19
46 | f 22 23 21
47 | f 19 24 20
48 | f 20 22 15
49 | f 15 21 14
50 | f 2 4 3
51 | f 4 8 7
52 | f 8 6 5
53 | f 2 10 11
54 | f 7 5 1
55 | f 2 13 14
56 | f 11 10 9
57 | f 6 11 12
58 | f 1 9 10
59 | f 5 12 9
60 | f 14 13 16
61 | f 6 16 13
62 | f 4 17 18
63 | f 8 15 16
64 | f 17 19 20
65 | f 8 18 20
66 | f 14 19 17
67 | f 14 21 23
68 | f 22 24 23
69 | f 19 23 24
70 | f 20 24 22
71 | f 15 22 21
72 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/ball2d.rs:
--------------------------------------------------------------------------------
1 | use parry2d::shape::Ball;
2 |
3 | fn main() {
4 | let ball = Ball::new(1.0);
5 | assert!(ball.radius == 1.0);
6 | }
7 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/contact_query2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry2, Vector2};
4 | use parry2d::query;
5 | use parry2d::shape::{Ball, Cuboid};
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector2::new(1.0, 1.0));
9 | let ball = Ball::new(1.0);
10 | let prediction = 1.0;
11 |
12 | let cuboid_pos = Isometry2::identity();
13 | let ball_pos_penetrating = Isometry2::translation(1.0, 1.0);
14 | let ball_pos_in_prediction = Isometry2::translation(2.0, 2.0);
15 | let ball_pos_too_far = Isometry2::translation(3.0, 3.0);
16 |
17 | let ctct_penetrating = query::contact(
18 | &ball_pos_penetrating,
19 | &ball,
20 | &cuboid_pos,
21 | &cuboid,
22 | prediction,
23 | )
24 | .unwrap();
25 | let ctct_in_prediction = query::contact(
26 | &ball_pos_in_prediction,
27 | &ball,
28 | &cuboid_pos,
29 | &cuboid,
30 | prediction,
31 | )
32 | .unwrap();
33 | let ctct_too_far =
34 | query::contact(&ball_pos_too_far, &ball, &cuboid_pos, &cuboid, prediction).unwrap();
35 |
36 | assert!(ctct_penetrating.unwrap().dist <= 0.0);
37 | assert!(ctct_in_prediction.unwrap().dist >= 0.0);
38 | assert_eq!(ctct_too_far, None);
39 | }
40 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/convex2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 | extern crate num_traits as num;
3 |
4 | use na::Point2;
5 | use parry2d::shape::ConvexPolygon;
6 |
7 | fn main() {
8 | let points = [
9 | Point2::new(-1.0, 1.0),
10 | Point2::new(-0.5, -0.5),
11 | Point2::new(0.0, 0.5),
12 | Point2::new(0.5, -0.5),
13 | Point2::new(1.0, 1.0),
14 | ];
15 |
16 | let convex = ConvexPolygon::from_convex_hull(&points).expect("Invalid convex polygon.");
17 | assert!(convex.points().len() == 4);
18 | }
19 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/convex_hull2d.rs:
--------------------------------------------------------------------------------
1 | mod common_macroquad2d;
2 |
3 | use core::f32::consts::{FRAC_PI_2, FRAC_PI_4};
4 |
5 | use common_macroquad2d::{draw_point, draw_polygon, lissajous_2d_with_params, na_from_mquad};
6 | use macroquad::prelude::*;
7 | use nalgebra::Point2;
8 | use parry2d::transformation;
9 |
10 | const RENDER_SCALE: f32 = 30.0;
11 |
12 | #[macroquad::main("convex_hull2d")]
13 | async fn main() {
14 | let count = 9;
15 | let mut pts = vec![Point2::default(); count];
16 |
17 | let render_pos = Point2::new(300.0, 300.0);
18 |
19 | loop {
20 | let elapsed_time = get_time() as f32;
21 | let elapsed_time_slow = elapsed_time * 0.2;
22 | clear_background(BLACK);
23 |
24 | for (i, pt) in pts.iter_mut().enumerate() {
25 | *pt = na_from_mquad(lissajous_2d_with_params(
26 | (i * i) as f32 + elapsed_time_slow,
27 | 2.0 + i as f32 / 3.0,
28 | (i as f32 / count as f32) + elapsed_time_slow.cos() * 0.1,
29 | (elapsed_time_slow as f32 + i as f32).cos() * 0.1 + FRAC_PI_2,
30 | FRAC_PI_4,
31 | )) * 5f32;
32 | draw_point(*pt, RENDER_SCALE, render_pos, RED);
33 | }
34 |
35 | /*
36 | *
37 | * Compute the convex hull.
38 | *
39 | */
40 | let convex_hull = transformation::convex_hull(&pts);
41 | draw_polygon(&convex_hull, RENDER_SCALE, render_pos, WHITE);
42 | next_frame().await
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/convex_try_new2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Point2;
4 | use parry2d::shape::ConvexPolygon;
5 |
6 | fn main() {
7 | let points = vec![
8 | Point2::new(-1.0, 1.0),
9 | Point2::new(-0.5, -0.5),
10 | Point2::new(0.5, -0.5),
11 | Point2::new(1.0, 1.0),
12 | ];
13 |
14 | let convex = ConvexPolygon::from_convex_polyline(points).expect("Invalid convex polygon.");
15 | assert!(convex.points().len() == 4);
16 | }
17 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/cuboid2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Vector2;
4 | use parry2d::shape::Cuboid;
5 |
6 | fn main() {
7 | let cuboid = Cuboid::new(Vector2::new(2.0, 1.0));
8 |
9 | assert!(cuboid.half_extents.x == 2.0);
10 | assert!(cuboid.half_extents.y == 1.0);
11 | }
12 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/distance_query2d.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate approx; // for relative_eq!
3 | extern crate nalgebra as na;
4 |
5 | use na::{Isometry2, Vector2};
6 | use parry2d::query;
7 | use parry2d::shape::{Ball, Cuboid};
8 |
9 | fn main() {
10 | let cuboid = Cuboid::new(Vector2::new(1.0, 1.0));
11 | let ball = Ball::new(1.0);
12 |
13 | let cuboid_pos = Isometry2::identity();
14 | let ball_pos_intersecting = Isometry2::translation(0.0, 1.0);
15 | let ball_pos_disjoint = Isometry2::translation(0.0, 3.0);
16 |
17 | let dist_intersecting =
18 | query::distance(&ball_pos_intersecting, &ball, &cuboid_pos, &cuboid).unwrap();
19 | let dist_disjoint = query::distance(&ball_pos_disjoint, &ball, &cuboid_pos, &cuboid).unwrap();
20 |
21 | assert_eq!(dist_intersecting, 0.0);
22 | assert!(relative_eq!(dist_disjoint, 1.0, epsilon = 1.0e-7));
23 | }
24 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/plane2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Vector2;
4 | use parry2d::shape::HalfSpace;
5 |
6 | fn main() {
7 | let halfspace = HalfSpace::new(Vector2::::y_axis());
8 |
9 | assert!(halfspace.normal.x == 0.0);
10 | assert!(halfspace.normal.y == 1.0);
11 | }
12 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/polyline2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Point2;
4 | use parry2d::shape::Polyline;
5 |
6 | fn main() {
7 | let points = vec![
8 | Point2::new(0.0, 1.0),
9 | Point2::new(-1.0, -1.0),
10 | Point2::new(0.0, -0.5),
11 | Point2::new(1.0, -1.0),
12 | ];
13 |
14 | let indices = vec![
15 | [0, 1],
16 | [1, 2],
17 | [2, 3],
18 | [3, 0], // This forms a loop.
19 | ];
20 |
21 | // Build the polyline.
22 | let polyline = Polyline::new(points, Some(indices));
23 |
24 | assert_eq!(polyline.vertices().len(), 4);
25 | }
26 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/proximity_query2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry2, Vector2};
4 | use parry2d::query;
5 | use parry2d::shape::{Ball, Cuboid};
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector2::new(1.0, 1.0));
9 | let ball = Ball::new(1.0);
10 |
11 | let cuboid_pos = Isometry2::identity();
12 | let ball_pos_intersecting = Isometry2::translation(1.0, 1.0);
13 | let ball_pos_disjoint = Isometry2::translation(3.0, 3.0);
14 |
15 | assert!(query::intersection_test(&ball_pos_intersecting, &ball, &cuboid_pos, &cuboid).unwrap());
16 | assert!(!query::intersection_test(&ball_pos_disjoint, &ball, &cuboid_pos, &cuboid).unwrap());
17 | }
18 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/solid_point_query2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry2, Point2, Vector2};
4 | use parry2d::query::PointQuery;
5 | use parry2d::shape::Cuboid;
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector2::new(1.0, 2.0));
9 | let pt_inside = Point2::origin();
10 | let pt_outside = Point2::new(2.0, 2.0);
11 |
12 | // Solid projection.
13 | assert_eq!(
14 | cuboid.distance_to_point(&Isometry2::identity(), &pt_inside, true),
15 | 0.0
16 | );
17 |
18 | // Non-solid projection.
19 | assert_eq!(
20 | cuboid.distance_to_point(&Isometry2::identity(), &pt_inside, false),
21 | -1.0
22 | );
23 |
24 | // The other point is outside of the cuboid so the `solid` flag has no effect.
25 | assert_eq!(
26 | cuboid.distance_to_point(&Isometry2::identity(), &pt_outside, false),
27 | 1.0
28 | );
29 | assert_eq!(
30 | cuboid.distance_to_point(&Isometry2::identity(), &pt_outside, true),
31 | 1.0
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/solid_ray_cast2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry2, Point2, Vector2};
4 | use parry2d::query::{Ray, RayCast};
5 | use parry2d::shape::Cuboid;
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector2::new(1.0, 2.0));
9 | let ray_inside = Ray::new(Point2::origin(), Vector2::y());
10 | let ray_miss = Ray::new(Point2::new(2.0, 2.0), Vector2::new(1.0, 1.0));
11 |
12 | // Solid cast.
13 | assert_eq!(
14 | cuboid
15 | .cast_ray(&Isometry2::identity(), &ray_inside, f32::MAX, true)
16 | .unwrap(),
17 | 0.0
18 | );
19 |
20 | // Non-solid cast.
21 | assert_eq!(
22 | cuboid
23 | .cast_ray(&Isometry2::identity(), &ray_inside, f32::MAX, false)
24 | .unwrap(),
25 | 2.0
26 | );
27 |
28 | // The other ray does not intersect this shape.
29 | assert!(cuboid
30 | .cast_ray(&Isometry2::identity(), &ray_miss, f32::MAX, false)
31 | .is_none());
32 | assert!(cuboid
33 | .cast_ray(&Isometry2::identity(), &ray_miss, f32::MAX, true)
34 | .is_none());
35 | }
36 |
--------------------------------------------------------------------------------
/crates/parry2d/examples/time_of_impact_query2d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry2, Vector2};
4 | use parry2d::query;
5 | use parry2d::query::ShapeCastOptions;
6 | use parry2d::shape::{Ball, Cuboid};
7 |
8 | fn main() {
9 | let cuboid = Cuboid::new(Vector2::new(1.0, 1.0));
10 | let ball = Ball::new(1.0);
11 |
12 | let cuboid_pos = Isometry2::identity();
13 | let ball_pos_intersecting = Isometry2::translation(1.0, 1.0);
14 | let ball_pos_will_touch = Isometry2::translation(2.0, 2.0);
15 | let ball_pos_wont_touch = Isometry2::translation(3.0, 3.0);
16 |
17 | let box_vel1 = Vector2::new(-1.0, 1.0);
18 | let box_vel2 = Vector2::new(1.0, 1.0);
19 |
20 | let ball_vel1 = Vector2::new(2.0, 2.0);
21 | let ball_vel2 = Vector2::new(-0.5, -0.5);
22 |
23 | let toi_intersecting = query::cast_shapes(
24 | &ball_pos_intersecting,
25 | &ball_vel1,
26 | &ball,
27 | &cuboid_pos,
28 | &box_vel1,
29 | &cuboid,
30 | ShapeCastOptions::default(),
31 | )
32 | .unwrap();
33 | let toi_will_touch = query::cast_shapes(
34 | &ball_pos_will_touch,
35 | &ball_vel2,
36 | &ball,
37 | &cuboid_pos,
38 | &box_vel2,
39 | &cuboid,
40 | ShapeCastOptions::default(),
41 | )
42 | .unwrap();
43 | let toi_wont_touch = query::cast_shapes(
44 | &ball_pos_wont_touch,
45 | &ball_vel1,
46 | &ball,
47 | &cuboid_pos,
48 | &box_vel1,
49 | &cuboid,
50 | ShapeCastOptions::default(),
51 | )
52 | .unwrap();
53 |
54 | assert_eq!(toi_intersecting.map(|hit| hit.time_of_impact), Some(0.0));
55 | println!("Toi: {:?}", toi_will_touch);
56 | assert!(toi_will_touch.is_some() && toi_will_touch.unwrap().time_of_impact > 0.0);
57 | assert_eq!(toi_wont_touch.map(|hit| hit.time_of_impact), None);
58 | }
59 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/geometry/aabb_scale.rs:
--------------------------------------------------------------------------------
1 | use na::{Point2, Vector2};
2 | use parry2d::bounding_volume::Aabb;
3 |
4 | #[test]
5 | fn test_aabb_scale_wrt_center() {
6 | let aabb = Aabb::from_half_extents(Point2::new(1.0, 2.0), Vector2::new(4.0, 5.0));
7 | let scale = Vector2::new(10.0, -20.0);
8 | let scaled_aabb = aabb.scaled_wrt_center(&scale);
9 | let scaled_aabb_neg = aabb.scaled_wrt_center(&-scale);
10 | let scaled_aabb_abs = aabb.scaled_wrt_center(&scale.abs());
11 |
12 | assert_eq!(&scaled_aabb, &scaled_aabb_neg);
13 | assert_eq!(&scaled_aabb, &scaled_aabb_abs);
14 | assert_eq!(aabb.center(), scaled_aabb.center());
15 | assert_eq!(scaled_aabb.half_extents(), Vector2::new(40.0, 100.0));
16 | }
17 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/geometry/ball_ball_toi.rs:
--------------------------------------------------------------------------------
1 | // Issue #35
2 |
3 | use na::{self, Isometry2, Vector2};
4 | use parry2d::query;
5 | use parry2d::query::details::ShapeCastOptions;
6 | use parry2d::shape::Ball;
7 |
8 | #[test]
9 | fn test_ball_ball_toi() {
10 | let b = Ball::new(0.5);
11 | let m1 = Isometry2::identity();
12 | let m2 = Isometry2::translation(0.0, 10.0);
13 | let v1 = Vector2::new(0.0, 10.0);
14 | let v2 = Vector2::zeros();
15 |
16 | let cast = query::cast_shapes(&m1, &v1, &b, &m2, &v2, &b, ShapeCastOptions::default()).unwrap();
17 |
18 | assert_eq!(cast.unwrap().time_of_impact, 0.9);
19 | }
20 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/geometry/ball_cuboid_contact.rs:
--------------------------------------------------------------------------------
1 | use nalgebra::{Isometry2, Vector2};
2 | use parry2d::query;
3 | use parry2d::shape::{Ball, Cuboid};
4 | #[cfg(feature = "improved_fixed_point_support")]
5 | use simba::scalar::FixedI40F24;
6 |
7 | #[test]
8 | fn test_ball_cuboid_query_contact() {
9 | let cuboid = Cuboid::new(Vector2::new(0.5, 0.5));
10 | let cuboid_pos = Isometry2::translation(0.0, 4.0);
11 | let ball = Ball::new(0.5);
12 | let ball_pos = Isometry2::translation(0.0517938, 3.05178815);
13 | let ct = query::contact(&cuboid_pos, &cuboid, &ball_pos, &ball, 0.0).unwrap();
14 | assert!(ct.is_some());
15 | let ct = query::contact(&ball_pos, &ball, &cuboid_pos, &cuboid, 0.0).unwrap();
16 | assert!(ct.is_some());
17 | }
18 |
19 | #[test]
20 | fn test_false_negative() {
21 | let contact = query::contact(
22 | &Isometry2::translation(1.0, 1.0),
23 | &Ball::new(1.0),
24 | &Isometry2::identity(),
25 | &Cuboid::new(Vector2::new(1.0, 1.0)),
26 | 1.0,
27 | )
28 | .unwrap()
29 | .unwrap();
30 |
31 | assert!(contact.dist < 0.0);
32 | }
33 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/geometry/epa_convergence.rs:
--------------------------------------------------------------------------------
1 | use na::Vector2;
2 | use parry2d::{
3 | math::{Isometry, Point, Real},
4 | query,
5 | shape::{Capsule, ConvexPolygon, SharedShape},
6 | };
7 |
8 | /// Original issue: https://github.com/dimforge/parry/issues/205
9 | #[test]
10 | fn capsule_convergence() {
11 | let shape1 = Capsule::new_y(5.0, 10.0);
12 | let mut vec = Vec::>::with_capacity(3);
13 | vec.push(Point::::new(64.0, 507.0));
14 | vec.push(Point::::new(440.0, 326.0));
15 | vec.push(Point::::new(1072.0, 507.0));
16 | let shape2 = ConvexPolygon::from_convex_polyline(vec);
17 | let shape2 = shape2.unwrap();
18 | let transform1 = Isometry::new(Vector2::new(381.592, 348.491), 0.0);
19 | let transform2 = Isometry::new(Vector2::new(0.0, 0.0), 0.0);
20 |
21 | let _res = query::details::contact_support_map_support_map(
22 | &transform1.inv_mul(&transform2),
23 | &shape1,
24 | &shape2,
25 | 10.0,
26 | )
27 | .expect("Penetration not found.");
28 | let shared_shape1 = SharedShape::new(shape1);
29 | let shared_shape2 = SharedShape::new(shape2);
30 |
31 | if let Ok(Some(_contact)) = query::contact(
32 | &transform1,
33 | shared_shape1.as_ref(),
34 | &transform2,
35 | shared_shape2.as_ref(),
36 | 1.0,
37 | ) {
38 | println!("collision");
39 | } else {
40 | panic!("no collision");
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/geometry/mod.rs:
--------------------------------------------------------------------------------
1 | mod aabb_scale;
2 | mod ball_ball_toi;
3 | mod ball_cuboid_contact;
4 | mod epa2;
5 | mod epa_convergence;
6 | mod ray_cast;
7 | mod time_of_impact2;
8 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/lib.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate approx;
3 | extern crate nalgebra as na;
4 | extern crate parry2d;
5 |
6 | mod geometry;
7 | mod query;
8 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/query/mod.rs:
--------------------------------------------------------------------------------
1 | mod point_composite_shape;
2 | mod point_triangle;
3 |
--------------------------------------------------------------------------------
/crates/parry2d/tests/query/point_triangle.rs:
--------------------------------------------------------------------------------
1 | use parry2d::{math::Point, query::PointQuery, shape::Triangle};
2 |
3 | #[test]
4 | fn project_local_point_point_on_ab() {
5 | let verts = [
6 | Point::new(2.0, 1.0),
7 | Point::new(0.0, 1.0),
8 | Point::new(1.0, 0.0),
9 | ];
10 | let tri1 = Triangle::new(verts[0], verts[1], verts[2]);
11 | let tri2 = Triangle::new(verts[2], verts[0], verts[1]);
12 |
13 | let query_pt = Point::new(1.4, 1.0);
14 |
15 | let proj1 = tri1.project_local_point(&query_pt, false); // Used to fail on 0.14 and earlier
16 | let proj2 = tri2.project_local_point(&query_pt, false);
17 |
18 | assert_eq!(proj1.point, proj2.point);
19 | assert_eq!(proj1.point, query_pt);
20 | }
21 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/all.rs:
--------------------------------------------------------------------------------
1 | #![feature(test)]
2 | #![allow(unused_macros)]
3 |
4 | extern crate nalgebra as na;
5 | extern crate parry3d;
6 | extern crate rand;
7 | extern crate test;
8 |
9 | mod bounding_volume;
10 | mod common;
11 | mod query;
12 | mod support_map;
13 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/common/generators.rs:
--------------------------------------------------------------------------------
1 | use na::Point3;
2 | use parry3d::shape::TriMesh;
3 | use rand::Rng;
4 |
5 | pub fn generate_trimesh_around_origin(rng: &mut R) -> TriMesh {
6 | let pts = (0..3000).map(|_| rng.gen::>() * 3.0).collect();
7 | let indices = (0..1000).map(|i| [i * 3, i * 3 + 1, i * 3 + 2]).collect();
8 |
9 | TriMesh::new(pts, indices).unwrap()
10 | }
11 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/common/mod.rs:
--------------------------------------------------------------------------------
1 | pub use self::default_gen::generate;
2 | pub use self::generators::generate_trimesh_around_origin;
3 | pub use self::unref::unref;
4 |
5 | mod default_gen;
6 | mod generators;
7 | mod unref;
8 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/common/unref.rs:
--------------------------------------------------------------------------------
1 | pub trait Unref {
2 | fn unref(a: Self) -> T;
3 | }
4 |
5 | impl<'a> Unref for &'a f32 {
6 | #[inline(always)]
7 | fn unref(a: &f32) -> f32 {
8 | *a
9 | }
10 | }
11 |
12 | impl<'a> Unref for &'a f64 {
13 | #[inline(always)]
14 | fn unref(a: &f64) -> f64 {
15 | *a
16 | }
17 | }
18 |
19 | impl<'a> Unref for &'a bool {
20 | #[inline(always)]
21 | fn unref(a: &bool) -> bool {
22 | *a
23 | }
24 | }
25 |
26 | impl<'a, T> Unref<&'a T> for &'a T {
27 | #[inline(always)]
28 | fn unref(a: &'a T) -> &'a T {
29 | a
30 | }
31 | }
32 |
33 | #[inline(always)]
34 | pub fn unref, O>(val: T) -> O {
35 | Unref::unref(val)
36 | }
37 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/query/algorithm.rs:
--------------------------------------------------------------------------------
1 | use na::Point3;
2 | use parry3d::query::gjk::{CSOPoint, VoronoiSimplex};
3 | use test::Bencher;
4 |
5 | #[bench]
6 | fn bench_johnson_simplex(bh: &mut Bencher) {
7 | let a = CSOPoint::single_point(Point3::new(-0.5f32, -0.5, -0.5));
8 | let b = CSOPoint::single_point(Point3::new(0.0, 0.5, 0.0));
9 | let c = CSOPoint::single_point(Point3::new(0.5, -0.5, -0.5));
10 | let d = CSOPoint::single_point(Point3::new(0.0, -0.5, -0.5));
11 |
12 | bh.iter(|| {
13 | let mut spl = VoronoiSimplex::new();
14 |
15 | spl.reset(a);
16 |
17 | spl.add_point(b);
18 | spl.add_point(c);
19 | spl.add_point(d);
20 |
21 | test::black_box(spl.project_origin_and_reduce());
22 | })
23 | }
24 |
25 | #[bench]
26 | fn bench_johnson_simplex_tls(bh: &mut Bencher) {
27 | let a = CSOPoint::single_point(Point3::new(-0.5f32, -0.5, -0.5));
28 | let b = CSOPoint::single_point(Point3::new(0.0, 0.5, 0.0));
29 | let c = CSOPoint::single_point(Point3::new(0.5, -0.5, -0.5));
30 | let d = CSOPoint::single_point(Point3::new(0.0, -0.5, -0.5));
31 |
32 | bh.iter(|| {
33 | let mut spl = VoronoiSimplex::new();
34 |
35 | spl.reset(a);
36 |
37 | spl.add_point(b);
38 | spl.add_point(c);
39 | spl.add_point(d);
40 |
41 | test::black_box(spl.project_origin_and_reduce());
42 | })
43 | }
44 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/query/contacts.rs:
--------------------------------------------------------------------------------
1 | use crate::common::{generate, unref};
2 | use na::Isometry3;
3 | use parry3d::query;
4 | use parry3d::shape::{Ball, Capsule, Cone, Cuboid, Cylinder};
5 | use rand::SeedableRng;
6 | use rand_isaac::IsaacRng;
7 | use test::Bencher;
8 |
9 | #[path = "../common/macros.rs"]
10 | #[macro_use]
11 | mod macros;
12 |
13 | bench_free_fn!(
14 | bench_ball_against_ball,
15 | query::contact,
16 | pos1: Isometry3,
17 | b1: Ball,
18 | pos2: Isometry3,
19 | b2: Ball,
20 | prediction: f32
21 | );
22 |
23 | bench_free_fn!(
24 | bench_cuboid_against_cuboid,
25 | query::contact,
26 | pos1: Isometry3,
27 | b1: Cuboid,
28 | pos2: Isometry3,
29 | b2: Cuboid,
30 | prediction: f32
31 | );
32 |
33 | bench_free_fn!(
34 | bench_capsule_against_capsule,
35 | query::contact,
36 | pos1: Isometry3,
37 | b1: Capsule,
38 | pos2: Isometry3,
39 | b2: Capsule,
40 | prediction: f32
41 | );
42 |
43 | bench_free_fn!(
44 | bench_cone_against_cone,
45 | query::contact,
46 | pos1: Isometry3,
47 | b1: Cone,
48 | pos2: Isometry3,
49 | b2: Cone,
50 | prediction: f32
51 | );
52 |
53 | bench_free_fn!(
54 | bench_cylinder_against_cylinder,
55 | query::contact,
56 | pos1: Isometry3,
57 | b1: Cylinder,
58 | pos2: Isometry3,
59 | b2: Cylinder,
60 | prediction: f32
61 | );
62 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/query/mod.rs:
--------------------------------------------------------------------------------
1 | mod algorithm;
2 | mod contacts;
3 | mod ray;
4 |
--------------------------------------------------------------------------------
/crates/parry3d/benches/support_map/mod.rs:
--------------------------------------------------------------------------------
1 | use crate::common::{generate, unref};
2 | use na::{Isometry3, Vector3};
3 | use parry3d::shape::ConvexPolyhedron;
4 | use parry3d::shape::SupportMap;
5 | use parry3d::shape::{Ball, Capsule, Cone, Cuboid, Cylinder, Segment, Triangle};
6 | use rand::SeedableRng;
7 | use rand_isaac::IsaacRng;
8 | use test::Bencher;
9 |
10 | #[path = "../common/macros.rs"]
11 | #[macro_use]
12 | mod macros;
13 |
14 | bench_method!(
15 | bench_ball_support_map,
16 | support_point,
17 | c: Ball,
18 | m: Isometry3,
19 | dir: Vector3
20 | );
21 | bench_method!(
22 | bench_cuboid_support_map,
23 | support_point,
24 | c: Cuboid,
25 | m: Isometry3,
26 | dir: Vector3
27 | );
28 | bench_method!(
29 | bench_capsule_support_map,
30 | support_point,
31 | c: Capsule,
32 | m: Isometry3,
33 | dir: Vector3
34 | );
35 | bench_method!(
36 | bench_cone_support_map,
37 | support_point,
38 | c: Cone,
39 | m: Isometry3,
40 | dir: Vector3
41 | );
42 | bench_method!(
43 | bench_cylinder_support_map,
44 | support_point,
45 | c: Cylinder,
46 | m: Isometry3,
47 | dir: Vector3
48 | );
49 | bench_method!(
50 | bench_segment_support_map,
51 | support_point,
52 | c: Segment,
53 | m: Isometry3,
54 | dir: Vector3
55 | );
56 | bench_method!(
57 | bench_triangle_support_map,
58 | support_point,
59 | c: Triangle,
60 | m: Isometry3,
61 | dir: Vector3
62 | );
63 | bench_method!(
64 | bench_convex_support_map,
65 | support_point,
66 | c: ConvexPolyhedron,
67 | m: Isometry3,
68 | dir: Vector3
69 | );
70 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/ball3d.rs:
--------------------------------------------------------------------------------
1 | use parry3d::shape::Ball;
2 |
3 | fn main() {
4 | let ball = Ball::new(1.0f32);
5 | assert!(ball.radius == 1.0);
6 | }
7 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/capsule.rs:
--------------------------------------------------------------------------------
1 | use parry3d::shape::Capsule;
2 |
3 | fn main() {
4 | let capsule = Capsule::new_y(0.5f32, 0.75);
5 |
6 | assert!(capsule.half_height() == 0.5);
7 | assert!(capsule.radius == 0.75);
8 | }
9 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/cone.rs:
--------------------------------------------------------------------------------
1 | use parry3d::shape::Cone;
2 |
3 | fn main() {
4 | let cone = Cone::new(0.5f32, 0.75);
5 |
6 | assert!(cone.half_height == 0.5);
7 | assert!(cone.radius == 0.75);
8 | }
9 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/contact_query3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry3, Vector3};
4 | use parry3d::query;
5 | use parry3d::shape::{Ball, Cuboid};
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
9 | let ball = Ball::new(1.0);
10 | let prediction = 1.0;
11 |
12 | let cuboid_pos = Isometry3::identity();
13 | let ball_pos_penetrating = Isometry3::translation(1.0, 1.0, 1.0);
14 | let ball_pos_in_prediction = Isometry3::translation(2.0, 2.0, 2.0);
15 | let ball_pos_too_far = Isometry3::translation(3.0, 3.0, 3.0);
16 |
17 | let ctct_penetrating = query::contact(
18 | &ball_pos_penetrating,
19 | &ball,
20 | &cuboid_pos,
21 | &cuboid,
22 | prediction,
23 | )
24 | .unwrap();
25 | let ctct_in_prediction = query::contact(
26 | &ball_pos_in_prediction,
27 | &ball,
28 | &cuboid_pos,
29 | &cuboid,
30 | prediction,
31 | )
32 | .unwrap();
33 | let ctct_too_far =
34 | query::contact(&ball_pos_too_far, &ball, &cuboid_pos, &cuboid, prediction).unwrap();
35 |
36 | assert!(ctct_penetrating.unwrap().dist <= 0.0);
37 | assert!(ctct_in_prediction.unwrap().dist >= 0.0);
38 | assert_eq!(ctct_too_far, None);
39 | }
40 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/convex3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Point3;
4 | use parry3d::shape::ConvexPolyhedron;
5 |
6 | fn main() {
7 | let points = [
8 | Point3::new(0.0f32, 0.0, 1.0),
9 | Point3::new(0.0, 0.0, -1.0),
10 | Point3::new(0.0, 1.0, 0.0),
11 | Point3::new(0.0, -1.0, 0.0),
12 | Point3::new(1.0, 0.0, 0.0),
13 | Point3::new(-1.0, 0.0, 0.0),
14 | Point3::new(0.0, 0.0, 0.0),
15 | ];
16 |
17 | let convex = ConvexPolyhedron::from_convex_hull(&points).expect("Invalid convex shape.");
18 | convex.check_geometry();
19 | }
20 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/convex_try_new3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Point3;
4 | use parry3d::shape::ConvexPolyhedron;
5 |
6 | fn main() {
7 | let points = vec![
8 | Point3::new(0.0f32, 0.0, 1.0),
9 | Point3::new(0.0, 0.0, -1.0),
10 | Point3::new(0.0, 1.0, 0.0),
11 | Point3::new(0.0, -1.0, 0.0),
12 | Point3::new(1.0, 0.0, 0.0),
13 | Point3::new(-1.0, 0.0, 0.0),
14 | ];
15 |
16 | let indices = vec![
17 | [0, 4, 2],
18 | [0, 3, 4],
19 | [5, 0, 2],
20 | [5, 3, 0],
21 | [1, 5, 2],
22 | [1, 3, 5],
23 | [4, 1, 2],
24 | [4, 3, 1],
25 | ];
26 |
27 | let convex =
28 | ConvexPolyhedron::from_convex_mesh(points, &indices).expect("Invalid convex shape.");
29 | convex.check_geometry();
30 | }
31 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/cuboid3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Vector3;
4 | use parry3d::shape::Cuboid;
5 |
6 | fn main() {
7 | let cuboid = Cuboid::new(Vector3::new(2.0f32, 1.0, 3.0));
8 |
9 | assert!(cuboid.half_extents.x == 2.0);
10 | assert!(cuboid.half_extents.y == 1.0);
11 | assert!(cuboid.half_extents.z == 3.0);
12 | }
13 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/cylinder.rs:
--------------------------------------------------------------------------------
1 | use parry3d::shape::Cylinder;
2 |
3 | fn main() {
4 | let cylinder = Cylinder::new(0.5f32, 1.0);
5 |
6 | assert!(cylinder.half_height == 0.5);
7 | assert!(cylinder.radius == 1.0);
8 | }
9 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/distance_query3d.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate approx; // for relative_eq!
3 | extern crate nalgebra as na;
4 |
5 | use na::{Isometry3, Vector3};
6 | use parry3d::query;
7 | use parry3d::shape::{Ball, Cuboid};
8 |
9 | fn main() {
10 | let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
11 | let ball = Ball::new(1.0);
12 |
13 | let cuboid_pos = Isometry3::identity();
14 | let ball_pos_intersecting = Isometry3::translation(0.0, 1.0, 0.0);
15 | let ball_pos_disjoint = Isometry3::translation(0.0, 3.0, 0.0);
16 |
17 | let dist_intersecting =
18 | query::distance(&ball_pos_intersecting, &ball, &cuboid_pos, &cuboid).unwrap();
19 | let dist_disjoint = query::distance(&ball_pos_disjoint, &ball, &cuboid_pos, &cuboid).unwrap();
20 |
21 | assert_eq!(dist_intersecting, 0.0);
22 | assert!(relative_eq!(dist_disjoint, 1.0, epsilon = 1.0e-7));
23 | }
24 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/getting_started.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry3, Point3, Vector3};
4 | use parry3d::query::{Ray, RayCast};
5 | use parry3d::shape::Cuboid;
6 |
7 | fn main() {
8 | let cube = Cuboid::new(Vector3::new(1.0f32, 1.0, 1.0));
9 | let ray = Ray::new(Point3::new(0.0f32, 0.0, -1.0), Vector3::z());
10 |
11 | assert!(cube.intersects_ray(&Isometry3::identity(), &ray, f32::MAX));
12 | }
13 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/mesh3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Point3;
4 | use parry3d::shape::TriMesh;
5 |
6 | fn main() {
7 | let points = vec![
8 | Point3::new(0.0, 1.0, 0.0),
9 | Point3::new(-1.0, -0.5, 0.0),
10 | Point3::new(0.0, -0.5, -1.0),
11 | Point3::new(1.0, -0.5, 0.0),
12 | ];
13 |
14 | let indices = vec![[0u32, 1, 2], [0, 2, 3], [0, 3, 1]];
15 |
16 | // Build the mesh.
17 | let mesh = TriMesh::new(points, indices).unwrap();
18 |
19 | assert!(mesh.vertices().len() == 4);
20 | }
21 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/plane3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Vector3;
4 | use parry3d::shape::HalfSpace;
5 |
6 | fn main() {
7 | let halfspace = HalfSpace::new(Vector3::::y_axis());
8 |
9 | assert!(halfspace.normal.x == 0.0);
10 | assert!(halfspace.normal.y == 1.0);
11 | assert!(halfspace.normal.z == 0.0);
12 | }
13 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/polyline3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::Point3;
4 | use parry3d::shape::Polyline;
5 |
6 | fn main() {
7 | let points = vec![
8 | Point3::new(0.0, 1.0, 0.0),
9 | Point3::new(-1.0, -1.0, 1.0),
10 | Point3::new(0.0, -0.5, 0.0),
11 | Point3::new(1.0, -1.0, -1.0),
12 | Point3::new(0.0, 1.0, 0.0), // This forms a loop.
13 | ];
14 |
15 | // Build the polyline.
16 | let polyline = Polyline::new(points, None);
17 |
18 | assert!(polyline.vertices().len() == 5);
19 | }
20 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/proximity_query3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry3, Vector3};
4 | use parry3d::query;
5 | use parry3d::shape::{Ball, Cuboid};
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
9 | let ball = Ball::new(1.0);
10 | let cuboid_pos = Isometry3::identity();
11 | let ball_pos_intersecting = Isometry3::translation(1.0, 1.0, 1.0);
12 | let ball_pos_disjoint = Isometry3::translation(3.0, 3.0, 3.0);
13 |
14 | let intersecting =
15 | query::intersection_test(&ball_pos_intersecting, &ball, &cuboid_pos, &cuboid).unwrap();
16 | let not_intersecting =
17 | !query::intersection_test(&ball_pos_disjoint, &ball, &cuboid_pos, &cuboid).unwrap();
18 |
19 | assert!(intersecting);
20 | assert!(not_intersecting);
21 | }
22 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/solid_point_query3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry3, Point3, Vector3};
4 | use parry3d::query::PointQuery;
5 | use parry3d::shape::Cuboid;
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector3::new(1.0, 2.0, 2.0));
9 | let pt_inside = Point3::origin();
10 | let pt_outside = Point3::new(2.0, 2.0, 2.0);
11 |
12 | // Solid projection.
13 | assert_eq!(
14 | cuboid.distance_to_point(&Isometry3::identity(), &pt_inside, true),
15 | 0.0
16 | );
17 |
18 | // Non-solid projection.
19 | assert_eq!(
20 | cuboid.distance_to_point(&Isometry3::identity(), &pt_inside, false),
21 | -1.0
22 | );
23 |
24 | // The other point is outside of the cuboid so the `solid` flag has no effect.
25 | assert_eq!(
26 | cuboid.distance_to_point(&Isometry3::identity(), &pt_outside, false),
27 | 1.0
28 | );
29 | assert_eq!(
30 | cuboid.distance_to_point(&Isometry3::identity(), &pt_outside, true),
31 | 1.0
32 | );
33 | }
34 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/solid_ray_cast3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry3, Point3, Vector3};
4 | use parry3d::query::{Ray, RayCast};
5 | use parry3d::shape::Cuboid;
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector3::new(1.0, 2.0, 1.0));
9 | let ray_inside = Ray::new(Point3::origin(), Vector3::y());
10 | let ray_miss = Ray::new(Point3::new(2.0, 2.0, 2.0), Vector3::new(1.0, 1.0, 1.0));
11 |
12 | // Solid cast.
13 | assert_eq!(
14 | cuboid
15 | .cast_ray(&Isometry3::identity(), &ray_inside, f32::MAX, true)
16 | .unwrap(),
17 | 0.0
18 | );
19 |
20 | // Non-solid cast.
21 | assert_eq!(
22 | cuboid
23 | .cast_ray(&Isometry3::identity(), &ray_inside, f32::MAX, false)
24 | .unwrap(),
25 | 2.0
26 | );
27 |
28 | // The other ray does not intersect this shape.
29 | assert!(cuboid
30 | .cast_ray(&Isometry3::identity(), &ray_miss, f32::MAX, false)
31 | .is_none());
32 | assert!(cuboid
33 | .cast_ray(&Isometry3::identity(), &ray_miss, f32::MAX, true)
34 | .is_none());
35 | }
36 |
--------------------------------------------------------------------------------
/crates/parry3d/examples/time_of_impact_query3d.rs:
--------------------------------------------------------------------------------
1 | extern crate nalgebra as na;
2 |
3 | use na::{Isometry3, Vector3};
4 | use parry3d::query::{self, ShapeCastOptions};
5 | use parry3d::shape::{Ball, Cuboid};
6 |
7 | fn main() {
8 | let cuboid = Cuboid::new(Vector3::new(1.0, 1.0, 1.0));
9 | let ball = Ball::new(1.0);
10 |
11 | let cuboid_pos = Isometry3::identity();
12 | let ball_pos_intersecting = Isometry3::translation(1.0, 1.0, 1.0);
13 | let ball_pos_will_touch = Isometry3::translation(2.0, 2.0, 2.0);
14 | let ball_pos_wont_touch = Isometry3::translation(3.0, 3.0, 3.0);
15 |
16 | let cuboid_vel1 = Vector3::new(-1.0, 1.0, 1.0);
17 | let cuboid_vel2 = Vector3::new(1.0, 1.0, 1.0);
18 |
19 | let ball_vel1 = Vector3::new(2.0, 2.0, 2.0);
20 | let ball_vel2 = Vector3::new(-0.5, -0.5, -0.5);
21 |
22 | let toi_intersecting = query::cast_shapes(
23 | &ball_pos_intersecting,
24 | &ball_vel1,
25 | &ball,
26 | &cuboid_pos,
27 | &cuboid_vel1,
28 | &cuboid,
29 | ShapeCastOptions::default(),
30 | )
31 | .unwrap();
32 | let toi_will_touch = query::cast_shapes(
33 | &ball_pos_will_touch,
34 | &ball_vel2,
35 | &ball,
36 | &cuboid_pos,
37 | &cuboid_vel2,
38 | &cuboid,
39 | ShapeCastOptions::default(),
40 | )
41 | .unwrap();
42 | let toi_wont_touch = query::cast_shapes(
43 | &ball_pos_wont_touch,
44 | &ball_vel1,
45 | &ball,
46 | &cuboid_pos,
47 | &cuboid_vel1,
48 | &cuboid,
49 | ShapeCastOptions::default(),
50 | )
51 | .unwrap();
52 |
53 | assert_eq!(toi_intersecting.map(|hit| hit.time_of_impact), Some(0.0));
54 | assert!(toi_will_touch.is_some() && toi_will_touch.unwrap().time_of_impact > 0.0);
55 | assert_eq!(toi_wont_touch.map(|hit| hit.time_of_impact), None);
56 | }
57 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/aabb_scale.rs:
--------------------------------------------------------------------------------
1 | use na::{Point3, Vector3};
2 | use parry3d::bounding_volume::Aabb;
3 |
4 | #[test]
5 | fn test_aabb_scale_wrt_center() {
6 | let aabb = Aabb::from_half_extents(Point3::new(1.0, 2.0, 3.0), Vector3::new(4.0, 5.0, 6.0));
7 | let scale = Vector3::new(10.0, -20.0, 50.0);
8 | let scaled_aabb = aabb.scaled_wrt_center(&scale);
9 | let scaled_aabb_neg = aabb.scaled_wrt_center(&-scale);
10 | let scaled_aabb_abs = aabb.scaled_wrt_center(&scale.abs());
11 |
12 | assert_eq!(&scaled_aabb, &scaled_aabb_neg);
13 | assert_eq!(&scaled_aabb, &scaled_aabb_abs);
14 | assert_eq!(aabb.center(), scaled_aabb.center());
15 | assert_eq!(scaled_aabb.half_extents(), Vector3::new(40.0, 100.0, 300.0));
16 | }
17 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/ball_ball_toi.rs:
--------------------------------------------------------------------------------
1 | // Issue #35
2 |
3 | use na::{self, Isometry3, Vector3};
4 | use parry3d::query::{self, ShapeCastOptions};
5 | use parry3d::shape::Ball;
6 |
7 | #[test]
8 | fn test_ball_ball_toi() {
9 | let b = Ball::new(0.5);
10 | let m1 = Isometry3::identity();
11 | let m2 = Isometry3::translation(0.0, 10.0, 0.0);
12 | let vel1 = Vector3::new(0.0, 10.0, 0.0);
13 | let vel2 = Vector3::zeros();
14 |
15 | let cast =
16 | query::cast_shapes(&m1, &vel1, &b, &m2, &vel2, &b, ShapeCastOptions::default()).unwrap();
17 |
18 | assert_eq!(cast.unwrap().time_of_impact, 0.9);
19 | }
20 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/ball_triangle_toi.rs:
--------------------------------------------------------------------------------
1 | // Issue #123
2 |
3 | use na::{self, Isometry3, Point3, Vector3};
4 | use parry3d::query::{self, ShapeCastOptions};
5 | use parry3d::shape::{Ball, Triangle};
6 |
7 | #[test]
8 | fn ball_triangle_toi_infinite_loop_issue() {
9 | let b = Ball::new(0.375f32);
10 | let t = Triangle::new(
11 | Point3::new(0.5, -0.5, 0.0),
12 | Point3::new(-0.5, -0.5, 0.0),
13 | Point3::new(-0.5, 0.5, 0.0),
14 | );
15 |
16 | let m1 = Isometry3::translation(0.0, 0.0, 0.0);
17 | let m2 = Isometry3::translation(11.5, 5.5, 0.0);
18 | let vel1 = Vector3::new(0.0, 0.000000000000000000000000000000000000000006925, 0.0);
19 | let vel2 = Vector3::zeros();
20 |
21 | let cast =
22 | query::cast_shapes(&m1, &vel1, &b, &m2, &vel2, &t, ShapeCastOptions::default()).unwrap();
23 |
24 | println!("ShapeCastHit: {:?}", cast);
25 | assert!(cast.is_none()); // The provided velocity is too small.
26 | }
27 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/cylinder_cuboid_contact.rs:
--------------------------------------------------------------------------------
1 | use na::{self, Isometry3, Vector3};
2 | use parry3d::query;
3 | use parry3d::shape::{Cuboid, Cylinder};
4 |
5 | // Issue #157.
6 | #[test]
7 | fn cylinder_cuboid_contact() {
8 | let cyl = Cylinder::new(0.925, 0.5);
9 | let cyl_at = Isometry3::translation(10.97, 0.925, 61.02);
10 | let cuboid = Cuboid::new(Vector3::new(0.05, 0.75, 0.5));
11 | let cuboid_at = Isometry3::translation(11.50, 0.75, 60.5);
12 | let distance = query::details::distance_support_map_support_map(
13 | &cyl_at.inv_mul(&cuboid_at),
14 | &cyl,
15 | &cuboid,
16 | );
17 |
18 | let intersecting = query::details::intersection_test_support_map_support_map(
19 | &cyl_at.inv_mul(&cuboid_at),
20 | &cyl,
21 | &cuboid,
22 | );
23 |
24 | let contact = query::details::contact_support_map_support_map(
25 | &cyl_at.inv_mul(&cuboid_at),
26 | &cyl,
27 | &cuboid,
28 | 10.0,
29 | );
30 |
31 | assert!(distance == 0.0);
32 | assert!(intersecting);
33 | assert!(contact.is_some());
34 | }
35 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/mod.rs:
--------------------------------------------------------------------------------
1 | mod aabb_scale;
2 | mod ball_ball_toi;
3 | mod ball_triangle_toi;
4 | mod convex_hull;
5 | mod cuboid_ray_cast;
6 | mod cylinder_cuboid_contact;
7 | mod epa3;
8 | mod still_objects_toi;
9 | mod time_of_impact3;
10 | mod trimesh_connected_components;
11 | mod trimesh_intersection;
12 | mod trimesh_trimesh_toi;
13 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/still_objects_toi.rs:
--------------------------------------------------------------------------------
1 | use na::{self, Isometry3, Vector3};
2 | use parry3d::query::{cast_shapes, ShapeCastOptions};
3 | use parry3d::shape::Cuboid;
4 |
5 | /**
6 | * Issue #141
7 | * Sets up a situation like this:
8 | * ```raw
9 | * +---+
10 | * | 1 |
11 | * | |
12 | * +---+
13 | *
14 | * +---+
15 | * | 2 |
16 | * | |
17 | * +---+
18 | * ```
19 | * with box 1 having the provided v_y.
20 | */
21 | fn collide(v_y: f32) -> Option {
22 | let pos1 = Isometry3::translation(0.0, 1.1, 0.0);
23 | let pos2 = Isometry3::identity();
24 | let vel1 = Vector3::y() * v_y;
25 | let vel2 = Vector3::zeros();
26 | let cuboid = Cuboid::new(Vector3::new(0.5, 0.5, 0.5));
27 |
28 | cast_shapes(
29 | &pos1,
30 | &vel1,
31 | &cuboid,
32 | &pos2,
33 | &vel2,
34 | &cuboid,
35 | ShapeCastOptions::default(),
36 | )
37 | .unwrap()
38 | .map(|hit| hit.time_of_impact)
39 | }
40 |
41 | #[test]
42 | fn no_movement() {
43 | assert_eq!(collide(0.0), None);
44 | }
45 |
46 | #[test]
47 | fn moving_up_misses() {
48 | assert_eq!(collide(1.0), None);
49 | }
50 |
51 | #[test]
52 | fn moving_down_hits() {
53 | assert!(collide(-1.0).is_some());
54 | }
55 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/trimesh_connected_components.rs:
--------------------------------------------------------------------------------
1 | use parry3d::math::Point;
2 | use parry3d::shape::{TriMesh, TriMeshFlags};
3 |
4 | #[test]
5 | // From https://github.com/dimforge/parry/issues/115
6 | fn mesh_connected_components_grouped_faces() {
7 | let verts = vec![
8 | // Face 0
9 | Point::new(15.82, 6.455, -0.15), // <- Vertex shared with face 1.
10 | Point::new(9.915, 6.455, -0.15),
11 | Point::new(9.915, 6.4, 0.0), // <- Vertex shared with face 1.
12 | // Face1
13 | Point::new(15.82, 6.455, -0.15), // <- Vertex shared with face 0.
14 | Point::new(9.915, 6.4, 0.0), // <- Vertex shared with face 0.
15 | Point::new(15.82, 6.4, 0.0),
16 | ];
17 |
18 | let mut roof = TriMesh::new(verts, vec![[0, 1, 2], [3, 4, 5]]).unwrap();
19 |
20 | if let Err(e) =
21 | roof.set_flags(TriMeshFlags::MERGE_DUPLICATE_VERTICES | TriMeshFlags::CONNECTED_COMPONENTS)
22 | {
23 | dbg!(e);
24 | assert!(false);
25 | }
26 |
27 | let components = roof.connected_components().unwrap();
28 | println!("components: {:?}", components);
29 | assert_eq!(components.ranges.len(), 2); // Only one connected-component (two range values).
30 | assert_eq!(components.grouped_faces.len(), 2); // Only two faces in the connected-component.
31 | }
32 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/geometry/trimesh_trimesh_toi.rs:
--------------------------------------------------------------------------------
1 | // Issue #194
2 |
3 | use na::{zero, Isometry3, Point3, Vector3};
4 | use parry3d::math::Real;
5 | use parry3d::query::{self, ShapeCastOptions};
6 | use parry3d::shape::TriMesh;
7 |
8 | fn build_pyramid() -> TriMesh {
9 | let points = vec![
10 | Point3::new(0.0, 1.0, 0.0),
11 | Point3::new(-1.0, -0.5, 0.0),
12 | Point3::new(0.0, -0.5, -1.0),
13 | Point3::new(1.0, -0.5, 0.0),
14 | ];
15 |
16 | let indices = vec![[0u32, 1, 2], [0, 2, 3], [0, 3, 1]];
17 |
18 | TriMesh::new(points, indices).unwrap()
19 | }
20 |
21 | fn do_toi_test() -> Option {
22 | const SPEED: Real = 100000.0;
23 |
24 | let shape_one = build_pyramid();
25 | let shape_two = build_pyramid();
26 |
27 | let pos_one = Vector3::new(0.0, 0.0, 0.0);
28 | let pos_two = Vector3::new(1000.0, 0.0, 0.0);
29 |
30 | let transform_one = Isometry3::new(pos_one, zero());
31 | let transform_two = Isometry3::new(pos_two, zero());
32 |
33 | let vel_one = Vector3::new(SPEED, 0.0, 0.0);
34 | let vel_two = Vector3::new(0.0, 0.0, 0.0);
35 |
36 | query::cast_shapes(
37 | &transform_one,
38 | &vel_one,
39 | &shape_one,
40 | &transform_two,
41 | &vel_two,
42 | &shape_two,
43 | ShapeCastOptions::default(),
44 | )
45 | .unwrap()
46 | .map(|hit| hit.time_of_impact)
47 | }
48 |
49 | #[test]
50 | fn trimesh_trimesh_toi() {
51 | let time_of_impact = do_toi_test();
52 | assert_eq!(time_of_impact, Some(0.00998));
53 | }
54 |
--------------------------------------------------------------------------------
/crates/parry3d/tests/lib.rs:
--------------------------------------------------------------------------------
1 | #[macro_use]
2 | extern crate approx;
3 | extern crate nalgebra as na;
4 | extern crate parry3d;
5 |
6 | mod geometry;
7 |
--------------------------------------------------------------------------------
/publish.sh:
--------------------------------------------------------------------------------
1 | #! /bin/bash
2 |
3 | tmp=`mktemp -d`
4 |
5 | echo $tmp
6 |
7 | cp -r src $tmp/.
8 | cp -r LICENSE README.md $tmp/.
9 |
10 | ### Publish the 2D version.
11 | sed 's#\.\./\.\./src#src#g' crates/parry2d/Cargo.toml > $tmp/Cargo.toml
12 | rm -rf $tmp/examples
13 | cp -r crates/parry2d/examples $tmp/examples
14 | currdir=`pwd`
15 | cd $tmp && cargo publish
16 | cd $currdir
17 |
18 | ### Publish the 2D f64 version.
19 | sed 's#\.\./\.\./src#src#g' crates/parry2d-f64/Cargo.toml > $tmp/Cargo.toml
20 | cd $tmp && cargo publish
21 | cd $currdir
22 |
23 |
24 | ### Publish the 3D version.
25 | sed 's#\.\./\.\./src#src#g' crates/parry3d/Cargo.toml > $tmp/Cargo.toml
26 | rm -rf $tmp/examples
27 | cp -r crates/parry3d/examples $tmp/examples
28 | cp -r LICENSE README.md $tmp/.
29 | cd $tmp && cargo publish
30 | cd $currdir
31 |
32 | ### Publish the 3D f64 version.
33 | sed 's#\.\./\.\./src#src#g' crates/parry3d-f64/Cargo.toml > $tmp/Cargo.toml
34 | cp -r LICENSE README.md $tmp/.
35 | cd $tmp && cargo publish
36 |
37 | rm -rf $tmp
38 |
39 |
--------------------------------------------------------------------------------
/rustfmt.toml:
--------------------------------------------------------------------------------
1 | #unstable_features = true
2 | #indent_style = "Block"
3 | #where_single_line = true
4 | #brace_style = "PreferSameLine"
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_ball.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Point, Real, Vector};
3 | use crate::shape::Ball;
4 |
5 | /// Computes the Axis-Aligned Bounding Box of a ball transformed by `center`.
6 | #[inline]
7 | pub fn ball_aabb(center: &Point, radius: Real) -> Aabb {
8 | Aabb::new(
9 | *center + Vector::repeat(-radius),
10 | *center + Vector::repeat(radius),
11 | )
12 | }
13 |
14 | /// Computes the Axis-Aligned Bounding Box of a ball.
15 | #[inline]
16 | pub fn local_ball_aabb(radius: Real) -> Aabb {
17 | let half_extents = Point::from(Vector::repeat(radius));
18 |
19 | Aabb::new(-half_extents, half_extents)
20 | }
21 |
22 | impl Ball {
23 | /// Computes the world-space [`Aabb`] of this ball transformed by `pos`.
24 | #[inline]
25 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
26 | ball_aabb(&Point::::from(pos.translation.vector), self.radius)
27 | }
28 |
29 | /// Computes the local-space [`Aabb`] of this ball.
30 | #[inline]
31 | pub fn local_aabb(&self) -> Aabb {
32 | local_ball_aabb(self.radius)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_capsule.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Real, Vector};
3 | use crate::shape::Capsule;
4 |
5 | impl Capsule {
6 | /// The axis-aligned bounding box of this capsule.
7 | #[inline]
8 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
9 | self.transform_by(pos).local_aabb()
10 | }
11 |
12 | /// The axis-aligned bounding box of this capsule.
13 | #[inline]
14 | pub fn local_aabb(&self) -> Aabb {
15 | let a = self.segment.a;
16 | let b = self.segment.b;
17 | let mins = a.coords.inf(&b.coords) - Vector::repeat(self.radius);
18 | let maxs = a.coords.sup(&b.coords) + Vector::repeat(self.radius);
19 | Aabb::new(mins.into(), maxs.into())
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_convex_polygon.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::ConvexPolygon;
4 |
5 | impl ConvexPolygon {
6 | /// Computes the world-space [`Aabb`] of this convex polygon, transformed by `pos`.
7 | #[inline]
8 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
9 | super::details::point_cloud_aabb(pos, self.points())
10 | }
11 |
12 | /// Computes the local-space [`Aabb`] of this convex polygon.
13 | #[inline]
14 | pub fn local_aabb(&self) -> Aabb {
15 | super::details::local_point_cloud_aabb(self.points())
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_convex_polyhedron.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::ConvexPolyhedron;
4 |
5 | impl ConvexPolyhedron {
6 | /// Computes the world-space [`Aabb`] of this convex polyhedron, transformed by `pos`.
7 | #[inline]
8 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
9 | super::details::point_cloud_aabb(pos, self.points())
10 | }
11 |
12 | /// Computes the local-space [`Aabb`] of this convex polyhedron.
13 | #[inline]
14 | pub fn local_aabb(&self) -> Aabb {
15 | super::details::local_point_cloud_aabb(self.points())
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_cuboid.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Point, Real};
3 | use crate::shape::Cuboid;
4 | use crate::utils::IsometryOps;
5 |
6 | impl Cuboid {
7 | /// Computes the world-space [`Aabb`] of this cuboid, transformed by `pos`.
8 | #[inline]
9 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
10 | let center = Point::from(pos.translation.vector);
11 | let ws_half_extents = pos.absolute_transform_vector(&self.half_extents);
12 |
13 | Aabb::from_half_extents(center, ws_half_extents)
14 | }
15 |
16 | /// Computes the local-space [`Aabb`] of this cuboid.
17 | #[inline]
18 | pub fn local_aabb(&self) -> Aabb {
19 | let half_extents = Point::from(self.half_extents);
20 |
21 | Aabb::new(-half_extents, half_extents)
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_halfspace.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Point, Real};
3 | use crate::num::Bounded;
4 | use crate::shape::HalfSpace;
5 | use na;
6 |
7 | impl HalfSpace {
8 | /// Computes the world-space [`Aabb`] of this half-space.
9 | #[inline]
10 | pub fn aabb(&self, _pos: &Isometry) -> Aabb {
11 | self.local_aabb()
12 | }
13 |
14 | /// Computes the local-space [`Aabb`] of this half-space.
15 | #[inline]
16 | pub fn local_aabb(&self) -> Aabb {
17 | // We divide by 2.0 so that we can still make some operations with it (like loosening)
18 | // without breaking the box.
19 | let max = Point::max_value() * na::convert::(0.5f64);
20 | Aabb::new(-max, max)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_heightfield.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::HeightField;
4 |
5 | impl HeightField {
6 | /// Computes the world-space [`Aabb`] of this heightfield, transformed by `pos`.
7 | #[inline]
8 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
9 | self.root_aabb().transform_by(pos)
10 | }
11 |
12 | /// Computes the local-space [`Aabb`] of this heightfield.
13 | #[inline]
14 | pub fn local_aabb(&self) -> Aabb {
15 | *self.root_aabb()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_support_map.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume;
2 | use crate::bounding_volume::Aabb;
3 | use crate::math::{Isometry, Real};
4 | use crate::shape::Segment;
5 | #[cfg(feature = "dim3")]
6 | use crate::shape::{Cone, Cylinder};
7 |
8 | #[cfg(feature = "dim3")]
9 | impl Cone {
10 | /// Computes the world-space [`Aabb`] of this cone, transformed by `pos`.
11 | #[inline]
12 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
13 | bounding_volume::details::support_map_aabb(pos, self)
14 | }
15 |
16 | /// Computes the local-space [`Aabb`] of this cone.
17 | #[inline]
18 | pub fn local_aabb(&self) -> Aabb {
19 | bounding_volume::details::local_support_map_aabb(self)
20 | }
21 | }
22 |
23 | #[cfg(feature = "dim3")]
24 | impl Cylinder {
25 | /// Computes the world-space [`Aabb`] of this cylinder, transformed by `pos`.
26 | #[inline]
27 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
28 | bounding_volume::details::support_map_aabb(pos, self)
29 | }
30 |
31 | /// Computes the local-space [`Aabb`] of this cylinder.
32 | #[inline]
33 | pub fn local_aabb(&self) -> Aabb {
34 | bounding_volume::details::local_support_map_aabb(self)
35 | }
36 | }
37 |
38 | impl Segment {
39 | /// Computes the world-space [`Aabb`] of this segment, transformed by `pos`.
40 | #[inline]
41 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
42 | self.transformed(pos).local_aabb()
43 | }
44 |
45 | /// Computes the local-space [`Aabb`] of this segment.
46 | #[inline]
47 | pub fn local_aabb(&self) -> Aabb {
48 | bounding_volume::details::local_support_map_aabb(self)
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_triangle.rs:
--------------------------------------------------------------------------------
1 | use crate::{
2 | bounding_volume::Aabb,
3 | math::{Isometry, Point, Real, DIM},
4 | shape::Triangle,
5 | };
6 |
7 | impl Triangle {
8 | /// Computes the world-space [`Aabb`] of this triangle, transformed by `pos`.
9 | #[inline]
10 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
11 | self.transformed(pos).local_aabb()
12 | }
13 |
14 | /// Computes the local-space [`Aabb`] of this triangle.
15 | #[inline]
16 | pub fn local_aabb(&self) -> Aabb {
17 | let a = self.a.coords;
18 | let b = self.b.coords;
19 | let c = self.c.coords;
20 |
21 | let mut min = Point::origin();
22 | let mut max = Point::origin();
23 |
24 | for d in 0..DIM {
25 | min.coords[d] = a[d].min(b[d]).min(c[d]);
26 | max.coords[d] = a[d].max(b[d]).max(c[d]);
27 | }
28 |
29 | Aabb::new(min, max)
30 | }
31 | }
32 |
33 | #[cfg(test)]
34 | #[cfg(feature = "dim3")]
35 | mod test {
36 | use crate::{
37 | bounding_volume::details::support_map_aabb,
38 | math::{Isometry, Point, Real, Translation},
39 | shape::Triangle,
40 | };
41 | use na::{RealField, UnitQuaternion};
42 |
43 | #[test]
44 | fn triangle_aabb_matches_support_map_aabb() {
45 | let t = Triangle::new(
46 | Point::new(0.3, -0.1, 0.2),
47 | Point::new(-0.7, 1.0, 0.0),
48 | Point::new(-0.7, 1.5, 0.0),
49 | );
50 |
51 | let m = Isometry::from_parts(
52 | Translation::new(-0.2, 5.0, 0.2),
53 | UnitQuaternion::from_euler_angles(0.0, Real::frac_pi_2(), 0.0),
54 | );
55 |
56 | assert_eq!(t.aabb(&m), support_map_aabb(&m, &t));
57 |
58 | // TODO: also test local Aabb once support maps have a local Aabb
59 | // function too
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/src/bounding_volume/aabb_voxels.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Isometry, Real, Translation};
3 | use crate::shape::{Cuboid, Voxels};
4 |
5 | impl Voxels {
6 | /// Computes the world-space Aabb of this set of voxels, transformed by `pos`.
7 | #[inline]
8 | pub fn aabb(&self, pos: &Isometry) -> Aabb {
9 | let shift = Translation::from(self.domain_center());
10 | Cuboid::new(self.extents() / 2.0).aabb(&(pos * shift))
11 | }
12 |
13 | /// Computes the local-space Aabb of this set of voxels.
14 | #[inline]
15 | pub fn local_aabb(&self) -> Aabb {
16 | Cuboid::new(self.extents() / 2.0)
17 | .local_aabb()
18 | .translated(&self.domain_center().coords)
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_ball.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Point, Real};
3 | use crate::shape::Ball;
4 |
5 | impl Ball {
6 | /// Computes the world-space bounding sphere of this ball, transformed by `pos`.
7 | #[inline]
8 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
9 | let bv: BoundingSphere = self.local_bounding_sphere();
10 | bv.transform_by(pos)
11 | }
12 |
13 | /// Computes the local-space Aabb of this ball.
14 | #[inline]
15 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
16 | BoundingSphere::new(Point::origin(), self.radius)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_capsule.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::Capsule;
4 |
5 | impl Capsule {
6 | /// Computes the world-space bounding sphere of this capsule, transformed by `pos`.
7 | #[inline]
8 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
9 | self.local_bounding_sphere().transform_by(pos)
10 | }
11 |
12 | /// Computes the world-space bounding sphere of this capsule.
13 | #[inline]
14 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
15 | let radius = self.radius + self.half_height();
16 | BoundingSphere::new(self.center(), radius)
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_cone.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Point, Real};
3 | use crate::shape::Cone;
4 | use na::ComplexField;
5 |
6 | impl Cone {
7 | /// Computes the world-space bounding sphere of this cone, transformed by `pos`.
8 | #[inline]
9 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
10 | let bv: BoundingSphere = self.local_bounding_sphere();
11 | bv.transform_by(pos)
12 | }
13 |
14 | /// Computes the local-space bounding sphere of this cone.
15 | #[inline]
16 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
17 | let radius =
18 | ComplexField::sqrt(self.radius * self.radius + self.half_height * self.half_height);
19 |
20 | BoundingSphere::new(Point::origin(), radius)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_convex.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume;
2 | use crate::bounding_volume::BoundingSphere;
3 | use crate::math::{Isometry, Real};
4 | use crate::shape::ConvexPolyhedron;
5 |
6 | impl ConvexPolyhedron {
7 | /// Computes the world-space bounding sphere of this convex polyhedron, transformed by `pos`.
8 | #[inline]
9 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
10 | let bv: BoundingSphere = self.local_bounding_sphere();
11 | bv.transform_by(pos)
12 | }
13 |
14 | /// Computes the local-space bounding sphere of this convex polyhedron.
15 | #[inline]
16 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
17 | bounding_volume::details::point_cloud_bounding_sphere(self.points())
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_convex_polygon.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume;
2 | use crate::bounding_volume::BoundingSphere;
3 | use crate::math::{Isometry, Real};
4 | use crate::shape::ConvexPolygon;
5 |
6 | impl ConvexPolygon {
7 | /// Computes the world-space bounding sphere of this convex polygon, transformed by `pos`.
8 | #[inline]
9 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
10 | let bv: BoundingSphere = self.local_bounding_sphere();
11 | bv.transform_by(pos)
12 | }
13 |
14 | /// Computes the local-space bounding sphere of this convex polygon.
15 | #[inline]
16 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
17 | bounding_volume::details::point_cloud_bounding_sphere(self.points())
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_cuboid.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Point, Real};
3 | use crate::shape::Cuboid;
4 |
5 | impl Cuboid {
6 | /// Computes the world-space bounding sphere of this cuboid, transformed by `pos`.
7 | #[inline]
8 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
9 | let bv: BoundingSphere = self.local_bounding_sphere();
10 | bv.transform_by(pos)
11 | }
12 |
13 | /// Computes the local-space bounding sphere of this cuboid.
14 | #[inline]
15 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
16 | let radius = self.half_extents.norm();
17 | BoundingSphere::new(Point::origin(), radius)
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_cylinder.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Point, Real};
3 | use crate::shape::Cylinder;
4 | use na::ComplexField;
5 |
6 | impl Cylinder {
7 | /// Computes the world-space bounding sphere of this cylinder, transformed by `pos`.
8 | #[inline]
9 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
10 | let bv: BoundingSphere = self.local_bounding_sphere();
11 | bv.transform_by(pos)
12 | }
13 |
14 | /// Computes the local-space bounding sphere of this cylinder.
15 | #[inline]
16 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
17 | let radius =
18 | ComplexField::sqrt(self.radius * self.radius + self.half_height * self.half_height);
19 |
20 | BoundingSphere::new(Point::origin(), radius)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_halfspace.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Point, Real};
3 | use crate::shape::HalfSpace;
4 |
5 | use num::Bounded;
6 |
7 | impl HalfSpace {
8 | /// Computes the world-space bounding sphere of this half-space, transformed by `pos`.
9 | #[inline]
10 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
11 | let bv: BoundingSphere = self.local_bounding_sphere();
12 | bv.transform_by(pos)
13 | }
14 |
15 | /// Computes the local-space bounding sphere of this half-space.
16 | #[inline]
17 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
18 | let radius = Real::max_value();
19 |
20 | BoundingSphere::new(Point::origin(), radius)
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_heightfield.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::HeightField;
4 |
5 | impl HeightField {
6 | /// Computes the world-space bounding sphere of this height-field, transformed by `pos`.
7 | #[inline]
8 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
9 | self.local_aabb().bounding_sphere().transform_by(pos)
10 | }
11 |
12 | /// Computes the local-space bounding sphere of this height-field.
13 | #[inline]
14 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
15 | self.local_aabb().bounding_sphere()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_polyline.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::Polyline;
4 |
5 | impl Polyline {
6 | /// Computes the world-space bounding sphere of this polyline, transformed by `pos`.
7 | #[inline]
8 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
9 | self.local_aabb().bounding_sphere().transform_by(pos)
10 | }
11 |
12 | /// Computes the local-space bounding sphere of this polyline.
13 | #[inline]
14 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
15 | self.local_aabb().bounding_sphere()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_segment.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume;
2 | use crate::bounding_volume::BoundingSphere;
3 | use crate::math::{Isometry, Real};
4 | use crate::shape::Segment;
5 |
6 | impl Segment {
7 | /// Computes the world-space bounding sphere of this segment, transformed by `pos`.
8 | #[inline]
9 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
10 | let bv: BoundingSphere = self.local_bounding_sphere();
11 | bv.transform_by(pos)
12 | }
13 |
14 | /// Computes the local-space bounding sphere of this segment.
15 | #[inline]
16 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
17 | let pts = [self.a, self.b];
18 | bounding_volume::details::point_cloud_bounding_sphere(&pts[..])
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_triangle.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume;
2 | use crate::bounding_volume::BoundingSphere;
3 | use crate::math::{Isometry, Real};
4 | use crate::shape::Triangle;
5 |
6 | impl Triangle {
7 | /// Computes the world-space bounding sphere of this triangle, transformed by `pos`.
8 | #[inline]
9 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
10 | let bv: BoundingSphere = self.local_bounding_sphere();
11 | bv.transform_by(pos)
12 | }
13 |
14 | /// Computes the local-space bounding sphere of this triangle.
15 | #[inline]
16 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
17 | let pts = [self.a, self.b, self.c];
18 | bounding_volume::details::point_cloud_bounding_sphere(&pts[..])
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_trimesh.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::TriMesh;
4 |
5 | impl TriMesh {
6 | /// Computes the world-space bounding sphere of this triangle mesh, transformed by `pos`.
7 | #[inline]
8 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
9 | self.local_aabb().bounding_sphere().transform_by(pos)
10 | }
11 |
12 | /// Computes the local-space bounding sphere of this triangle mesh.
13 | #[inline]
14 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
15 | self.local_aabb().bounding_sphere()
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_utils.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Point, Real};
2 | use crate::utils;
3 | use na::{self, ComplexField};
4 |
5 | use super::BoundingSphere;
6 |
7 | /// Computes the bounding sphere of a set of point, given its center.
8 | #[inline]
9 | pub fn point_cloud_bounding_sphere_with_center(
10 | pts: &[Point],
11 | center: Point,
12 | ) -> BoundingSphere {
13 | let mut sqradius = 0.0;
14 |
15 | for pt in pts.iter() {
16 | let distance_squared = na::distance_squared(pt, ¢er);
17 |
18 | if distance_squared > sqradius {
19 | sqradius = distance_squared
20 | }
21 | }
22 | BoundingSphere::new(center, ComplexField::sqrt(sqradius))
23 | }
24 |
25 | /// Computes a bounding sphere of the specified set of point.
26 | #[inline]
27 | pub fn point_cloud_bounding_sphere(pts: &[Point]) -> BoundingSphere {
28 | point_cloud_bounding_sphere_with_center(pts, utils::center(pts))
29 | }
30 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_sphere_voxels.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::BoundingSphere;
2 | use crate::math::{Isometry, Real, Translation};
3 | use crate::shape::{Cuboid, Voxels};
4 |
5 | impl Voxels {
6 | /// Computes the world-space bounding sphere of this set of voxels, transformed by `pos`.
7 | #[inline]
8 | pub fn bounding_sphere(&self, pos: &Isometry) -> BoundingSphere {
9 | let shift = Translation::from(self.domain_center().coords);
10 | Cuboid::new(self.extents() / 2.0).bounding_sphere(&(pos * shift))
11 | }
12 |
13 | /// Computes the local-space bounding sphere of this set of voxels.
14 | #[inline]
15 | pub fn local_bounding_sphere(&self) -> BoundingSphere {
16 | Cuboid::new(self.extents() / 2.0)
17 | .local_bounding_sphere()
18 | .translated(&(self.domain_center().coords))
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/src/bounding_volume/bounding_volume.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Point, Real};
2 |
3 | /// Trait of bounding volumes.
4 | ///
5 | /// Bounding volumes are coarse approximations of shapes. It usually have constant time
6 | /// intersection, inclusion test. Two bounding volume must also be mergeable into a bigger bounding
7 | /// volume.
8 | pub trait BoundingVolume {
9 | // TODO: keep that ? What about non-spacial bounding volumes (e.g. bounding cones, curvature
10 | // bounds, etc.) ?
11 | /// Returns a point inside of this bounding volume. This is ideally its center.
12 | fn center(&self) -> Point;
13 |
14 | /// Checks if this bounding volume intersect with another one.
15 | fn intersects(&self, _: &Self) -> bool;
16 |
17 | /// Checks if this bounding volume contains another one.
18 | fn contains(&self, _: &Self) -> bool;
19 |
20 | /// Merges this bounding volume with another one. The merge is done in-place.
21 | fn merge(&mut self, _: &Self);
22 |
23 | /// Merges this bounding volume with another one.
24 | fn merged(&self, _: &Self) -> Self;
25 |
26 | /// Enlarges this bounding volume.
27 | fn loosen(&mut self, _: Real);
28 |
29 | /// Creates a new, enlarged version, of this bounding volume.
30 | fn loosened(&self, _: Real) -> Self;
31 |
32 | /// Tighten this bounding volume.
33 | fn tighten(&mut self, _: Real);
34 |
35 | /// Creates a new, tightened version, of this bounding volume.
36 | fn tightened(&self, _: Real) -> Self;
37 | }
38 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_ball.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | #[cfg(feature = "dim3")]
3 | use crate::math::Vector;
4 | use crate::math::{Point, PrincipalAngularInertia, Real};
5 | use na::RealField;
6 |
7 | impl MassProperties {
8 | pub(crate) fn ball_volume_unit_angular_inertia(
9 | radius: Real,
10 | ) -> (Real, PrincipalAngularInertia) {
11 | #[cfg(feature = "dim2")]
12 | {
13 | let volume = Real::pi() * radius * radius;
14 | let i = radius * radius / 2.0;
15 | (volume, i)
16 | }
17 | #[cfg(feature = "dim3")]
18 | {
19 | let volume = Real::pi() * radius * radius * radius * 4.0 / 3.0;
20 | let i = radius * radius * 2.0 / 5.0;
21 |
22 | (volume, Vector::repeat(i))
23 | }
24 | }
25 |
26 | /// Computes the mass properties of a ball.
27 | pub fn from_ball(density: Real, radius: Real) -> Self {
28 | let (vol, unit_i) = Self::ball_volume_unit_angular_inertia(radius);
29 | let mass = vol * density;
30 | Self::new(Point::origin(), mass, unit_i * mass)
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_capsule.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{Point, Real};
3 | #[cfg(feature = "dim3")]
4 | use crate::shape::Capsule;
5 |
6 | impl MassProperties {
7 | /// Computes the mass properties of a capsule.
8 | pub fn from_capsule(density: Real, a: Point, b: Point, radius: Real) -> Self {
9 | let half_height = (b - a).norm() / 2.0;
10 | let (cyl_vol, cyl_unit_i) = Self::cylinder_y_volume_unit_inertia(half_height, radius);
11 | let (ball_vol, ball_unit_i) = Self::ball_volume_unit_angular_inertia(radius);
12 | let cap_vol = cyl_vol + ball_vol;
13 | let cap_mass = cap_vol * density;
14 | let mut cap_i = (cyl_unit_i * cyl_vol + ball_unit_i * ball_vol) * density;
15 | let local_com = na::center(&a, &b);
16 |
17 | #[cfg(feature = "dim2")]
18 | {
19 | let h = half_height * 2.0;
20 | let extra = (h * h * 0.25 + h * radius * 3.0 / 8.0) * ball_vol * density;
21 | cap_i += extra;
22 | Self::new(local_com, cap_mass, cap_i)
23 | }
24 |
25 | #[cfg(feature = "dim3")]
26 | {
27 | let h = half_height * 2.0;
28 | let extra = (h * h * 0.25 + h * radius * 3.0 / 8.0) * ball_vol * density;
29 | cap_i.x += extra;
30 | cap_i.z += extra;
31 | let local_frame = Capsule::new(a, b, radius).rotation_wrt_y();
32 | Self::with_principal_inertia_frame(local_com, cap_mass, cap_i, local_frame)
33 | }
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_compound.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{Isometry, Real};
3 | use crate::shape::SharedShape;
4 |
5 | impl MassProperties {
6 | /// Computes the mass properties of a compound shape.
7 | pub fn from_compound(density: Real, shapes: &[(Isometry, SharedShape)]) -> Self {
8 | shapes
9 | .iter()
10 | .map(|s| s.1.mass_properties(density).transform_by(&s.0))
11 | .sum()
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_cone.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{Point, PrincipalAngularInertia, Real, Rotation, Vector};
3 | use na::RealField;
4 |
5 | impl MassProperties {
6 | pub(crate) fn cone_y_volume_unit_inertia(
7 | half_height: Real,
8 | radius: Real,
9 | ) -> (Real, PrincipalAngularInertia) {
10 | let volume = radius * radius * Real::pi() * half_height * 2.0 / 3.0;
11 | let sq_radius = radius * radius;
12 | let sq_height = half_height * half_height * 4.0;
13 | let off_principal = sq_radius * 3.0 / 20.0 + sq_height * 3.0 / 80.0;
14 | let principal = sq_radius * 3.0 / 10.0;
15 |
16 | (volume, Vector::new(off_principal, principal, off_principal))
17 | }
18 |
19 | /// Computes the mass properties of a cone.
20 | pub fn from_cone(density: Real, half_height: Real, radius: Real) -> Self {
21 | let (cyl_vol, cyl_unit_i) = Self::cone_y_volume_unit_inertia(half_height, radius);
22 | let cyl_mass = cyl_vol * density;
23 |
24 | Self::with_principal_inertia_frame(
25 | Point::new(0.0, -half_height / 2.0, 0.0),
26 | cyl_mass,
27 | cyl_unit_i * cyl_mass,
28 | Rotation::identity(),
29 | )
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_convex_polyhedron.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{Point, Real, DIM};
3 |
4 | impl MassProperties {
5 | /// Computes the mass properties of a convex polyhedron.
6 | pub fn from_convex_polyhedron(
7 | density: Real,
8 | vertices: &[Point],
9 | indices: &[[u32; DIM]],
10 | ) -> MassProperties {
11 | Self::from_trimesh(density, vertices, indices)
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_cuboid.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{Point, PrincipalAngularInertia, Real, Vector};
3 |
4 | impl MassProperties {
5 | pub(crate) fn cuboid_volume_unit_inertia(
6 | half_extents: Vector,
7 | ) -> (Real, PrincipalAngularInertia) {
8 | #[cfg(feature = "dim2")]
9 | {
10 | let volume = half_extents.x * half_extents.y * 4.0;
11 | let ix = (half_extents.x * half_extents.x) / 3.0;
12 | let iy = (half_extents.y * half_extents.y) / 3.0;
13 |
14 | (volume, ix + iy)
15 | }
16 |
17 | #[cfg(feature = "dim3")]
18 | {
19 | let volume = half_extents.x * half_extents.y * half_extents.z * 8.0;
20 | let ix = (half_extents.x * half_extents.x) / 3.0;
21 | let iy = (half_extents.y * half_extents.y) / 3.0;
22 | let iz = (half_extents.z * half_extents.z) / 3.0;
23 |
24 | (volume, Vector::new(iy + iz, ix + iz, ix + iy))
25 | }
26 | }
27 |
28 | /// Computes the mass properties of a cuboid.
29 | pub fn from_cuboid(density: Real, half_extents: Vector) -> Self {
30 | let (vol, unit_i) = Self::cuboid_volume_unit_inertia(half_extents);
31 | let mass = vol * density;
32 | Self::new(Point::origin(), mass, unit_i * mass)
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_cylinder.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{PrincipalAngularInertia, Real, Vector};
3 | #[cfg(feature = "dim3")]
4 | use {
5 | crate::math::{Point, Rotation},
6 | na::RealField,
7 | };
8 |
9 | impl MassProperties {
10 | pub(crate) fn cylinder_y_volume_unit_inertia(
11 | half_height: Real,
12 | radius: Real,
13 | ) -> (Real, PrincipalAngularInertia) {
14 | #[cfg(feature = "dim2")]
15 | {
16 | Self::cuboid_volume_unit_inertia(Vector::new(radius, half_height))
17 | }
18 |
19 | #[cfg(feature = "dim3")]
20 | {
21 | let volume = half_height * radius * radius * Real::pi() * 2.0;
22 | let sq_radius = radius * radius;
23 | let sq_height = half_height * half_height * 4.0;
24 | let off_principal = (sq_radius * 3.0 + sq_height) / 12.0;
25 |
26 | let inertia = Vector::new(off_principal, sq_radius / 2.0, off_principal);
27 | (volume, inertia)
28 | }
29 | }
30 |
31 | /// Computes the mass properties of a cylinder.
32 | #[cfg(feature = "dim3")]
33 | pub fn from_cylinder(density: Real, half_height: Real, radius: Real) -> Self {
34 | let (cyl_vol, cyl_unit_i) = Self::cylinder_y_volume_unit_inertia(half_height, radius);
35 | let cyl_mass = cyl_vol * density;
36 |
37 | Self::with_principal_inertia_frame(
38 | Point::origin(),
39 | cyl_mass,
40 | cyl_unit_i * cyl_mass,
41 | Rotation::identity(),
42 | )
43 | }
44 | }
45 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_triangle.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{Point, Real};
3 | use crate::shape::Triangle;
4 |
5 | impl MassProperties {
6 | /// Computes the mass properties of a triangle.
7 | pub fn from_triangle(
8 | density: Real,
9 | a: &Point,
10 | b: &Point,
11 | c: &Point,
12 | ) -> MassProperties {
13 | let triangle = Triangle::new(*a, *b, *c);
14 | let area = triangle.area();
15 | let com = triangle.center();
16 |
17 | if area == 0.0 {
18 | return MassProperties::new(com, 0.0, 0.0);
19 | }
20 |
21 | let ipart = triangle.unit_angular_inertia();
22 |
23 | Self::new(com, area * density, ipart * area * density)
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/mass_properties/mass_properties_voxels.rs:
--------------------------------------------------------------------------------
1 | use crate::mass_properties::MassProperties;
2 | use crate::math::{Point, Real};
3 | use crate::shape::Voxels;
4 |
5 | impl MassProperties {
6 | /// Computes the mass properties of a set of voxels.
7 | pub fn from_voxels(density: Real, voxels: &Voxels) -> Self {
8 | let mut com = Point::origin();
9 | let mut num_not_empty = 0;
10 | let mut angular_inertia = na::zero();
11 | let block_ref_mprops = MassProperties::from_cuboid(density, voxels.voxel_size() / 2.0);
12 |
13 | for vox in voxels.voxels() {
14 | if !vox.state.is_empty() {
15 | com += vox.center.coords;
16 | num_not_empty += 1;
17 | }
18 | }
19 |
20 | com.coords /= num_not_empty as Real;
21 |
22 | for vox in voxels.voxels() {
23 | if !vox.state.is_empty() {
24 | angular_inertia +=
25 | block_ref_mprops.construct_shifted_inertia_matrix(vox.center - com);
26 | }
27 | }
28 |
29 | let mass = block_ref_mprops.mass() * num_not_empty as Real;
30 |
31 | #[cfg(feature = "dim2")]
32 | return Self::new(com, mass, angular_inertia);
33 | #[cfg(feature = "dim3")]
34 | return Self::with_inertia_matrix(com, mass, angular_inertia);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/mass_properties/mod.rs:
--------------------------------------------------------------------------------
1 | //! Mass properties (mass, inertia, center-of-mass) of shapes.
2 |
3 | pub use self::mass_properties::MassProperties;
4 |
5 | mod mass_properties;
6 | mod mass_properties_ball;
7 | mod mass_properties_capsule;
8 | #[cfg(feature = "alloc")]
9 | mod mass_properties_compound;
10 | #[cfg(feature = "dim3")]
11 | mod mass_properties_cone;
12 | #[cfg(feature = "dim2")]
13 | #[cfg(feature = "alloc")]
14 | mod mass_properties_convex_polygon;
15 | #[cfg(feature = "dim3")]
16 | #[cfg(feature = "alloc")]
17 | mod mass_properties_convex_polyhedron;
18 | mod mass_properties_cuboid;
19 | mod mass_properties_cylinder;
20 | #[cfg(feature = "dim2")]
21 | mod mass_properties_triangle;
22 | #[cfg(feature = "dim2")]
23 | #[cfg(feature = "alloc")]
24 | mod mass_properties_trimesh2d;
25 | #[cfg(feature = "dim3")]
26 | #[cfg(feature = "alloc")]
27 | mod mass_properties_trimesh3d;
28 |
29 | #[cfg(feature = "alloc")]
30 | mod mass_properties_voxels;
31 |
32 | /// Free functions for some special-cases of mass-properties computation.
33 | pub mod details {
34 | #[cfg(feature = "dim2")]
35 | #[cfg(feature = "alloc")]
36 | pub use super::mass_properties_convex_polygon::convex_polygon_area_and_center_of_mass;
37 | #[cfg(feature = "dim2")]
38 | #[cfg(feature = "alloc")]
39 | pub use super::mass_properties_trimesh2d::trimesh_area_and_center_of_mass;
40 | #[cfg(feature = "dim3")]
41 | #[cfg(feature = "alloc")]
42 | pub use super::mass_properties_trimesh3d::{
43 | tetrahedron_unit_inertia_tensor_wrt_point, trimesh_signed_volume_and_center_of_mass,
44 | };
45 | }
46 |
--------------------------------------------------------------------------------
/src/partitioning/mod.rs:
--------------------------------------------------------------------------------
1 | //! Spatial partitioning tools.
2 |
3 | #[cfg(feature = "alloc")]
4 | pub use self::qbvh::{
5 | CenterDataSplitter, IndexedData, NodeIndex, Qbvh, QbvhDataGenerator, QbvhNode,
6 | QbvhNonOverlappingDataSplitter, QbvhProxy, QbvhUpdateWorkspace, SimdNodeIndex,
7 | };
8 | #[cfg(feature = "parallel")]
9 | pub use self::visitor::{ParallelSimdSimultaneousVisitor, ParallelSimdVisitor};
10 | pub use self::visitor::{
11 | SimdBestFirstVisitStatus, SimdBestFirstVisitor, SimdSimultaneousVisitStatus,
12 | SimdSimultaneousVisitor, SimdVisitStatus, SimdVisitor, SimdVisitorWithContext,
13 | };
14 |
15 | /// A quaternary bounding-volume-hierarchy.
16 | #[deprecated(note = "Renamed to Qbvh")]
17 | #[cfg(feature = "alloc")]
18 | pub type SimdQbvh = Qbvh;
19 |
20 | #[cfg(feature = "alloc")]
21 | mod qbvh;
22 | mod visitor;
23 |
--------------------------------------------------------------------------------
/src/partitioning/qbvh/mod.rs:
--------------------------------------------------------------------------------
1 | pub use self::{
2 | build::{CenterDataSplitter, QbvhDataGenerator, QbvhNonOverlappingDataSplitter},
3 | update::QbvhUpdateWorkspace,
4 | };
5 |
6 | pub use self::qbvh::{
7 | IndexedData, NodeIndex, Qbvh, QbvhNode, QbvhNodeFlags, QbvhProxy, SimdNodeIndex,
8 | };
9 |
10 | mod qbvh;
11 | mod utils;
12 |
13 | mod build;
14 | mod traversal;
15 | mod update;
16 |
--------------------------------------------------------------------------------
/src/partitioning/qbvh/utils.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Point, Real};
3 |
4 | pub fn split_indices_wrt_dim<'a>(
5 | indices: &'a mut [usize],
6 | aabbs: &[Aabb],
7 | split_point: &Point,
8 | dim: usize,
9 | enable_fallback_split: bool,
10 | ) -> (&'a mut [usize], &'a mut [usize]) {
11 | let mut icurr = 0;
12 | let mut ilast = indices.len();
13 |
14 | // The loop condition we can just do 0..indices.len()
15 | // instead of the test icurr < ilast because we know
16 | // we will iterate exactly once per index.
17 | for _ in 0..indices.len() {
18 | let i = indices[icurr];
19 | let center = aabbs[i].center();
20 |
21 | if center[dim] > split_point[dim] {
22 | ilast -= 1;
23 | indices.swap(icurr, ilast);
24 | } else {
25 | icurr += 1;
26 | }
27 | }
28 |
29 | if enable_fallback_split && (icurr == 0 || icurr == indices.len()) {
30 | // We don't want to return one empty set. But
31 | // this can happen if all the coordinates along the
32 | // given dimension are equal.
33 | // In this is the case, we just split in the middle.
34 | let half = indices.len() / 2;
35 | indices.split_at_mut(half)
36 | } else {
37 | indices.split_at_mut(icurr)
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/src/query/clip/clip_aabb_polygon.rs:
--------------------------------------------------------------------------------
1 | use crate::bounding_volume::Aabb;
2 | use crate::math::{Point, Real, Vector};
3 | use alloc::vec::Vec;
4 |
5 | impl Aabb {
6 | /// Computes the intersections between this Aabb and the given polygon.
7 | ///
8 | /// The results is written into `points` directly. The input points are
9 | /// assumed to form a convex polygon where all points lie on the same plane.
10 | /// In order to avoid internal allocations, uses `self.clip_polygon_with_workspace`
11 | /// instead.
12 | #[inline]
13 | pub fn clip_polygon(&self, points: &mut Vec>) {
14 | let mut workspace = Vec::new();
15 | self.clip_polygon_with_workspace(points, &mut workspace)
16 | }
17 |
18 | /// Computes the intersections between this Aabb and the given polygon.
19 | ///
20 | /// The results is written into `points` directly. The input points are
21 | /// assumed to form a convex polygon where all points lie on the same plane.
22 | #[inline]
23 | pub fn clip_polygon_with_workspace(
24 | &self,
25 | points: &mut Vec>,
26 | workspace: &mut Vec>,
27 | ) {
28 | super::clip_halfspace_polygon(&self.mins, &-Vector::x(), points, workspace);
29 | super::clip_halfspace_polygon(&self.maxs, &Vector::x(), workspace, points);
30 |
31 | super::clip_halfspace_polygon(&self.mins, &-Vector::y(), points, workspace);
32 | super::clip_halfspace_polygon(&self.maxs, &Vector::y(), workspace, points);
33 |
34 | #[cfg(feature = "dim3")]
35 | {
36 | super::clip_halfspace_polygon(&self.mins, &-Vector::z(), points, workspace);
37 | super::clip_halfspace_polygon(&self.maxs, &Vector::z(), workspace, points);
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/src/query/clip/clip_halfspace_polygon.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Point, Real, Vector};
2 | use crate::query::{self, Ray};
3 | use alloc::vec::Vec;
4 |
5 | /// Cuts a polygon with the given half-space.
6 | ///
7 | /// Given the half-space `center` and outward `normal`,
8 | /// this computes the intersecting between the half-space and
9 | /// the polygon. (Note that a point `pt` is considered as inside of
10 | /// the half-space if `normal.dot(&(pt - center)) <= 0.0`.
11 | pub fn clip_halfspace_polygon(
12 | center: &Point,
13 | normal: &Vector,
14 | polygon: &[Point],
15 | result: &mut Vec>,
16 | ) {
17 | result.clear();
18 |
19 | if polygon.is_empty() {
20 | return;
21 | }
22 |
23 | let keep_point = |pt: &Point| (pt - center).dot(normal) <= 0.0;
24 | let last_pt = polygon.last().unwrap();
25 | let mut last_keep = keep_point(last_pt);
26 |
27 | if last_keep {
28 | result.push(*last_pt);
29 | }
30 |
31 | for i in 0..polygon.len() {
32 | let pt = &polygon[i];
33 | let keep = keep_point(pt);
34 |
35 | if keep != last_keep {
36 | // We crossed the plane, so we need
37 | // to cut the edge.
38 | let prev_i = if i == 0 { polygon.len() - 1 } else { i - 1 };
39 | let prev_pt = &polygon[prev_i];
40 | let ray = Ray::new(*prev_pt, pt - prev_pt);
41 |
42 | if let Some(time_of_impact) =
43 | query::details::ray_toi_with_halfspace(center, normal, &ray)
44 | {
45 | if time_of_impact > 0.0 && time_of_impact < 1.0 {
46 | result.push(ray.origin + ray.dir * time_of_impact)
47 | }
48 | }
49 |
50 | last_keep = keep;
51 | }
52 |
53 | if keep && i != polygon.len() - 1 {
54 | result.push(*pt);
55 | }
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/query/clip/mod.rs:
--------------------------------------------------------------------------------
1 | pub use self::clip_aabb_line::clip_aabb_line;
2 | #[cfg(feature = "alloc")]
3 | pub use self::clip_halfspace_polygon::clip_halfspace_polygon;
4 | pub use self::clip_segment_segment::clip_segment_segment;
5 | #[cfg(feature = "dim2")]
6 | pub use self::clip_segment_segment::clip_segment_segment_with_normal;
7 |
8 | mod clip_aabb_line;
9 | #[cfg(feature = "alloc")]
10 | mod clip_aabb_polygon;
11 | #[cfg(feature = "alloc")]
12 | mod clip_halfspace_polygon;
13 | mod clip_segment_segment;
14 |
--------------------------------------------------------------------------------
/src/query/closest_points/closest_points.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Point, Real};
2 |
3 | use core::mem;
4 |
5 | /// Closest points information.
6 | #[derive(Debug, PartialEq, Clone, Copy)]
7 | #[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
8 | #[cfg_attr(
9 | feature = "rkyv",
10 | derive(rkyv::Archive, rkyv::Deserialize, rkyv::Serialize),
11 | archive(check_bytes)
12 | )]
13 | pub enum ClosestPoints {
14 | /// The two objects are intersecting.
15 | Intersecting,
16 | /// The two objects are non-intersecting but closer than a given user-defined distance.
17 | WithinMargin(Point, Point),
18 | /// The two objects are non-intersecting and further than a given user-defined distance.
19 | Disjoint,
20 | }
21 |
22 | impl ClosestPoints {
23 | /// Swaps the two points.
24 | pub fn flip(&mut self) {
25 | if let ClosestPoints::WithinMargin(ref mut p1, ref mut p2) = *self {
26 | mem::swap(p1, p2)
27 | }
28 | }
29 |
30 | /// Returns the result of swapping the two points if `self` is `WithinMargin`.
31 | #[must_use]
32 | pub fn flipped(&self) -> Self {
33 | if let ClosestPoints::WithinMargin(p1, p2) = *self {
34 | ClosestPoints::WithinMargin(p2, p1)
35 | } else {
36 | *self
37 | }
38 | }
39 |
40 | /// Transform the points in `self` by `pos1` and `pos2`.
41 | #[must_use]
42 | pub fn transform_by(self, pos1: &Isometry, pos2: &Isometry) -> Self {
43 | if let ClosestPoints::WithinMargin(p1, p2) = self {
44 | ClosestPoints::WithinMargin(pos1 * p1, pos2 * p2)
45 | } else {
46 | self
47 | }
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/query/closest_points/closest_points_ball_ball.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Point, Real};
2 | use crate::query::ClosestPoints;
3 | use crate::shape::Ball;
4 |
5 | /// Closest points between balls.
6 | ///
7 | /// Each returned point is expressed on the local-space of the corresponding shape.
8 | #[inline]
9 | pub fn closest_points_ball_ball(
10 | pos12: &Isometry,
11 | b1: &Ball,
12 | b2: &Ball,
13 | margin: Real,
14 | ) -> ClosestPoints {
15 | assert!(
16 | margin >= 0.0,
17 | "The proximity margin must be positive or null."
18 | );
19 |
20 | let r1 = b1.radius;
21 | let r2 = b2.radius;
22 | let delta_pos = pos12.translation.vector;
23 | let distance = delta_pos.norm();
24 | let sum_radius = r1 + r2;
25 |
26 | if distance - margin <= sum_radius {
27 | if distance <= sum_radius {
28 | ClosestPoints::Intersecting
29 | } else {
30 | let normal = delta_pos.normalize();
31 | let p1 = Point::from(normal * r1);
32 | let p2 = Point::from(pos12.inverse_transform_vector(&normal) * -r2);
33 | ClosestPoints::WithinMargin(p1, p2)
34 | }
35 | } else {
36 | ClosestPoints::Disjoint
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/query/closest_points/closest_points_ball_convex_polyhedron.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Real};
2 | use crate::query::ClosestPoints;
3 | use crate::shape::{Ball, Shape};
4 |
5 | /// ClosestPoints between a ball and a convex polyhedron.
6 | ///
7 | /// This function panics if the input shape does not implement
8 | /// both the ConvexPolyhedron and PointQuery traits.
9 | #[inline]
10 | pub fn closest_points_ball_convex_polyhedron(
11 | pos12: &Isometry,
12 | ball1: &Ball,
13 | shape2: &(impl Shape + ?Sized),
14 | prediction: Real,
15 | ) -> ClosestPoints {
16 | match crate::query::details::contact_ball_convex_polyhedron(pos12, ball1, shape2, prediction) {
17 | Some(contact) => {
18 | if contact.dist <= 0.0 {
19 | ClosestPoints::Intersecting
20 | } else {
21 | ClosestPoints::WithinMargin(contact.point1, contact.point2)
22 | }
23 | }
24 | None => ClosestPoints::Disjoint,
25 | }
26 | }
27 |
28 | /// ClosestPoints between a convex polyhedron and a ball.
29 | ///
30 | /// This function panics if the input shape does not implement
31 | /// both the ConvexPolyhedron and PointQuery traits.
32 | #[inline]
33 | pub fn closest_points_convex_polyhedron_ball(
34 | pos12: &Isometry,
35 | shape1: &(impl Shape + ?Sized),
36 | ball2: &Ball,
37 | prediction: Real,
38 | ) -> ClosestPoints {
39 | match crate::query::details::contact_convex_polyhedron_ball(pos12, shape1, ball2, prediction) {
40 | Some(contact) => {
41 | if contact.dist <= 0.0 {
42 | ClosestPoints::Intersecting
43 | } else {
44 | ClosestPoints::WithinMargin(contact.point1, contact.point2)
45 | }
46 | }
47 | None => ClosestPoints::Disjoint,
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/query/closest_points/closest_points_halfspace_support_map.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Real};
2 | use crate::query::ClosestPoints;
3 | use crate::shape::HalfSpace;
4 | use crate::shape::SupportMap;
5 |
6 | /// Closest points between a halfspace and a support-mapped shape (Cuboid, ConvexHull, etc.)
7 | pub fn closest_points_halfspace_support_map(
8 | pos12: &Isometry,
9 | halfspace: &HalfSpace,
10 | other: &G,
11 | margin: Real,
12 | ) -> ClosestPoints {
13 | assert!(
14 | margin >= 0.0,
15 | "The proximity margin must be positive or null."
16 | );
17 |
18 | let deepest = other.support_point(pos12, &-halfspace.normal);
19 | let distance = halfspace.normal.dot(&(-deepest.coords));
20 |
21 | if distance >= -margin {
22 | if distance >= 0.0 {
23 | ClosestPoints::Intersecting
24 | } else {
25 | let p1 = deepest + *halfspace.normal * distance;
26 | let p2 = pos12.inverse_transform_point(&deepest);
27 | ClosestPoints::WithinMargin(p1, p2)
28 | }
29 | } else {
30 | ClosestPoints::Disjoint
31 | }
32 | }
33 |
34 | /// Closest points between a support-mapped shape (Cuboid, ConvexHull, etc.) and a halfspace.
35 | pub fn closest_points_support_map_halfspace(
36 | pos12: &Isometry,
37 | other: &G,
38 | halfspace: &HalfSpace,
39 | margin: Real,
40 | ) -> ClosestPoints {
41 | closest_points_halfspace_support_map(&pos12.inverse(), halfspace, other, margin).flipped()
42 | }
43 |
--------------------------------------------------------------------------------
/src/query/closest_points/closest_points_shape_shape.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Real};
2 | use crate::query::{ClosestPoints, DefaultQueryDispatcher, QueryDispatcher, Unsupported};
3 | use crate::shape::Shape;
4 |
5 | /// Computes the pair of closest points between two shapes.
6 | ///
7 | /// Returns `ClosestPoints::Disjoint` if the objects are separated by a distance greater than `max_dist`.
8 | /// The result points in `ClosestPoints::WithinMargin` are expressed in world-space.
9 | pub fn closest_points(
10 | pos1: &Isometry,
11 | g1: &dyn Shape,
12 | pos2: &Isometry,
13 | g2: &dyn Shape,
14 | max_dist: Real,
15 | ) -> Result {
16 | let pos12 = pos1.inv_mul(pos2);
17 | DefaultQueryDispatcher
18 | .closest_points(&pos12, g1, g2, max_dist)
19 | .map(|res| res.transform_by(pos1, pos2))
20 | }
21 |
--------------------------------------------------------------------------------
/src/query/contact/contact_ball_ball.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Point, Real, Vector};
2 | use crate::query::Contact;
3 | use crate::shape::Ball;
4 | use na::{self, ComplexField, Unit};
5 | use num::Zero;
6 |
7 | /// Contact between balls.
8 | #[inline]
9 | pub fn contact_ball_ball(
10 | pos12: &Isometry,
11 | b1: &Ball,
12 | b2: &Ball,
13 | prediction: Real,
14 | ) -> Option {
15 | let r1 = b1.radius;
16 | let r2 = b2.radius;
17 | let center2_1 = pos12.translation.vector;
18 | let distance_squared = center2_1.norm_squared();
19 | let sum_radius = r1 + r2;
20 | let sum_radius_with_error = sum_radius + prediction;
21 |
22 | if distance_squared < sum_radius_with_error * sum_radius_with_error {
23 | let normal1 = if !distance_squared.is_zero() {
24 | Unit::new_normalize(center2_1)
25 | } else {
26 | Vector::x_axis()
27 | };
28 | let normal2 = -pos12.inverse_transform_unit_vector(&normal1);
29 | let point1 = Point::from(*normal1 * r1);
30 | let point2 = Point::from(*normal2 * r2);
31 |
32 | Some(Contact::new(
33 | point1,
34 | point2,
35 | normal1,
36 | normal2,
37 | ComplexField::sqrt(distance_squared) - sum_radius,
38 | ))
39 | } else {
40 | None
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/src/query/contact/contact_halfspace_support_map.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Real};
2 | use crate::query::Contact;
3 | use crate::shape::{HalfSpace, SupportMap};
4 |
5 | /// Contact between a halfspace and a support-mapped shape (Cuboid, ConvexHull, etc.)
6 | pub fn contact_halfspace_support_map(
7 | pos12: &Isometry,
8 | halfspace: &HalfSpace,
9 | other: &G,
10 | prediction: Real,
11 | ) -> Option {
12 | let deepest = other.support_point_toward(pos12, &-halfspace.normal);
13 | let distance = halfspace.normal.dot(&deepest.coords);
14 |
15 | if distance <= prediction {
16 | let point1 = deepest - halfspace.normal.into_inner() * distance;
17 | let point2 = pos12.inverse_transform_point(&deepest);
18 | let normal2 = pos12.inverse_transform_unit_vector(&-halfspace.normal);
19 |
20 | Some(Contact::new(
21 | point1,
22 | point2,
23 | halfspace.normal,
24 | normal2,
25 | distance,
26 | ))
27 | } else {
28 | None
29 | }
30 | }
31 |
32 | /// Contact between a support-mapped shape (Cuboid, ConvexHull, etc.) and a halfspace.
33 | pub fn contact_support_map_halfspace(
34 | pos12: &Isometry,
35 | other: &G,
36 | halfspace: &HalfSpace,
37 | prediction: Real,
38 | ) -> Option {
39 | contact_halfspace_support_map(pos12, halfspace, other, prediction).map(|c| c.flipped())
40 | }
41 |
--------------------------------------------------------------------------------
/src/query/contact/contact_shape_shape.rs:
--------------------------------------------------------------------------------
1 | use crate::math::{Isometry, Real};
2 | use crate::query::{Contact, DefaultQueryDispatcher, QueryDispatcher, Unsupported};
3 | use crate::shape::Shape;
4 |
5 | /// Computes one pair of contact points point between two shapes.
6 | ///
7 | /// Returns `None` if the objects are separated by a distance greater than `prediction`.
8 | /// The result is given in world-space.
9 | pub fn contact(
10 | pos1: &Isometry,
11 | g1: &dyn Shape,
12 | pos2: &Isometry,
13 | g2: &dyn Shape,
14 | prediction: Real,
15 | ) -> Result