image_framework_ymj/include/open3d/geometry/Octree.h

427 lines
17 KiB
C
Raw Normal View History

2024-12-06 16:25:16 +08:00
// ----------------------------------------------------------------------------
// - 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