cartographer/cartographer/mapping_2d/map_limits.h

194 lines
7.5 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::AlignedBox2d& edge_limits) {
SetLimits(resolution, edge_limits);
}
MapLimits(const double resolution, const double max_x, const double max_y,
const CellLimits& cell_limits) {
SetLimits(resolution, max_x, max_y, cell_limits);
}
MapLimits(const double resolution, const double center_x,
const double center_y) {
SetLimits(resolution, center_x + 100 * resolution,
center_y + 100 * resolution, CellLimits(200, 200));
}
// 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 limits of the grid from edge to edge in meters.
const Eigen::AlignedBox2d& edge_limits() const { return edge_limits_; }
// Returns the limits of the grid between the centers of the edge cells in
// meters.
const Eigen::AlignedBox2d& centered_limits() const {
return centered_limits_;
}
// 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 {
return mapping_2d::GetXYIndexOfCellContainingPoint(
x, y, centered_limits_.max().x(), centered_limits_.max().y(),
resolution_);
}
// 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();
return MapLimits(resolution, bounding_box.cast<double>());
}
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::LaserFan3D laser_fan_3d = sensor::TransformLaserFan3D(
Decompress(data.laser_fan_3d), node.pose.cast<float>());
bounding_box.extend(laser_fan_3d.origin.head<2>());
for (const Eigen::Vector3f& hit : laser_fan_3d.returns) {
bounding_box.extend(hit.head<2>());
}
} else {
const sensor::LaserFan laser_fan = sensor::TransformLaserFan(
data.laser_fan, transform::Project2D(node.pose).cast<float>());
bounding_box.extend(laser_fan.origin);
for (const Eigen::Vector2f& hit : laser_fan.point_cloud) {
bounding_box.extend(hit);
}
for (const Eigen::Vector2f& miss : laser_fan.missing_echo_point_cloud) {
bounding_box.extend(miss);
}
}
}
return bounding_box;
}
private:
// Sets the cell size to the specified resolution in meters and the limits of
// the grid to the specified bounding box in meters.
void SetLimits(double resolution, const Eigen::AlignedBox2d& limits) {
CHECK(!limits.isEmpty());
const int num_x_cells =
common::RoundToInt((mapping_2d::Center(limits.max().y(), resolution) -
mapping_2d::Center(limits.min().y(), resolution)) /
resolution) +
1;
const int num_y_cells =
common::RoundToInt((mapping_2d::Center(limits.max().x(), resolution) -
mapping_2d::Center(limits.min().x(), resolution)) /
resolution) +
1;
SetLimits(resolution, limits.max().x(), limits.max().y(),
CellLimits(num_x_cells, num_y_cells));
}
// Sets the cell size to the specified resolution in meters and the limits of
// the grid to the specified bounding box.
//
// Note that implementing this in terms of the previous SetLimits method
// results in unnecessary (and expensive?) calls to common::RoundToInt.
//
// TODO(whess): Measure whether it really is still too slow. Otherwise,
// simplify.
void SetLimits(double resolution, double max_x, double max_y,
const CellLimits& limits) {
CHECK_GT(resolution, 0.);
CHECK_GT(limits.num_x_cells, 0.);
CHECK_GT(limits.num_y_cells, 0.);
resolution_ = resolution;
cell_limits_ = limits;
centered_limits_.max().x() = Center(max_x, resolution);
centered_limits_.max().y() = Center(max_y, resolution);
centered_limits_.min().x() = centered_limits_.max().x() -
resolution_ * (cell_limits_.num_y_cells - 1);
centered_limits_.min().y() = centered_limits_.max().y() -
resolution_ * (cell_limits_.num_x_cells - 1);
UpdateEdgeLimits();
}
// Updates the edge limits from the previously calculated centered limits.
void UpdateEdgeLimits() {
const double half_resolution = resolution_ / 2.;
edge_limits_.min().x() = centered_limits_.min().x() - half_resolution;
edge_limits_.min().y() = centered_limits_.min().y() - half_resolution;
edge_limits_.max().x() = centered_limits_.max().x() + half_resolution;
edge_limits_.max().y() = centered_limits_.max().y() + half_resolution;
}
double resolution_;
Eigen::AlignedBox2d edge_limits_;
Eigen::AlignedBox2d centered_limits_;
CellLimits cell_limits_;
};
} // namespace mapping_2d
} // namespace cartographer
#endif // CARTOGRAPHER_MAPPING_2D_MAP_LIMITS_H_