cesium-native/CesiumGltfReader/test/TestExtensionModelExtStruct...

233 lines
7.2 KiB
C++

#include <CesiumAsync/AsyncSystem.h>
#include <CesiumGltf/ExtensionModelExtStructuralMetadata.h>
#include <CesiumGltfReader/GltfReader.h>
#include <CesiumGltfReader/GltfSharedAssetSystem.h>
#include <CesiumNativeTests/SimpleAssetAccessor.h>
#include <CesiumNativeTests/SimpleAssetRequest.h>
#include <CesiumNativeTests/SimpleAssetResponse.h>
#include <CesiumNativeTests/SimpleTaskProcessor.h>
#include <doctest/doctest.h>
#include <cstddef>
#include <cstdint>
#include <map>
#include <memory>
#include <span>
#include <string>
#include <utility>
#include <vector>
using namespace CesiumGltf;
using namespace CesiumUtility;
using namespace CesiumNativeTests;
TEST_CASE(
"Can deserialize EXT_structural_metadata example with propertyTables") {
const std::string s = R"(
{
"asset": {
"version": "2.0"
},
"extensions": {
"EXT_structural_metadata": {
"schema": {
"classes": {
"tree": {
"properties": {
"height": {
"description": "Height of tree measured from ground level",
"type": "SCALAR",
"componentType": "FLOAT32"
},
"birdCount": {
"description": "Number of birds perching on the tree",
"type": "SCALAR",
"componentType": "UINT8",
"min": 1
},
"species": {
"description": "Species of the tree",
"type": "STRING"
}
}
}
}
},
"propertyTables": [
{
"class": "tree",
"count": 10,
"properties": {
"height": {
"values": 0
},
"birdCount": {
"values": 1
},
"species": {
"values": 2,
"stringOffsets": 3
}
}
}
]
}
}
}
)";
CesiumGltfReader::GltfReaderOptions options;
CesiumGltfReader::GltfReader reader;
CesiumGltfReader::GltfReaderResult readerResult = reader.readGltf(
std::span(reinterpret_cast<const std::byte*>(s.c_str()), s.size()),
options);
REQUIRE(readerResult.errors.empty());
REQUIRE(readerResult.model.has_value());
ExtensionModelExtStructuralMetadata* pMetadata =
readerResult.model->getExtension<ExtensionModelExtStructuralMetadata>();
REQUIRE(pMetadata);
REQUIRE(pMetadata->schema != nullptr);
REQUIRE(pMetadata->schema->classes.size() == 1);
auto treesIt = pMetadata->schema->classes.find("tree");
REQUIRE(treesIt != pMetadata->schema->classes.end());
REQUIRE(treesIt->second.properties.size() == 3);
auto birdCountIt = treesIt->second.properties.find("birdCount");
REQUIRE(birdCountIt != treesIt->second.properties.end());
REQUIRE(!birdCountIt->second.max.has_value());
REQUIRE(birdCountIt->second.min.has_value());
REQUIRE(birdCountIt->second.min->getSafeNumberOrDefault(-1) == 1);
}
TEST_CASE("Can load an external structural metadata schema from a URI") {
const std::string schema = R"(
{
"classes" : {
"exampleMetadataClass" : {
"name" : "Example metadata class",
"description" : "An example metadata class for property attributes",
"properties" : {
"intensity" : {
"name" : "Example intensity property",
"description" : "An example property for the intensity, with component type FLOAT32",
"type" : "SCALAR",
"componentType" : "FLOAT32"
},
"classification" : {
"name" : "Example classification property",
"description" : "An example property for the classification, with the classificationEnumType",
"type" : "ENUM",
"enumType" : "classificationEnumType"
}
}
}
},
"enums" : {
"classificationEnumType" : {
"valueType": "UINT16",
"values" : [ {
"name" : "MediumVegetation",
"value" : 0
}, {
"name" : "Buildings",
"value" : 1
} ]
}
}
}
)";
const std::string gltf = R"(
{
"extensions" : {
"EXT_structural_metadata" : {
"schemaUri" : "MetadataSchema.json",
"propertyAttributes" : [ {
"class" : "exampleMetadataClass",
"properties" : {
"intensity" : {
"attribute" : "_INTENSITY"
},
"classification" : {
"attribute" : "_CLASSIFICATION"
}
}
} ]
}
},
"extensionsUsed" : [ "EXT_structural_metadata" ],
"asset" : {
"version" : "2.0"
}
}
)";
auto pMockTaskProcessor = std::make_shared<SimpleTaskProcessor>();
CesiumAsync::AsyncSystem asyncSystem{pMockTaskProcessor};
auto pMockGltfBufferResponse = std::make_unique<SimpleAssetResponse>(
uint16_t(200),
"test.gltf",
CesiumAsync::HttpHeaders{},
std::vector<std::byte>(
reinterpret_cast<const std::byte*>(gltf.c_str()),
reinterpret_cast<const std::byte*>(gltf.c_str() + gltf.size())));
auto pMockGltfBufferRequest = std::make_unique<SimpleAssetRequest>(
"GET",
"test.gltf",
CesiumAsync::HttpHeaders{},
std::move(pMockGltfBufferResponse));
auto pMockSchemaResponse = std::make_unique<SimpleAssetResponse>(
uint16_t(200),
"MetadataSchema.json",
CesiumAsync::HttpHeaders{},
std::vector<std::byte>(
reinterpret_cast<const std::byte*>(schema.c_str()),
reinterpret_cast<const std::byte*>(schema.c_str() + schema.size())));
auto pMockSchemaRequest = std::make_unique<SimpleAssetRequest>(
"GET",
"MetadataSchema.json",
CesiumAsync::HttpHeaders{},
std::move(pMockSchemaResponse));
std::map<std::string, std::shared_ptr<SimpleAssetRequest>> mapUrlToRequest{
{"test.gltf", std::move(pMockGltfBufferRequest)},
{"MetadataSchema.json", std::move(pMockSchemaRequest)}};
auto pMockAssetAccessor =
std::make_shared<SimpleAssetAccessor>(std::move(mapUrlToRequest));
CesiumGltfReader::GltfReaderOptions options;
options.resolveExternalStructuralMetadata = true;
options.pSharedAssetSystem =
CesiumGltfReader::GltfSharedAssetSystem::getDefault();
CesiumGltfReader::GltfReader reader;
CesiumGltfReader::GltfReaderResult readerResult =
reader.loadGltf(asyncSystem, "test.gltf", {}, pMockAssetAccessor, options)
.waitInMainThread();
REQUIRE(readerResult.errors.empty());
REQUIRE(readerResult.model.has_value());
ExtensionModelExtStructuralMetadata* pMetadata =
readerResult.model->getExtension<ExtensionModelExtStructuralMetadata>();
REQUIRE(pMetadata);
REQUIRE(pMetadata->schema != nullptr);
REQUIRE(pMetadata->schema->classes.size() == 1);
auto it = pMetadata->schema->classes.find("exampleMetadataClass");
REQUIRE(it != pMetadata->schema->classes.end());
REQUIRE(it->second.properties.size() == 2);
REQUIRE(pMetadata->schema->enums.size() == 1);
REQUIRE(
pMetadata->schema->enums.find("classificationEnumType") !=
pMetadata->schema->enums.end());
}