- 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。