cartographer/cartographer/mapping_2d/map_limits.h

136 lines
5.1 KiB
C++

/*
* Copyright 2016 The Cartographer Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef CARTOGRAPHER_MAPPING_2D_MAP_LIMITS_H_
#define CARTOGRAPHER_MAPPING_2D_MAP_LIMITS_H_
#include <utility>
#include <vector>
#include "Eigen/Core"
#include "Eigen/Geometry"
#include "cartographer/common/math.h"
#include "cartographer/mapping/trajectory_node.h"
#include "cartographer/mapping_2d/xy_index.h"
#include "cartographer/sensor/laser.h"
#include "cartographer/sensor/point_cloud.h"
#include "cartographer/transform/rigid_transform.h"
#include "cartographer/transform/transform.h"
#include "glog/logging.h"
namespace cartographer {
namespace mapping_2d {
// Defines the limits of a grid map. This class must remain inlined for
// performance reasons.
class MapLimits {
public:
MapLimits(const double resolution, const Eigen::Vector2d& max,
const CellLimits& cell_limits)
: resolution_(resolution), max_(max), cell_limits_(cell_limits) {
CHECK_GT(resolution_, 0.);
CHECK_GT(cell_limits.num_x_cells, 0.);
CHECK_GT(cell_limits.num_y_cells, 0.);
}
// Returns the cell size in meters. All cells are square and the resolution is
// the length of one side.
double resolution() const { return resolution_; }
// Returns the corner of the limits, i.e., all pixels have positions with
// smaller coordinates.
const Eigen::Vector2d& max() const { return max_; }
// Returns the limits of the grid in number of cells.
const CellLimits& cell_limits() const { return cell_limits_; }
// Returns the index of the cell containing the point ('x', 'y') which may be
// outside the map, i.e., negative or too large indices that will return
// false for Contains().
Eigen::Array2i GetXYIndexOfCellContainingPoint(const double x,
const double y) const {
// Index values are row major and the top left has Eigen::Array2i::Zero()
// and contains (centered_max_x, centered_max_y). We need to flip and
// rotate.
return Eigen::Array2i(
common::RoundToInt((max_.y() - y) / resolution_ - 0.5),
common::RoundToInt((max_.x() - x) / resolution_ - 0.5));
}
// Returns true of the ProbabilityGrid contains 'xy_index'.
bool Contains(const Eigen::Array2i& xy_index) const {
return (Eigen::Array2i(0, 0) <= xy_index).all() &&
(xy_index <
Eigen::Array2i(cell_limits_.num_x_cells, cell_limits_.num_y_cells))
.all();
}
// Computes MapLimits that contain the origin, and all laser rays (both
// returns and missing echoes) in the 'trajectory'.
static MapLimits ComputeMapLimits(
const double resolution,
const std::vector<mapping::TrajectoryNode>& trajectory_nodes) {
Eigen::AlignedBox2f bounding_box = ComputeMapBoundingBox(trajectory_nodes);
// Add some padding to ensure all rays are still contained in the map after
// discretization.
const float kPadding = 3.f * resolution;
bounding_box.min() -= kPadding * Eigen::Vector2f::Ones();
bounding_box.max() += kPadding * Eigen::Vector2f::Ones();
const Eigen::Vector2d pixel_sizes =
bounding_box.sizes().cast<double>() / resolution;
return MapLimits(resolution, bounding_box.max().cast<double>(),
CellLimits(common::RoundToInt(pixel_sizes.y()),
common::RoundToInt(pixel_sizes.x())));
}
static Eigen::AlignedBox2f ComputeMapBoundingBox(
const std::vector<mapping::TrajectoryNode>& trajectory_nodes) {
Eigen::AlignedBox2f bounding_box(Eigen::Vector2f::Zero());
for (const auto& node : trajectory_nodes) {
const auto& data = *node.constant_data;
if (!data.laser_fan_3d.returns.empty()) {
const sensor::LaserFan laser_fan = sensor::TransformLaserFan(
Decompress(data.laser_fan_3d), node.pose.cast<float>());
bounding_box.extend(laser_fan.origin.head<2>());
for (const Eigen::Vector3f& hit : laser_fan.returns) {
bounding_box.extend(hit.head<2>());
}
} else {
const sensor::LaserFan laser_fan = sensor::TransformLaserFan(
data.laser_fan_2d, node.pose.cast<float>());
bounding_box.extend(laser_fan.origin.head<2>());
for (const Eigen::Vector3f& hit : laser_fan.returns) {
bounding_box.extend(hit.head<2>());
}
for (const Eigen::Vector3f& miss : laser_fan.misses) {
bounding_box.extend(miss.head<2>());
}
}
}
return bounding_box;
}
private:
double resolution_;
Eigen::Vector2d max_;
CellLimits cell_limits_;
};
} // namespace mapping_2d
} // namespace cartographer
#endif // CARTOGRAPHER_MAPPING_2D_MAP_LIMITS_H_