image_framework_ymj/include/open3d/geometry/Octree.h
2024-12-06 16:25:16 +08:00

427 lines
17 KiB
C++
Executable File
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ----------------------------------------------------------------------------
// - Open3D: www.open3d.org -
// ----------------------------------------------------------------------------
// Copyright (c) 2018-2023 www.open3d.org
// SPDX-License-Identifier: MIT
// ----------------------------------------------------------------------------
#pragma once
#include <cstddef>
#include <memory>
#include <vector>
#include "open3d/geometry/Geometry3D.h"
#include "open3d/utility/IJsonConvertible.h"
namespace open3d {
namespace geometry {
class PointCloud;
class VoxelGrid;
/// \class OctreeNodeInfo
///
/// \brief OctreeNode's information.
///
/// OctreeNodeInfo is computed on the fly, not stored with the Node.
class OctreeNodeInfo {
public:
/// \brief Default Constructor.
///
/// Initializes all values as 0.
OctreeNodeInfo() : origin_(0, 0, 0), size_(0), depth_(0), child_index_(0) {}
/// \brief Parameterized Constructor.
///
/// \param origin Origin coordinate of the node
/// \param size Size of the node.
/// \param depth Depth of the node to the root. The root is of depth 0.
/// \param child_index Nodes child index of itself.
OctreeNodeInfo(const Eigen::Vector3d& origin,
const double& size,
const size_t& depth,
const size_t& child_index)
: origin_(origin),
size_(size),
depth_(depth),
child_index_(child_index) {}
~OctreeNodeInfo() {}
public:
/// Origin coordinate of the node.
Eigen::Vector3d origin_;
/// Size of the node.
double size_;
/// Depth of the node to the root. The root is of depth 0.
size_t depth_;
/// Nodes child index of itself. For non-root nodes, child_index is 0~7;
/// root nodes child_index is -1.
size_t child_index_;
};
/// \class OctreeNode
///
/// \brief The base class for octree node.
///
/// Design decision: do not store origin and size of a node
/// - Good: better space efficiency.
/// - Bad: need to recompute origin and size when traversing.
class OctreeNode : public utility::IJsonConvertible {
public:
/// \brief Default Constructor.
///
OctreeNode() {}
virtual ~OctreeNode() {}
/// Factory function to construct an OctreeNode by parsing the json value.
static std::shared_ptr<OctreeNode> ConstructFromJsonValue(
const Json::Value& value);
};
/// \class OctreeInternalNode
///
/// \brief OctreeInternalNode class, containing OctreeNode children.
///
/// Children node ordering conventions are as follows.
///
/// For illustration, assume,
/// - root_node: origin == (0, 0, 0), size == 2
///
/// Then,
/// - children_[0]: origin == (0, 0, 0), size == 1
/// - children_[1]: origin == (1, 0, 0), size == 1, along X-axis next to child 0
/// - children_[2]: origin == (0, 1, 0), size == 1, along Y-axis next to child 0
/// - children_[3]: origin == (1, 1, 0), size == 1, in X-Y plane
/// - children_[4]: origin == (0, 0, 1), size == 1, along Z-axis next to child 0
/// - children_[5]: origin == (1, 0, 1), size == 1, in X-Z plane
/// - children_[6]: origin == (0, 1, 1), size == 1, in Y-Z plane
/// - children_[7]: origin == (1, 1, 1), size == 1, furthest from child 0
class OctreeInternalNode : public OctreeNode {
public:
/// \brief Default Constructor.
///
OctreeInternalNode() : children_(8) {}
static std::shared_ptr<OctreeNodeInfo> GetInsertionNodeInfo(
const std::shared_ptr<OctreeNodeInfo>& node_info,
const Eigen::Vector3d& point);
/// \brief Get lambda function for initializing OctreeInternalNode.
///
/// When the init function is called, an empty OctreeInternalNode is
/// created.
static std::function<std::shared_ptr<OctreeInternalNode>()>
GetInitFunction();
/// \brief Get lambda function for updating OctreeInternalNode.
///
/// This update function does nothing.
static std::function<void(std::shared_ptr<OctreeInternalNode>)>
GetUpdateFunction();
bool ConvertToJsonValue(Json::Value& value) const override;
bool ConvertFromJsonValue(const Json::Value& value) override;
public:
/// Use vector instead of C-array for Pybind11, otherwise, need to define
/// more helper functions
/// https://github.com/pybind/pybind11/issues/546#issuecomment-265707318
/// List of children Nodes.
std::vector<std::shared_ptr<OctreeNode>> children_;
};
/// \class OctreeInternalPointNode
///
/// \brief OctreeInternalPointNode class is an OctreeInternalNode containing
/// a list of indices which is the union of all its children's list of indices.
class OctreeInternalPointNode : public OctreeInternalNode {
public:
/// \brief Default Constructor.
///
OctreeInternalPointNode() : OctreeInternalNode() {}
/// \brief Get lambda function for initializing OctreeInternalPointNode.
///
/// When the init function is called, an empty OctreeInternalPointNode is
/// created.
static std::function<std::shared_ptr<OctreeInternalNode>()>
GetInitFunction();
/// \brief Get lambda function for updating OctreeInternalPointNode.
///
/// When called, the update function adds the input point index to the
/// corresponding node's list of indices of children points.
static std::function<void(std::shared_ptr<OctreeInternalNode>)>
GetUpdateFunction(size_t idx);
bool ConvertToJsonValue(Json::Value& value) const override;
bool ConvertFromJsonValue(const Json::Value& value) override;
public:
/// Indices of points associated with any children of this node
std::vector<size_t> indices_;
};
/// \class OctreeLeafNode
///
/// \brief OctreeLeafNode base class.
class OctreeLeafNode : public OctreeNode {
public:
virtual bool operator==(const OctreeLeafNode& other) const = 0;
/// Clone this OctreeLeafNode.
virtual std::shared_ptr<OctreeLeafNode> Clone() const = 0;
};
/// \class OctreeColorLeafNode
///
/// \brief OctreeColorLeafNode class is an OctreeLeafNode containing color.
class OctreeColorLeafNode : public OctreeLeafNode {
public:
bool operator==(const OctreeLeafNode& other) const override;
/// Clone this OctreeLeafNode.
std::shared_ptr<OctreeLeafNode> Clone() const override;
/// \brief Get lambda function for initializing OctreeLeafNode.
///
/// When the init function is called, an empty OctreeColorLeafNode is
/// created.
static std::function<std::shared_ptr<OctreeLeafNode>()> GetInitFunction();
/// \brief Get lambda function for updating OctreeLeafNode.
///
/// When called, the update function updates the corresponding node with the
/// input color.
///
/// \param color Color of the node.
static std::function<void(std::shared_ptr<OctreeLeafNode>)>
GetUpdateFunction(const Eigen::Vector3d& color);
bool ConvertToJsonValue(Json::Value& value) const override;
bool ConvertFromJsonValue(const Json::Value& value) override;
/// TODO: flexible data, with lambda function for handling node
/// Color of the node.
Eigen::Vector3d color_ = Eigen::Vector3d(0, 0, 0);
};
/// \class OctreePointColorLeafNode
///
/// \brief OctreePointColorLeafNode class is an OctreeColorLeafNode containing
/// a list of indices corresponding to the point cloud points contained in
/// this leaf node.
class OctreePointColorLeafNode : public OctreeColorLeafNode {
public:
bool operator==(const OctreeLeafNode& other) const override;
/// Clone this OctreeLeafNode.
std::shared_ptr<OctreeLeafNode> Clone() const override;
/// \brief Get lambda function for initializing OctreeLeafNode.
///
/// When the init function is called, an empty OctreePointColorLeafNode is
/// created.
static std::function<std::shared_ptr<OctreeLeafNode>()> GetInitFunction();
/// \brief Get lambda function for updating OctreeLeafNode.
///
/// When called, the update function adds the point cloud point index to
/// the corresponding node index list.
///
/// \param index Point cloud point index associated with node.
/// \param color Color of the node.
static std::function<void(std::shared_ptr<OctreeLeafNode>)>
GetUpdateFunction(size_t index, const Eigen::Vector3d& color);
bool ConvertToJsonValue(Json::Value& value) const override;
bool ConvertFromJsonValue(const Json::Value& value) override;
/// Associated point indices with this node.
std::vector<size_t> indices_;
};
/// \class Octree
///
/// \brief Octree datastructure.
class Octree : public Geometry3D, public utility::IJsonConvertible {
public:
/// \brief Default Constructor.
Octree()
: Geometry3D(Geometry::GeometryType::Octree),
origin_(0, 0, 0),
size_(0),
max_depth_(0) {}
/// \brief Parameterized Constructor.
///
/// \param max_depth Sets the value of the max depth of the Octree.
Octree(const size_t& max_depth)
: Geometry3D(Geometry::GeometryType::Octree),
origin_(0, 0, 0),
size_(0),
max_depth_(max_depth) {}
/// \brief Parameterized Constructor.
///
/// \param max_depth Sets the value of the max depth of the Octree.
/// \param origin Sets the global min bound of the Octree.
/// \param size Sets the outer bounding box edge size for the whole octree.
Octree(const size_t& max_depth,
const Eigen::Vector3d& origin,
const double& size)
: Geometry3D(Geometry::GeometryType::Octree),
origin_(origin),
size_(size),
max_depth_(max_depth) {}
Octree(const Octree& src_octree);
~Octree() override {}
public:
Octree& Clear() override;
bool IsEmpty() const override;
Eigen::Vector3d GetMinBound() const override;
Eigen::Vector3d GetMaxBound() const override;
Eigen::Vector3d GetCenter() const override;
/// Creates the axis-aligned bounding box around the object.
/// Further details in AxisAlignedBoundingBox::AxisAlignedBoundingBox()
AxisAlignedBoundingBox GetAxisAlignedBoundingBox() const override;
/// Creates an oriented bounding box that is identical to the
/// axis-aligned bounding from GetAxisAlignedBoundingBox().
OrientedBoundingBox GetOrientedBoundingBox(
bool robust = false) const override;
/// Creates an oriented bounding box that is identical to the
/// axis-aligned bounding from GetAxisAlignedBoundingBox().
OrientedBoundingBox GetMinimalOrientedBoundingBox(
bool robust = false) const override;
Octree& Transform(const Eigen::Matrix4d& transformation) override;
Octree& Translate(const Eigen::Vector3d& translation,
bool relative = true) override;
Octree& Scale(const double scale, const Eigen::Vector3d& center) override;
Octree& Rotate(const Eigen::Matrix3d& R,
const Eigen::Vector3d& center) override;
bool ConvertToJsonValue(Json::Value& value) const override;
bool ConvertFromJsonValue(const Json::Value& value) override;
public:
/// \brief Convert octree from point cloud.
///
/// \param point_cloud Input point cloud.
/// \param size_expand A small expansion size such that the octree is
/// slightly bigger than the original point cloud bounds to accommodate all
/// points.
void ConvertFromPointCloud(const geometry::PointCloud& point_cloud,
double size_expand = 0.01);
/// Root of the octree.
std::shared_ptr<OctreeNode> root_node_ = nullptr;
/// Global min bound (include). A point is within bound iff
/// origin_ <= point < origin_ + size_.
Eigen::Vector3d origin_;
/// Outer bounding box edge size for the whole octree. A point is within
/// bound iff origin_ <= point < origin_ + size_.
double size_;
/// Max depth of octree. The depth is defined as the distance from the
/// deepest leaf node to root. A tree with only the root node has depth 0.
size_t max_depth_;
/// \brief Insert a point to the octree.
///
/// \param point Coordinates of the point.
/// \param fl_init Initialization fcn used to create new leaf node
/// (if needed) associated with the point.
/// \param fl_update Update fcn used to update the leaf node
/// associated with the point.
/// \param fi_init Initialize fcn used to create a new internal node
/// (if needed) which is an ancestor of the point's leaf node. If omitted,
/// the default OctreeInternalNode function is used.
/// \param fi_update Update fcn used to update the internal node
/// which is an ancestor of the point's leaf node. If omitted, the default
/// OctreeInternalNode function is used.
void InsertPoint(
const Eigen::Vector3d& point,
const std::function<std::shared_ptr<OctreeLeafNode>()>& fl_init,
const std::function<void(std::shared_ptr<OctreeLeafNode>)>&
fl_update,
const std::function<std::shared_ptr<OctreeInternalNode>()>&
fi_init = nullptr,
const std::function<void(std::shared_ptr<OctreeInternalNode>)>&
fi_update = nullptr);
/// \brief DFS traversal of Octree from the root, with callback function
/// called for each node.
///
/// \param f Callback which fires with each traversed internal/leaf node.
/// Arguments supply information about the node being traversed and other
/// node-specific data. A Boolean return value is used for early-stopping.
/// If f returns true, children of this node will not be traversed.
void Traverse(
const std::function<bool(const std::shared_ptr<OctreeNode>&,
const std::shared_ptr<OctreeNodeInfo>&)>&
f);
/// \brief Const version of Traverse. DFS traversal of Octree from the root,
/// with callback function called for each node.
///
/// \param f Callback which fires with each traversed internal/leaf node.
/// Arguments supply information about the node being traversed and other
/// node-specific data. A Boolean return value is used for early-stopping.
/// If f returns true, children of this node will not be traversed.
void Traverse(
const std::function<bool(const std::shared_ptr<OctreeNode>&,
const std::shared_ptr<OctreeNodeInfo>&)>&
f) const;
std::pair<std::shared_ptr<OctreeLeafNode>, std::shared_ptr<OctreeNodeInfo>>
/// \brief Returns leaf OctreeNode and OctreeNodeInfo where the querypoint
/// should reside.
///
/// \param point Coordinates of the point.
LocateLeafNode(const Eigen::Vector3d& point) const;
/// \brief Return true if point within bound, that is,
/// origin <= point < origin + size.
///
/// \param point Coordinates of the point.
/// \param origin Origin coordinates.
/// \param size Size of the Octree.
static bool IsPointInBound(const Eigen::Vector3d& point,
const Eigen::Vector3d& origin,
const double& size);
/// Returns true if the Octree is completely the same, used for testing.
bool operator==(const Octree& other) const;
/// Convert to VoxelGrid.
std::shared_ptr<geometry::VoxelGrid> ToVoxelGrid() const;
/// Convert from voxel grid.
void CreateFromVoxelGrid(const geometry::VoxelGrid& voxel_grid);
private:
static void TraverseRecurse(
const std::shared_ptr<OctreeNode>& node,
const std::shared_ptr<OctreeNodeInfo>& node_info,
const std::function<bool(const std::shared_ptr<OctreeNode>&,
const std::shared_ptr<OctreeNodeInfo>&)>&
f);
void InsertPointRecurse(
const std::shared_ptr<OctreeNode>& node,
const std::shared_ptr<OctreeNodeInfo>& node_info,
const Eigen::Vector3d& point,
const std::function<std::shared_ptr<OctreeLeafNode>()>& f_l_init,
const std::function<void(std::shared_ptr<OctreeLeafNode>)>&
f_l_update,
const std::function<std::shared_ptr<OctreeInternalNode>()>&
f_i_init,
const std::function<void(std::shared_ptr<OctreeInternalNode>)>&
f_i_update);
};
} // namespace geometry
} // namespace open3d