Rerun UVec2D 编码类型详解:uint32 二维向量的定义、Arrow 数据布局与三语言实现
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
UVec2D 是 Rerun 数据模型(Data Model)中定义在encodings命名空间下的基础编码类型,表示一个由两个 32 位无符号整数(uint32)构成的二维向量,常用于表示非负整数类型的坐标、尺寸或索引。本文基于 Rerun 开源仓库中的类型定义文档与源码实现,系统讲解 UVec2D 的语义、底层 Arrow 数据布局(FixedSizeList(2 x non-null UInt32)),以及它在 Rust / Python / C++ 三种 SDK 中的构造方式、便捷方法与互转能力,帮助你理解 Rerun 类型系统的生成机制与序列化约定。
类型定位:数据模型中的"编码(Encoding)"基础类型
Rerun 的数据模型在 crates/store/re_sdk_types/src/encodings/mod.rs 中集中声明了一批与rerun.encodings.*对应的基础编码类型,包括Vec2D、DVec2D、IVec3D、UVec3D、UVec4D以及本文主角UVec2D等。这些类型并非某个具体可视化组件的专属字段,而是数据模型层面的通用"积木"——它们定义了某种结构化数据在内存与 Arrow 列式存储中的标准表示方式,可被上层组件(Component)与蓝图(Blueprint)复用。
从类型定义文档 docs/content/reference/types/encodings/uvec2d.md 可以确认其官方语义:
UVec2D:A uint32 vector in 2D space.
即"二维空间中的一个 uint32 向量"。选择uint32而非int32(对应IVec3D这类有符号类型)或float(对应Vec2D/DVec2D),意味着该类型面向的是一组天然为非负整数的二维数据,例如像素尺寸、栅格坐标、计数索引等场景。
该文档属于自动生成(auto-generated)的类型参考页,其原始定义位于类型定义源文件 crates/build/re_type_definitions/rerun/encodings/uvec2d.def.rs:
// This is a Rerun type definition for the SDK, not executable code. // It is parsed by `re_types_builder` to generate the Rust, Python and C++ bindings. /// A uint32 vector in 2D space. #[rerun::rerun_type] #[arrow(transparent)] #[python(aliases = "npt.NDArray[Any] | npt.ArrayLike | Sequence[int]")] #[python( array_aliases = "npt.NDArray[Any] | npt.ArrayLike | Sequence[Sequence[int]] | Sequence[int]" )] #[rust(derive(Default, Copy, PartialEq, Eq, Hash, bytemuck::Pod, bytemuck::Zeroable))] #[rust(repr = "C")] #[rust(tuple_struct)] #[rerun(state = "stable")] pub struct UVec2D { pub xy: [u32; 2], }从这份定义可以看出 Rerun 类型系统的几个关键设计:
- 单一事实来源(Single Source of Truth):
.def.rs是供re_types_builder解析的类型定义(而非可执行代码),Rust、Python、C++ 三种 SDK 的绑定全部由它生成,保证三语言语义一致; #[arrow(transparent)]:声明该类型在 Arrow 层采用"透明"布局——不额外包一层 struct,直接映射为定长列表;#[rust(repr = "C")]+tuple_struct:生成的 Rust 结构体使用 C 内存布局的元组结构体,为bytemuck零拷贝转换(Pod/Zeroable)与跨 FFI 边界传递创造条件;#[rerun(state = "stable")]:标记该类型处于稳定状态,说明其数据布局与序列化格式已被视为公共接口的一部分。
Arrow 数据布局:FixedSizeList(2 x non-null UInt32)
类型参考文档 uvec2d.md 明确给出了 UVec2D 对应的 Arrow 数据类型:
FixedSizeList(2 x non-null UInt32)这一布局在生成的 Rust 绑定 crates/store/re_sdk_types/src/encodings/uvec2d.rs 中有完全一致的实现:
impl ::re_types_core::ArrowDataType for UVec2D { #[inline] fn arrow_data_type() -> arrow::datatypes::DataType { use arrow::datatypes::*; DataType::FixedSizeList( std::sync::Arc::new(Field::new("item", DataType::UInt32, false)), 2, ) } }其含义可以拆解为:
| 组成部分 | 含义 |
|---|---|
FixedSizeList | 定长列表,每个元素固定包含 2 个子元素,存储紧凑、无需单独的长度字段 |
UInt32 | 子元素为 32 位无符号整数(u32) |
non-null(Field::new("item", …, false)的false) | 子元素不允许为 null,保证每个[x, y]都完整有效 |
序列化路径(ToArrow)在 uvec2d.rs 中实现:先将每个UVec2D实例取其内部的[u32; 2]元组字段,展平为连续的u32值数组,再包装为FixedSizeListArray(内层是PrimitiveArray<UInt32Type>),外层无 validity 位图(即无 null 元素)。这种"展平 + 定长切片"的布局让整批数据在内存中连续排布,利于批量处理与按值拷贝。
反序列化路径(FromArrow)在 uvec2d.rs 中实现,并带有严格的健壮性校验:
- 首先调用
err_on_nulls(arrow_data, "rerun.encodings.UVec2D"),拒绝包含 null 的数据; - 将输入强制转换为
FixedSizeListArray,并校验value_length() == 2,不匹配即返回DeserializationError::datatype_mismatch; - 最后通过
bytemuck::try_cast_slice将连续的u32缓冲零拷贝重解释为[u32; 2]切片,逐个构造UVec2D实例。
可见 UVec2D 在序列化/反序列化两侧都做到了无逐元素复制,直接复用 Arrow 的连续缓冲,这与#[repr(C)]+Pod的派生是配套的设计。
Rust 侧 API:常量、访问器与互操作
Rust 的UVec2D分为自动生成部分与手工扩展部分(_ext.rs)。生成的类型本体见 crates/store/re_sdk_types/src/encodings/uvec2d.rs:
pub struct UVec2D(pub [u32; 2usize]);派生了Clone, Debug, Default, Copy, PartialEq, Eq, Hash, bytemuck::Pod, bytemuck::Zeroable, SizeBytes,并实现了From<[u32; 2usize]>与From<UVec2D> for [u32; 2usize]的双向转换。
手工扩展部分位于 crates/store/re_sdk_types/src/encodings/uvec2d_ext.rs,提供了日常使用所需的便捷 API:
- 常量:
UVec2D::ZERO(加法单位元[0, 0])与UVec2D::ONE(乘法单位元[1, 1]); - 构造:
UVec2D::new(x: u32, y: u32),const fn可在常量上下文中使用; - 访问器:
x()/y()分别返回索引 0 与索引 1 的分量,set_x()/set_y()用于赋值; - 便捷转换:
From<(u32, u32)>、From<&(u32, u32)>、From<&[u32; 2]>、From<&Self>一应俱全——源码注释特别说明,这些 by-ref 转换是为了让使用者在处理切片时无需手动解引用即可完成Into/IntoIterator链式转换; - 索引:实现
std::ops::Index(基于std::slice::SliceIndex<[u32]>),支持v[0]、v[1]等切片式下标访问; - 显示:实现
Display,输出格式为[x, y],便于日志与调试; - glam 互操作(feature "glam" 启用时):与游戏/图形常用数学库
glam::UVec2双向互转——From<UVec2D> for glam::UVec2(from_slice)与From<glam::UVec2> for UVec2D(to_array),使 UVec2D 可以直接接入图形学管线。
Python 侧 API:NumPy 兼容与类型别名
Python 绑定由 rerun_py/rerun_sdk/rerun/encodings/uvec2d.py 与扩展 rerun_py/rerun_sdk/rerun/encodings/uvec2d_ext.py 组成。
生成的类UVec2D是一个基于attrs的定长二维向量封装:
@define(init=False) class UVec2D(UVec2DExt): """**Encoding**: A uint32 vector in 2D space.""" def __init__(self: Any, xy: UVec2DLike) -> None: self.__attrs_init__(xy=xy) xy: npt.NDArray[np.uint32] = field(converter=to_np_uint32)关键点:
- 唯一的字段
xy经过to_np_uint32转换器强制归一为npt.NDArray[np.uint32],即传入 Pythonint列表、NumPy 数组均可,最终统一为uint32的 NumPy 数组; - 实现了
__array__(支持np.asarray(uvec2d)直接转 NumPy 数组)与__len__(恒为 2),与 NumPy 生态无缝协作; - 类型别名体系完整:
UVec2DLike = UVec2D | npt.NDArray[Any] | npt.ArrayLike | Sequence[int]表示单个实例的合法输入;UVec2DArrayLike进一步覆盖"多个实例"的批量输入(Sequence[UVec2DLike] | Sequence[Sequence[int]]等),可参见 uvec2d.py。
批量对象UVec2DBatch通过_ARROW_DATATYPE = pa.list_(pa.field("item", pa.uint32(), nullable=False, metadata={}), 2)与 Python 侧 Arrow 类型对齐,其_native_to_pa_array委托给扩展类UVec2DExt.native_to_pa_array_override(见 uvec2d_ext.py):
@staticmethod def native_to_pa_array_override(data: UVec2DArrayLike, data_type: pa.DataType) -> pa.Array: points = flat_np_uint32_array_from_array_like(data, 2) return pa.FixedSizeListArray.from_arrays(points, type=data_type)其中flat_np_uint32_array_from_array_like(data, 2)负责把任意形状的类数组输入展平为末尾维度为 2 的uint32数组,再交给pa.FixedSizeListArray.from_arrays组装成定长列表,与 Rust 侧的"展平 + FixedSizeList"序列化策略完全对应。
C++ 侧 API:聚合结构体与 Loggable 特化
C++ 绑定位于 rerun_cpp/src/rerun/encodings/uvec2d.hpp(扩展部分来自 uvec2d_ext.cpp):
namespace rerun::encodings { struct UVec2D { std::array<uint32_t, 2> xy; // extensions from uvec2d_ext.cpp: UVec2D(uint32_t x, uint32_t y) : xy{x, y} {} explicit UVec2D(const uint32_t* xy_) : xy{xy_[0], xy_[1]} {} uint32_t x() const { return xy[0]; } uint32_t y() const { return xy[1]; } // generated code: UVec2D() = default; UVec2D(std::array<uint32_t, 2> xy_) : xy(xy_) {} UVec2D& operator=(std::array<uint32_t, 2> xy_) { xy = xy_; return *this; } }; }要点:
- 底层存储是
std::array<uint32_t, 2>,与 Rust 的[u32; 2]一一对应; - 提供
(x, y)与uint32_t*指针两种扩展构造函数,以及x()/y()访问器; - 在
rerun命名空间下特化了Loggable<encodings::UVec2D>,其ComponentType字符串为"rerun.encodings.UVec2D",并通过arrow_data_type()、to_arrow()、fill_arrow_array_builder()三个接口完成 Arrow 序列化,与 Rust / Python 侧形成三语言对等的encodings类型注册体系。
与同族向量类型的区分
从 encodings/mod.rs 的导出列表可以看到,Rerun 的 encodings 模块同时提供了多个向量族类型。UVec2D 与它们的差异可以从类型定义源码直接确认:
| 类型 | 维度 | 元素类型 | 典型语义 |
|---|---|---|---|
Vec2D | 2D | f32 | 浮点二维向量 |
DVec2D | 2D | f64 | 双精度浮点二维向量 |
IVec3D | 3D | i32 | 有符号整型三维向量 |
UVec2D | 2D | u32 | 无符号整型二维向量(本文) |
UVec3D | 3D | u32 | 无符号整型三维向量 |
UVec4D | 4D | u32 | 无符号整型四维向量 |
选择建议:当二维数据本质上不允许出现负数(例如尺寸、像素坐标、计数)时优先使用UVec2D;若需要负坐标或小数坐标,则应改用IVec3D同族的带符号整型类型或Vec2D/DVec2D浮点类型。这种"按语义选类型"的约定也正是 Rerun 类型系统将编码类型细分化的目的所在。
小结
- 语义:
UVec2D表示二维空间中的一个uint32向量,官方描述为 "A uint32 vector in 2D space",属于rerun.encodings.*命名空间下的稳定(stable)编码类型; - 数据布局:Arrow 层为
FixedSizeList(2 x non-null UInt32),序列化采用"展平为连续u32缓冲 + 定长列表"的零拷贝友好策略,反序列化带 null 校验与长度校验; - 跨语言一致性:类型由 uvec2d.def.rs 单一来源定义,自动生成 Rust(uvec2d.rs + uvec2d_ext.rs)、Python(uvec2d.py + uvec2d_ext.py)、C++(uvec2d.hpp)三套绑定,三者共享相同的语义与 Arrow 布局;
- 上手方式:Rust 用
UVec2D::new(x, y)并支持与glam::UVec2互转;Python 用UVec2D([x, y])且可直接与 NumPy 互操作;C++ 用UVec2D(x, y)构造并经Loggable特化接入 Arrow 序列化。
如需进一步了解同族类型,可继续阅读 docs/content/reference/types/encodings/vec2d.md、dvec2d.md、uvec3d.md 与 uvec4d.md 等参考文档,以及 encodings 模块的完整源码 crates/store/re_sdk_types/src/encodings/mod.rs。
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考