Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Simplify chunked octree traversals #84

Merged
merged 22 commits into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from 19 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
4be1065
Explicitly define struct ctors for compatibility with emplace_back
victorreijgwart Nov 8, 2024
1f365fb
Refactor TfTransformer to return by value, signal failure using optional
victorreijgwart Nov 8, 2024
ab59bd9
Use ChunkedNdtreeNodeRef to simplify chunked map accessors
victorreijgwart Nov 9, 2024
0b1a86f
Minor code cleanup
victorreijgwart Nov 10, 2024
af7ecc4
Simplify integrator code by using new ChunkedNdtree API features
victorreijgwart Sep 25, 2024
129f95b
Add QueryAccelerator for chunked wavelet octrees
victorreijgwart Nov 11, 2024
4f85fd8
Correctly handle constness in chunked octree node ptrs/refs
victorreijgwart Nov 11, 2024
bd9cfcf
Minor code cleanup
victorreijgwart Nov 11, 2024
35ec8ae
Add accelerated HashedChunkedWaveletOctree accessors to Python API
victorreijgwart Nov 11, 2024
6eade89
Improve consistency between coding using regular and chunked octrees
victorreijgwart Nov 11, 2024
d6e7f74
Simplify and improve clarity of old code
victorreijgwart Nov 12, 2024
26fba56
Add method to erase individual nodes from chunked octrees
victorreijgwart Nov 12, 2024
beb4c5c
Simplify thresholding and pruning code
victorreijgwart Nov 18, 2024
642680f
Optimize child node access by eliminating redundant lookup
victorreijgwart Nov 18, 2024
9269a3b
Code cleanup and consistency improvements to prepare PR#84
victorreijgwart Nov 21, 2024
620f161
Tidy up constructors and moves vs copies
victorreijgwart Nov 21, 2024
3de0323
Attempt to address 'maybe uninitialized' warnings from GCC >= 11
victorreijgwart Nov 21, 2024
d7a20b3
Switch from `nullptr_t` to `std::nullptr_t` type for portability
victorreijgwart Nov 21, 2024
75f4edf
Reintroduce the option to profile with Tracy
victorreijgwart Nov 22, 2024
57ad3bc
Revert "Reintroduce the option to profile with Tracy"
victorreijgwart Nov 25, 2024
9c9554d
Minor release management script improvements
victorreijgwart Nov 25, 2024
85320a0
Update changelogs
victorreijgwart Nov 25, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions docs/pages/tutorials/python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -104,10 +104,6 @@ If you need to look up multiple node values, we recommend using our batched quer
.. literalinclude:: ../../../examples/python/queries/accelerated_queries.py
:language: python

.. note::

So far batched queries are only implemented for HashedWaveletOctree maps. We will add support for HashedChunkedWaveletOctree maps in the near future.

.. _python-code-examples-interpolation:

Real coordinates
Expand Down
4 changes: 2 additions & 2 deletions interfaces/ros1/wavemap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/../../../library/cpp

# Include the library's tests in catkin's run_tests target
include(cmake/append_to_catkin_tests.cmake)
append_to_catkin_tests(test_wavemap_io)
append_to_catkin_tests(test_wavemap_core)
append_to_catkin_tests(test_wavemap_io)

# Support installs
# Mark targets for installation
Expand All @@ -38,6 +38,6 @@ install(TARGETS wavemap_core wavemap_io wavemap_pipeline
RUNTIME DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION})
# Mark headers for installation
install(DIRECTORY
${CMAKE_CURRENT_SOURCE_DIR}/../../../library/cpp/include/wavemap/
"${CMAKE_CURRENT_SOURCE_DIR}/../../../library/cpp/include/wavemap/"
DESTINATION ${CATKIN_PACKAGE_INCLUDE_DESTINATION}
FILES_MATCHING PATTERN "*.h")
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#define WAVEMAP_ROS_UTILS_TF_TRANSFORMER_H_

#include <map>
#include <optional>
#include <string>

#include <tf2_ros/transform_listener.h>
Expand All @@ -26,13 +27,11 @@ class TfTransformer {
const ros::Time& frame_timestamp);

// Lookup transforms and convert them to Kindr
bool lookupTransform(const std::string& to_frame_id,
const std::string& from_frame_id,
const ros::Time& frame_timestamp,
Transformation3D& transform);
bool lookupLatestTransform(const std::string& to_frame_id,
const std::string& from_frame_id,
Transformation3D& transform);
std::optional<Transformation3D> lookupTransform(
const std::string& to_frame_id, const std::string& from_frame_id,
const ros::Time& frame_timestamp);
std::optional<Transformation3D> lookupLatestTransform(
const std::string& to_frame_id, const std::string& from_frame_id);

// Strip leading slashes if needed to avoid TF errors
static std::string sanitizeFrameId(const std::string& string);
Expand All @@ -50,10 +49,9 @@ class TfTransformer {
bool waitForTransformImpl(const std::string& to_frame_id,
const std::string& from_frame_id,
const ros::Time& frame_timestamp) const;
bool lookupTransformImpl(const std::string& to_frame_id,
const std::string& from_frame_id,
const ros::Time& frame_timestamp,
Transformation3D& transform);
std::optional<Transformation3D> lookupTransformImpl(
const std::string& to_frame_id, const std::string& from_frame_id,
const ros::Time& frame_timestamp);
};
} // namespace wavemap

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,11 @@ void DepthImageTopicInput::processQueue() {
: config_.sensor_frame_id;

// Get the sensor pose in world frame
Transformation3D T_W_C;
const ros::Time stamp =
oldest_msg.header.stamp + ros::Duration(config_.time_offset);
if (!transformer_->lookupTransform(world_frame_, sensor_frame_id, stamp,
T_W_C)) {
const auto T_W_C =
transformer_->lookupTransform(world_frame_, sensor_frame_id, stamp);
if (!T_W_C) {
const auto newest_msg = depth_image_queue_.back();
if ((newest_msg.header.stamp - oldest_msg.header.stamp).toSec() <
config_.max_wait_for_pose) {
Expand Down Expand Up @@ -105,7 +105,7 @@ void DepthImageTopicInput::processQueue() {
// Create the posed depth image input
PosedImage<> posed_depth_image(cv_image->image.rows, cv_image->image.cols);
cv::cv2eigen<FloatingPoint>(cv_image->image, posed_depth_image.getData());
posed_depth_image.setPose(T_W_C);
posed_depth_image.setPose(*T_W_C);

// Integrate the depth image
ROS_DEBUG_STREAM("Inserting depth image with "
Expand Down
10 changes: 5 additions & 5 deletions interfaces/ros1/wavemap_ros/src/inputs/pointcloud_topic_input.cc
Original file line number Diff line number Diff line change
Expand Up @@ -236,16 +236,16 @@ void PointcloudTopicInput::processQueue() {
}
} else {
// Get the pointcloud's pose
Transformation3D T_W_C;
if (!transformer_->lookupTransform(
world_frame_, oldest_msg.getSensorFrame(),
convert::nanoSecondsToRosTime(oldest_msg.getTimeBase()), T_W_C)) {
const auto T_W_C = transformer_->lookupTransform(
world_frame_, oldest_msg.getSensorFrame(),
convert::nanoSecondsToRosTime(oldest_msg.getTimeBase()));
if (!T_W_C) {
// Try to get this pointcloud's pose again at the next iteration
return;
}

// Convert to a posed pointcloud
posed_pointcloud = PosedPointcloud<>(T_W_C);
posed_pointcloud = PosedPointcloud<>(*T_W_C);
posed_pointcloud.resize(oldest_msg.getPoints().size());
for (unsigned point_idx = 0; point_idx < oldest_msg.getPoints().size();
++point_idx) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,9 @@ void CropMapOperation::run(bool force_run) {
return;
}

Transformation3D T_W_B;
if (!transformer_->lookupTransform(world_frame_, config_.body_frame,
current_time, T_W_B)) {
const auto T_W_B = transformer_->lookupTransform(
world_frame_, config_.body_frame, current_time);
if (!T_W_B) {
ROS_WARN_STREAM(
"Could not look up center point for map cropping. TF lookup of "
"body_frame \""
Expand All @@ -62,7 +62,7 @@ void CropMapOperation::run(bool force_run) {

const IndexElement tree_height = occupancy_map_->getTreeHeight();
const FloatingPoint min_cell_width = occupancy_map_->getMinCellWidth();
const Point3D t_W_B = T_W_B.getPosition();
const Point3D t_W_B = T_W_B->getPosition();

auto indicator_fn = [tree_height, min_cell_width, &config = config_, &t_W_B](
const Index3D& block_index, const auto& /*block*/) {
Expand Down
16 changes: 8 additions & 8 deletions interfaces/ros1/wavemap_ros/src/utils/pointcloud_undistorter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,15 @@ PointcloudUndistorter::Result PointcloudUndistorter::undistortPointcloud(
undistortion::StampedPoseBuffer pose_buffer;
pose_buffer.reserve(num_time_steps);
for (int step_idx = 0; step_idx < num_time_steps; ++step_idx) {
auto& stamped_pose = pose_buffer.emplace_back();
stamped_pose.stamp = start_time + step_idx * step_size;
if (!transformer_->lookupTransform(
fixed_frame, stamped_pointcloud.getSensorFrame(),
convert::nanoSecondsToRosTime(stamped_pose.stamp),
stamped_pose.pose)) {
const auto stamp = start_time + step_idx * step_size;
const auto pose = transformer_->lookupTransform(
fixed_frame, stamped_pointcloud.getSensorFrame(),
convert::nanoSecondsToRosTime(stamp));
if (pose) {
pose_buffer.emplace_back(stamp, *pose);
} else {
ROS_WARN_STREAM("Failed to buffer intermediate pose at time "
<< convert::nanoSecondsToRosTime(stamped_pose.stamp)
<< ".");
<< convert::nanoSecondsToRosTime(stamp) << ".");
return Result::kIntermediateTimeNotInTfBuffer;
}
}
Expand Down
29 changes: 12 additions & 17 deletions interfaces/ros1/wavemap_ros/src/utils/tf_transformer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -20,20 +20,17 @@ bool TfTransformer::waitForTransform(const std::string& to_frame_id,
sanitizeFrameId(from_frame_id), frame_timestamp);
}

bool TfTransformer::lookupLatestTransform(const std::string& to_frame_id,
const std::string& from_frame_id,
Transformation3D& transform) {
std::optional<Transformation3D> TfTransformer::lookupLatestTransform(
const std::string& to_frame_id, const std::string& from_frame_id) {
return lookupTransformImpl(sanitizeFrameId(to_frame_id),
sanitizeFrameId(from_frame_id), {}, transform);
sanitizeFrameId(from_frame_id), {});
}

bool TfTransformer::lookupTransform(const std::string& to_frame_id,
const std::string& from_frame_id,
const ros::Time& frame_timestamp,
Transformation3D& transform) {
std::optional<Transformation3D> TfTransformer::lookupTransform(
const std::string& to_frame_id, const std::string& from_frame_id,
const ros::Time& frame_timestamp) {
return lookupTransformImpl(sanitizeFrameId(to_frame_id),
sanitizeFrameId(from_frame_id), frame_timestamp,
transform);
sanitizeFrameId(from_frame_id), frame_timestamp);
}

std::string TfTransformer::sanitizeFrameId(const std::string& string) {
Expand Down Expand Up @@ -64,16 +61,14 @@ bool TfTransformer::waitForTransformImpl(
return false;
}

bool TfTransformer::lookupTransformImpl(const std::string& to_frame_id,
const std::string& from_frame_id,
const ros::Time& frame_timestamp,
Transformation3D& transform) {
std::optional<Transformation3D> TfTransformer::lookupTransformImpl(
const std::string& to_frame_id, const std::string& from_frame_id,
const ros::Time& frame_timestamp) {
if (!isTransformAvailable(to_frame_id, from_frame_id, frame_timestamp)) {
return false;
return std::nullopt;
}
geometry_msgs::TransformStamped transform_msg =
tf_buffer_.lookupTransform(to_frame_id, from_frame_id, frame_timestamp);
transform = convert::transformMsgToTransformation3D(transform_msg.transform);
return true;
return convert::transformMsgToTransformation3D(transform_msg.transform);
}
} // namespace wavemap
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@ void blockToRosMsg(const HashedWaveletOctree::BlockIndex& block_index,
// Convenience type for elements on the stack used to iterate over the map
struct StackElement {
const FloatingPoint scale;
const HashedWaveletOctreeBlock::NodeType& node;
HashedWaveletOctreeBlock::OctreeType::NodeConstRefType node;
};

// Serialize the block's metadata
Expand Down Expand Up @@ -534,7 +534,7 @@ void blockToRosMsg(const HashedChunkedWaveletOctree::BlockIndex& block_index,
// Define convenience types and constants
struct StackElement {
const FloatingPoint scale;
HashedChunkedWaveletOctreeBlock::ChunkedOctreeType::NodeConstRefType node;
HashedChunkedWaveletOctreeBlock::OctreeType::NodeConstRefType node;
};

// Serialize the block's metadata
Expand Down
1 change: 1 addition & 0 deletions library/cpp/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ option(BUILD_SHARED_LIBS
option(USE_SYSTEM_EIGEN "Use system pre-installed Eigen" ON)
option(USE_SYSTEM_GLOG "Use system pre-installed glog" ON)
option(USE_SYSTEM_BOOST "Use system pre-installed Boost" ON)
option(TRACY_ENABLE "Enable profiling with Tracy" OFF)

# CMake helpers and general wavemap tooling (e.g. to run clang-tidy CI)
include(GNUInstallDirs)
Expand Down
12 changes: 11 additions & 1 deletion library/cpp/cmake/find-wavemap-deps.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -55,4 +55,14 @@ else ()
endif ()

# Optional dependencies
find_package(tracy QUIET)
if (TRACY_ENABLE)
find_package(Tracy QUIET)
if (NOT Tracy_FOUND)
message(FATAL_ERROR
"Profiling is enabled (TRACY_ENABLE=ON), but Tracy is not available. "
"Please switch it to OFF or install Tracy as a system package with: "
"cmake -S . -B build -DTRACY_ENABLE=ON -DBUILD_SHARED_LIBS=true "
"-DCMAKE_BUILD_TYPE=Release && cmake --build build --parallel && "
"sudo make install")
endif ()
endif ()
5 changes: 5 additions & 0 deletions library/cpp/cmake/wavemap-extras.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,11 @@ function(set_wavemap_target_properties target)
# General C++ defines
target_compile_definitions(${target} PUBLIC EIGEN_INITIALIZE_MATRICES_BY_NAN)

# Profiling related C++ defines
if (TRACY_ENABLE)
target_compile_definitions(${target} PUBLIC TRACY_ENABLE)
endif ()

# Conditional compilation options
if (DCHECK_ALWAYS_ON)
target_compile_definitions(${target} PUBLIC DCHECK_ALWAYS_ON)
Expand Down
13 changes: 9 additions & 4 deletions library/cpp/include/wavemap/core/config/string_list.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,15 @@ struct StringList {

// Constructors
StringList() = default;
StringList(ValueType value) : value(std::move(value)) {} // NOLINT
StringList(const ValueType& value) : value(value) {} // NOLINT
StringList(ValueType&& value) : value(std::move(value)) {} // NOLINT

// Assignment operator
StringList& operator=(ValueType rhs) {
StringList& operator=(const ValueType& rhs) {
value = rhs;
return *this;
}
StringList& operator=(ValueType&& rhs) {
value = std::move(rhs);
return *this;
}
Expand All @@ -29,8 +34,8 @@ struct StringList {
bool operator!=(const StringList& rhs) const { return value != rhs.value; }

// Allow implicit conversions to the underlying type
operator ValueType&() { return value; }
operator const ValueType&() const { return value; }
operator ValueType&() { return value; } // NOLINT
operator const ValueType&() const { return value; } // NOLINT

// Method to load from configs
static std::optional<StringList> from(const param::Value& param);
Expand Down
6 changes: 6 additions & 0 deletions library/cpp/include/wavemap/core/data_structure/aabb.h
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#ifndef WAVEMAP_CORE_DATA_STRUCTURE_AABB_H_
#define WAVEMAP_CORE_DATA_STRUCTURE_AABB_H_

#include <algorithm>
#include <limits>
#include <string>
#include <utility>

#include "wavemap/core/common.h"
#include "wavemap/core/utils/math/int_math.h"
Expand All @@ -23,6 +25,10 @@ struct AABB {
PointType min = PointType::Constant(kInitialMin);
PointType max = PointType::Constant(kInitialMax);

AABB() = default;
AABB(const PointT& min, const PointT& max) : min(min), max(max) {}
AABB(PointT&& min, PointT&& max) : min(std::move(min)), max(std::move(max)) {}

void includePoint(const PointType& point) {
min = min.cwiseMin(point);
max = max.cwiseMax(point);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,20 +28,14 @@ class ChunkedNdtree {
explicit ChunkedNdtree(HeightType max_height);
~ChunkedNdtree() = default;

bool empty() const { return root_chunk_.empty(); }
bool empty() const { return getRootNode().empty(); }
size_t size() const;
void clear() { root_chunk_.clear(); }
void prune();

HeightType getMaxHeight() const { return max_height_; }
size_t getMemoryUsage() const;

// TODO(victorr): Add methods to directly query and operate on chunks,
// once a proper index type for chunks has been defined.
// The ChunkIndex type would be similar to NdtreeIndex, but has
// to account for the chunks having a branching factor that
// differs from 2 (probably 2^(dim * chunk_height)).

bool hasNode(const IndexType& index) const { return getNode(index); }
NodePtrType getNode(const IndexType& index);
NodeConstPtrType getNode(const IndexType& index) const;
Expand Down
Loading
Loading