|
Mundy: Multibody Nonlocal Dynamics Version of the Day
|
Geometric primitives and utilities.
See the MundyGeom directory reference.
This subpackage contains small Kokkos-friendly geometric primitives and the free functions that act on them. The core functionality includes
MundyGeom builds directly on MundyMath. A Point<Scalar> behaves like a Vector3<Scalar>, so most geometry code is ordinary vector arithmetic wrapped in shape-specific names. Just like MundyMath, the API is intentionally free-function heavy: you construct light primitives, then call distance, compute_aabb, wrap_rigid, translate, and similar algorithms on them.
The default primitive aliases own their coordinate data, but the primitive templates can also store view-backed points and orientations. The same free functions work with both owning and view-backed primitives.
Primitives are light value types. They store the data that defines a shape; they do not allocate, own mesh entities, or hide the underlying math. Prefer explicit construction, since default constructors for sized shapes often do not encode meaningful radii or lengths.
| Type | Stored data | Use when you mean |
|---|---|---|
| Point<Scalar> | x, y, z | A position in 3D space. |
| Line<Scalar> | center, direction | An infinite oriented line. |
| LineSegment<Scalar> | start, end | A finite segment between two points. |
| VSegment<Scalar> | start, middle, end | Two connected finite segments. |
| AABB<Scalar> | min_corner, max_corner | An axis-aligned bounding box. |
| Sphere<Scalar> | center, radius | A ball with no orientation. |
| Ellipsoid<Scalar> | center, orientation, radii | An oriented ellipsoid. |
| Spherocylinder<Scalar> | center, orientation, radius, length | A capsule-like body aligned with its body z-axis. |
| SpherocylinderSegment<Scalar> | start, end, radius | A capsule-like body stored by endpoints. |
| Circle3D<Scalar> | center, orientation, radius | An oriented circle in 3D. |
| Ring<Scalar> | center, orientation, major_radius, minor_radius | An oriented thick ring. |
Oriented shapes use a Quaternion<Scalar>. The center is always in the lab frame, and the orientation maps the body's local frame into the lab frame. For rods and circular primitives, the body z-axis is the natural long axis or normal.
Accessors are named after the geometry rather than hidden behind a generic trait layer.
For AABB, [] treats the box as {x_min, y_min, z_min, x_max, y_max, z_max}.
Geom views come from MundyMath views. Since Point is an accessor-backed Vector3, and primitives are templated on their point and orientation types, a primitive can hold non-owning components without copying the underlying data.
The same pattern applies to oriented shapes by viewing both the point data and the quaternion data.
Use views when geometry is a typed window into existing storage. View semantics apply to accessor-backed math components; extra scalar fields such as radius and length remain scalar values. Algorithms that synthesize new geometry, such as translate, generally return owning results.
Several periodic helpers are defined in terms of a primitive's reference point. This is the point used for rigid image shifts and rigid wrapping.
| Primitive | reference_point(shape) |
|---|---|
| Point | the point itself |
| Line | center() |
| LineSegment | start() |
| VSegment | start() |
| AABB | min_corner() |
| Sphere | center() |
| Ellipsoid | center() |
| Spherocylinder | center() |
| SpherocylinderSegment | start() |
| Circle3D | center() |
| Ring | center() |
That reference point is what shift_image(shape, lattice_vector, metric) moves between periodic images.
The main interface is a single overloaded family of free functions:
For most surface-bearing objects, the default meaning is a signed separation distance: positive means separated, zero means touching, and negative means overlapping.
When you need geometric witnesses, use an overload with output arguments.
Here closest is the closest point on s, u is the segment parameter, and sep points from the first argument toward the second.
Most calls use the default overload directly, but some families support an explicit distance tag.
| Tag | Meaning | Common use |
|---|---|---|
| SharedNormalSigned{} | Signed separation measured along a shared normal. | Surface-based queries such as sphere-sphere or ellipsoid-ellipsoid. |
| Euclidean{} | Standard Euclidean distance. | Queries such as Circle3D-Circle3D. |
The overload family is broad, but the outputs follow a small set of recurring patterns.
| Output | Meaning |
|---|---|
| sep | Separation vector from the first object toward the second. |
| closest_point | Closest point on the second queried object for one-sided queries. |
| closest_point1, closest_point2 | Closest points on both objects for pair queries. |
| arch_length | Query-specific line/segment parameter. For lines it is the signed coordinate along direction(). For line segments it is the affine parameter on the stored endpoints. |
| shared_normal | Shared witness normal for implicit surface methods. |
The currently supported distance families are explicit rather than fully generic.
| Family | Default call | Common witness overloads |
|---|---|---|
| Point-point | distance(p, q) | distance(p, q, sep) |
| Point-line | distance(p, line) | distance(p, line, closest_point, arch_length, sep) |
| Point-line segment | distance(p, segment) | distance(p, segment, closest_point, arch_length, sep) |
| Line-line | distance(line0, line1) | distance(line0, line1, closest_point0, closest_point1, arch_length0, arch_length1, sep) |
| Point-sphere | distance(p, sphere) | distance(p, sphere, sep) |
| Line-sphere | distance(line, sphere) | distance(line, sphere, closest_point, arch_length, sep) |
| Line segment-sphere | distance(segment, sphere) | distance(segment, sphere, closest_point, arch_length, sep) |
| Sphere-sphere | distance(sphere0, sphere1) | distance(sphere0, sphere1, sep) |
| Point-ellipsoid | distance(p, ellipsoid) | distance(p, ellipsoid, closest_point, shared_normal) |
| Ellipsoid-ellipsoid | distance(e0, e1) | distance(e0, e1, closest_point0, closest_point1, shared_normal0, shared_normal1) |
| Circle3D-circle3D | distance(circle0, circle1) | distance(circle0, circle1, closest_point0, closest_point1, shared_normal0, shared_normal1) |
Two especially useful witness-heavy calls are
and
Not every primitive pair has a distance overload. When in doubt, treat the table above as the supported surface area.
MundyGeom provides cheap conservative bounding queries for broad-phase filtering and neighbor pruning.
compute_aabb returns an axis-aligned box in the current coordinate frame. compute_bounding_radius returns a scalar radius large enough to contain the primitive about its geometric center.
| Operation | Supported shapes | Meaning |
|---|---|---|
| compute_aabb(shape) | Point, LineSegment, Sphere, Ellipsoid, Spherocylinder, SpherocylinderSegment | Conservative axis-aligned box in the current frame. |
| compute_aabb(shape, metric) | same families | Periodic-aware AABB, unwrapping multi-point objects near their reference point before boxing. |
| compute_bounding_radius(shape) | Point, LineSegment, Sphere, Ellipsoid, Spherocylinder, SpherocylinderSegment | Conservative scalar radius about the geometric center. |
| intersects(aabb0, aabb1) | AABB pairs | true when two AABBs overlap or touch. |
This is intentionally a conservative layer: it is cheap enough for broad-phase work, then you follow with an exact query such as distance only when needed.
A metric defines what “nearby” means. In free space, the separation from x to y is just y - x. In periodic space, the metric applies the minimum-image convention.
| Metric | Interpretation |
|---|---|
| EuclideanMetric<Scalar> | No periodic directions. |
| PeriodicMetric<Scalar> | Fully periodic general cell given by a cell matrix. |
| PeriodicMetricX<Scalar> | Periodic only in x. |
| PeriodicMetricY<Scalar> | Periodic only in y. |
| PeriodicMetricXY<Scalar> | Periodic in x and y. |
| PeriodicMetricYZ<Scalar> | Periodic in y and z. |
| PeriodicScaledMetric<Scalar> | Axis-aligned periodic box given by side lengths. |
| Operation | Meaning |
|---|---|
| metric.sep(x, y) | Minimum-image separation from x to y. |
| metric.wrap(x) | Wrap a point into the primary cell. |
| metric.shift_image(x, lattice_vector) | Shift a point by an integer lattice image. |
| metric.to_fractional(x) / metric.from_fractional(x_frac) | Convert between real and fractional coordinates. |
| Operation | Use when |
|---|---|
| shift_image(shape, lattice_vector, metric) | The whole object should move to a specified image. |
| wrap_rigid(shape, metric) / wrap_rigid_inplace(shape, metric) | The shape should move as one rigid object using its reference point. |
| wrap_points(shape, metric) / wrap_points_inplace(shape, metric) | Each stored point may be wrapped independently. |
| unwrap_points_to_ref(shape, metric, ref) / unwrap_points_to_ref_inplace(shape, metric, ref) | A multi-point shape should be made coherent near ref. |
For multi-point physical bodies, wrap_rigid is usually the right choice. wrap_points is useful when you want each stored point independently in the primary cell, but it can make long objects look broken across image boundaries until you call unwrap_points_to_ref.
Transforms follow the same pattern as MundyMath: return-by-value by default, _inplace when mutation is desired.
| Operation | Meaning |
|---|---|
| translate(shape, disp) | Return a translated copy. |
| translate_inplace(shape, disp) | Translate the object in place. |
| Operation | Meaning |
|---|---|
| rotate(shape, q) | Rotate about the origin by quaternion q. |
| rotate_inplace(shape, q) | Rotate in place about the origin. |
Rotation is defined for all common primitives except AABB. Rotating an AABB is intentionally not supported because the result is ambiguous: an oriented box and its enclosing axis-aligned box are different objects.
Random helpers build test geometry and synthetic examples from a Kokkos-friendly random generator. The low-level generators give you points, directions, and orientations; the higher-level generators assemble full primitives.
| Generator | Meaning |
|---|---|
| generate_random_point<Scalar>(box, rng) | Uniform point in an AABB. |
| generate_random_unit_vector<Scalar>(rng) | Uniform unit vector on the sphere. |
| generate_random_unit_quaternion<Scalar>(rng) | Random unit quaternion. |
| Generator family | Available forms |
|---|---|
| generate_random_line | random center in box and random direction |
| generate_random_line_segment | endpoint-sampled form, or center/length-bounded form |
| generate_random_vsegment | point-sampled form, or center/length-bounded form |
| generate_random_circle3D | center in box, bounded radius, random orientation |
| generate_random_aabb | point-sampled form, or center/size-bounded form |
| generate_random_sphere | center in box, bounded radius |
| generate_random_spherocylinder | endpoint-sampled form, or center/radius/length-bounded form |
| generate_random_spherocylinder_segment | endpoint-sampled form, or radius/length-bounded form |
| generate_random_ring | center in box, bounded major/minor radii, random orientation |
| generate_random_ellipsoid | center in box, bounded semi-axis radii, random orientation |
In practice, the random API mirrors the rest of MundyGeom: explicit primitive constructors, explicit free functions, and no hidden ownership model.