Crates.io | wedged |
lib.rs | wedged |
version | 0.1.0 |
source | src |
created_at | 2022-01-24 04:13:00.88669 |
updated_at | 2022-01-24 04:13:00.88669 |
description | A robust and generalized library for Geometric Algebra in Rust. |
homepage | |
repository | https://github.com/jsmith628/wedged |
max_upload_size | |
id | 519992 |
size | 400,963 |
A robust and generalized library for Geometric Algebra in Rust.
Geometric algebra is an extension of linear algebra where vectors are extended with a multiplication operation called the geometric product, which produces new kinds of operations and vector-like objects that are useful in simplifying and generalizing a number of tricky systems in math and physics.
For instance:
For more information and an in depth explanation, I highly recommend Geometric Algebra for Computer Science by Leo Durst, Daniel Frontijne, and Stephann Mann. A lot of inspiration for this library comes from that book, and the concepts are explained in a way that's easy to follow and visual without falling too deep into overly abstract math.
This crate is split up into a number of modules each representing a different interpretation of the underlying algebra:
algebra
contains the most raw form of Geometric algebra defined purely
algebraically. This is primarily used as the core all the other systems are
built upon, but it is useful as well for various physical quantities (like
position and angular velocity) and abstract mathematical objectssubspace
interprets the structs in algebra
as weighted vector spaces and
orthogonal transformation (like rotations and reflections) in ℝnhomogenous
(planned) interprets the structs in algebra
as affine spaces
and their operations in ℝn-1 using homogeneous coordinatesAdditionally, the module wedged::base
contains the core components common
to all subsystems.
Naming in geometric algebra can vary slightly across authors, so the particular conventions have been chosen:
wedged
, a SimpleBlade
refers to an object constructed from the
wedge product of vectors whereas a Blade
refers to any object of a
particular gradeRotor
is used exclusively for objects with unit norm that encode rotations
whereas Even
is used for a general object from the even subalgebraMultivector
s refer to a general element in the algebra*
/Mul
, ^
/BitXor
, and %
/Rem
are used for the geometric,
wedge, and generalized dot products respectivelyAdditionally, most structs in this crate support indexing where each component
is ordered according to a particular basis convention chosen for this crate.
See the docs on BasisBlade
For more information.
In order to generalize code for different scalar types and dimensions,
wedged
makes heavy use of generics. The system is based upon the
system in nalgebra
, and, to increase interoperability, reuses a lot of its
components.
The system is designed such that a number of different levels of abstraction are possible:
use wedged::algebra::*;
let v1 = Vec3::new(1.0, 0.0, 0.0);
let v2 = Vec3::new(0.0, 1.0, 0.0);
let plane = v1 ^ v2;
let cross = plane.dual();
assert_eq!(plane, BiVec3::new(0.0,0.0,1.0));
assert_eq!(cross, Vec3::new(0.0,0.0,1.0));
When not using generics, things act much like you would expect from a vector library.
use wedged::algebra::*;
use wedged::base::ops::*;
fn midpoint<T:Clone+ClosedAdd+ClosedDiv+One>(v1:Vec3<T>, v2:Vec3<T>) -> Vec3<T> {
let two = T::one() + T::one();
(v1 + v2) / two
}
fn cross<T:RefRing>(v1:Vec3<T>, v2:Vec3<T>) -> Vec3<T> {
(v1 ^ v2).dual()
}
let v1 = Vec3::new(1.0, 0.0, 0.0);
let v2 = Vec3::new(0.0, 1.0, 0.0);
assert_eq!(cross(v1,v2), Vec3::new(0.0,0.0,1.0));
assert_eq!(midpoint(v1,v2), Vec3::new(0.5,0.5,0.0));
let v1 = Vec3::new(1.0f32, 0.0, 0.0);
let v2 = Vec3::new(0.0f32, 1.0, 0.0);
assert_eq!(cross(v1,v2), Vec3::new(0.0f32,0.0,1.0));
assert_eq!(midpoint(v1,v2), Vec3::new(0.5f32,0.5,0.0));
For generic scalars, wedged
structs implement traits and functions based on
what their scalars implement. For instance:
Index
, AsRef<[T]>
, and Borrow<[T]>
are always
implementedClone
, fmt
traits, PartialEq
, Eq
, Hash
, and Default
are all implemented if the scalar implements themCopy
is implemented if the scalar is Copy
the struct isn't a Dynamic
dimensionAdd
, Sub
, and Neg
as well as scalar operations
like Mul
and Div
. are implemented if the scalar has them. The assign
variants and operations between references are implemented as well if the
scalars implement them.Mul
), wedge (BitXor
), and dot (Rem
) products
are implemented if the scalar has addition, subtraction, negation, zero and
multiplication between referencesnalgebra::real_field
Div
usually has the same requirements as Mul
, but is only implemented
on a few specific structs (like Rotor
and Versor
)In order to make managing these requirements easier, a number of trait aliases
are included in wedged::base::ops
that combine common groupings of operations
together
use wedged::base::*;
use wedged::algebra::*;
fn point_velocity<T,N:Dim>(p:VecN<T,N>, angular_vel: BiVecN<T,N>) -> VecN<T,N> where
T:AllocBlade<N,U1>+AllocBlade<N,U2>+RefRing
{
p % angular_vel
}
let p = Vec2::new(2.0,0.0);
let av = BiVec2::new(3.0);
assert_eq!(point_velocity(p, av), Vec2::new(0.0,6.0));
let p = Vec3::new(0.0,2.0,0.0);
let av = BiVec3::new(3.0,0.0,0.0);
assert_eq!(point_velocity(p, av), Vec3::new(0.0,0.0,6.0));
For a generic dimension, for every wedged
struct
used in the function or trait, the scalar must have the corresponding Alloc*
trait bound for that struct. These are all included in wedged::base::alloc
,
and there is one for each subset of the geometric algebra.
For example, for a scalar T
and dimension N
, using a VecN
requires T:AllocBlade<N,U1>
bound, using an Even
needs a T:AllocEven<N>
bound, etc.
Finally, even if a non-generic scalar is used, these are still required inside a where clause on the function or trait.
use wedged::base::*;
use wedged::algebra::*;
fn project<T,N:Dim,G:Dim>(v:VecN<T,N>, b:Blade<T,N,G>) -> VecN<T,N> where
U1: DimSymSub<G>,
DimSymDiff<U1,G>: DimSymSub<G,Output=U1>,
T:AllocBlade<N,U1> + AllocBlade<N,G> + AllocBlade<N,DimSymDiff<U1,G>> + RefDivRing
{
let l = b.norm_sqrd();
(v % &b) % b.reverse()/l
}
let v = Vec3::new(1.0, 2.0, 0.0);
let line = Vec3::new(0.0, 1.0, 0.0);
let plane = BiVec3::new(0.0, 1.0, 0.0);
assert_eq!(project(v,line), Vec3::new(0.0, 2.0, 0.0));
assert_eq!(project(v,plane), Vec3::new(1.0, 0.0, 0.0));
Using a generic grade follows nearly the same rules as for generic dimensions but with an added generic for the grade. However, with grade altering operations like the wedge or dot products are used, additional bounds are required to allow the compiler to add or subtract the grades of the two blades.
For instance:
The wedge ^
product requires G1: DimAdd<G2>
The dot %
product requires G1: DimSymSub<G2>