Skip to main content

oxiphysics_geometry/
lib.rs

1// Copyright 2026 COOLJAPAN OU (Team KitaSan)
2// SPDX-License-Identifier: Apache-2.0
3
4//! Geometric shape types for collision detection and physics simulation.
5//!
6//! Provides primitives (sphere, box, capsule, cylinder, cone) and complex
7//! shapes (convex hull, triangle mesh, compound, height field) with support
8//! point queries, volume/inertia computation, and ray casting.
9#![warn(missing_docs)]
10
11mod error;
12pub use error::*;
13
14pub mod shape;
15pub use shape::{RayHit, Shape};
16
17pub mod sphere;
18pub use sphere::Sphere;
19
20pub mod box_shape;
21pub use box_shape::BoxShape;
22
23pub mod capsule;
24pub use capsule::Capsule;
25
26pub mod cylinder;
27pub use cylinder::Cylinder;
28
29pub mod cone;
30pub use cone::Cone;
31
32pub mod convex_hull;
33pub use convex_hull::functions::{
34    approximate_convex_decomposition, box_support, capsule_support, chamfer_build, chamfer_hull,
35    cylinder_support, deduplicate_points, ellipsoid_support, gjk_intersect, hull_aspect_ratio,
36    hull_face_normals, hull_face_offsets, hull_sphericity, icosahedron_vertices, lower_hull_2d,
37    minkowski_difference_hull, minkowski_difference_hulls, minkowski_sum_hull, minkowski_sum_hulls,
38    monotone_chain_hull_2d, octahedron_vertices, point_cloud_aabb, point_cloud_centroid,
39    point_cloud_covariance, simplify_hull_points, sphere_support, tetrahedron_vertices,
40    upper_hull_2d, vertex_decimation,
41};
42pub use convex_hull::types::{
43    ConvexHull, ConvexHull3D, ConvexHullAabb, HullWithQuality, IncrementalConvexHull,
44};
45
46pub mod triangle_mesh;
47pub use triangle_mesh::TriangleMesh;
48
49pub mod heightfield;
50pub use heightfield::HeightField;
51
52pub mod compound;
53pub use compound::Compound;
54
55pub mod torus;
56pub use torus::Torus;
57
58pub mod mesh_ops;
59pub use mesh_ops::TriMesh;
60
61pub mod quickhull;
62pub use quickhull::ConvexHull3DVec;
63
64pub mod swept;
65
66pub mod csg;
67
68pub mod parametric;
69
70pub mod mesh_repair;
71
72pub mod spatial_hash;
73
74pub mod voronoi;
75
76pub mod decimation;
77
78pub mod offset_surface;
79pub use offset_surface::{
80    OffsetMesh, Sdf, SdfBox, SdfCapsule, SdfCone, SdfCylinder, SdfDifference, SdfIntersection,
81    SdfOffset, SdfPlane, SdfScaled, SdfSmoothIntersection, SdfSmoothUnion, SdfSphere, SdfTorus,
82    SdfTranslated, SdfUnion, VoxelSdf, approximate_medial_axis, detect_edge_features,
83    extract_zero_crossings_slice, generate_shell, inward_offset, offset_curve_3d,
84    offset_polyhedron, outward_offset, variable_offset,
85};
86
87pub mod point_cloud;
88pub use point_cloud::functions::{
89    aabb_extent, compute_bounding_box, compute_point_cloud_normals, estimate_normals,
90    farthest_point_sampling, fpfh_feature, icp_align, icp_point_to_point, pca_obb,
91    ransac_fit_plane, statistical_outlier_removal, voxel_downsample,
92};
93pub use point_cloud::types::{
94    IcpRegistration, IcpResult, KdNode3D, KdTree3D, NormalEstimation, PointCloud, PointCloudFilter,
95    RansacPlaneResult,
96};
97
98pub mod mesh_quality;
99
100pub mod remesh;
101
102pub mod boolean_ops;
103
104pub mod geodesic;
105
106pub mod subdivision;
107
108pub mod mesh_param;
109pub use mesh_param::{
110    LscmParameterization, ParamTriMesh, TutteParameterization, boundary_vertices, build_halfedge,
111    fill_holes, is_boundary_vertex, loop_subdivision, midpoint_subdivision,
112    remove_duplicate_vertices, texture_distortion, uv_overlap_check, uv_stretch, vertex_neighbors,
113};
114
115pub use voronoi::{
116    DelaunayTriangle, DelaunayTriangulation, LegacyVoronoiCell, Point2D, VoronoiCell,
117    VoronoiDiagram, VoronoiSite, bowyer_watson, circumcircle, delaunay_to_voronoi, in_circumcircle,
118    is_delaunay, lloyd_relaxation, nearest_site, power_diagram, voronoi_area,
119};
120
121#[cfg(test)]
122mod prop_tests {
123    use super::*;
124    use oxiphysics_core::math::Vec3;
125    use proptest::prelude::*;
126
127    fn positive_f64() -> impl Strategy<Value = f64> {
128        0.01_f64..50.0_f64
129    }
130
131    fn coord_f64() -> impl Strategy<Value = f64> {
132        -50.0_f64..50.0_f64
133    }
134
135    proptest! {
136        #[test]
137        fn prop_sphere_bbox_contains_center(radius in positive_f64()) {
138            let sphere = Sphere::new(radius);
139            let bb = sphere.bounding_box();
140            prop_assert!(
141                bb.contains_point(&Vec3::zeros()),
142                "sphere bbox does not contain center for radius={}", radius
143            );
144        }
145
146        #[test]
147        fn prop_box_support_within_extents(
148            hx in positive_f64(),
149            hy in positive_f64(),
150            hz in positive_f64(),
151            dx in coord_f64(),
152            dy in coord_f64(),
153            dz in coord_f64(),
154        ) {
155            let half_extents = Vec3::new(hx, hy, hz);
156            let b = BoxShape::new(half_extents);
157            let dir = Vec3::new(dx, dy, dz);
158            let sp = b.support_point(&dir);
159            let eps = 1e-9;
160            prop_assert!(sp.x.abs() <= hx + eps, "|sp.x|={} > hx={}", sp.x.abs(), hx);
161            prop_assert!(sp.y.abs() <= hy + eps, "|sp.y|={} > hy={}", sp.y.abs(), hy);
162            prop_assert!(sp.z.abs() <= hz + eps, "|sp.z|={} > hz={}", sp.z.abs(), hz);
163        }
164
165        #[test]
166        fn prop_sphere_volume_positive(radius in positive_f64()) {
167            let sphere = Sphere::new(radius);
168            prop_assert!(sphere.volume() > 0.0, "sphere volume not positive for radius={}", radius);
169        }
170
171        #[test]
172        fn prop_sphere_inertia_symmetric(
173            radius in positive_f64(),
174            mass in positive_f64(),
175        ) {
176            let sphere = Sphere::new(radius);
177            let it = sphere.inertia_tensor(mass);
178            for i in 0..3 {
179                for j in 0..3 {
180                    let diff = (it[(i, j)] - it[(j, i)]).abs();
181                    prop_assert!(diff < 1e-9, "inertia not symmetric at ({},{})={} vs ({},{})={}", i, j, it[(i,j)], j, i, it[(j,i)]);
182                }
183            }
184        }
185
186        #[test]
187        fn prop_sphere_raycast_hit_on_surface(
188            radius in positive_f64(),
189            // Ray from far away along X axis
190            offset in 1.01_f64..50.0_f64,
191        ) {
192            let sphere = Sphere::new(radius);
193            let origin = Vec3::new(-(offset + radius + 1.0), 0.0, 0.0);
194            let dir = Vec3::new(1.0, 0.0, 0.0);
195            if let Some(hit) = sphere.ray_cast(&origin, &dir, 1000.0) {
196                let dist_from_center = hit.point.norm();
197                prop_assert!(
198                    (dist_from_center - radius).abs() < 1e-6,
199                    "hit point not on sphere surface: dist={}, radius={}", dist_from_center, radius
200                );
201            }
202        }
203
204        #[test]
205        fn prop_capsule_volume_ge_sphere(
206            radius in positive_f64(),
207            half_height in positive_f64(),
208        ) {
209            let capsule = Capsule::new(radius, half_height);
210            let sphere = Sphere::new(radius);
211            prop_assert!(
212                capsule.volume() >= sphere.volume() - 1e-9,
213                "capsule volume {} < sphere volume {}", capsule.volume(), sphere.volume()
214            );
215        }
216    }
217}
218pub mod bspline;
219pub mod implicit;
220pub mod implicit_surfaces;
221pub mod level_set;
222pub mod mesh_processing;
223pub mod origami;
224pub mod sphere_packing;
225pub mod topology;
226
227pub mod architectural_geometry;
228
229pub mod fractal_geometry;
230
231pub mod computational_geometry;
232
233pub mod implicit_geometry;
234
235pub mod robot_geometry;
236
237pub mod medical_geometry;
238
239pub mod procedural_geometry;
240
241pub mod spline_geometry;
242
243pub mod discrete_geometry;
244
245pub mod terrain_processing;
246
247pub mod cell_complex;
248pub mod convex_decomposition;
249pub mod voxel_grid;
250pub use voxel_grid::VoxelGrid;
251pub mod vhacd;
252pub use vhacd::{VHacdConfig, VHacdError, VHacdVoxel};
253pub mod geodesic_geometry;
254pub mod medial_axis;
255pub mod mesh_boolean;
256pub mod mesh_repair_ext;
257pub mod mesh_simplification;
258pub mod nurbs_geometry;
259pub mod offset_geometry;
260pub mod signed_distance_field;
261pub mod topology_geometry;