380 lines
13 KiB
C++
380 lines
13 KiB
C++
#include <Cesium3DTilesContent/ImplicitTilingUtilities.h>
|
|
#include <CesiumGeometry/OrientedBoundingBox.h>
|
|
#include <CesiumGeospatial/BoundingRegion.h>
|
|
#include <CesiumGeospatial/S2CellBoundingVolume.h>
|
|
|
|
#include <catch2/catch.hpp>
|
|
#include <libmorton/morton.h>
|
|
|
|
#include <algorithm>
|
|
|
|
using namespace CesiumGeometry;
|
|
using namespace CesiumGeospatial;
|
|
using namespace Cesium3DTilesContent;
|
|
|
|
TEST_CASE("ImplicitTilingUtilities child tile iteration") {
|
|
SECTION("QuadtreeTileID") {
|
|
QuadtreeTileID parent(11, 2, 3);
|
|
|
|
QuadtreeChildren children = ImplicitTilingUtilities::getChildren(parent);
|
|
|
|
// Check we can enumerate the children with a range-based for loop.
|
|
int count = 0;
|
|
for (const QuadtreeTileID& tileID : children) {
|
|
CHECK(tileID.level == 12);
|
|
CHECK((tileID.x == 4 || tileID.x == 5));
|
|
CHECK((tileID.y == 6 || tileID.y == 7));
|
|
++count;
|
|
}
|
|
|
|
CHECK(count == 4);
|
|
|
|
// Check we have exactly the right children.
|
|
std::vector<QuadtreeTileID> expected{
|
|
QuadtreeTileID(12, 4, 6),
|
|
QuadtreeTileID(12, 5, 6),
|
|
QuadtreeTileID(12, 4, 7),
|
|
QuadtreeTileID(12, 5, 7)};
|
|
auto mismatch = std::mismatch(
|
|
children.begin(),
|
|
children.end(),
|
|
expected.begin(),
|
|
expected.end());
|
|
CHECK(mismatch.first == children.end());
|
|
CHECK(mismatch.second == expected.end());
|
|
}
|
|
|
|
SECTION("OctreeTileID") {
|
|
OctreeTileID parent(11, 2, 3, 4);
|
|
|
|
OctreeChildren children = ImplicitTilingUtilities::getChildren(parent);
|
|
|
|
// Check we can enumerate the children with a range-based for loop.
|
|
int count = 0;
|
|
for (const OctreeTileID& tileID : children) {
|
|
CHECK(tileID.level == 12);
|
|
CHECK((tileID.x == 4 || tileID.x == 5));
|
|
CHECK((tileID.y == 6 || tileID.y == 7));
|
|
CHECK((tileID.z == 8 || tileID.z == 9));
|
|
++count;
|
|
}
|
|
|
|
CHECK(count == 8);
|
|
|
|
// Check we have exactly the right children.
|
|
std::vector<OctreeTileID> expected{
|
|
OctreeTileID(12, 4, 6, 8),
|
|
OctreeTileID(12, 5, 6, 8),
|
|
OctreeTileID(12, 4, 7, 8),
|
|
OctreeTileID(12, 5, 7, 8),
|
|
OctreeTileID(12, 4, 6, 9),
|
|
OctreeTileID(12, 5, 6, 9),
|
|
OctreeTileID(12, 4, 7, 9),
|
|
OctreeTileID(12, 5, 7, 9)};
|
|
auto mismatch = std::mismatch(
|
|
children.begin(),
|
|
children.end(),
|
|
expected.begin(),
|
|
expected.end());
|
|
CHECK(mismatch.first == children.end());
|
|
CHECK(mismatch.second == expected.end());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("ImplicitTilingUtilities::resolveUrl") {
|
|
SECTION("quadtree") {
|
|
QuadtreeTileID tileID(11, 2, 3);
|
|
std::string url = ImplicitTilingUtilities::resolveUrl(
|
|
"https://example.com",
|
|
"tiles/{level}/{x}/{y}",
|
|
tileID);
|
|
CHECK(url == "https://example.com/tiles/11/2/3");
|
|
}
|
|
|
|
SECTION("octree") {
|
|
OctreeTileID tileID(11, 2, 3, 4);
|
|
std::string url = ImplicitTilingUtilities::resolveUrl(
|
|
"https://example.com",
|
|
"tiles/{level}/{x}/{y}/{z}",
|
|
tileID);
|
|
CHECK(url == "https://example.com/tiles/11/2/3/4");
|
|
}
|
|
}
|
|
|
|
TEST_CASE("ImplicitTilingUtilities::computeMortonIndex") {
|
|
SECTION("quadtree") {
|
|
QuadtreeTileID tileID(11, 2, 3);
|
|
CHECK(
|
|
ImplicitTilingUtilities::computeMortonIndex(tileID) ==
|
|
libmorton::morton2D_64_encode(2, 3));
|
|
}
|
|
|
|
SECTION("quadtree") {
|
|
OctreeTileID tileID(11, 2, 3, 4);
|
|
CHECK(
|
|
ImplicitTilingUtilities::computeMortonIndex(tileID) ==
|
|
libmorton::morton3D_64_encode(2, 3, 4));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("ImplicitTilingUtilities::computeRelativeMortonIndex") {
|
|
SECTION("quadtree") {
|
|
QuadtreeTileID rootID(11, 2, 3);
|
|
QuadtreeTileID tileID(12, 5, 6);
|
|
CHECK(
|
|
ImplicitTilingUtilities::computeRelativeMortonIndex(rootID, tileID) ==
|
|
1);
|
|
}
|
|
|
|
SECTION("octree") {
|
|
OctreeTileID rootID(11, 2, 3, 4);
|
|
OctreeTileID tileID(12, 5, 6, 8);
|
|
CHECK(
|
|
ImplicitTilingUtilities::computeRelativeMortonIndex(rootID, tileID) ==
|
|
1);
|
|
}
|
|
}
|
|
|
|
TEST_CASE("ImplicitTilingUtilities::getSubtreeRootID") {
|
|
SECTION("quadtree") {
|
|
QuadtreeTileID tileID(10, 2, 3);
|
|
CHECK(
|
|
ImplicitTilingUtilities::getSubtreeRootID(5, tileID) ==
|
|
QuadtreeTileID(10, 2, 3));
|
|
CHECK(
|
|
ImplicitTilingUtilities::getSubtreeRootID(4, tileID) ==
|
|
QuadtreeTileID(8, 0, 0));
|
|
}
|
|
|
|
SECTION("octree") {
|
|
OctreeTileID tileID(10, 2, 3, 4);
|
|
CHECK(
|
|
ImplicitTilingUtilities::getSubtreeRootID(5, tileID) ==
|
|
OctreeTileID(10, 2, 3, 4));
|
|
CHECK(
|
|
ImplicitTilingUtilities::getSubtreeRootID(4, tileID) ==
|
|
OctreeTileID(8, 0, 0, 1));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("ImplicitTilingUtilities::absoluteTileIDToRelative") {
|
|
SECTION("quadtree") {
|
|
CHECK(
|
|
ImplicitTilingUtilities::absoluteTileIDToRelative(
|
|
QuadtreeTileID(0, 0, 0),
|
|
QuadtreeTileID(11, 2, 3)) == QuadtreeTileID(11, 2, 3));
|
|
CHECK(
|
|
ImplicitTilingUtilities::absoluteTileIDToRelative(
|
|
QuadtreeTileID(11, 2, 3),
|
|
QuadtreeTileID(11, 2, 3)) == QuadtreeTileID(0, 0, 0));
|
|
CHECK(
|
|
ImplicitTilingUtilities::absoluteTileIDToRelative(
|
|
QuadtreeTileID(11, 2, 3),
|
|
QuadtreeTileID(12, 5, 7)) == QuadtreeTileID(1, 1, 1));
|
|
}
|
|
|
|
SECTION("octree") {
|
|
CHECK(
|
|
ImplicitTilingUtilities::absoluteTileIDToRelative(
|
|
OctreeTileID(0, 0, 0, 0),
|
|
OctreeTileID(11, 2, 3, 4)) == OctreeTileID(11, 2, 3, 4));
|
|
CHECK(
|
|
ImplicitTilingUtilities::absoluteTileIDToRelative(
|
|
OctreeTileID(11, 2, 3, 4),
|
|
OctreeTileID(11, 2, 3, 4)) == OctreeTileID(0, 0, 0, 0));
|
|
CHECK(
|
|
ImplicitTilingUtilities::absoluteTileIDToRelative(
|
|
OctreeTileID(11, 2, 3, 4),
|
|
OctreeTileID(12, 5, 7, 9)) == OctreeTileID(1, 1, 1, 1));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("ImplicitTilingUtilities::computeLevelDenominator") {
|
|
CHECK(ImplicitTilingUtilities::computeLevelDenominator(0) == 1.0);
|
|
CHECK(ImplicitTilingUtilities::computeLevelDenominator(1) == 2.0);
|
|
CHECK(ImplicitTilingUtilities::computeLevelDenominator(2) == 4.0);
|
|
}
|
|
|
|
TEST_CASE("ImplicitTilingUtilities::computeBoundingVolume") {
|
|
SECTION("OrientedBoundingBox") {
|
|
SECTION("quadtree") {
|
|
OrientedBoundingBox root(glm::dvec3(1.0, 2.0, 3.0), glm::dmat3(10.0));
|
|
|
|
OrientedBoundingBox l1x0y0 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 0, 0));
|
|
CHECK(l1x0y0.getCenter() == glm::dvec3(-4.0, -3.0, 3.0));
|
|
CHECK(l1x0y0.getLengths() == glm::dvec3(10.0, 10.0, 20.0));
|
|
|
|
OrientedBoundingBox l1x1y0 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 1, 0));
|
|
CHECK(l1x1y0.getCenter() == glm::dvec3(6.0, -3.0, 3.0));
|
|
CHECK(l1x1y0.getLengths() == glm::dvec3(10.0, 10.0, 20.0));
|
|
|
|
OrientedBoundingBox l1x0y1 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 0, 1));
|
|
CHECK(l1x0y1.getCenter() == glm::dvec3(-4.0, 7.0, 3.0));
|
|
CHECK(l1x0y1.getLengths() == glm::dvec3(10.0, 10.0, 20.0));
|
|
}
|
|
|
|
SECTION("octree") {
|
|
OrientedBoundingBox root(glm::dvec3(1.0, 2.0, 3.0), glm::dmat3(10.0));
|
|
|
|
OrientedBoundingBox l1x0y0z0 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 0, 0, 0));
|
|
CHECK(l1x0y0z0.getCenter() == glm::dvec3(-4.0, -3.0, -2.0));
|
|
CHECK(l1x0y0z0.getLengths() == glm::dvec3(10.0, 10.0, 10.0));
|
|
|
|
OrientedBoundingBox l1x1y0z0 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 1, 0, 0));
|
|
CHECK(l1x1y0z0.getCenter() == glm::dvec3(6.0, -3.0, -2.0));
|
|
CHECK(l1x1y0z0.getLengths() == glm::dvec3(10.0, 10.0, 10.0));
|
|
|
|
OrientedBoundingBox l1x0y1z0 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 0, 1, 0));
|
|
CHECK(l1x0y1z0.getCenter() == glm::dvec3(-4.0, 7.0, -2.0));
|
|
CHECK(l1x0y1z0.getLengths() == glm::dvec3(10.0, 10.0, 10.0));
|
|
|
|
OrientedBoundingBox l1x0y0z1 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 0, 0, 1));
|
|
CHECK(l1x0y0z1.getCenter() == glm::dvec3(-4.0, -3.0, 8.0));
|
|
CHECK(l1x0y0z1.getLengths() == glm::dvec3(10.0, 10.0, 10.0));
|
|
}
|
|
}
|
|
|
|
SECTION("BoundingRegion") {
|
|
SECTION("quadtree") {
|
|
BoundingRegion root(GlobeRectangle(1.0, 2.0, 3.0, 4.0), 10.0, 20.0);
|
|
|
|
BoundingRegion l1x0y0 = ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 0, 0));
|
|
CHECK(l1x0y0.getRectangle().getWest() == 1.0);
|
|
CHECK(l1x0y0.getRectangle().getSouth() == 2.0);
|
|
CHECK(l1x0y0.getRectangle().getEast() == 2.0);
|
|
CHECK(l1x0y0.getRectangle().getNorth() == 3.0);
|
|
CHECK(l1x0y0.getMinimumHeight() == 10.0);
|
|
CHECK(l1x0y0.getMaximumHeight() == 20.0);
|
|
|
|
BoundingRegion l1x1y0 = ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 1, 0));
|
|
CHECK(l1x1y0.getRectangle().getWest() == 2.0);
|
|
CHECK(l1x1y0.getRectangle().getSouth() == 2.0);
|
|
CHECK(l1x1y0.getRectangle().getEast() == 3.0);
|
|
CHECK(l1x1y0.getRectangle().getNorth() == 3.0);
|
|
CHECK(l1x1y0.getMinimumHeight() == 10.0);
|
|
CHECK(l1x1y0.getMaximumHeight() == 20.0);
|
|
|
|
BoundingRegion l1x0y1 = ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 0, 1));
|
|
CHECK(l1x0y1.getRectangle().getWest() == 1.0);
|
|
CHECK(l1x0y1.getRectangle().getSouth() == 3.0);
|
|
CHECK(l1x0y1.getRectangle().getEast() == 2.0);
|
|
CHECK(l1x0y1.getRectangle().getNorth() == 4.0);
|
|
CHECK(l1x0y1.getMinimumHeight() == 10.0);
|
|
CHECK(l1x0y1.getMaximumHeight() == 20.0);
|
|
}
|
|
|
|
SECTION("octree") {
|
|
BoundingRegion root(GlobeRectangle(1.0, 2.0, 3.0, 4.0), 10.0, 20.0);
|
|
|
|
BoundingRegion l1x0y0z0 = ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 0, 0, 0));
|
|
CHECK(l1x0y0z0.getRectangle().getWest() == 1.0);
|
|
CHECK(l1x0y0z0.getRectangle().getSouth() == 2.0);
|
|
CHECK(l1x0y0z0.getRectangle().getEast() == 2.0);
|
|
CHECK(l1x0y0z0.getRectangle().getNorth() == 3.0);
|
|
CHECK(l1x0y0z0.getMinimumHeight() == 10.0);
|
|
CHECK(l1x0y0z0.getMaximumHeight() == 15.0);
|
|
|
|
BoundingRegion l1x1y0z0 = ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 1, 0, 0));
|
|
CHECK(l1x1y0z0.getRectangle().getWest() == 2.0);
|
|
CHECK(l1x1y0z0.getRectangle().getSouth() == 2.0);
|
|
CHECK(l1x1y0z0.getRectangle().getEast() == 3.0);
|
|
CHECK(l1x1y0z0.getRectangle().getNorth() == 3.0);
|
|
CHECK(l1x1y0z0.getMinimumHeight() == 10.0);
|
|
CHECK(l1x1y0z0.getMaximumHeight() == 15.0);
|
|
|
|
BoundingRegion l1x0y1z0 = ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 0, 1, 0));
|
|
CHECK(l1x0y1z0.getRectangle().getWest() == 1.0);
|
|
CHECK(l1x0y1z0.getRectangle().getSouth() == 3.0);
|
|
CHECK(l1x0y1z0.getRectangle().getEast() == 2.0);
|
|
CHECK(l1x0y1z0.getRectangle().getNorth() == 4.0);
|
|
CHECK(l1x0y1z0.getMinimumHeight() == 10.0);
|
|
CHECK(l1x0y1z0.getMaximumHeight() == 15.0);
|
|
|
|
BoundingRegion l1x0y0z1 = ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
OctreeTileID(1, 0, 0, 1));
|
|
CHECK(l1x0y0z1.getRectangle().getWest() == 1.0);
|
|
CHECK(l1x0y0z1.getRectangle().getSouth() == 2.0);
|
|
CHECK(l1x0y0z1.getRectangle().getEast() == 2.0);
|
|
CHECK(l1x0y0z1.getRectangle().getNorth() == 3.0);
|
|
CHECK(l1x0y0z1.getMinimumHeight() == 15.0);
|
|
CHECK(l1x0y0z1.getMaximumHeight() == 20.0);
|
|
}
|
|
}
|
|
|
|
SECTION("S2") {
|
|
SECTION("quadtree") {
|
|
S2CellBoundingVolume root(
|
|
S2CellID::fromQuadtreeTileID(1, QuadtreeTileID(0, 0, 0)),
|
|
10.0,
|
|
20.0);
|
|
|
|
S2CellBoundingVolume l1x0y0 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 0, 0));
|
|
CHECK(l1x0y0.getCellID().getFace() == 1);
|
|
CHECK(
|
|
l1x0y0.getCellID().getID() ==
|
|
S2CellID::fromQuadtreeTileID(1, QuadtreeTileID(1, 0, 0)).getID());
|
|
CHECK(l1x0y0.getMinimumHeight() == 10.0);
|
|
CHECK(l1x0y0.getMaximumHeight() == 20.0);
|
|
|
|
S2CellBoundingVolume l1x1y0 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 1, 0));
|
|
CHECK(l1x1y0.getCellID().getFace() == 1);
|
|
CHECK(
|
|
l1x1y0.getCellID().getID() ==
|
|
S2CellID::fromQuadtreeTileID(1, QuadtreeTileID(1, 1, 0)).getID());
|
|
CHECK(l1x1y0.getMinimumHeight() == 10.0);
|
|
CHECK(l1x1y0.getMaximumHeight() == 20.0);
|
|
|
|
S2CellBoundingVolume l1x0y1 =
|
|
ImplicitTilingUtilities::computeBoundingVolume(
|
|
root,
|
|
QuadtreeTileID(1, 0, 1));
|
|
CHECK(l1x0y1.getCellID().getFace() == 1);
|
|
CHECK(
|
|
l1x0y1.getCellID().getID() ==
|
|
S2CellID::fromQuadtreeTileID(1, QuadtreeTileID(1, 0, 1)).getID());
|
|
CHECK(l1x0y1.getMinimumHeight() == 10.0);
|
|
CHECK(l1x0y1.getMaximumHeight() == 20.0);
|
|
}
|
|
}
|
|
}
|