14 个版本
0.3.8 | 2022 年 7 月 19 日 |
---|---|
0.3.6 | 2022 年 7 月 18 日 |
0.3.3 | 2022 年 6 月 13 日 |
0.3.1 | 2022 年 5 月 3 日 |
0.1.1 | 2022 年 4 月 29 日 |
#2484 in 算法
695 每月下载量
在 3 个包中使用(通过 wmath)
125KB
3.5K SLoC
模块 :: math_adapter
数学适配器集合,使您的应用程序与数学库的实现解耦,并提供库间兼容性和低成本的可交换性。
从具体数学库的实现中解耦是有用的。这使得它们可以互换,并利用它们之间的互操作性。
选择后端
目前,您可以选择将 cgmath
或 nalgebra
作为后端,并且这两个数学库都集成在包中。尽管如此,默认情况下,math_adapter
不包含任何一个,也不会通过不必要的依赖增加可执行文件的大小。要选择后端,请使用功能
cgmath
- 使用cgmath
作为后端cgmath_ops
- 使用cgmath
作为后端并制作适配器,以便引用其函数和运算符nalgebra
- 使用nalgebra
作为后端nalgebra_ops
- 使用nalgebra
作为后端,并制作适配器以引用其函数和运算符
可以使用多个数学库,但应隐式使用其中的一个库的函数和运算符。即使没有选择 *_ops
功能,也可以显式使用所选数学库的函数和运算符。
为了进行显式转换,使用方法 clone_as_cgmath()
、clone_as_nalgebra()
。要使用具有 *_ops
功能的特征进行显式转换,请使用 clone_as_foreign()
。在这种情况下,解引用工作如同重新解释。适配器或外部的数学对象可以转换/重新解释为类似对象。
将来,每个后端都将驻留在独立的包中。
例如,要使用具有运算符及其函数的 nalgebra
,包括 math_adapter
,如下所示
math_adapter = { version = "*", features = [ "nalgebra_ops" ] }
数学对象
每个数学库定义了自己的数学对象版本。在大多数情况下,它们的布局相同,但即使如此,编译器也会将它们视为不同的对象。math_adapter
也提供了这样的数学对象,以及将或从外部类似对象转换/重新解释的手段。这些包括
- 向量,它们被称为 X1< T >、X2< T >、X3< T >、X4< T > ... Xn< T >。
- 矩阵,它们被称为 MatX1< T >、MatX2< T >、MatX3< T > ... MatXn< T >。
- 四元数,它被称为 Quat< T >。
- 欧拉角,它被称为 Euler< T >。
- 分解变换,它被称为 TransformationDecomposed< T >
转换与重新解释
要应用来自另一个库的函数,您可以将数学对象转换为或重新解释。它们之间有什么区别?
重新解释发生在编译时。如果两个相似结构的布局(大小、对齐、填充和顺序)相同,则可以进行重新解释。例如,结构 cgmath::Vector2
和 nalgebra::Vector2
是不同的结构,但它们具有完全相同的布局。这就是为什么可以将一个解释为另一个,反之亦然是安全的。重新解释告诉编译器使用一个数据结构,就像它是另一个一样。它没有运行时和编译时的成本。如 as_foreign()
、as_foreign_mut()
、as_cgmath()
、as_cgmath_mut()
、as_nalgebra()
、as_nalgebra_mut()
这样的方法重新解释数学对象。
转换是不同的。转换是指从另一个结构的组件中重新构建一个新的结构实例。它具有非零的运行时和编译时成本。尽管它经常被编译器优化为重新解释。使用转换而不是重新解释更安全。问题是重新解释基于对布局的几个假设,这些假设可能被数学库的作者或编译器的作者更改。在理论上!在实践中,这是不太可能的。甚至更有可能,大多数数学库都定义了具有 #[ repr( C ) ]
的对象,这 限制了此类结构的布局,并保护了它们免受未来更改的影响。
每个结构都可以转换为另一个语义上相似的具有不同布局的结构,但只有相同的布局时才能进行重新解释。因此,实现了几个特质。
*NominalInterface
- 接口,暴露转换和访问元素的功能。*BasicInterface
- 接口,扩展X2NominalInterface
并暴露创建此类新实例的功能。*CanonicalInterface
- 接口,扩展X2BasicInterface
并暴露重新解释的功能。
关系:Canonical > Basic > Nominal
。
示例 :: 元素
向量的元素数量编码在类型名称中,长度为 X2
的向量,长度为 2
的 X3
的向量,以此类推。每个结构都实现了构造函数 make()
,make_nan()
和 make_default()
,以构造该类型的新实例。要访问元素,请使用方法 x()
,y()
,z()
或 _0()
,_1()
,_2()
。
#[ cfg( feature = "use_std" ) ]
{
use math_adapter::prelude::*;
use math_adapter::X2;
// vector of length 2 and its elements
let src1 = X2::make( 1, 3 );
assert_eq!( src1.x(), 1 );
assert_eq!( src1.y(), 3 );
assert_eq!( src1._0(), 1 );
assert_eq!( src1._1(), 3 );
}
示例 :: 运算符
选择一个功能 *_ops
以重用选择数学库的运算符和函数。
#[ cfg( feature = "use_std" ) ]
{
use math_adapter::prelude::*;
use math_adapter::X2;
// if back-end math lib is chosen then operators and functions are available
#[ cfg( feature = "cgmath_ops" ) ]
{
let src1 = X2::make( 1, 2 );
let src2 = X2::make( 3, 4 );
let got = src1 + src2;
let exp = X2::make( 4, 6 );
assert_eq!( got, exp );
println!( "src1 + src2 : {:?}", got );
}
// enable feature *_ops to get access to functions
#[ cfg( feature = "cgmath_ops" ) ]
{
let src = X2::make( 1, 2 );
assert_eq!( src.sum(), 3 ); /* sum comes from `cgmath` */
println!( "src.sum() : {:?}", src.sum() );
}
}
示例 :: 互操作性
功能 *_ops
意味着请求使用选择数学库的运算符和函数。但不是选择单个后端数学库,您可以使用多个。使用方法 as_*_clone()
,as_*
,as_*_mut
将原始数学对象转换或重新解释为所选后端的对等物。您不必在每个调用中使用相同的后端,您可以针对特定调用选择数学库,并结合每个数学库的最佳之处。
#[ cfg( feature = "use_std" ) ]
{
use math_adapter::prelude::*;
use math_adapter::X2;
// ! compile-time error, because if no `*_ops` feature was chosen
// {
// let src = X2::make( 1, 3 ); /* make a canonical 2D vector */
// println!( "src.sum() : {:?}", src.sum() ); /* use `sum()` of chosen math lib back-end */
// }
// enable feature *_ops should be enabled to get access to functions
#[ cfg( all( feature = "cgmath", feature = "nalgebra" ) ) ]
{
let src = X2::make( 1, 3 ); /* make a canonical 2D vector */
println!( "src.as_cgmath().sum() : {:?}", src.as_cgmath().sum() ); /* use `sum()` of `cgmath` */
println!( "src.as_nalgebra().sum() : {:?}", src.as_nalgebra().sum() ); /* use `sum()` of `nalgebra` */
}
// you can convert / reinterpret any vector.
// for example you can create `cgmath::Vector2`, but apply a function of `nalgebra::Vector2`
#[ cfg( all( feature = "cgmath", feature = "nalgebra" ) ) ]
{
let src = math_adapter::cgmath::Vector2::< i32 >::make( 1, 3 ); /* make a `cgmath` 2D vector */
println!( "src.as_nalgebra().sum() : {:?}", src.as_nalgebra().sum() ); /* use `sum()` of `nalgebra` */
}
}
添加到您的项目
cargo add math_adapter
从存储库尝试
git clone https://github.com/Wandalen/wMath
cd wMath
cd module/math_adapter/sample/rust/math_adapter_trivial_sample
cargo run
依赖关系
~3–22MB
~294K SLoC