Skip to content

Commit

Permalink
Add BoundingCylinder
Browse files Browse the repository at this point in the history
  • Loading branch information
j9liu committed Dec 16, 2024
1 parent 4e40219 commit 21a6672
Show file tree
Hide file tree
Showing 11 changed files with 355 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,30 @@ class ImplicitTilingUtilities {
const CesiumGeometry::OctreeTileID& tileID,
const CesiumGeospatial::Ellipsoid& ellipsoid
CESIUM_DEFAULT_ELLIPSOID) noexcept;

/**
* @brief Computes the bounding volume for an implicit quadtree tile
* with the given ID as a bounding cylinder.
*
* @param rootBoundingVolume The oriented bounding box of the root tile.
* @param tileID The tile ID for which to compute the oriented bounding box.
* @return The oriented bounding box for the given implicit tile.
*/
static CesiumGeometry::BoundingCylinder computeBoundingVolume(
const CesiumGeometry::BoundingCylinder& rootBoundingVolume,
const CesiumGeometry::QuadtreeTileID& tileID) noexcept;

/**
* @brief Computes the bounding volume for an implicit octree tile with
* the given ID as a bounding cylinder.
*
* @param rootBoundingVolume The bounding cylinder of the root tile.
* @param tileID The tile ID for which to compute the bounding cylinder.
* @return The bounding cylinder for the given implicit tile.
*/
static CesiumGeometry::BoundingCylinder computeBoundingVolume(
const CesiumGeometry::BoundingCylinder& rootBoundingVolume,
const CesiumGeometry::OctreeTileID& tileID) noexcept;
};

} // namespace Cesium3DTilesContent
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#pragma once

#include <CesiumGeometry/BoundingCylinder.h>
#include <CesiumGeometry/BoundingSphere.h>
#include <CesiumGeometry/OrientedBoundingBox.h>
#include <CesiumGeospatial/BoundingRegion.h>
Expand Down Expand Up @@ -122,6 +123,32 @@ class TileBoundingVolumes {
static void setS2CellBoundingVolume(
Cesium3DTiles::BoundingVolume& boundingVolume,
const CesiumGeospatial::S2CellBoundingVolume& s2BoundingVolume);

/**
* @brief Gets the bounding cylinder defined in the
* `3DTILES_bounding_volume_cylinder` extension of a
* {@link Cesium3DTiles::BoundingVolume}, if any.
*
* @param boundingVolume The bounding volume from which to get the cylinder.
* @return The cylinder, or `std::nullopt` if the bounding volume does not
* define a cylinder. The cylinder is defined in the tile's coordinate system.
*/
static std::optional<CesiumGeometry::BoundingCylinder>
getBoundingCylinder(const Cesium3DTiles::BoundingVolume& boundingVolume);

/**
* @brief Adds the `3DTILES_bounding_volume_cylinder` extension to a
* {@link Cesium3DTiles::BoundingVolume} based on a
* {@link CesiumGeometry::BoundingCylinder}.
*
* Other bounding volume types, if any, are not modified.
*
* @param boundingVolume The bounding volume to set.
* @param boundingCylinder The bounding cylinder with which to set the property.
*/
static void setBoundingCylinder(
Cesium3DTiles::BoundingVolume& boundingVolume,
const CesiumGeometry::BoundingCylinder& boundingCylinder);
};

} // namespace Cesium3DTilesContent
27 changes: 27 additions & 0 deletions Cesium3DTilesContent/src/ImplicitTilingUtilities.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ Cesium3DTiles::BoundingVolume computeBoundingVolumeInternal(

std::optional<OrientedBoundingBox> maybeBox =
TileBoundingVolumes::getOrientedBoundingBox(rootBoundingVolume);

if (maybeBox) {
OrientedBoundingBox obb =
ImplicitTilingUtilities::computeBoundingVolume(*maybeBox, tileID);
Expand Down Expand Up @@ -168,6 +169,14 @@ Cesium3DTiles::BoundingVolume computeBoundingVolumeInternal(
TileBoundingVolumes::setS2CellBoundingVolume(result, s2);
}

std::optional<BoundingCylinder> maybeCylinder =
TileBoundingVolumes::getBoundingCylinder(rootBoundingVolume, ellipsoid);
if (maybeCylinder) {
BoundingCylinder cylinder =
ImplicitTilingUtilities::computeBoundingVolume(*maybeCylinder tileID);
TileBoundingVolumes::setBoundingCylinder(result, maybeCylinder);
}

return result;
}
} // namespace
Expand Down Expand Up @@ -334,6 +343,24 @@ ImplicitTilingUtilities::computeBoundingVolume(
ellipsoid);
}

CesiumGeometry::BoundingCylinder ImplicitTilingUtilities::computeBoundingVolume(
const CesiumGeometry::BoundingCylinder& rootBoundingVolume,
const CesiumGeometry::QuadtreeTileID& tileID) noexcept {
CesiumGeometry::OrientedBoundingBox result = computeBoundingVolume(
CesiumGeometry::OrientedBoundingBox::fromCylinder(rootBoundingVolume),
tileID);
return result.toCylinder();
}

CesiumGeometry::BoundingCylinder ImplicitTilingUtilities::computeBoundingVolume(
const CesiumGeometry::BoundingCylinder& rootBoundingVolume,
const CesiumGeometry::OctreeTileID& tileID) noexcept {
CesiumGeometry::OrientedBoundingBox result = computeBoundingVolume(
CesiumGeometry::OrientedBoundingBox::fromCylinder(rootBoundingVolume),
tileID);
return result.toCylinder();
}

double
ImplicitTilingUtilities::computeLevelDenominator(uint32_t level) noexcept {
return static_cast<double>(1 << level);
Expand Down
41 changes: 41 additions & 0 deletions Cesium3DTilesContent/src/TileBoundingVolumes.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <Cesium3DTiles/BoundingVolume.h>
#include <Cesium3DTiles/Extension3dTilesBoundingVolumeS2.h>
#include <Cesium3DTiles/Extension3dTilesBoundingVolumeCylinder.h>
#include <Cesium3DTilesContent/TileBoundingVolumes.h>

using namespace Cesium3DTiles;
Expand Down Expand Up @@ -110,4 +111,44 @@ void TileBoundingVolumes::setS2CellBoundingVolume(
extension.maximumHeight = s2BoundingVolume.getMaximumHeight();
}

std::optional<BoundingCylinder> TileBoundingVolumes::getBoundingCylinder(
const BoundingVolume& boundingVolume) {
const Extension3dTilesBoundingVolumeCylinder* pExtension =
boundingVolume.getExtension<Extension3dTilesBoundingVolumeCylinder>();
if (!pExtension)
return std::nullopt;

if (pExtension->cylinder.size() < 12)
return std::nullopt;

const std::vector<double>& a = pExtension->cylinder;
return CesiumGeometry::BoundingCylinder(
glm::dvec3(a[0], a[1], a[2]),
glm::dmat3(a[3], a[4], a[5], a[6], a[7], a[8], a[9], a[10], a[11]));
}

void TileBoundingVolumes::setBoundingCylinder(
Cesium3DTiles::BoundingVolume& boundingVolume,
const CesiumGeometry::BoundingCylinder& boundingCylinder) {
Extension3dTilesBoundingVolumeCylinder& extension =
boundingVolume.addExtension<Extension3dTilesBoundingVolumeCylinder>();

const glm::dvec3& center = boundingCylinder.getCenter();
const glm::dmat3& halfAxes = boundingCylinder.getHalfAxes();

extension.cylinder = {
center.x,
center.y,
center.z,
halfAxes[0].x,
halfAxes[0].y,
halfAxes[0].z,
halfAxes[1].x,
halfAxes[1].y,
halfAxes[1].z,
halfAxes[2].x,
halfAxes[2].y,
halfAxes[2].z};
}

} // namespace Cesium3DTilesContent
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

#include "Library.h"

#include <CesiumGeometry/BoundingCylinder.h>
#include <CesiumGeometry/BoundingSphere.h>
#include <CesiumGeometry/OrientedBoundingBox.h>
#include <CesiumGeospatial/BoundingRegion.h>
Expand All @@ -25,13 +26,15 @@ namespace Cesium3DTilesSelection {
* @see CesiumGeospatial::BoundingRegion
* @see CesiumGeospatial::BoundingRegionWithLooseFittingHeights
* @see CesiumGeospatial::S2CellBoundingVolume
* @see CesiumGeometry::BoundingCylinder
*/
typedef std::variant<
CesiumGeometry::BoundingSphere,
CesiumGeometry::OrientedBoundingBox,
CesiumGeospatial::BoundingRegion,
CesiumGeospatial::BoundingRegionWithLooseFittingHeights,
CesiumGeospatial::S2CellBoundingVolume>
CesiumGeospatial::S2CellBoundingVolume,
CesiumGeometry::BoundingCylinder>
BoundingVolume;

/**
Expand Down
19 changes: 19 additions & 0 deletions Cesium3DTilesSelection/src/BoundingVolume.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ BoundingVolume transformBoundingVolume(
// S2 Cells are not transformed.
return s2CellBoundingVolume;
}

BoundingVolume
operator()(const BoundingCylinder& boundingCylinder) noexcept {
return boundingCylinder.transform(transform);
}
};

return std::visit(Operation{transform}, boundingVolume);
Expand Down Expand Up @@ -67,6 +72,10 @@ glm::dvec3 getBoundingVolumeCenter(const BoundingVolume& boundingVolume) {
glm::dvec3 operator()(const S2CellBoundingVolume& s2Cell) noexcept {
return s2Cell.getCenter();
}

glm::dvec3 operator()(const BoundingCylinder& boundingCylinder) noexcept {
return boundingCylinder.getCenter();
}
};

return std::visit(Operation{}, boundingVolume);
Expand Down Expand Up @@ -190,6 +199,11 @@ std::optional<GlobeRectangle> estimateGlobeRectangle(
operator()(const S2CellBoundingVolume& s2Cell) {
return s2Cell.getCellID().computeBoundingRectangle();
}

std::optional<GlobeRectangle>
operator()(const BoundingCylinder& boundingCylinder) {
return operator()(OrientedBoundingBox::fromCylinder(boundingCylinder));
}
};

return std::visit(Operation{ellipsoid}, boundingVolume);
Expand Down Expand Up @@ -238,6 +252,11 @@ OrientedBoundingBox getOrientedBoundingBoxFromBoundingVolume(
operator()(const CesiumGeospatial::S2CellBoundingVolume& s2) const {
return s2.computeBoundingRegion(ellipsoid).getBoundingBox();
}

OrientedBoundingBox
operator()(const CesiumGeometry::BoundingCylinder& cylinder) const {
return OrientedBoundingBox::fromCylinder(cylinder);
}
};

return std::visit(Operation{ellipsoid}, boundingVolume);
Expand Down
125 changes: 125 additions & 0 deletions CesiumGeometry/include/CesiumGeometry/BoundingCylinder.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#pragma once

#include "CullingResult.h"
#include "Library.h"
#include "OrientedBoundingBox.h"

namespace CesiumGeometry {

class Plane;

/**
* @brief A bounding volume defined as a closed and convex cylinder with any
* orientation.
*
* NOTE: This uses a {@link OrientedBoundingBox} underneath the hood to
* approximate the result, similar to the way CesiumJS approximates cylinders.
* The output will not be accurate to the actual cylinder itself.
*
* TODO: Update this to more accurately represent a cylinder, and thus return
* more accurate results.
*
* @see OrientedBoundingBox
*/
class CESIUMGEOMETRY_API BoundingCylinder final {
public:
/**
* @brief Construct a new instance.
*
* @param center The center of the cylinder.
* @param halfAxes The three orthogonal half-axes of the bounding cylinder.
* Equivalently, the transformation matrix to rotate and scale a cylinder with
* a radius and height of 1 that is centered at the origin.
*
* @snippet TestBoundingCylinder.cpp Constructor
*/
BoundingCylinder(
const glm::dvec3& center,
const glm::dmat3& halfAxes) noexcept
: _box(center, halfAxes),
_radius(glm::length(halfAxes[0])),
_height(2.0 * glm::length(halfAxes[2])) {}

/**
* @brief Gets the center of the cylinder.
*/
constexpr const glm::dvec3& getCenter() const noexcept {
return this->_box.getCenter();
}

/**
* @brief Gets the three orthogonal half-axes of the cylinder.
* Equivalently, the transformation matrix to rotate and scale a cylinder with
* a radius and height of 1 that is centered at the origin.
*/
constexpr const glm::dmat3& getHalfAxes() const noexcept {
return this->_box.getHalfAxes();
}

/**
* @brief Gets the radius of the cylinder.
*/
constexpr double getRadius() const noexcept { return this->_radius; }

/**
* @brief Gets the height of the cylinder.
*/
constexpr double getHeight() const noexcept { return this->_height; }

/**
* @brief Gets the inverse transformation matrix, to rotate from world space
* to local space relative to the cylinder.
*/
constexpr const glm::dmat3& getInverseHalfAxes() const noexcept {
return this->_box.getInverseHalfAxes();
}

/**
* @brief Determines on which side of a plane the bounding cylinder is
* located.
*
* @param plane The plane to test against.
* @return The {@link CullingResult}:
* * `Inside` if the entire cylinder is on the side of the plane the normal
* is pointing.
* * `Outside` if the entire cylinder is on the opposite side.
* * `Intersecting` if the cylinder intersects the plane.
*/
CullingResult intersectPlane(const Plane& plane) const noexcept;

/**
* @brief Computes the distance squared from a given position to the closest
* point on the bounding volume. The bounding volume and the position must be
* expressed in the same coordinate system.
*
* @param position The position
* @return The estimated distance squared from the bounding box to the point.
*/
double
computeDistanceSquaredToPosition(const glm::dvec3& position) const noexcept;

/**
* @brief Computes whether the given position is contained within the bounding
* cylinder.
*
* @param position The position.
* @return Whether the position is contained within the bounding cylinder.
*/
bool contains(const glm::dvec3& position) const noexcept;

/**
* @brief Transforms this bounding cylinder to another coordinate system using
* a 4x4 matrix.
*
* @param transformation The transformation.
* @return The bounding cylinder in the new coordinate system.
*/
BoundingCylinder transform(const glm::dmat4& transformation) const noexcept;

private:
OrientedBoundingBox _box;
double _radius;
double _height;
};

} // namespace CesiumGeometry
Loading

0 comments on commit 21a6672

Please sign in to comment.