parent
ea55e837d2
commit
cb41777b9e
|
@ -19,11 +19,13 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <ostream>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
|
||||
#include "cartographer/common/port.h"
|
||||
#include "glog/logging.h"
|
||||
|
||||
namespace cartographer {
|
||||
|
@ -109,7 +111,8 @@ class NestedVectorsById {
|
|||
std::vector<std::vector<ValueType>> data_;
|
||||
};
|
||||
|
||||
// Like std::map, but indexed by 'IdType' which can be 'NodeId' or 'SubmapId'.
|
||||
// Reminiscent of std::map, but indexed by 'IdType' which can be 'NodeId' or
|
||||
// 'SubmapId'.
|
||||
template <typename IdType, typename DataType>
|
||||
class MapById {
|
||||
private:
|
||||
|
@ -121,25 +124,24 @@ class MapById {
|
|||
const DataType& data;
|
||||
};
|
||||
|
||||
class ConstIterator
|
||||
: public std::iterator<std::forward_iterator_tag, IdDataReference> {
|
||||
class ConstIterator {
|
||||
public:
|
||||
explicit ConstIterator(const MapById& map_by_id)
|
||||
: current_trajectory_(map_by_id.trajectories_.begin()),
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = IdDataReference;
|
||||
using difference_type = int64;
|
||||
using pointer = const IdDataReference*;
|
||||
using reference = const IdDataReference&;
|
||||
|
||||
explicit ConstIterator(const MapById& map_by_id, const int trajectory_id)
|
||||
: current_trajectory_(
|
||||
map_by_id.trajectories_.lower_bound(trajectory_id)),
|
||||
end_trajectory_(map_by_id.trajectories_.end()) {
|
||||
if (current_trajectory_ != end_trajectory_) {
|
||||
current_data_ = current_trajectory_->second.data_.begin();
|
||||
end_data_ = current_trajectory_->second.data_.end();
|
||||
AdvanceToValidDataIterator();
|
||||
}
|
||||
}
|
||||
|
||||
static ConstIterator EndIterator(const MapById& map_by_id) {
|
||||
auto it = ConstIterator(map_by_id);
|
||||
it.current_trajectory_ = it.end_trajectory_;
|
||||
return it;
|
||||
}
|
||||
|
||||
IdDataReference operator*() const {
|
||||
CHECK(current_trajectory_ != end_trajectory_);
|
||||
return IdDataReference{
|
||||
|
@ -154,6 +156,16 @@ class MapById {
|
|||
return *this;
|
||||
}
|
||||
|
||||
ConstIterator& operator--() {
|
||||
while (current_trajectory_ == end_trajectory_ ||
|
||||
current_data_ == current_trajectory_->second.data_.begin()) {
|
||||
--current_trajectory_;
|
||||
current_data_ = current_trajectory_->second.data_.end();
|
||||
}
|
||||
--current_data_;
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool operator==(const ConstIterator& it) const {
|
||||
if (current_trajectory_ == end_trajectory_ ||
|
||||
it.current_trajectory_ == it.end_trajectory_) {
|
||||
|
@ -168,20 +180,18 @@ class MapById {
|
|||
private:
|
||||
void AdvanceToValidDataIterator() {
|
||||
CHECK(current_trajectory_ != end_trajectory_);
|
||||
while (current_data_ == end_data_) {
|
||||
while (current_data_ == current_trajectory_->second.data_.end()) {
|
||||
++current_trajectory_;
|
||||
if (current_trajectory_ == end_trajectory_) {
|
||||
return;
|
||||
}
|
||||
current_data_ = current_trajectory_->second.data_.begin();
|
||||
end_data_ = current_trajectory_->second.data_.end();
|
||||
}
|
||||
}
|
||||
|
||||
typename std::map<int, MapByIndex>::const_iterator current_trajectory_;
|
||||
typename std::map<int, MapByIndex>::const_iterator end_trajectory_;
|
||||
typename std::map<int, DataType>::const_iterator current_data_;
|
||||
typename std::map<int, DataType>::const_iterator end_data_;
|
||||
};
|
||||
|
||||
// Appends data to a 'trajectory_id', creating trajectories as needed.
|
||||
|
@ -217,6 +227,11 @@ class MapById {
|
|||
trajectory.data_.erase(it);
|
||||
}
|
||||
|
||||
bool Contains(const IdType& id) const {
|
||||
return trajectories_.count(id.trajectory_id) != 0 &&
|
||||
trajectories_.at(id.trajectory_id).data_.count(GetIndex(id)) != 0;
|
||||
}
|
||||
|
||||
const DataType& at(const IdType& id) const {
|
||||
return trajectories_.at(id.trajectory_id).data_.at(GetIndex(id));
|
||||
}
|
||||
|
@ -225,8 +240,25 @@ class MapById {
|
|||
return trajectories_.at(id.trajectory_id).data_.at(GetIndex(id));
|
||||
}
|
||||
|
||||
ConstIterator begin() const { return ConstIterator(*this); }
|
||||
ConstIterator end() const { return ConstIterator::EndIterator(*this); }
|
||||
// Support querying by trajectory.
|
||||
ConstIterator BeginOfTrajectory(const int trajectory_id) const {
|
||||
return ConstIterator(*this, trajectory_id);
|
||||
}
|
||||
ConstIterator EndOfTrajectory(const int trajectory_id) const {
|
||||
return BeginOfTrajectory(trajectory_id + 1);
|
||||
}
|
||||
|
||||
// Returns 0 if 'trajectory_id' does not exist.
|
||||
size_t SizeOfTrajectoryOrZero(const int trajectory_id) const {
|
||||
return trajectories_.count(trajectory_id)
|
||||
? trajectories_.at(trajectory_id).data_.size()
|
||||
: 0;
|
||||
}
|
||||
|
||||
ConstIterator begin() const { return BeginOfTrajectory(0); }
|
||||
ConstIterator end() const {
|
||||
return BeginOfTrajectory(std::numeric_limits<int>::max());
|
||||
}
|
||||
|
||||
bool empty() const { return begin() == end(); }
|
||||
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "cartographer/mapping/id.h"
|
||||
|
||||
#include <deque>
|
||||
#include <iterator>
|
||||
#include <utility>
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
|
@ -40,6 +41,9 @@ TEST(IdTest, MapByIdIterator) {
|
|||
map_by_id.Append(42, 3);
|
||||
map_by_id.Append(0, 0);
|
||||
map_by_id.Append(0, 1);
|
||||
EXPECT_EQ(2, (*map_by_id.BeginOfTrajectory(7)).data);
|
||||
EXPECT_TRUE(std::next(map_by_id.BeginOfTrajectory(7)) ==
|
||||
map_by_id.EndOfTrajectory(7));
|
||||
std::deque<std::pair<NodeId, int>> expected_id_data = {
|
||||
{NodeId{0, 0}, 0},
|
||||
{NodeId{0, 1}, 1},
|
||||
|
@ -55,6 +59,23 @@ TEST(IdTest, MapByIdIterator) {
|
|||
EXPECT_TRUE(expected_id_data.empty());
|
||||
}
|
||||
|
||||
TEST(IdTest, MapByIdPrevIterator) {
|
||||
MapById<NodeId, int> map_by_id;
|
||||
map_by_id.Append(42, 42);
|
||||
auto it = map_by_id.end();
|
||||
ASSERT_TRUE(it != map_by_id.begin());
|
||||
std::advance(it, -1);
|
||||
EXPECT_TRUE(it == map_by_id.begin());
|
||||
}
|
||||
|
||||
TEST(IdTest, InsertIntoMapById) {
|
||||
MapById<NodeId, int> map_by_id;
|
||||
EXPECT_EQ(0, map_by_id.SizeOfTrajectoryOrZero(42));
|
||||
map_by_id.Append(42, 42);
|
||||
map_by_id.Insert(NodeId{42, 5}, 42);
|
||||
EXPECT_EQ(2, map_by_id.SizeOfTrajectoryOrZero(42));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
} // namespace mapping
|
||||
} // namespace cartographer
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <iterator>
|
||||
#include <limits>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
|
@ -55,30 +56,27 @@ std::vector<mapping::SubmapId> SparsePoseGraph::GrowSubmapTransformsAsNeeded(
|
|||
const int trajectory_id,
|
||||
const std::vector<std::shared_ptr<const Submap>>& insertion_submaps) {
|
||||
CHECK(!insertion_submaps.empty());
|
||||
auto submap_data = optimization_problem_.submap_data();
|
||||
const auto& submap_data = optimization_problem_.submap_data();
|
||||
if (insertion_submaps.size() == 1) {
|
||||
// If we don't already have an entry for the first submap, add one.
|
||||
if (static_cast<size_t>(trajectory_id) >= submap_data.size() ||
|
||||
submap_data[trajectory_id].empty()) {
|
||||
if (submap_data.SizeOfTrajectoryOrZero(trajectory_id) == 0) {
|
||||
optimization_problem_.AddSubmap(
|
||||
trajectory_id,
|
||||
sparse_pose_graph::ComputeSubmapPose(*insertion_submaps[0]));
|
||||
submap_data = optimization_problem_.submap_data();
|
||||
}
|
||||
CHECK_EQ(submap_data[trajectory_id].size(), 1);
|
||||
CHECK_EQ(1, submap_data.SizeOfTrajectoryOrZero(trajectory_id));
|
||||
const mapping::SubmapId submap_id{trajectory_id, 0};
|
||||
CHECK(submap_data_.at(submap_id).submap == insertion_submaps.front());
|
||||
return {submap_id};
|
||||
}
|
||||
CHECK_EQ(2, insertion_submaps.size());
|
||||
CHECK(!submap_data.at(trajectory_id).empty());
|
||||
const mapping::SubmapId last_submap_id{
|
||||
trajectory_id, submap_data.at(trajectory_id).rbegin()->first};
|
||||
const auto end_it = submap_data.EndOfTrajectory(trajectory_id);
|
||||
CHECK(submap_data.BeginOfTrajectory(trajectory_id) != end_it);
|
||||
const mapping::SubmapId last_submap_id = (*std::prev(end_it)).id;
|
||||
if (submap_data_.at(last_submap_id).submap == insertion_submaps.front()) {
|
||||
// In this case, 'last_submap_id' is the ID of 'insertions_submaps.front()'
|
||||
// and 'insertions_submaps.back()' is new.
|
||||
const auto& first_submap_pose =
|
||||
submap_data.at(trajectory_id).at(last_submap_id.submap_index).pose;
|
||||
const auto& first_submap_pose = submap_data.at(last_submap_id).pose;
|
||||
optimization_problem_.AddSubmap(
|
||||
trajectory_id,
|
||||
first_submap_pose *
|
||||
|
@ -189,10 +187,7 @@ void SparsePoseGraph::ComputeConstraint(const mapping::NodeId& node_id,
|
|||
// submap's trajectory, it suffices to do a match constrained to a local
|
||||
// search window.
|
||||
const transform::Rigid2d initial_relative_pose =
|
||||
optimization_problem_.submap_data()
|
||||
.at(submap_id.trajectory_id)
|
||||
.at(submap_id.submap_index)
|
||||
.pose.inverse() *
|
||||
optimization_problem_.submap_data().at(submap_id).pose.inverse() *
|
||||
optimization_problem_.node_data()
|
||||
.at(node_id.trajectory_id)
|
||||
.at(node_id.node_index)
|
||||
|
@ -250,10 +245,7 @@ void SparsePoseGraph::ComputeConstraintsForScan(
|
|||
constant_data->initial_pose *
|
||||
transform::Rigid3d::Rotation(constant_data->gravity_alignment.inverse()));
|
||||
const transform::Rigid2d optimized_pose =
|
||||
optimization_problem_.submap_data()
|
||||
.at(matching_id.trajectory_id)
|
||||
.at(matching_id.submap_index)
|
||||
.pose *
|
||||
optimization_problem_.submap_data().at(matching_id).pose *
|
||||
sparse_pose_graph::ComputeSubmapPose(*insertion_submaps.front())
|
||||
.inverse() *
|
||||
pose;
|
||||
|
@ -428,14 +420,9 @@ void SparsePoseGraph::AddSubmapFromProto(const int trajectory_id,
|
|||
submap_data_.Append(trajectory_id, SubmapData());
|
||||
submap_data_.at(submap_id).submap = submap_ptr;
|
||||
// Immediately show the submap at the optimized pose.
|
||||
CHECK_GE(static_cast<size_t>(submap_data_.num_trajectories()),
|
||||
optimized_submap_transforms_.size());
|
||||
optimized_submap_transforms_.resize(submap_data_.num_trajectories());
|
||||
CHECK_EQ(optimized_submap_transforms_.at(trajectory_id).size(),
|
||||
submap_id.submap_index);
|
||||
optimized_submap_transforms_.at(trajectory_id)
|
||||
.emplace(submap_id.submap_index,
|
||||
sparse_pose_graph::SubmapData{initial_pose_2d});
|
||||
CHECK_EQ(submap_id,
|
||||
optimized_submap_transforms_.Append(
|
||||
trajectory_id, sparse_pose_graph::SubmapData{initial_pose_2d}));
|
||||
AddWorkItem([this, submap_id, initial_pose_2d]() REQUIRES(mutex_) {
|
||||
CHECK_EQ(frozen_trajectories_.count(submap_id.trajectory_id), 1);
|
||||
submap_data_.at(submap_id).state = SubmapState::kFinished;
|
||||
|
@ -500,7 +487,7 @@ void SparsePoseGraph::RunOptimization() {
|
|||
optimization_problem_.Solve(constraints_, frozen_trajectories_);
|
||||
common::MutexLocker locker(&mutex_);
|
||||
|
||||
const auto submap_data = optimization_problem_.submap_data();
|
||||
const auto& submap_data = optimization_problem_.submap_data();
|
||||
const auto& node_data = optimization_problem_.node_data();
|
||||
for (int trajectory_id = 0;
|
||||
trajectory_id != static_cast<int>(node_data.size()); ++trajectory_id) {
|
||||
|
@ -601,19 +588,18 @@ SparsePoseGraph::GetAllSubmapData() {
|
|||
}
|
||||
|
||||
transform::Rigid3d SparsePoseGraph::ComputeLocalToGlobalTransform(
|
||||
const std::vector<std::map<int, sparse_pose_graph::SubmapData>>&
|
||||
const mapping::MapById<mapping::SubmapId, sparse_pose_graph::SubmapData>&
|
||||
submap_transforms,
|
||||
const int trajectory_id) const {
|
||||
if (trajectory_id >= static_cast<int>(submap_transforms.size()) ||
|
||||
submap_transforms.at(trajectory_id).empty()) {
|
||||
auto begin_it = submap_transforms.BeginOfTrajectory(trajectory_id);
|
||||
auto end_it = submap_transforms.EndOfTrajectory(trajectory_id);
|
||||
if (begin_it == end_it) {
|
||||
return transform::Rigid3d::Identity();
|
||||
}
|
||||
|
||||
const int submap_index = submap_transforms.at(trajectory_id).rbegin()->first;
|
||||
const mapping::SubmapId last_optimized_submap_id{trajectory_id, submap_index};
|
||||
const mapping::SubmapId last_optimized_submap_id = (*std::prev(end_it)).id;
|
||||
// Accessing 'local_pose' in Submap is okay, since the member is const.
|
||||
return transform::Embed3D(
|
||||
submap_transforms.at(trajectory_id).at(submap_index).pose) *
|
||||
submap_transforms.at(last_optimized_submap_id).pose) *
|
||||
submap_data_.at(last_optimized_submap_id)
|
||||
.submap->local_pose()
|
||||
.inverse();
|
||||
|
@ -625,16 +611,10 @@ mapping::SparsePoseGraph::SubmapData SparsePoseGraph::GetSubmapDataUnderLock(
|
|||
return {};
|
||||
}
|
||||
auto submap = submap_data_.at(submap_id).submap;
|
||||
if (submap_id.trajectory_id <
|
||||
static_cast<int>(optimized_submap_transforms_.size()) &&
|
||||
submap_id.submap_index < static_cast<int>(optimized_submap_transforms_
|
||||
.at(submap_id.trajectory_id)
|
||||
.size())) {
|
||||
if (optimized_submap_transforms_.Contains(submap_id)) {
|
||||
// We already have an optimized pose.
|
||||
return {submap, transform::Embed3D(
|
||||
optimized_submap_transforms_.at(submap_id.trajectory_id)
|
||||
.at(submap_id.submap_index)
|
||||
.pose)};
|
||||
optimized_submap_transforms_.at(submap_id).pose)};
|
||||
}
|
||||
// We have to extrapolate.
|
||||
return {submap, ComputeLocalToGlobalTransform(optimized_submap_transforms_,
|
||||
|
@ -647,7 +627,8 @@ SparsePoseGraph::TrimmingHandle::TrimmingHandle(SparsePoseGraph* const parent)
|
|||
|
||||
int SparsePoseGraph::TrimmingHandle::num_submaps(
|
||||
const int trajectory_id) const {
|
||||
return parent_->optimization_problem_.submap_data().at(trajectory_id).size();
|
||||
const auto& submap_data = parent_->optimization_problem_.submap_data();
|
||||
return submap_data.SizeOfTrajectoryOrZero(trajectory_id);
|
||||
}
|
||||
|
||||
void SparsePoseGraph::TrimmingHandle::MarkSubmapAsTrimmed(
|
||||
|
|
|
@ -161,7 +161,7 @@ class SparsePoseGraph : public mapping::SparsePoseGraph {
|
|||
// Computes the local to global frame transform based on the given optimized
|
||||
// 'submap_transforms'.
|
||||
transform::Rigid3d ComputeLocalToGlobalTransform(
|
||||
const std::vector<std::map<int, sparse_pose_graph::SubmapData>>&
|
||||
const mapping::MapById<mapping::SubmapId, sparse_pose_graph::SubmapData>&
|
||||
submap_transforms,
|
||||
int trajectory_id) const REQUIRES(mutex_);
|
||||
|
||||
|
@ -214,7 +214,7 @@ class SparsePoseGraph : public mapping::SparsePoseGraph {
|
|||
int num_trajectory_nodes_ GUARDED_BY(mutex_) = 0;
|
||||
|
||||
// Current submap transforms used for displaying data.
|
||||
std::vector<std::map<int, sparse_pose_graph::SubmapData>>
|
||||
mapping::MapById<mapping::SubmapId, sparse_pose_graph::SubmapData>
|
||||
optimized_submap_transforms_ GUARDED_BY(mutex_);
|
||||
|
||||
// List of all trimmers to consult when optimizations finish.
|
||||
|
|
|
@ -255,15 +255,9 @@ const std::vector<std::map<int, NodeData>>& OptimizationProblem::node_data()
|
|||
return node_data_;
|
||||
}
|
||||
|
||||
std::vector<std::map<int, SubmapData>> OptimizationProblem::submap_data()
|
||||
const {
|
||||
std::vector<std::map<int, SubmapData>> result;
|
||||
for (const auto& submap_id_data : submap_data_) {
|
||||
result.resize(submap_id_data.id.trajectory_id + 1);
|
||||
result[submap_id_data.id.trajectory_id].emplace(
|
||||
submap_id_data.id.submap_index, submap_id_data.data);
|
||||
}
|
||||
return result;
|
||||
const mapping::MapById<mapping::SubmapId, SubmapData>&
|
||||
OptimizationProblem::submap_data() const {
|
||||
return submap_data_;
|
||||
}
|
||||
|
||||
} // namespace sparse_pose_graph
|
||||
|
|
|
@ -80,7 +80,7 @@ class OptimizationProblem {
|
|||
const std::set<int>& frozen_trajectories);
|
||||
|
||||
const std::vector<std::map<int, NodeData>>& node_data() const;
|
||||
std::vector<std::map<int, SubmapData>> submap_data() const;
|
||||
const mapping::MapById<mapping::SubmapId, SubmapData>& submap_data() const;
|
||||
|
||||
private:
|
||||
struct TrajectoryData {
|
||||
|
|
|
@ -58,9 +58,14 @@ class CompressedPointCloud {
|
|||
};
|
||||
|
||||
// Forward iterator for compressed point clouds.
|
||||
class CompressedPointCloud::ConstIterator
|
||||
: public std::iterator<std::forward_iterator_tag, Eigen::Vector3f> {
|
||||
class CompressedPointCloud::ConstIterator {
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = Eigen::Vector3f;
|
||||
using difference_type = int64;
|
||||
using pointer = const Eigen::Vector3f*;
|
||||
using reference = const Eigen::Vector3f&;
|
||||
|
||||
// Creates begin iterator.
|
||||
explicit ConstIterator(const CompressedPointCloud* compressed_point_cloud);
|
||||
|
||||
|
|
Loading…
Reference in New Issue