将含双精度数组的自定义结构体映射到Eigen::Matrix,如何移除临时变量?
问题描述
我有一个来自第三方库的C语言结构体:
typedef struct Point3d { #ifdef __cplusplus enum{ SIZE = 3 }; typedef double value_type; ///< type export double& operator[](size_t index) { return vec[index];} ///< random-access const double& operator[](size_t index) const { return vec[index];} ///< random-access #endif double vec[3]; ///< point data, e.g. 0=x,1=y,2=z void* data; ///< pointer to additional user-defined data } Point3d;
该结构体被用作数组,示例如下:
Point3d* mypoints = new Point3d[200];
我需要将这个数组中Point3d::vec的3个双精度值映射到Eigen::Matrix<double, 3, Eigen::Dynamic>。参考现有实现写了如下函数:
Eigen::Matrix<double, 3, Eigen::Dynamic> exportToEigen(Point3d *points, int size) { Eigen::MatrixXd result(size, 3); constexpr int stride = sizeof(ALG3D_Point3d)/sizeof(double); Eigen::VectorXd X = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>( &points[0].vec[0], size ); Eigen::VectorXd Y = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>( &points[0].vec[1], size ); Eigen::VectorXd Z = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>( &points[0].vec[2], size ); result << X, Y, Z; return result.transpose(); }
现在想知道:能否在不使用临时X、Y、Z这些Eigen::VectorXd变量的情况下完成该映射?
解决方案
当然可以直接完成映射,不需要临时变量,以下是两种优化实现:
方案1:直接赋值到矩阵行
Eigen::Matrix<double, 3, Eigen::Dynamic> exportToEigen(Point3d *points, int size) { Eigen::Matrix<double, 3, Eigen::Dynamic> result(3, size); constexpr int stride = sizeof(Point3d) / sizeof(double); // 修正原代码中ALG3D_Point3d的拼写错误 // 直接将映射结果赋值到矩阵对应行 result.row(0) = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>( &points[0].vec[0], size ); result.row(1) = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>( &points[0].vec[1], size ); result.row(2) = Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>( &points[0].vec[2], size ); return result; }
方案2:利用逗号初始化语法
Eigen::Matrix<double, 3, Eigen::Dynamic> exportToEigen(Point3d *points, int size) { constexpr int stride = sizeof(Point3d) / sizeof(double); return (Eigen::Matrix<double, 3, Eigen::Dynamic>() << Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>(&points[0].vec[0], size), Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>(&points[0].vec[1], size), Eigen::Map<Eigen::VectorXd, Eigen::Unaligned, Eigen::InnerStride<stride>>(&points[0].vec[2], size) ).finished().transpose(); }
关键说明
- 原代码中
ALG3D_Point3d是笔误,需修正为Point3d,才能正确计算步长stride——该值表示两个相邻同维度坐标之间间隔的double元素数,确保映射能正确跳过结构体中的额外数据。 - 两种方案都直接将
Eigen::Map的结果赋值给目标矩阵的对应部分,避免了临时VectorXd变量的创建,代码更简洁且效率与原实现一致。 - 由于原数据的内存布局(每个点的XYZ连续存储,且点之间包含额外指针数据)与
Eigen::Matrix<double,3,Dynamic>的布局不匹配,无法通过单一映射完成整个矩阵的视图创建,分维度处理是最优的无临时变量方案。
内容的提问来源于stack exchange,提问作者IjonTichy
相关产品推荐
相关产品推荐

