- MapById中的IdType、DataType是两个模板参数,目前只会出现二种场景。一是node时,对应NodeId/TrajectoryNode;二是submap时,对应SubmapId/InternalSubmapData。
一、MapById
MapById是cartographer提供的一个工具类,行为类似std::map。
<cartographer>/cartographer/mapping/id.h ------ template <typename IdType, typename DataType> class MapById { ... private: struct MapByIndex { bool can_append_ = true; std::map<int, DataType> data_; }; static int GetIndex(const NodeId& id) { return id.node_index; } static int GetIndex(const SubmapId& id) { return id.submap_index; } std::map<int, MapByIndex> trajectories_; };
MapById有一个std::map<int, MapByIndex>类型的成员trajectories_,用于存储映射数据。MapById的first是二级key,第一级是trajectory_id,第二级是node_id或submap_id,第二级key的类型一定是int。这解释了为什么MapByIndex中的data_这个std::map的first是int。
IdType、DataType是两个模板参数,目前只会出现二种场景,一是node时,二是submap时。
模板类 | 描述 | node时类型 | submap时类型 |
IdType | 作为MapById中的first | NodeId | SubmapId |
DataType | 作为MapById中的second | TrajectoryNode | InternalSubmapData |
为加深理解,让分析下MapById的两个成员函数at、Append。
const DataType& at(const IdType& id) const { return trajectories_.at(id.trajectory_id).data_.at(GetIndex(id)); }
at的作用是通过IdType得到DataType。之前已说过,MapById的key是两级key,trajectories_的first是一级key,data_这个std::map的first则是二级key,于是由这两个人key,就可得到存储在data_的second。可以肯定,得到的DataType的真实类型不是TrajectoryNode,就是InternalSubmapData。
// Appends data to a 'trajectory_id', creating trajectories as needed. IdType Append(const int trajectory_id, const DataType& data) { CHECK_GE(trajectory_id, 0); auto& trajectory = trajectories_[trajectory_id]; CHECK(trajectory.can_append_); const int index = trajectory.data_.empty() ? 0 : trajectory.data_.rbegin()->first + 1; trajectory.data_.emplace(index, data); return IdType{trajectory_id, index}; }
向参数trajectory_id指定的轨迹添加数据,如果该轨迹不存在,就创建。“就创建”指的是trajectories_中以trajectory_id为key的节点。要注意,二级key,也就栈内变量index,不是DataType成员,data将总是添加到trajectories_[trajectory_id]这条轨迹的末尾。
在计算index时,不清楚为什么不用可更为简单的“index = trajectory.data_.size()”,难道trajectory.data_中的first,即二级key的值,可能不连续?举个例子,某一时刻会删除trajectory.data_[i]这条(key, value)?
Append返回这个新添加节点在轨迹内的IdType。