258 lines
9.7 KiB
C++
258 lines
9.7 KiB
C++
#include <CesiumGeospatial/Cartographic.h>
|
|
#include <CesiumGeospatial/GlobeRectangle.h>
|
|
#include <CesiumUtility/Math.h>
|
|
|
|
#include <doctest/doctest.h>
|
|
|
|
#include <optional>
|
|
#include <utility>
|
|
|
|
using namespace CesiumGeospatial;
|
|
using namespace CesiumUtility;
|
|
|
|
TEST_CASE("GlobeRectangle::fromDegrees example") {
|
|
//! [fromDegrees]
|
|
CesiumGeospatial::GlobeRectangle rectangle =
|
|
CesiumGeospatial::GlobeRectangle::fromDegrees(0.0, 20.0, 10.0, 30.0);
|
|
//! [fromDegrees]
|
|
(void)rectangle;
|
|
}
|
|
|
|
TEST_CASE("GlobeRectangle::isEmpty") { CHECK(GlobeRectangle::EMPTY.isEmpty()); }
|
|
|
|
TEST_CASE("GlobeRectangle::equals") {
|
|
GlobeRectangle simple(0.1, 0.2, 0.3, 0.4);
|
|
|
|
SUBCASE("returns true for self") {
|
|
CHECK(GlobeRectangle::equals(simple, simple));
|
|
}
|
|
|
|
SUBCASE("returns true for equal rectangle") {
|
|
GlobeRectangle equalRectangle(0.1, 0.2, 0.3, 0.4);
|
|
CHECK(GlobeRectangle::equals(simple, equalRectangle));
|
|
}
|
|
|
|
SUBCASE("returns false for unequal rectangles") {
|
|
GlobeRectangle unequalWest(0.11, 0.2, 0.3, 0.4);
|
|
CHECK(!GlobeRectangle::equals(simple, unequalWest));
|
|
|
|
GlobeRectangle unequalSouth(0.1, 0.202, 0.3, 0.4);
|
|
CHECK(!GlobeRectangle::equals(simple, unequalSouth));
|
|
|
|
GlobeRectangle unequalEast(0.1, 0.2, 0.300004, 0.4);
|
|
CHECK(!GlobeRectangle::equals(simple, unequalEast));
|
|
|
|
GlobeRectangle unequalNorth(0.1, 0.2, 0.3, 0.5);
|
|
CHECK(!GlobeRectangle::equals(simple, unequalNorth));
|
|
}
|
|
|
|
SUBCASE("splitAtAntiMeridian") {
|
|
// Cross Prime meridian, do not cross Antimeridian
|
|
GlobeRectangle nonCrossing =
|
|
GlobeRectangle::fromDegrees(-10.0, -20.0, 30.0, 40.0);
|
|
std::pair<GlobeRectangle, std::optional<GlobeRectangle>> split =
|
|
nonCrossing.splitAtAntiMeridian();
|
|
CHECK(!split.second);
|
|
CHECK(split.first.getWest() == nonCrossing.getWest());
|
|
CHECK(split.first.getEast() == nonCrossing.getEast());
|
|
CHECK(split.first.getSouth() == nonCrossing.getSouth());
|
|
CHECK(split.first.getNorth() == nonCrossing.getNorth());
|
|
|
|
// Do not cross Prime or Antimeridian
|
|
GlobeRectangle nonCrossing2 =
|
|
GlobeRectangle::fromDegrees(10.0, -20.0, 30.0, 40.0);
|
|
split = nonCrossing2.splitAtAntiMeridian();
|
|
CHECK(!split.second);
|
|
CHECK(split.first.getWest() == nonCrossing2.getWest());
|
|
CHECK(split.first.getEast() == nonCrossing2.getEast());
|
|
CHECK(split.first.getSouth() == nonCrossing2.getSouth());
|
|
CHECK(split.first.getNorth() == nonCrossing2.getNorth());
|
|
|
|
// Cross Antimeridian
|
|
GlobeRectangle crossing1 =
|
|
GlobeRectangle::fromDegrees(160.0, -20.0, -170.0, 40.0);
|
|
split = crossing1.splitAtAntiMeridian();
|
|
CHECK(split.first.getWest() == crossing1.getWest());
|
|
CHECK(split.first.getEast() == Math::OnePi);
|
|
CHECK(split.first.getSouth() == crossing1.getSouth());
|
|
CHECK(split.first.getNorth() == crossing1.getNorth());
|
|
REQUIRE(split.second);
|
|
CHECK(split.second->getWest() == -Math::OnePi);
|
|
CHECK(split.second->getEast() == crossing1.getEast());
|
|
CHECK(split.second->getSouth() == crossing1.getSouth());
|
|
CHECK(split.second->getNorth() == crossing1.getNorth());
|
|
|
|
// Same test, offset, with different returned order
|
|
GlobeRectangle crossing2 =
|
|
GlobeRectangle::fromDegrees(170.0, -20.0, -160.0, 40.0);
|
|
split = crossing2.splitAtAntiMeridian();
|
|
CHECK(split.first.getWest() == -Math::OnePi);
|
|
CHECK(split.first.getEast() == crossing2.getEast());
|
|
CHECK(split.first.getSouth() == crossing2.getSouth());
|
|
CHECK(split.first.getNorth() == crossing2.getNorth());
|
|
REQUIRE(split.second);
|
|
CHECK(split.second->getWest() == crossing2.getWest());
|
|
CHECK(split.second->getEast() == Math::OnePi);
|
|
CHECK(split.second->getSouth() == crossing2.getSouth());
|
|
CHECK(split.second->getNorth() == crossing2.getNorth());
|
|
|
|
// Cross Prime and Antimeridian
|
|
GlobeRectangle crossing3 =
|
|
GlobeRectangle::fromDegrees(-10.0, -20.0, -160.0, 40.0);
|
|
split = crossing3.splitAtAntiMeridian();
|
|
CHECK(split.first.getWest() == crossing3.getWest());
|
|
CHECK(split.first.getEast() == Math::OnePi);
|
|
CHECK(split.first.getSouth() == crossing3.getSouth());
|
|
CHECK(split.first.getNorth() == crossing3.getNorth());
|
|
REQUIRE(split.second);
|
|
CHECK(split.second->getWest() == -Math::OnePi);
|
|
CHECK(split.second->getEast() == crossing3.getEast());
|
|
CHECK(split.second->getSouth() == crossing3.getSouth());
|
|
CHECK(split.second->getNorth() == crossing3.getNorth());
|
|
}
|
|
}
|
|
|
|
TEST_CASE("GlobeRectangle::equalsEpsilon") {
|
|
GlobeRectangle simple(0.1, 0.2, 0.3, 0.4);
|
|
|
|
SUBCASE("returns true for self") {
|
|
CHECK(GlobeRectangle::equalsEpsilon(simple, simple, Math::Epsilon6));
|
|
}
|
|
|
|
SUBCASE("returns true for exactly equal rectangle") {
|
|
GlobeRectangle equalRectangle(0.1, 0.2, 0.3, 0.4);
|
|
CHECK(
|
|
GlobeRectangle::equalsEpsilon(simple, equalRectangle, Math::Epsilon6));
|
|
}
|
|
|
|
SUBCASE("returns true for rectangle within epsilon") {
|
|
GlobeRectangle epsilonWest(0.10001, 0.200, 0.3, 0.4);
|
|
CHECK(GlobeRectangle::equalsEpsilon(simple, epsilonWest, Math::Epsilon3));
|
|
|
|
GlobeRectangle epsilonSouth(0.1, 0.2002, 0.3, 0.4);
|
|
CHECK(GlobeRectangle::equalsEpsilon(simple, epsilonSouth, Math::Epsilon3));
|
|
|
|
GlobeRectangle epsilonEast(0.1, 0.2, 0.30003, 0.4);
|
|
CHECK(GlobeRectangle::equalsEpsilon(simple, epsilonEast, Math::Epsilon3));
|
|
|
|
GlobeRectangle epsilonNorth(0.1, 0.2, 0.3, 0.4004);
|
|
CHECK(GlobeRectangle::equalsEpsilon(simple, epsilonNorth, Math::Epsilon3));
|
|
}
|
|
|
|
SUBCASE("returns false for rectangle outside epsilon") {
|
|
GlobeRectangle unequalWest(0.11, 0.2, 0.3, 0.4);
|
|
CHECK(!GlobeRectangle::equalsEpsilon(simple, unequalWest, Math::Epsilon3));
|
|
|
|
GlobeRectangle unequalSouth(0.1, 0.202, 0.3, 0.4);
|
|
CHECK(!GlobeRectangle::equalsEpsilon(simple, unequalSouth, Math::Epsilon3));
|
|
|
|
GlobeRectangle unequalEast(0.1, 0.2, 0.301, 0.4);
|
|
CHECK(!GlobeRectangle::equalsEpsilon(simple, unequalEast, Math::Epsilon3));
|
|
|
|
GlobeRectangle unequalNorth(0.1, 0.2, 0.3, 0.5);
|
|
CHECK(!GlobeRectangle::equalsEpsilon(simple, unequalNorth, Math::Epsilon3));
|
|
}
|
|
}
|
|
|
|
TEST_CASE("GlobeRectangle::computeCenter") {
|
|
GlobeRectangle simple(0.1, 0.2, 0.3, 0.4);
|
|
Cartographic center = simple.computeCenter();
|
|
CHECK(Math::equalsEpsilon(center.longitude, 0.2, 0.0, Math::Epsilon14));
|
|
CHECK(Math::equalsEpsilon(center.latitude, 0.3, 0.0, Math::Epsilon14));
|
|
|
|
GlobeRectangle wrapping(3.0, 0.2, -3.1, 0.4);
|
|
center = wrapping.computeCenter();
|
|
double expectedLongitude =
|
|
3.0 + ((Math::OnePi - 3.0) + (-3.1 - -Math::OnePi)) * 0.5;
|
|
CHECK(Math::equalsEpsilon(
|
|
center.longitude,
|
|
expectedLongitude,
|
|
0.0,
|
|
Math::Epsilon14));
|
|
CHECK(Math::equalsEpsilon(center.latitude, 0.3, 0.0, Math::Epsilon14));
|
|
|
|
GlobeRectangle wrapping2(3.1, 0.2, -3.0, 0.4);
|
|
center = wrapping2.computeCenter();
|
|
expectedLongitude =
|
|
-3.0 - ((Math::OnePi - 3.1) + (-3.0 - -Math::OnePi)) * 0.5;
|
|
CHECK(Math::equalsEpsilon(
|
|
center.longitude,
|
|
expectedLongitude,
|
|
0.0,
|
|
Math::Epsilon14));
|
|
CHECK(Math::equalsEpsilon(center.latitude, 0.3, 0.0, Math::Epsilon14));
|
|
}
|
|
|
|
TEST_CASE("GlobeRectangle::contains") {
|
|
GlobeRectangle simple(0.1, 0.2, 0.3, 0.4);
|
|
CHECK(simple.contains(Cartographic(0.1, 0.2)));
|
|
CHECK(simple.contains(Cartographic(0.1, 0.4)));
|
|
CHECK(simple.contains(Cartographic(0.3, 0.4)));
|
|
CHECK(simple.contains(Cartographic(0.3, 0.2)));
|
|
CHECK(simple.contains(Cartographic(0.2, 0.3)));
|
|
CHECK(!simple.contains(Cartographic(0.0, 0.2)));
|
|
|
|
GlobeRectangle wrapping(3.0, 0.2, -3.1, 0.4);
|
|
CHECK(wrapping.contains(Cartographic(Math::OnePi, 0.2)));
|
|
CHECK(wrapping.contains(Cartographic(-Math::OnePi, 0.2)));
|
|
CHECK(wrapping.contains(Cartographic(3.14, 0.2)));
|
|
CHECK(wrapping.contains(Cartographic(-3.14, 0.2)));
|
|
CHECK(!wrapping.contains(Cartographic(0.0, 0.2)));
|
|
}
|
|
|
|
TEST_CASE("GlobeRectangle::computeNormalizedCoordinates") {
|
|
GlobeRectangle simple(0.0, 0.0, 1.0, 1.0);
|
|
CHECK(
|
|
simple.computeNormalizedCoordinates(Cartographic(0.1, 0.1)) ==
|
|
glm::dvec2(0.1, 0.1));
|
|
CHECK(
|
|
simple.computeNormalizedCoordinates(Cartographic(0, 0.0)) ==
|
|
glm::dvec2(0.0, 0.0));
|
|
CHECK(
|
|
simple.computeNormalizedCoordinates(Cartographic(1.0, 1.0)) ==
|
|
glm::dvec2(1.0, 1.0));
|
|
|
|
GlobeRectangle wrapping =
|
|
GlobeRectangle::fromDegrees(175.0, 0.0, -175.0, 10.0);
|
|
CHECK(
|
|
wrapping.computeNormalizedCoordinates(
|
|
Cartographic::fromDegrees(175.0, 5.0)) == glm::dvec2(0.0, 0.5));
|
|
CHECK(
|
|
wrapping.computeNormalizedCoordinates(
|
|
Cartographic::fromDegrees(180.0, 10.0)) == glm::dvec2(0.5, 1.0));
|
|
CHECK(
|
|
wrapping.computeNormalizedCoordinates(
|
|
Cartographic::fromDegrees(-180.0, 0.0)) == glm::dvec2(0.5, 0.0));
|
|
CHECK(Math::equalsEpsilon(
|
|
wrapping.computeNormalizedCoordinates(
|
|
Cartographic::fromDegrees(-177.5, 0.0)),
|
|
glm::dvec2(0.75, 0.0),
|
|
Math::Epsilon6));
|
|
CHECK(
|
|
wrapping.computeNormalizedCoordinates(
|
|
Cartographic::fromDegrees(-175, 0.0)) == glm::dvec2(1.0, 0.0));
|
|
|
|
GlobeRectangle tile = GlobeRectangle::fromDegrees(0.5, 0, 1.0, 0.5);
|
|
CHECK(Math::equalsEpsilon(
|
|
tile.computeNormalizedCoordinates(Cartographic::fromDegrees(0.25, 0.25)),
|
|
glm::dvec2(-0.5, 0.5),
|
|
Math::Epsilon6));
|
|
CHECK(Math::equalsEpsilon(
|
|
tile.computeNormalizedCoordinates(Cartographic::fromDegrees(0.5, 0.75)),
|
|
glm::dvec2(0, 1.5),
|
|
Math::Epsilon6));
|
|
CHECK(Math::equalsEpsilon(
|
|
tile.computeNormalizedCoordinates(Cartographic::fromDegrees(0.75, 0.25)),
|
|
glm::dvec2(0.5, 0.5),
|
|
Math::Epsilon6));
|
|
|
|
GlobeRectangle bigWrapping =
|
|
GlobeRectangle::fromDegrees(179.0, -10.0, 10.0, 10.0);
|
|
CHECK(Math::equalsEpsilon(
|
|
bigWrapping.computeNormalizedCoordinates(
|
|
Cartographic::fromDegrees(5.0, 0.0)),
|
|
// Rectangle width is 191 degrees, position is 5 degrees west of east
|
|
// edge.
|
|
glm::dvec2(186.0 / 191.0, 0.5),
|
|
Math::Epsilon6));
|
|
} |