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

475 lines
20 KiB
C++
Executable File

// ----------------------------------------------------------------------------
// - Open3D: www.open3d.org -
// ----------------------------------------------------------------------------
// Copyright (c) 2018-2023 www.open3d.org
// SPDX-License-Identifier: MIT
// ----------------------------------------------------------------------------
#pragma once
#include "open3d/core/Tensor.h"
#include "open3d/core/TensorCheck.h"
#include "open3d/geometry/BoundingVolume.h"
#include "open3d/t/geometry/DrawableGeometry.h"
#include "open3d/t/geometry/Geometry.h"
#include "open3d/utility/Logging.h"
namespace open3d {
namespace t {
namespace geometry {
class OrientedBoundingBox;
/// \class AxisAlignedBoundingBox
/// \brief A bounding box that is aligned along the coordinate axes and defined
/// by the min_bound and max_bound.
///
/// - (min_bound, max_bound): Lower and upper bounds of the bounding box for all
/// axes.
/// - Usage
/// - AxisAlignedBoundingBox::GetMinBound()
/// - AxisAlignedBoundingBox::SetMinBound(const core::Tensor &min_bound)
/// - AxisAlignedBoundingBox::GetMaxBound()
/// - AxisAlignedBoundingBox::SetMaxBound(const core::Tensor &max_bound)
/// - Value tensor must have shape {3,}.
/// - Value tensor must have the same data type and device.
/// - Value tensor can only be float32 (default) or float64.
/// - The device of the tensor determines the device of the box.
///
/// - color: Color of the bounding box.
/// - Usage
/// - AxisAlignedBoundingBox::GetColor()
/// - AxisAlignedBoundingBox::SetColor(const core::Tensor &color)
/// - Value tensor must have shape {3,}.
/// - Value tensor can only be float32 (default) or float64.
/// - Value tensor can only be range [0.0, 1.0].
class AxisAlignedBoundingBox : public Geometry, public DrawableGeometry {
public:
/// \brief Construct an empty AxisAlignedBoundingBox on the provided device.
AxisAlignedBoundingBox(const core::Device &device = core::Device("CPU:0"));
/// \brief Construct an AxisAlignedBoundingBox from min/max bound.
///
/// The AxisAlignedBoundingBox will be created on the device of the given
/// bound tensor, which must be on the same device and have the same data
/// type.
/// \param min_bound Lower bounds of the bounding box for all axes. Tensor
/// of shape {3,}, and type float32 or float64.
/// \param max_bound Upper bounds of the bounding box for all axes. Tensor
/// of shape {3,}, and type float32 or float64.
AxisAlignedBoundingBox(const core::Tensor &min_bound,
const core::Tensor &max_bound);
virtual ~AxisAlignedBoundingBox() override {}
/// \brief Returns the device attribute of this AxisAlignedBoundingBox.
core::Device GetDevice() const override { return device_; }
/// \brief Returns the data type attribute of this AxisAlignedBoundingBox.
core::Dtype GetDtype() const { return dtype_; }
/// \brief Transfer the AxisAlignedBoundingBox to a specified device.
/// \param device The targeted device to convert to.
/// \param copy If true, a new AxisAlignedBoundingBox is always created; If
/// false, the copy is avoided when the original AxisAlignedBoundingBox is
/// already on the targeted device.
AxisAlignedBoundingBox To(const core::Device &device,
bool copy = false) const;
/// Returns copy of the AxisAlignedBoundingBox on the same device.
AxisAlignedBoundingBox Clone() const {
return To(GetDevice(), /*copy=*/true);
}
AxisAlignedBoundingBox &Clear() override;
bool IsEmpty() const override { return Volume() == 0; }
/// \brief Set the min bound of the box.
/// If the data type of the given tensor differs from the data type of the
/// box, an exception will be thrown.
///
/// If the min bound makes the box invalid, it will not be set to the box.
/// \param min_bound Tensor with {3,} shape, and type float32 or float64.
void SetMinBound(const core::Tensor &min_bound);
/// \brief Set the max bound of the box.
/// If the data type of the given tensor differs from the data type of the
/// box, an exception will be thrown.
///
/// If the max bound makes the box invalid, it will not be set to the box.
/// \param max_bound Tensor with {3,} shape, and type float32 or float64.
void SetMaxBound(const core::Tensor &max_bound);
/// \brief Set the color of the box.
/// If the data type of the given tensor differs from the data type of the
/// box, an exception will be thrown.
///
/// \param color Tensor with {3,} shape, and type float32 or float64,
/// with values in range [0.0, 1.0].
void SetColor(const core::Tensor &color);
public:
core::Tensor GetMinBound() const { return min_bound_; }
core::Tensor GetMaxBound() const { return max_bound_; }
core::Tensor GetColor() const { return color_; }
core::Tensor GetCenter() const { return (min_bound_ + max_bound_) * 0.5; }
/// \brief Translate the axis-aligned box by the given translation.
///
/// If relative is true, the translation is applied to the current min and
/// max bound. If relative is false, the translation is applied to make the
/// box's center at the given translation.
///
/// \param translation Translation tensor of shape (3,), type float32 or
/// float64, device same as the box.
/// \param relative Whether to perform relative translation.
AxisAlignedBoundingBox &Translate(const core::Tensor &translation,
bool relative = true);
/// \brief Scale the axis-aligned box.
/// If \f$mi\f$ is the min_bound and \f$ma\f$ is the max_bound of
/// the axis aligned bounding box, and \f$s\f$ and \f$c\f$ are the
/// provided scaling factor and center respectively, then the new
/// min_bound and max_bound are given by \f$mi = c + s (mi - c)\f$
/// and \f$ma = c + s (ma - c)\f$.
/// The scaling center will be the box center if it is not specified.
///
/// \param scale The scale parameter.
/// \param center Center used for the scaling operation. Tensor of shape
/// {3,}, type float32 or float64, device same as the box.
AxisAlignedBoundingBox &Scale(
double scale,
const utility::optional<core::Tensor> &center = utility::nullopt);
/// \brief Add operation for axis-aligned bounding box.
/// The device of other box must be the same as the device of the current
/// box.
AxisAlignedBoundingBox &operator+=(const AxisAlignedBoundingBox &other);
/// Get the extent/length of the bounding box in x, y, and z dimension.
core::Tensor GetExtent() const { return max_bound_ - min_bound_; }
/// Returns the half extent of the bounding box.
core::Tensor GetHalfExtent() const { return GetExtent() / 2; }
/// \brief Returns the maximum extent, i.e. the maximum of X, Y and Z axis'
/// extents.
double GetMaxExtent() const {
return GetExtent().Max({0}).To(core::Float64).Item<double>();
}
/// Calculates the percentage position of the given x-coordinate within
/// the x-axis range of this AxisAlignedBoundingBox.
double GetXPercentage(double x) const;
/// Calculates the percentage position of the given y-coordinate within
/// the y-axis range of this AxisAlignedBoundingBox.
double GetYPercentage(double y) const;
/// Calculates the percentage position of the given z-coordinate within
/// the z-axis range of this AxisAlignedBoundingBox.
double GetZPercentage(double z) const;
/// Returns the volume of the bounding box.
double Volume() const {
return GetExtent().Prod({0}).To(core::Float64).Item<double>();
}
/// \brief Returns the eight points that define the bounding box.
///
/// The Return tensor has shape {8, 3} and data type same as the box.
core::Tensor GetBoxPoints() const;
/// \brief Indices to points that are within the bounding box.
///
/// \param points Tensor with {N, 3} shape, and type float32 or float64.
core::Tensor GetPointIndicesWithinBoundingBox(
const core::Tensor &points) const;
/// Text description.
std::string ToString() const;
/// Convert to a legacy Open3D axis-aligned box.
open3d::geometry::AxisAlignedBoundingBox ToLegacy() const;
/// Convert to an oriented box.
OrientedBoundingBox GetOrientedBoundingBox() const;
/// Create an AxisAlignedBoundingBox from a legacy Open3D
/// axis-aligned box.
///
/// \param box Legacy AxisAlignedBoundingBox.
/// \param dtype The data type of the box for min_bound, max_bound and
/// color. The default is float32.
/// \param device The device of the box. The default is CPU:0.
static AxisAlignedBoundingBox FromLegacy(
const open3d::geometry::AxisAlignedBoundingBox &box,
const core::Dtype &dtype = core::Float32,
const core::Device &device = core::Device("CPU:0"));
/// Creates the axis-aligned box that encloses the set of points.
/// \param points A list of points with data type of float32 or float64 (N x
/// 3 tensor).
/// \return AxisAlignedBoundingBox with same data type and device as input
/// points.
static AxisAlignedBoundingBox CreateFromPoints(const core::Tensor &points);
protected:
/// The device to use for the bounding box. The default is CPU:0.
core::Device device_ = core::Device("CPU:0");
/// The data type of the bounding box.
core::Dtype dtype_ = core::Float32;
/// The lower x, y, z bounds of the bounding box.
core::Tensor min_bound_;
/// The upper x, y, z bounds of the bounding box.
core::Tensor max_bound_;
/// The color of the bounding box in RGB. The default is white.
core::Tensor color_;
};
/// \class OrientedBoundingBox
/// \brief A bounding box oriented along an arbitrary frame of reference.
///
/// - (center, rotation, extent): The oriented bounding box is defined by its
/// center position, rotation matrix and extent.
/// - Usage
/// - OrientedBoundingBox::GetCenter()
/// - OrientedBoundingBox::SetCenter(const core::Tensor &center)
/// - OrientedBoundingBox::GetRotation()
/// - OrientedBoundingBox::SetRotation(const core::Tensor &rotation)
/// - Value tensor of center and extent must have shape {3,}.
/// - Value tensor of rotation must have shape {3, 3}.
/// - Value tensor must have the same data type and device.
/// - Value tensor can only be float32 (default) or float64.
/// - The device of the tensor determines the device of the box.
///
/// - color: Color of the bounding box.
/// - Usage
/// - OrientedBoundingBox::GetColor()
/// - OrientedBoundingBox::SetColor(const core::Tensor &color)
/// - Value tensor must have shape {3,}.
/// - Value tensor can only be float32 (default) or float64.
/// - Value tensor can only be range [0.0, 1.0].
class OrientedBoundingBox : public Geometry, public DrawableGeometry {
public:
/// \brief Construct an empty OrientedBoundingBox on the provided device.
OrientedBoundingBox(const core::Device &device = core::Device("CPU:0"));
/// \brief Construct an OrientedBoundingBox from center, rotation and
/// extent.
///
/// The OrientedBoundingBox will be created on the device of the given
/// tensors, which must be on the same device and have the same data
/// type.
/// \param center Center of the bounding box. Tensor of shape {3,}, and type
/// float32 or float64.
/// \param rotation Rotation matrix of the bounding box. Tensor of shape {3,
/// 3}, and type float32 or float64.
/// \param extent Extent of the bounding box. Tensor of shape {3,}, and type
/// float32 or float64.
OrientedBoundingBox(const core::Tensor &center,
const core::Tensor &rotation,
const core::Tensor &extent);
virtual ~OrientedBoundingBox() override {}
/// \brief Returns the device attribute of this OrientedBoundingBox.
core::Device GetDevice() const override { return device_; }
/// \brief Returns the data type attribute of this OrientedBoundingBox.
core::Dtype GetDtype() const { return dtype_; }
/// Transfer the OrientedBoundingBox to a specified device.
/// \param device The targeted device to convert to.
/// \param copy If true, a new OrientedBoundingBox is always created; if
/// false, the copy is avoided when the original OrientedBoundingBox is
/// already on the targeted device.
OrientedBoundingBox To(const core::Device &device, bool copy = false) const;
/// Returns copy of the OrientedBoundingBox on the same device.
OrientedBoundingBox Clone() const { return To(GetDevice(), /*copy=*/true); }
OrientedBoundingBox &Clear() override;
bool IsEmpty() const override { return Volume() == 0; }
/// \brief Set the center of the box.
/// If the data type of the given tensor differs from the data type of the
/// box, an exception will be thrown.
///
/// \param center Tensor with {3,} shape, and type float32 or float64.
void SetCenter(const core::Tensor &center);
/// \brief Set the rotation matrix of the box.
/// If the data type of the given tensor differs from the data type of the
/// box, an exception will be thrown.
///
/// \param rotation Tensor with {3, 3} shape, and type float32 or float64.
void SetRotation(const core::Tensor &rotation);
/// \brief Set the extent of the box.
/// If the data type of the given tensor differs from the data type of the
/// box, an exception will be thrown.
///
/// \param extent Tensor with {3,} shape, and type float32 or float64.
void SetExtent(const core::Tensor &extent);
/// \brief Set the color of the box.
///
/// \param color Tensor with {3,} shape, and type float32 or float64,
/// with values in range [0.0, 1.0].
void SetColor(const core::Tensor &color);
public:
core::Tensor GetMinBound() const;
core::Tensor GetMaxBound() const;
core::Tensor GetColor() const { return color_; }
core::Tensor GetCenter() const { return center_; }
core::Tensor GetRotation() const { return rotation_; }
core::Tensor GetExtent() const { return extent_; }
/// \brief Translate the oriented box by the given translation.
/// If relative is true, the translation is added to the center of the box.
/// If false, the center will be assigned to the translation.
///
/// \param translation Translation tensor of shape {3,}, type float32 or
/// float64, device same as the box.
/// \param relative Whether to perform relative translation.
OrientedBoundingBox &Translate(const core::Tensor &translation,
bool relative = true);
/// \brief Rotate the oriented box by the given rotation matrix. If the
/// rotation matrix is not orthogonal, the rotation will no be applied.
/// The rotation center will be the box center if it is not specified.
///
/// \param rotation Rotation matrix of shape {3, 3}, type float32 or
/// float64, device same as the box.
/// \param center Center of the rotation, default is null, which means use
/// center of the box as rotation center.
OrientedBoundingBox &Rotate(
const core::Tensor &rotation,
const utility::optional<core::Tensor> &center = utility::nullopt);
/// \brief Transform the oriented box by the given transformation matrix.
///
/// \param transformation Transformation matrix of shape {4, 4}, type
/// float32 or float64, device same as the box.
OrientedBoundingBox &Transform(const core::Tensor &transformation);
/// \brief Scale the axis-aligned box.
/// If \f$mi\f$ is the min_bound and \f$ma\f$ is the max_bound of
/// the axis aligned bounding box, and \f$s\f$ and \f$c\f$ are the
/// provided scaling factor and center respectively, then the new
/// min_bound and max_bound are given by \f$mi = c + s (mi - c)\f$
/// and \f$ma = c + s (ma - c)\f$.
/// The scaling center will be the box center if it is not specified.
///
/// \param scale The scale parameter.
/// \param center Center used for the scaling operation. Tensor of shape
/// {3,}, type float32 or float64, device same as the box.
OrientedBoundingBox &Scale(
double scale,
const utility::optional<core::Tensor> &center = utility::nullopt);
/// Returns the volume of the bounding box.
double Volume() const {
return GetExtent().Prod({0}).To(core::Float64).Item<double>();
}
/// \brief Returns the eight points that define the bounding box.
///
/// The Return tensor has shape {8, 3} and data type same as the box.
///
/// \verbatim
/// ------- x
/// /|
/// / |
/// / | z
/// y
/// 0 ------------------- 1
/// /| /|
/// / | / |
/// / | / |
/// / | / |
/// 2 ------------------- 7 |
/// | |____________|____| 6
/// | /3 | /
/// | / | /
/// | / | /
/// |/ |/
/// 5 ------------------- 4
/// \endverbatim
core::Tensor GetBoxPoints() const;
/// \brief Indices to points that are within the bounding box.
///
/// \param points Tensor with {N, 3} shape, and type float32 or float64.
core::Tensor GetPointIndicesWithinBoundingBox(
const core::Tensor &points) const;
/// Text description.
std::string ToString() const;
/// Convert to a legacy Open3D oriented box.
open3d::geometry::OrientedBoundingBox ToLegacy() const;
/// Convert to an axis-aligned box.
AxisAlignedBoundingBox GetAxisAlignedBoundingBox() const;
/// Create an oriented bounding box from the AxisAlignedBoundingBox.
///
/// \param aabb AxisAlignedBoundingBox object from which
/// OrientedBoundingBox is created.
/// \return OrientedBoundingBox with the same device and dtype as input box.
static OrientedBoundingBox CreateFromAxisAlignedBoundingBox(
const AxisAlignedBoundingBox &aabb);
/// Create an OrientedBoundingBox from a legacy Open3D oriented box.
///
/// \param box Legacy OrientedBoundingBox.
/// \param dtype The data type of the box for min_bound max_bound and color.
/// The default is float32.
/// \param device The device of the box. The default is CPU:0.
static OrientedBoundingBox FromLegacy(
const open3d::geometry::OrientedBoundingBox &box,
const core::Dtype &dtype = core::Float32,
const core::Device &device = core::Device("CPU:0"));
/// Creates an oriented bounding box using a PCA.
/// Note that this is only an approximation to the minimum oriented
/// bounding box that could be computed for example with O'Rourke's
/// algorithm (cf. http://cs.smith.edu/~jorourke/Papers/MinVolBox.pdf,
/// https://www.geometrictools.com/Documentation/MinimumVolumeBox.pdf)
/// This is a wrapper for a CPU implementation.
///
/// \param points A list of points with data type of float32 or float64 (N x
/// 3 tensor, where N must be larger than 3).
/// \param robust If set to true uses a more robust method which works in
/// degenerate cases but introduces noise to the points coordinates.
/// \return OrientedBoundingBox with same data type and device as input
/// points.
static OrientedBoundingBox CreateFromPoints(const core::Tensor &points,
bool robust = false);
protected:
core::Device device_ = core::Device("CPU:0");
core::Dtype dtype_ = core::Float32;
core::Tensor center_;
core::Tensor rotation_;
core::Tensor extent_;
core::Tensor color_;
};
} // namespace geometry
} // namespace t
} // namespace open3d