Rerun Vector2D 组件深度解析:2D 向量数据模型、Arrow 编码与 Arrows2D 可视化
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
Vector2D是 Rerun 数据模型中用于表示二维空间向量的核心组件(Component),也是Arrows2D图元(Archetype)唯一必需的组成部分。本文以仓库中 组件参考文档 为主体,结合 Rust / Python 两套 SDK 的源码实现,完整讲解Vector2D的语义定义、底层Vec2D编码、Arrow 内存布局、跨语言 API 用法及其在Arrows2D可视化链路中的角色,帮助你在日志机器人运动学、光流、速度场等二维矢量数据时正确选型与使用。
Vector2D 是什么:一个"稳定"的二维向量组件
在 Rerun 的类型体系中,组件(Component)是附着在实体(Entity)上的最小语义单元,而Vector2D的定位非常单纯——一个处于 2D 空间中的向量("A vector in 2D space.")。它与同样表示二维数据的Position2D(位置点)的关键区别在于语义:位置描述"在哪",向量描述"朝哪个方向、多长"。
从仓库中的类型定义源文件可以看到该组件的"官方契约":
// crates/build/re_type_definitions/rerun/components/vector2d.def.rs /// A vector in 2D space. #[rerun::rerun_type] #[rerun(state = "stable")] #[rust(derive(Default, Copy, PartialEq, bytemuck::Pod, bytemuck::Zeroable))] #[rust(repr = "transparent")] pub struct Vector2D { pub vector: rerun::encodings::Vec2D, }这段代码本身不是可执行的 Rust 代码,而是 Rerun 的类型定义 DSL(位于crates/build/re_type_definitions/下),由re_types_builder解析后统一生成 Rust、Python 与 C++ 三套 SDK 的绑定代码。其中值得注意的两个标记:
state = "stable":表明该组件处于稳定状态,其名称与内存布局受版本兼容性保障,可以放心用于长期存储的数据;repr = "transparent":生成的结构体是底层编码类型Vec2D的透明包装(transparent wrapper),零额外内存开销。
Rerun 编码:Vec2D 与透明包装结构
文档中明确列出Vector2D的 Rerun 编码(encoding)为Vec2D。编码(Encoding)是比组件更低一层的原始数据类型描述,它直接对应 Arrow 的内存表示,并且被多个组件复用(例如Position2D同样基于二维浮点编码)。
Rust 端生成的组件结构体如下:
// crates/store/re_sdk_types/src/components/vector2d.rs #[repr(transparent)] pub struct Vector2D(pub crate::encodings::Vec2D); impl ::re_types_core::WrapperComponent for Vector2D { type Encoding = crate::encodings::Vec2D; #[inline] fn name() -> ComponentType { "rerun.components.Vector2D".into() } }而编码Vec2D的实现(crates/store/re_sdk_types/src/encodings/vec2d.rs)本质就是一个[f32; 2]的强类型包装:
#[repr(C)] pub struct Vec2D(pub [f32; 2usize]);同时提供了便捷的类型互转:
impl From<[f32; 2usize]> for Vec2D { fn from(xy: [f32; 2usize]) -> Self { Self(xy) } } impl From<Vec2D> for [f32; 2usize] { fn from(value: Vec2D) -> Self { value.0 } }Python 端的结构完全对应:Vector2D类直接继承encodings.Vec2D并混入ComponentMixin,本身不新增字段(见 rerun_py/rerun_sdk/rerun/components/vector2d.py):
class Vector2D(encodings.Vec2D, ComponentMixin): """**Component**: A vector in 2D space.""" class Vector2DBatch(encodings.Vec2DBatch, ComponentBatchMixin): _COMPONENT_TYPE: str = "rerun.components.Vector2D"实用的扩展实现
在 crates/store/re_sdk_types/src/components/vector2d_ext.rs 中,Rust 端还提供了两个常用常量与外部数学库的互操作:
impl Vector2D { /// The zero vector, i.e. the additive identity. pub const ZERO: Self = Self(crate::encodings::Vec2D::ZERO); /// `[1, 1]`, i.e. the multiplicative identity. pub const ONE: Self = Self(crate::encodings::Vec2D::ONE); } #[cfg(feature = "glam")] impl From<Vector2D> for glam::Vec2 { /* ... */ } #[cfg(feature = "mint")] impl From<Vector2D> for mint::Vector2<f32> { /* ... */ }这意味着当你的应用已经基于glam(Vec2)或mint(Vector2<f32>)做向量运算时,可以直接通过From转换轻松接入 Rerun 的日志管线,无需手写逐元素拷贝。
Arrow 数据类型:FixedSizeList(2 × Float32)
Vector2D在 Arrow 层面的数据布局是文档中给出的核心事实:
FixedSizeList(2 x non-null Float32)即:外层是长度为 2 的定长列表(FixedSizeList,元素不可为 null),内层是两个非空Float32。这一布局在三个层面都有源码印证:
Rust 端(crates/store/re_sdk_types/src/encodings/vec2d.rs):
impl ::re_types_core::ArrowDataType for Vec2D { fn arrow_data_type() -> arrow::datatypes::DataType { DataType::FixedSizeList( std::sync::Arc::new(Field::new("item", DataType::Float32, false)), 2, ) } }序列化(ToArrow)时先展平为[f32; 2]的连续数组再构造FixedSizeListArray;反序列化(FromArrow)时校验value_length() == 2,并通过bytemuck::try_cast_slice把底层Float32Array的连续缓冲区直接重解释为[[f32; 2]]切片——这正是选择定长列表而非可变长度列表的原因:定长 + 无 null 使得每个向量恰好 8 字节,可以按元素零拷贝访问。
Python 端(rerun_py/rerun_sdk/rerun/encodings/vec2d.py):
class Vec2DBatch(BaseBatch[Vec2DArrayLike]): _ARROW_DATATYPE = pa.list_(pa.field("item", pa.float32(), nullable=False, metadata={}), 2)而输入数据在 vec2d_ext.py 中经由flat_np_float32_array_from_array_like(data, 2)(见 rerun_py/rerun_sdk/rerun/_validators.py)统一转成维度为 2 的扁平 float32 numpy 数组,再包成pa.FixedSizeListArray:
@staticmethod def native_to_pa_array_override(data: Vec2DArrayLike, data_type: pa.DataType) -> pa.Array: points = flat_np_float32_array_from_array_like(data, 2) return pa.FixedSizeListArray.from_arrays(points, type=data_type)因此 Python 侧你可以传入[[1.0, 2.0], [3.0, 4.0]]、np.array(...)等任意可转为(N, 2)float32 数组的对象,SDK 会统一校验并转换。
使用场景:作为 Arrows2D 的必选向量
Vector2D组件当前唯一的直接消费者是Arrows2D图元——用于绘制一批带可选颜色、半径、标签的二维箭头。从类型定义看(crates/build/re_type_definitions/rerun/archetypes/arrows2d.def.rs),vectors是Arrows2D唯一的**必需(required)**字段:
pub struct Arrows2D { /// All the vectors for each arrow in the batch. #[rerun(required)] pub vectors: Vec<rerun::components::Vector2D>, /// All the origin (base) positions for each arrow in the batch. /// If no origins are set, (0, 0) is used as the origin for each arrow. #[rerun(recommended)] pub origins: Option<Vec<rerun::components::Position2D>>, /// Optional radii for the arrows. #[rerun(optional)] pub radii: Option<Vec<rerun::components::Radius>>, // ... colors / labels / show_labels / draw_order / class_ids ... }理解"必需"的含义很重要:Arrows2D图元本身还带有origins、radii、colors、labels、draw_order、class_ids等字段,但它们全部可选——去掉任何一个,剩下的箭头依然能渲染;唯独删掉vectors后,Arrows2D就不再有意义。因此Vector2D是二维箭头可视化的数据基石,其余字段只是修饰。
可视化侧的印证
在渲染端,Arrows2DVisualizer(crates/views/re_view_spatial/src/visualizers/arrows2d.rs)通过查询信息明确把Vector2D声明为单必需组件:
impl VisualizerSystem for Arrows2DVisualizer { fn visualizer_query_info(&self, _app_options: &re_viewer_context::AppOptions) -> VisualizerQueryInfo { VisualizerQueryInfo::single_required_component::<Vector2D>( &Arrows2D::descriptor_vectors(), &Arrows2D::all_components(), ) // ... } }即:只要某个实体上存在rerun.components.Vector2D组件批次,空间视图(Spatial 2D / 3D,3D 时需在投影下)就会自动启用Arrows2DVisualizer来渲染这批向量。从源码结构看,vectors的语义与文档定义("All the vectors for each arrow in the batch")完全一致——每个Vector2D对应批量中的一根箭头。
各语言实战用法
Python
import rerun as rr rr.init("rerun_example_arrow2d") rr.spawn() rr.log( "arrows", rr.Arrows2D( vectors=[[1.0, 0.0], [0.0, -1.0], [-0.7, 0.7]], origins=[[0.25, 0.0], [0.25, 0.0], [-0.1, -0.1]], radii=0.025, colors=[[255, 0, 0], [0, 255, 0], [127, 0, 255]], labels=["right", "up", "left-down"], ), )Rust
use rerun::{Arrows2D, RecordingStreamBuilder}; fn main() -> Result<(), Box<dyn std::error::Error>> { let rec = rerun::RecordingStreamBuilder::new("rerun_example_arrow2d").spawn()?; rec.log( "arrows", &Arrows2D::from_vectors([[1.0, 0.0], [0.0, -1.0], [-0.7, 0.7]]) .with_radii([0.025]) .with_origins([[0.25, 0.0], [0.25, 0.0], [-0.1, -0.1]]) .with_colors([[255, 0, 0], [0, 255, 0], [127, 0, 255]]) .with_labels(["right", "up", "left-down"]), )?; Ok(()) }以上 Rust 示例直接取自 crates/store/re_sdk_types/src/archetypes/arrows2d.rs 中生成的文档注释。可以看出:
from_vectors(...)接受数组字面量,内部逐个Into<Vector2D>转换(Vector2D实现了From<T: Into<Vec2D>>,而Vec2D又实现了From<[f32; 2]>);- 未指定
origins时默认以(0, 0)为起点; radii的渲染语义为:箭杆按radius = 0.5 * radius绘制成线,箭头按height = 2.0 * radius、radius = 1.0 * radius绘制;labels只有一个时会显示在实体中心,多个时每个实例各显示一个。
类型生成链路与兼容性保证
Vector2D的代码并非手写,而是由构建期工具链驱动:
- 类型契约定义在 crates/build/re_type_definitions/rerun/components/vector2d.def.rs(DSL 源);
crates/build/re_types_builder/src/codegen/rust/api.rs依据 DSL 生成 Rust 绑定(即 crates/store/re_sdk_types/src/components/vector2d.rs,文件头注明 "DO NOT EDIT! This file was auto-generated");- 生成代码在
re_sdk_types的 components/mod.rs 与 reflection/mod.rs 中统一注册(组件名rerun.components.Vector2D),供日志与查询反射系统使用。
state = "stable"意味着该组件名与 Arrow 布局属于稳定接口。对于需要长期落盘(.rrd/ Parquet)或跨语言交换的 2D 向量数据,可以放心依赖这一布局:FixedSizeList(2 x non-null Float32)既能被 Arrow 生态广泛支持,又因为定长无 null 而保持紧凑(每向量 8 字节)。
小结
Vector2D是 Rerun 中表示 2D 向量的稳定组件,编码为Vec2D,Arrow 布局为FixedSizeList(2 × non-null Float32);- 它在 Rust 端是
#[repr(transparent)]的零开销包装,在 Python 端是encodings.Vec2D的直接子类,语义与内存表示完全统一; - 目前唯一使用方是
Arrows2D图元的必选字段vectors,用于批量绘制二维箭头(可配合origins、radii、colors、labels等可选字段); - 相关定义与实现可在仓库中直接追溯:组件参考文档、编码文档、类型 DSL 源、Rust 生成代码、Python 组件绑定、渲染可视化器。
【免费下载链接】rerunVisualize, query, and stream to train on multimodal robotics data.项目地址: https://gitcode.com/GitHub_Trending/re/rerun
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考