Add BoundingRegionWithLooseFittingHeights, better use of std::variant

This commit is contained in:
Kevin Ring 2020-08-24 17:38:04 +10:00
parent d18aad7ca2
commit f50aaae886
5 changed files with 189 additions and 87 deletions

View File

@ -5,9 +5,16 @@
#include "CesiumGeometry/OrientedBoundingBox.h"
#include "CesiumGeospatial/BoundingRegion.h"
#include "CesiumGeometry/BoundingSphere.h"
#include "CesiumGeospatial/BoundingRegionWithLooseFittingHeights.h"
namespace Cesium3DTiles {
typedef std::variant<CesiumGeometry::OrientedBoundingBox, CesiumGeospatial::BoundingRegion, CesiumGeometry::BoundingSphere> BoundingVolume;
typedef std::variant<
CesiumGeometry::BoundingSphere,
CesiumGeometry::OrientedBoundingBox,
CesiumGeospatial::BoundingRegion,
CesiumGeospatial::BoundingRegionWithLooseFittingHeights
> BoundingVolume;
CESIUM3DTILES_API BoundingVolume transformBoundingVolume(const glm::dmat4x4& transform, const BoundingVolume& boundingVolume);
CESIUM3DTILES_API glm::dvec3 getBoundingVolumeCenter(const BoundingVolume& boundingVolume);

View File

@ -7,59 +7,63 @@ using namespace CesiumGeospatial;
namespace Cesium3DTiles {
BoundingVolume transformBoundingVolume(const glm::dmat4x4& transform, const BoundingVolume& boundingVolume) {
switch (boundingVolume.index()) {
case 0:
{
const OrientedBoundingBox& boundingBox = std::get<OrientedBoundingBox>(boundingVolume);
glm::dvec3 center = transform * glm::dvec4(boundingBox.getCenter(), 1.0);
glm::dmat3 halfAxes = glm::dmat3(transform) * boundingBox.getHalfAxes();
return OrientedBoundingBox(center, halfAxes);
}
case 1:
{
// Regions are not transformed.
return boundingVolume;
}
case 2:
{
const BoundingSphere& boundingSphere = std::get<BoundingSphere>(boundingVolume);
glm::dvec3 center = transform * glm::dvec4(boundingSphere.getCenter(), 1.0);
struct Operation {
const glm::dmat4x4& transform;
double uniformScale = std::max(
std::max(
glm::length(glm::dvec3(transform[0])),
glm::length(glm::dvec3(transform[1]))
),
glm::length(glm::dvec3(transform[2]))
);
BoundingVolume operator()(const OrientedBoundingBox& boundingBox) {
glm::dvec3 center = transform * glm::dvec4(boundingBox.getCenter(), 1.0);
glm::dmat3 halfAxes = glm::dmat3(transform) * boundingBox.getHalfAxes();
return OrientedBoundingBox(center, halfAxes);
}
return BoundingSphere(center, boundingSphere.getRadius() * uniformScale);
}
default:
return boundingVolume;
}
BoundingVolume operator()(const BoundingRegion& boundingRegion) {
// Regions are not transformed.
return boundingRegion;
}
BoundingVolume operator()(const BoundingSphere& boundingSphere) {
glm::dvec3 center = transform * glm::dvec4(boundingSphere.getCenter(), 1.0);
double uniformScale = std::max(
std::max(
glm::length(glm::dvec3(transform[0])),
glm::length(glm::dvec3(transform[1]))
),
glm::length(glm::dvec3(transform[2]))
);
return BoundingSphere(center, boundingSphere.getRadius() * uniformScale);
}
BoundingVolume operator()(const BoundingRegionWithLooseFittingHeights& boundingRegion) {
// Regions are not transformed.
return boundingRegion;
}
};
return std::visit(Operation { transform }, boundingVolume);
}
glm::dvec3 getBoundingVolumeCenter(const BoundingVolume& boundingVolume) {
switch (boundingVolume.index()) {
case 0:
{
const OrientedBoundingBox& boundingBox = std::get<OrientedBoundingBox>(boundingVolume);
return boundingBox.getCenter();
}
case 1:
{
const BoundingRegion& region = std::get<BoundingRegion>(boundingVolume);
return region.getBoundingBox().getCenter();
}
case 2:
{
const BoundingSphere& boundingSphere = std::get<BoundingSphere>(boundingVolume);
return boundingSphere.getCenter();
}
default:
return glm::dvec3(0.0);
}
struct Operation {
glm::dvec3 operator()(const OrientedBoundingBox& boundingBox) {
return boundingBox.getCenter();
}
glm::dvec3 operator()(const BoundingRegion& boundingRegion) {
return boundingRegion.getBoundingBox().getCenter();
}
glm::dvec3 operator()(const BoundingSphere& boundingSphere) {
return boundingSphere.getCenter();
}
glm::dvec3 operator()(const BoundingRegionWithLooseFittingHeights& boundingRegion) {
return boundingRegion.getBoundingRegion().getBoundingBox().getCenter();
}
};
return std::visit(Operation {}, boundingVolume);
}
}

View File

@ -149,47 +149,51 @@ namespace Cesium3DTiles {
bool Camera::isBoundingVolumeVisible(const BoundingVolume& boundingVolume) const {
// TODO: use plane masks
switch (boundingVolume.index()) {
case 0:
{
const OrientedBoundingBox& boundingBox = std::get<OrientedBoundingBox>(boundingVolume);
return Cesium3DTiles::isBoundingVolumeVisible(boundingBox, this->_leftPlane, this->_rightPlane, this->_bottomPlane, this->_topPlane);
}
case 1:
{
const BoundingRegion& boundingRegion = std::get<BoundingRegion>(boundingVolume);
return Cesium3DTiles::isBoundingVolumeVisible(boundingRegion, this->_leftPlane, this->_rightPlane, this->_bottomPlane, this->_topPlane);
}
case 2:
{
const BoundingSphere& boundingSphere = std::get<BoundingSphere>(boundingVolume);
return Cesium3DTiles::isBoundingVolumeVisible(boundingSphere, this->_leftPlane, this->_rightPlane, this->_bottomPlane, this->_topPlane);
}
default:
return true;
}
struct Operation {
const Camera& camera;
bool operator()(const OrientedBoundingBox& boundingBox) {
return Cesium3DTiles::isBoundingVolumeVisible(boundingBox, camera._leftPlane, camera._rightPlane, camera._bottomPlane, camera._topPlane);
}
bool operator()(const BoundingRegion& boundingRegion) {
return Cesium3DTiles::isBoundingVolumeVisible(boundingRegion, camera._leftPlane, camera._rightPlane, camera._bottomPlane, camera._topPlane);
}
bool operator()(const BoundingSphere& boundingSphere) {
return Cesium3DTiles::isBoundingVolumeVisible(boundingSphere, camera._leftPlane, camera._rightPlane, camera._bottomPlane, camera._topPlane);
}
bool operator()(const BoundingRegionWithLooseFittingHeights& boundingRegion) {
return Cesium3DTiles::isBoundingVolumeVisible(boundingRegion.getBoundingRegion(), camera._leftPlane, camera._rightPlane, camera._bottomPlane, camera._topPlane);
}
};
return std::visit(Operation { *this }, boundingVolume);
}
double Camera::computeDistanceSquaredToBoundingVolume(const BoundingVolume& boundingVolume) const {
switch (boundingVolume.index()) {
case 0:
{
const OrientedBoundingBox& boundingBox = std::get<OrientedBoundingBox>(boundingVolume);
return boundingBox.computeDistanceSquaredToPosition(this->_position);
}
case 1:
{
const BoundingRegion& boundingRegion = std::get<BoundingRegion>(boundingVolume);
return boundingRegion.computeDistanceSquaredToPosition(this->_position);
}
case 2:
{
const BoundingSphere& boundingSphere = std::get<BoundingSphere>(boundingVolume);
return boundingSphere.computeDistanceSquaredToPosition(this->_position);
}
default:
return 0.0;
}
struct Operation {
const Camera& camera;
double operator()(const OrientedBoundingBox& boundingBox) {
return boundingBox.computeDistanceSquaredToPosition(camera._position);
}
double operator()(const BoundingRegion& boundingRegion) {
return boundingRegion.computeDistanceSquaredToPosition(camera._position);
}
double operator()(const BoundingSphere& boundingSphere) {
return boundingSphere.computeDistanceSquaredToPosition(camera._position);
}
double operator()(const BoundingRegionWithLooseFittingHeights& boundingRegion) {
return boundingRegion.computeConservativeDistanceSquaredToPosition(camera._position);
}
};
return std::visit(Operation { *this }, boundingVolume);
}
double Camera::computeScreenSpaceError(double geometricError, double distance) const {

View File

@ -0,0 +1,85 @@
#pragma once
#include "CesiumGeospatial/Library.h"
#include "CesiumGeospatial/BoundingRegion.h"
namespace CesiumGeospatial {
/**
* @brief A {@see BoundingRegion} whose heights might be very inaccurate and so distances should be estimated conservatively
* for level-of-detail computations.
*
* An instance of this class serves as a marker of the imprecision of the heights in a {@see BoundingRegion}, and also
* has a {@see BoundingRegionWithLooseFittingHeights::computeConservativeDistanceSquaredToPosition} method to compute
* the conservative distance metric.
*/
class CESIUMGEOSPATIAL_API BoundingRegionWithLooseFittingHeights {
public:
/**
* @brief Constructs a new bounding region.
*
* @param boundingRegion The bounding region that has imprecise heights.
*/
BoundingRegionWithLooseFittingHeights(const BoundingRegion& boundingRegion);
/**
* @brief Gets the bounding region that has imprecise heights.
*/
const BoundingRegion& getBoundingRegion() const { return this->_region; }
/**
* @brief Computes the conservative distance-squared from a position in ellipsoid-centered Cartesian coordinates
* to the closest point in this bounding region.
*
* It is conservative in that the distance is computed using whichever
* is _farther away_ of this bounding region's imprecise minimum and maximum heights, so the returned distance
* may be greater than what the distance to the bounding region would be if the heights were precise. When used for level-of-detail
* selection, this ensures that imprecise selection caused by the imprecise heights will cause _too little_ detail to
* be loaded rather than too much detail. This is important because overestimating the required level-of-detail can require
* an excessive number of tiles to be loaded.
*
* @param position The position.
* @param ellipsoid The ellipsoid on which this region is defined.
* @return The distance-squared from the position to the closest point in the bounding region.
*/
double computeConservativeDistanceSquaredToPosition(const glm::dvec3& position, const Ellipsoid& ellipsoid = Ellipsoid::WGS84) const { return this->_region.computeDistanceSquaredToPosition(position, ellipsoid); }
/**
* @brief Computes the conservative distance-squared from a longitude-latitude-height position
* to the closest point in this bounding region.
*
* It is conservative in that the distance is computed using whichever
* is _farther away_ of this bounding region's imprecise minimum and maximum heights, so the returned distance
* may be greater than what the distance to the bounding region would be if the heights were precise. When used for level-of-detail
* selection, this ensures that imprecise selection caused by the imprecise heights will cause _too little_ detail to
* be loaded rather than too much detail. This is important because overestimating the required level-of-detail can require
* an excessive number of tiles to be loaded.
*
* @param position The position.
* @param ellipsoid The ellipsoid on which this region is defined.
* @return The distance-squared from the position to the closest point in the bounding region.
*/
double computeConservativeDistanceSquaredToPosition(const Cartographic& position, const Ellipsoid& ellipsoid = Ellipsoid::WGS84) const { return this->_region.computeDistanceSquaredToPosition(position, ellipsoid); }
/**
* @brief Computes the conservative distance-squared from a position to the closest point in this bounding region, when the longitude-latitude-height
* and ellipsoid-centered Cartesian coordinates of the position are both already known.
*
* It is conservative in that the distance is computed using whichever
* is _farther away_ of this bounding region's imprecise minimum and maximum heights, so the returned distance
* may be greater than what the distance to the bounding region would be if the heights were precise. When used for level-of-detail
* selection, this ensures that imprecise selection caused by the imprecise heights will cause _too little_ detail to
* be loaded rather than too much detail. This is important because overestimating the required level-of-detail can require
* an excessive number of tiles to be loaded.
*
* @param cartographicPosition The position as a longitude-latitude-height.
* @param cartesianPosition The position as ellipsoid-centered Cartesian coordinates.
* @return The distance-squared from the position to the closest point in the bounding region.
*/
double computeConservativeDistanceSquaredToPosition(const Cartographic& cartographicPosition, const glm::dvec3& cartesianPosition) const { return this->_region.computeDistanceSquaredToPosition(cartographicPosition, cartesianPosition); }
private:
BoundingRegion _region;
};
}

View File

@ -0,0 +1,2 @@
#include "CesiumGeospatial/BoundingRegionWithLooseFittingHeights.h"