Files
BXSSP_Andriod/Plugins/CesiumForUnreal/Source/CesiumRuntime/Private/Tests/CesiumMetadataPickingBlueprintLibrary.spec.cpp

1370 lines
50 KiB
C++

// Copyright 2020-2024 CesiumGS, Inc. and Contributors
#include "CesiumMetadataPickingBlueprintLibrary.h"
#include "CesiumGltf/ExtensionExtMeshFeatures.h"
#include "CesiumGltf/ExtensionMeshPrimitiveExtStructuralMetadata.h"
#include "CesiumGltf/ExtensionModelExtStructuralMetadata.h"
#include "CesiumGltf/Model.h"
#include "CesiumGltfComponent.h"
#include "CesiumGltfPrimitiveComponent.h"
#include "CesiumGltfSpecUtility.h"
#include "Misc/AutomationTest.h"
BEGIN_DEFINE_SPEC(
FCesiumMetadataPickingSpec,
"Cesium.Unit.MetadataPicking",
EAutomationTestFlags::EditorContext | EAutomationTestFlags::ClientContext |
EAutomationTestFlags::ServerContext |
EAutomationTestFlags::CommandletContext |
EAutomationTestFlags::ProductFilter)
CesiumGltf::Model model;
CesiumGltf::MeshPrimitive* pPrimitive;
CesiumGltf::ExtensionExtMeshFeatures* pMeshFeatures;
CesiumGltf::ExtensionModelExtStructuralMetadata* pModelMetadata;
CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata* pPrimitiveMetadata;
CesiumGltf::PropertyTable* pPropertyTable;
CesiumGltf::PropertyTexture* pPropertyTexture;
TObjectPtr<UCesiumGltfComponent> pModelComponent;
TObjectPtr<UCesiumGltfPrimitiveComponent> pPrimitiveComponent;
END_DEFINE_SPEC(FCesiumMetadataPickingSpec)
void FCesiumMetadataPickingSpec::Define() {
Describe("FindUVFromHit", [this]() {
BeforeEach([this]() {
model = CesiumGltf::Model();
CesiumGltf::Mesh& mesh = model.meshes.emplace_back();
pPrimitive = &mesh.primitives.emplace_back();
pPrimitive->mode = CesiumGltf::MeshPrimitive::Mode::TRIANGLES;
pPrimitiveComponent = NewObject<UCesiumGltfPrimitiveComponent>();
pPrimitiveComponent->getPrimitiveData().pMeshPrimitive = pPrimitive;
std::vector<glm::vec3> positions{
glm::vec3(-1, 0, 0),
glm::vec3(0, 1, 0),
glm::vec3(1, 0, 0),
glm::vec3(-1, 3, 0),
glm::vec3(0, 4, 0),
glm::vec3(1, 3, 0),
};
CreateAttributeForPrimitive(
model,
*pPrimitive,
"POSITION",
CesiumGltf::AccessorSpec::Type::VEC3,
CesiumGltf::AccessorSpec::ComponentType::FLOAT,
positions);
int32_t positionAccessorIndex =
static_cast<int32_t>(model.accessors.size() - 1);
// For convenience when testing, the UVs are the same as the positions
// they correspond to. This means that the interpolated UV value should be
// directly equal to the barycentric coordinates of the triangle.
std::vector<glm::vec2> texCoords{
glm::vec2(-1, 0),
glm::vec2(0, 1),
glm::vec2(1, 0),
glm::vec2(-1, 0),
glm::vec2(0, 1),
glm::vec2(1, 0)};
CreateAttributeForPrimitive(
model,
*pPrimitive,
"TEXCOORD_0",
CesiumGltf::AccessorSpec::Type::VEC2,
CesiumGltf::AccessorSpec::ComponentType::FLOAT,
texCoords);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.PositionAccessor =
CesiumGltf::AccessorView<FVector3f>(model, positionAccessorIndex);
primData.TexCoordAccessorMap.emplace(
0,
CesiumGltf::AccessorView<CesiumGltf::AccessorTypes::VEC2<float>>(
model,
static_cast<int32_t>(model.accessors.size() - 1)));
});
It("returns false if hit has no valid component", [this]() {
FHitResult Hit;
Hit.Location = FVector_NetQuantize(0, -1, 0) *
CesiumPrimitiveData::positionScaleFactor;
Hit.FaceIndex = 0;
Hit.Component = nullptr;
FVector2D UV;
TestFalse(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 0, UV));
});
It("returns false if specified texcoord set does not exist", [this]() {
FHitResult Hit;
Hit.Location = FVector_NetQuantize(0, -1, 0) *
CesiumPrimitiveData::positionScaleFactor;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
FVector2D UV;
TestFalse(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 1, UV));
});
It("gets hit for primitive without indices", [this]() {
FHitResult Hit;
Hit.Location = FVector_NetQuantize(0, -1, 0) *
CesiumPrimitiveData::positionScaleFactor;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
FVector2D UV = FVector2D::Zero();
TestTrue(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 0, UV));
TestTrue("UV at point (X)", FMath::IsNearlyEqual(UV[0], 0.0));
TestTrue("UV at point (Y)", FMath::IsNearlyEqual(UV[1], 1.0));
Hit.Location = FVector_NetQuantize(0, -0.5, 0) *
CesiumPrimitiveData::positionScaleFactor;
TestTrue(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 0, UV));
TestTrue(
"UV at point inside triangle (X)",
FMath::IsNearlyEqual(UV[0], 0.0));
TestTrue(
"UV at point inside triangle (Y)",
FMath::IsNearlyEqual(UV[1], 0.5));
Hit.FaceIndex = 1;
Hit.Location = FVector_NetQuantize(0, -4, 0) *
CesiumPrimitiveData::positionScaleFactor;
TestTrue(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 0, UV));
TestTrue("UV at point (X)", FMath::IsNearlyEqual(UV[0], 0.0));
TestTrue("UV at point (Y)", FMath::IsNearlyEqual(UV[1], 1.0));
});
It("gets hit for primitive with indices", [this]() {
// Switch the order of the triangles.
const std::vector<uint8_t> indices{3, 4, 5, 0, 1, 2};
CreateIndicesForPrimitive(
model,
*pPrimitive,
CesiumGltf::AccessorSpec::ComponentType::UNSIGNED_BYTE,
indices);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.IndexAccessor = CesiumGltf::AccessorView<uint8_t>(
model,
static_cast<int32_t>(model.accessors.size() - 1));
FHitResult Hit;
Hit.Location = FVector_NetQuantize(0, -4, 0) *
CesiumPrimitiveData::positionScaleFactor;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
FVector2D UV = FVector2D::Zero();
TestTrue(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 0, UV));
TestTrue("UV at point (X)", FMath::IsNearlyEqual(UV[0], 0.0));
TestTrue("UV at point (Y)", FMath::IsNearlyEqual(UV[1], 1.0));
Hit.Location = FVector_NetQuantize(0, -3.5, 0) *
CesiumPrimitiveData::positionScaleFactor;
TestTrue(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 0, UV));
TestTrue(
"UV at point inside triangle (X)",
FMath::IsNearlyEqual(UV[0], 0.0));
TestTrue(
"UV at point inside triangle (Y)",
FMath::IsNearlyEqual(UV[1], 0.5));
Hit.FaceIndex = 1;
Hit.Location = FVector_NetQuantize(0, -1, 0) *
CesiumPrimitiveData::positionScaleFactor;
TestTrue(
"found hit",
UCesiumMetadataPickingBlueprintLibrary::FindUVFromHit(Hit, 0, UV));
TestTrue("UV at point (X)", FMath::IsNearlyEqual(UV[0], 0.0));
TestTrue("UV at point (Y)", FMath::IsNearlyEqual(UV[1], 1.0));
});
});
Describe("GetPropertyTableValuesFromHit", [this]() {
BeforeEach([this]() {
model = CesiumGltf::Model();
CesiumGltf::Mesh& mesh = model.meshes.emplace_back();
pPrimitive = &mesh.primitives.emplace_back();
pPrimitive->mode = CesiumGltf::MeshPrimitive::Mode::TRIANGLES;
// Two disconnected triangles.
std::vector<glm::vec3> positions{
glm::vec3(-1, 1, 0),
glm::vec3(1, 1, 0),
glm::vec3(1, -1, 0),
glm::vec3(2, 2, 0),
glm::vec3(-2, 2, 0),
glm::vec3(-2, -2, 0),
};
std::vector<std::byte> positionData(positions.size() * sizeof(glm::vec3));
std::memcpy(positionData.data(), positions.data(), positionData.size());
CreateAttributeForPrimitive(
model,
*pPrimitive,
"POSITION",
CesiumGltf::AccessorSpec::Type::VEC3,
CesiumGltf::AccessorSpec::ComponentType::FLOAT,
std::move(positionData));
pMeshFeatures =
&pPrimitive->addExtension<CesiumGltf::ExtensionExtMeshFeatures>();
pModelMetadata =
&model
.addExtension<CesiumGltf::ExtensionModelExtStructuralMetadata>();
std::string className = "testClass";
pModelMetadata->schema.emplace();
pModelMetadata->schema->classes[className];
pPropertyTable = &pModelMetadata->propertyTables.emplace_back();
pPropertyTable->classProperty = className;
pModelComponent = NewObject<UCesiumGltfComponent>();
pPrimitiveComponent =
NewObject<UCesiumGltfPrimitiveComponent>(pModelComponent);
pPrimitiveComponent->AttachToComponent(
pModelComponent,
FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
pPrimitiveComponent->getPrimitiveData().pMeshPrimitive = pPrimitive;
});
It("returns empty map for invalid component", [this]() {
int32_t positionAccessorIndex =
static_cast<int32_t>(model.accessors.size() - 1);
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId =
AddFeatureIDsAsAttributeToModel(model, *pPrimitive, featureIDs, 2, 0);
featureId.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.PositionAccessor =
CesiumGltf::AccessorView<FVector3f>(model, positionAccessorIndex);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
pModelComponent->Metadata = FCesiumModelMetadata(model, *pModelMetadata);
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
FHitResult Hit;
Hit.FaceIndex = -1;
Hit.Component = nullptr;
auto values =
UCesiumMetadataPickingBlueprintLibrary::GetPropertyTableValuesFromHit(
Hit);
TestTrue("empty values for invalid hit", values.IsEmpty());
});
It("returns empty map for invalid feature ID set index", [this]() {
int32_t positionAccessorIndex =
static_cast<int32_t>(model.accessors.size() - 1);
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId =
AddFeatureIDsAsAttributeToModel(model, *pPrimitive, featureIDs, 2, 0);
featureId.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.PositionAccessor =
CesiumGltf::AccessorView<FVector3f>(model, positionAccessorIndex);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
pModelComponent->Metadata = FCesiumModelMetadata(model, *pModelMetadata);
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
FHitResult Hit;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
auto values =
UCesiumMetadataPickingBlueprintLibrary::GetPropertyTableValuesFromHit(
Hit,
-1);
TestTrue("empty values for negative index", values.IsEmpty());
values =
UCesiumMetadataPickingBlueprintLibrary::GetPropertyTableValuesFromHit(
Hit,
1);
TestTrue(
"empty values for positive out-of-range index",
values.IsEmpty());
});
It("returns empty values if feature ID set is not associated with a property table",
[this]() {
int32_t positionAccessorIndex =
static_cast<int32_t>(model.accessors.size() - 1);
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
AddFeatureIDsAsAttributeToModel(model, *pPrimitive, featureIDs, 2, 0);
CesiumPrimitiveData& primData =
pPrimitiveComponent->getPrimitiveData();
primData.PositionAccessor =
CesiumGltf::AccessorView<FVector3f>(model, positionAccessorIndex);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
std::vector<glm::vec2> vec2Values{
glm::vec2(1.0f, 2.5f),
glm::vec2(3.1f, -4.0f)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::FLOAT32,
vec2Values);
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
FHitResult Hit;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
const auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTableValuesFromHit(Hit);
TestTrue("values are empty", values.IsEmpty());
});
It("returns values for first feature ID set by default", [this]() {
int32_t positionAccessorIndex =
static_cast<int32_t>(model.accessors.size() - 1);
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId =
AddFeatureIDsAsAttributeToModel(model, *pPrimitive, featureIDs, 2, 0);
featureId.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.PositionAccessor =
CesiumGltf::AccessorView<FVector3f>(model, positionAccessorIndex);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
std::vector<glm::vec2> vec2Values{
glm::vec2(1.0f, 2.5f),
glm::vec2(3.1f, -4.0f)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::FLOAT32,
vec2Values);
pModelComponent->Metadata = FCesiumModelMetadata(model, *pModelMetadata);
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
FHitResult Hit;
Hit.Component = pPrimitiveComponent;
for (size_t i = 0; i < scalarValues.size(); i++) {
Hit.FaceIndex = i;
const auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTableValuesFromHit(Hit);
TestEqual("number of values", values.Num(), 2);
TestTrue(
"contains scalar value",
values.Contains(FString(scalarPropertyName.c_str())));
TestTrue(
"contains vec2 value",
values.Contains(FString(vec2PropertyName.c_str())));
const FCesiumMetadataValue* pScalarValue =
values.Find(FString(scalarPropertyName.c_str()));
if (pScalarValue) {
TestEqual(
"scalar value",
UCesiumMetadataValueBlueprintLibrary::GetInteger(
*pScalarValue,
0),
scalarValues[i]);
}
const FCesiumMetadataValue* pVec2Value =
values.Find(FString(vec2PropertyName.c_str()));
if (pVec2Value) {
FVector2D expected(
static_cast<double>(vec2Values[i][0]),
static_cast<double>(vec2Values[i][1]));
TestEqual(
"vec2 value",
UCesiumMetadataValueBlueprintLibrary::GetVector2D(
*pVec2Value,
FVector2D::Zero()),
expected);
}
}
});
It("returns values for specified feature ID set", [this]() {
int32_t positionAccessorIndex =
static_cast<int32_t>(model.accessors.size() - 1);
std::vector<uint8_t> featureIDs0{1, 1, 1, 0, 0, 0};
CesiumGltf::FeatureId& featureId0 = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs0,
2,
0);
std::vector<uint8_t> featureIDs1{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId1 = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs1,
2,
1);
featureId0.propertyTable = featureId1.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.PositionAccessor =
CesiumGltf::AccessorView<FVector3f>(model, positionAccessorIndex);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
std::vector<glm::vec2> vec2Values{
glm::vec2(1.0f, 2.5f),
glm::vec2(3.1f, -4.0f)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::FLOAT32,
vec2Values);
pModelComponent->Metadata = FCesiumModelMetadata(model, *pModelMetadata);
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
FHitResult Hit;
Hit.Component = pPrimitiveComponent;
for (size_t i = 0; i < scalarValues.size(); i++) {
Hit.FaceIndex = i;
const auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTableValuesFromHit(Hit, 1);
TestEqual("number of values", values.Num(), 2);
TestTrue(
"contains scalar value",
values.Contains(FString(scalarPropertyName.c_str())));
TestTrue(
"contains vec2 value",
values.Contains(FString(vec2PropertyName.c_str())));
const FCesiumMetadataValue* pScalarValue =
values.Find(FString(scalarPropertyName.c_str()));
if (pScalarValue) {
TestEqual(
"scalar value",
UCesiumMetadataValueBlueprintLibrary::GetInteger(
*pScalarValue,
0),
scalarValues[i]);
}
const FCesiumMetadataValue* pVec2Value =
values.Find(FString(vec2PropertyName.c_str()));
FVector2D expected(
static_cast<double>(vec2Values[i][0]),
static_cast<double>(vec2Values[i][1]));
if (pVec2Value) {
TestEqual(
"vec2 value",
UCesiumMetadataValueBlueprintLibrary::GetVector2D(
*pVec2Value,
FVector2D::Zero()),
expected);
}
}
});
});
Describe("GetPropertyTextureValuesFromHit", [this]() {
BeforeEach([this]() {
model = CesiumGltf::Model();
CesiumGltf::Mesh& mesh = model.meshes.emplace_back();
pPrimitive = &mesh.primitives.emplace_back();
pPrimitive->mode = CesiumGltf::MeshPrimitive::Mode::TRIANGLES;
std::vector<glm::vec3> positions{
glm::vec3(-1, 0, 0),
glm::vec3(0, 1, 0),
glm::vec3(1, 0, 0),
glm::vec3(-1, 3, 0),
glm::vec3(0, 4, 0),
glm::vec3(1, 3, 0),
};
CreateAttributeForPrimitive(
model,
*pPrimitive,
"POSITION",
CesiumGltf::AccessorSpec::Type::VEC3,
CesiumGltf::AccessorSpec::ComponentType::FLOAT,
GetValuesAsBytes(positions));
int32_t positionAccessorIndex =
static_cast<int32_t>(model.accessors.size() - 1);
// For convenience when testing, the UVs are the same as the positions
// they correspond to. This means that the interpolated UV value should be
// directly equal to the barycentric coordinates of the triangle.
std::vector<glm::vec2> texCoords0{
glm::vec2(-1, 0),
glm::vec2(0, 1),
glm::vec2(1, 0),
glm::vec2(-1, 0),
glm::vec2(0, 1),
glm::vec2(1, 0)};
CreateAttributeForPrimitive(
model,
*pPrimitive,
"TEXCOORD_0",
CesiumGltf::AccessorSpec::Type::VEC2,
CesiumGltf::AccessorSpec::ComponentType::FLOAT,
texCoords0);
pModelMetadata =
&model
.addExtension<CesiumGltf::ExtensionModelExtStructuralMetadata>();
std::string className = "testClass";
pModelMetadata->schema.emplace();
pModelMetadata->schema->classes[className];
pPropertyTexture = &pModelMetadata->propertyTextures.emplace_back();
pPropertyTexture->classProperty = className;
pPrimitiveMetadata = &pPrimitive->addExtension<
CesiumGltf::ExtensionMeshPrimitiveExtStructuralMetadata>();
pPrimitiveMetadata->propertyTextures.push_back(0);
pModelComponent = NewObject<UCesiumGltfComponent>();
pPrimitiveComponent =
NewObject<UCesiumGltfPrimitiveComponent>(pModelComponent);
pPrimitiveComponent->AttachToComponent(
pModelComponent,
FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.pMeshPrimitive = pPrimitive;
primData.PositionAccessor =
CesiumGltf::AccessorView<FVector3f>(model, positionAccessorIndex);
primData.TexCoordAccessorMap.emplace(
0,
CesiumGltf::AccessorView<CesiumGltf::AccessorTypes::VEC2<float>>(
model,
static_cast<int32_t>(model.accessors.size() - 1)));
});
It("returns empty map for invalid component", [this]() {
std::string scalarPropertyName("scalarProperty");
std::array<int8_t, 4> scalarValues{-1, 2, -3, 4};
AddPropertyTexturePropertyToModel(
model,
*pPropertyTexture,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT8,
scalarValues,
{0});
pModelComponent->Metadata = FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.Metadata =
FCesiumPrimitiveMetadata(*pPrimitive, *pPrimitiveMetadata);
FHitResult Hit;
Hit.FaceIndex = -1;
Hit.Component = nullptr;
auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTextureValuesFromHit(Hit);
TestTrue("empty values for invalid hit", values.IsEmpty());
});
It("returns empty map for invalid primitive property texture index",
[this]() {
std::string scalarPropertyName("scalarProperty");
std::array<int8_t, 4> scalarValues{-1, 2, -3, 4};
AddPropertyTexturePropertyToModel(
model,
*pPropertyTexture,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT8,
scalarValues,
{0});
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData =
pPrimitiveComponent->getPrimitiveData();
primData.Metadata =
FCesiumPrimitiveMetadata(*pPrimitive, *pPrimitiveMetadata);
FHitResult Hit;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTextureValuesFromHit(Hit, -1);
TestTrue("empty values for negative index", values.IsEmpty());
values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTextureValuesFromHit(Hit, 1);
TestTrue(
"empty values for positive out-of-range index",
values.IsEmpty());
});
It("returns empty values if property texture does not exist in model metadata",
[this]() {
std::string scalarPropertyName("scalarProperty");
std::array<int8_t, 4> scalarValues{-1, 2, -3, 4};
AddPropertyTexturePropertyToModel(
model,
*pPropertyTexture,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT8,
scalarValues,
{0});
pModelComponent->Metadata = FCesiumModelMetadata();
pPrimitiveMetadata->propertyTextures.clear();
pPrimitiveMetadata->propertyTextures.push_back(1);
CesiumPrimitiveData& primData =
pPrimitiveComponent->getPrimitiveData();
primData.Metadata =
FCesiumPrimitiveMetadata(*pPrimitive, *pPrimitiveMetadata);
FHitResult Hit;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
const auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTextureValuesFromHit(Hit);
TestTrue("values are empty", values.IsEmpty());
});
It("returns values for first primitive property texture by default",
[this]() {
std::string scalarPropertyName("scalarProperty");
std::array<int8_t, 4> scalarValues{-1, 2, -3, 4};
AddPropertyTexturePropertyToModel(
model,
*pPropertyTexture,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT8,
scalarValues,
{0});
std::array<glm::u8vec2, 4> vec2Values{
glm::u8vec2(1, 2),
glm::u8vec2(0, 4),
glm::u8vec2(8, 8),
glm::u8vec2(10, 23)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTexturePropertyToModel(
model,
*pPropertyTexture,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::UINT8,
vec2Values,
{0, 1});
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData =
pPrimitiveComponent->getPrimitiveData();
primData.Metadata =
FCesiumPrimitiveMetadata(*pPrimitive, *pPrimitiveMetadata);
FHitResult Hit;
Hit.FaceIndex = 0;
Hit.Component = pPrimitiveComponent;
std::array<FVector_NetQuantize, 3> locations{
FVector_NetQuantize(1, 0, 0),
FVector_NetQuantize(0, -1, 0),
FVector_NetQuantize(0, -0.25, 0)};
std::array<int8_t, 3> expectedScalar{
scalarValues[1],
scalarValues[2],
scalarValues[0]};
std::array<FVector2D, 3> expectedVec2{
FVector2D(vec2Values[1][0], vec2Values[1][1]),
FVector2D(vec2Values[2][0], vec2Values[2][1]),
FVector2D(vec2Values[0][0], vec2Values[0][1])};
for (size_t i = 0; i < locations.size(); i++) {
Hit.Location =
locations[i] * CesiumPrimitiveData::positionScaleFactor;
const auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTextureValuesFromHit(Hit);
TestEqual("number of values", values.Num(), 2);
TestTrue(
"contains scalar value",
values.Contains(FString(scalarPropertyName.c_str())));
TestTrue(
"contains vec2 value",
values.Contains(FString(vec2PropertyName.c_str())));
const FCesiumMetadataValue* pScalarValue =
values.Find(FString(scalarPropertyName.c_str()));
if (pScalarValue) {
TestEqual(
"scalar value",
UCesiumMetadataValueBlueprintLibrary::GetInteger(
*pScalarValue,
0),
expectedScalar[i]);
}
const FCesiumMetadataValue* pVec2Value =
values.Find(FString(vec2PropertyName.c_str()));
if (pVec2Value) {
TestEqual(
"vec2 value",
UCesiumMetadataValueBlueprintLibrary::GetVector2D(
*pVec2Value,
FVector2D::Zero()),
expectedVec2[i]);
}
}
});
It("returns values for specified property texture", [this]() {
std::string scalarPropertyName("scalarProperty");
std::array<int8_t, 4> scalarValues{-1, 2, -3, 4};
AddPropertyTexturePropertyToModel(
model,
*pPropertyTexture,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT8,
scalarValues,
{0});
// Make another property texture
CesiumGltf::PropertyTexture& propertyTexture =
pModelMetadata->propertyTextures.emplace_back();
propertyTexture.classProperty = "testClass";
std::array<int8_t, 4> newScalarValues = {100, -20, 33, -4};
AddPropertyTexturePropertyToModel(
model,
propertyTexture,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT8,
newScalarValues,
{0});
pModelComponent->Metadata = FCesiumModelMetadata(model, *pModelMetadata);
pPrimitiveMetadata->propertyTextures.push_back(1);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.Metadata =
FCesiumPrimitiveMetadata(*pPrimitive, *pPrimitiveMetadata);
FHitResult Hit;
Hit.Component = pPrimitiveComponent;
Hit.FaceIndex = 0;
std::array<FVector_NetQuantize, 3> locations{
FVector_NetQuantize(1, 0, 0),
FVector_NetQuantize(0, -1, 0),
FVector_NetQuantize(0, -0.25, 0)};
std::array<int8_t, 3> expectedScalar{
newScalarValues[1],
newScalarValues[2],
newScalarValues[0]};
for (size_t i = 0; i < locations.size(); i++) {
Hit.Location = locations[i] * CesiumPrimitiveData::positionScaleFactor;
const auto values = UCesiumMetadataPickingBlueprintLibrary::
GetPropertyTextureValuesFromHit(Hit, 1);
TestEqual("number of values", values.Num(), 1);
TestTrue(
"contains scalar value",
values.Contains(FString(scalarPropertyName.c_str())));
const FCesiumMetadataValue* pScalarValue =
values.Find(FString(scalarPropertyName.c_str()));
if (pScalarValue) {
TestEqual(
"scalar value",
UCesiumMetadataValueBlueprintLibrary::GetInteger(
*pScalarValue,
0),
expectedScalar[i]);
}
}
});
});
PRAGMA_DISABLE_DEPRECATION_WARNINGS
Describe("Deprecated", [this]() {
Describe("GetMetadataValuesForFace", [this]() {
BeforeEach([this]() {
model = CesiumGltf::Model();
CesiumGltf::Mesh& mesh = model.meshes.emplace_back();
pPrimitive = &mesh.primitives.emplace_back();
// Two disconnected triangles.
std::vector<glm::vec3> positions{
glm::vec3(-1, 1, 0),
glm::vec3(1, 1, 0),
glm::vec3(1, -1, 0),
glm::vec3(2, 2, 0),
glm::vec3(-2, 2, 0),
glm::vec3(-2, -2, 0),
};
std::vector<std::byte> positionData(
positions.size() * sizeof(glm::vec3));
std::memcpy(positionData.data(), positions.data(), positionData.size());
CreateAttributeForPrimitive(
model,
*pPrimitive,
"POSITION",
CesiumGltf::AccessorSpec::Type::VEC3,
CesiumGltf::AccessorSpec::ComponentType::FLOAT,
std::move(positionData));
pMeshFeatures =
&pPrimitive->addExtension<CesiumGltf::ExtensionExtMeshFeatures>();
pModelMetadata = &model.addExtension<
CesiumGltf::ExtensionModelExtStructuralMetadata>();
std::string className = "testClass";
pModelMetadata->schema.emplace();
pModelMetadata->schema->classes[className];
pPropertyTable = &pModelMetadata->propertyTables.emplace_back();
pPropertyTable->classProperty = className;
pModelComponent = NewObject<UCesiumGltfComponent>();
pPrimitiveComponent =
NewObject<UCesiumGltfPrimitiveComponent>(pModelComponent);
pPrimitiveComponent->AttachToComponent(
pModelComponent,
FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData = pPrimitiveComponent->getPrimitiveData();
});
It("returns empty map for invalid face index", [this]() {
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs,
2,
0);
featureId.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
auto values =
UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace(
pPrimitiveComponent,
-1);
TestTrue("empty values for negative index", values.IsEmpty());
values =
UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace(
pPrimitiveComponent,
2);
TestTrue(
"empty values for positive out-of-range index",
values.IsEmpty());
});
It("returns empty map for invalid feature ID set index", [this]() {
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs,
2,
0);
featureId.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
auto values =
UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace(
pPrimitiveComponent,
0,
-1);
TestTrue("empty values for negative index", values.IsEmpty());
values =
UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace(
pPrimitiveComponent,
0,
1);
TestTrue(
"empty values for positive out-of-range index",
values.IsEmpty());
});
It("returns empty values if feature ID set is not associated with a property table",
[this]() {
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs,
2,
0);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
std::vector<glm::vec2> vec2Values{
glm::vec2(1.0f, 2.5f),
glm::vec2(3.1f, -4.0f)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::FLOAT32,
vec2Values);
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData =
pPrimitiveComponent->getPrimitiveData();
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
const auto values =
UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace(
pPrimitiveComponent,
0);
TestTrue("values are empty", values.IsEmpty());
});
It("returns values for first feature ID set by default", [this]() {
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs,
2,
0);
featureId.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
std::vector<glm::vec2> vec2Values{
glm::vec2(1.0f, 2.5f),
glm::vec2(3.1f, -4.0f)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::FLOAT32,
vec2Values);
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
for (size_t i = 0; i < scalarValues.size(); i++) {
const auto values =
UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace(
pPrimitiveComponent,
static_cast<int64_t>(i));
TestEqual("number of values", values.Num(), 2);
TestTrue(
"contains scalar value",
values.Contains(FString(scalarPropertyName.c_str())));
TestTrue(
"contains vec2 value",
values.Contains(FString(vec2PropertyName.c_str())));
const FCesiumMetadataValue* pScalarValue =
values.Find(FString(scalarPropertyName.c_str()));
if (pScalarValue) {
TestEqual(
"scalar value",
UCesiumMetadataValueBlueprintLibrary::GetInteger(
*pScalarValue,
0),
scalarValues[i]);
}
const FCesiumMetadataValue* pVec2Value =
values.Find(FString(vec2PropertyName.c_str()));
if (pVec2Value) {
FVector2D expected(
static_cast<double>(vec2Values[i][0]),
static_cast<double>(vec2Values[i][1]));
TestEqual(
"vec2 value",
UCesiumMetadataValueBlueprintLibrary::GetVector2D(
*pVec2Value,
FVector2D::Zero()),
expected);
}
}
});
It("returns values for specified feature ID set", [this]() {
std::vector<uint8_t> featureIDs0{1, 1, 1, 0, 0, 0};
CesiumGltf::FeatureId& featureId0 = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs0,
2,
0);
std::vector<uint8_t> featureIDs1{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId1 = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs1,
2,
1);
featureId0.propertyTable = featureId1.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
std::vector<glm::vec2> vec2Values{
glm::vec2(1.0f, 2.5f),
glm::vec2(3.1f, -4.0f)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::FLOAT32,
vec2Values);
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
for (size_t i = 0; i < scalarValues.size(); i++) {
const auto values =
UCesiumMetadataPickingBlueprintLibrary::GetMetadataValuesForFace(
pPrimitiveComponent,
i,
1);
TestEqual("number of values", values.Num(), 2);
TestTrue(
"contains scalar value",
values.Contains(FString(scalarPropertyName.c_str())));
TestTrue(
"contains vec2 value",
values.Contains(FString(vec2PropertyName.c_str())));
const FCesiumMetadataValue& scalarValue =
*values.Find(FString(scalarPropertyName.c_str()));
TestEqual(
"scalar value",
UCesiumMetadataValueBlueprintLibrary::GetInteger(scalarValue, 0),
scalarValues[i]);
const FCesiumMetadataValue& vec2Value =
*values.Find(FString(vec2PropertyName.c_str()));
FVector2D expected(
static_cast<double>(vec2Values[i][0]),
static_cast<double>(vec2Values[i][1]));
TestEqual(
"vec2 value",
UCesiumMetadataValueBlueprintLibrary::GetVector2D(
vec2Value,
FVector2D::Zero()),
expected);
}
});
});
Describe("GetMetadataValuesForFaceAsStrings", [this]() {
BeforeEach([this]() {
model = CesiumGltf::Model();
CesiumGltf::Mesh& mesh = model.meshes.emplace_back();
pPrimitive = &mesh.primitives.emplace_back();
// Two disconnected triangles.
std::vector<glm::vec3> positions{
glm::vec3(-1, 1, 0),
glm::vec3(1, 1, 0),
glm::vec3(1, -1, 0),
glm::vec3(2, 2, 0),
glm::vec3(-2, 2, 0),
glm::vec3(-2, -2, 0),
};
std::vector<std::byte> positionData(
positions.size() * sizeof(glm::vec3));
std::memcpy(positionData.data(), positions.data(), positionData.size());
CreateAttributeForPrimitive(
model,
*pPrimitive,
"POSITION",
CesiumGltf::AccessorSpec::Type::VEC3,
CesiumGltf::AccessorSpec::ComponentType::FLOAT,
std::move(positionData));
pMeshFeatures =
&pPrimitive->addExtension<CesiumGltf::ExtensionExtMeshFeatures>();
pModelMetadata = &model.addExtension<
CesiumGltf::ExtensionModelExtStructuralMetadata>();
std::string className = "testClass";
pModelMetadata->schema.emplace();
pModelMetadata->schema->classes[className];
pPropertyTable = &pModelMetadata->propertyTables.emplace_back();
pPropertyTable->classProperty = className;
pModelComponent = NewObject<UCesiumGltfComponent>();
pPrimitiveComponent =
NewObject<UCesiumGltfPrimitiveComponent>(pModelComponent);
pPrimitiveComponent->AttachToComponent(
pModelComponent,
FAttachmentTransformRules(EAttachmentRule::KeepRelative, false));
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData = pPrimitiveComponent->getPrimitiveData();
});
It("returns values for first feature ID set by default", [this]() {
std::vector<uint8_t> featureIDs{0, 0, 0, 1, 1, 1};
CesiumGltf::FeatureId& featureId = AddFeatureIDsAsAttributeToModel(
model,
*pPrimitive,
featureIDs,
2,
0);
featureId.propertyTable =
static_cast<int64_t>(pModelMetadata->propertyTables.size() - 1);
std::vector<int32_t> scalarValues{1, 2};
pPropertyTable->count = static_cast<int64_t>(scalarValues.size());
const std::string scalarPropertyName("scalarProperty");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
scalarPropertyName,
CesiumGltf::ClassProperty::Type::SCALAR,
CesiumGltf::ClassProperty::ComponentType::INT32,
scalarValues);
std::vector<glm::vec2> vec2Values{
glm::vec2(1.0f, 2.5f),
glm::vec2(3.1f, -4.0f)};
const std::string vec2PropertyName("vec2Property");
AddPropertyTablePropertyToModel(
model,
*pPropertyTable,
vec2PropertyName,
CesiumGltf::ClassProperty::Type::VEC2,
CesiumGltf::ClassProperty::ComponentType::FLOAT32,
vec2Values);
pModelComponent->Metadata =
FCesiumModelMetadata(model, *pModelMetadata);
CesiumPrimitiveData& primData = pPrimitiveComponent->getPrimitiveData();
primData.Features =
FCesiumPrimitiveFeatures(model, *pPrimitive, *pMeshFeatures);
for (size_t i = 0; i < scalarValues.size(); i++) {
const auto strings = UCesiumMetadataPickingBlueprintLibrary::
GetMetadataValuesForFaceAsStrings(
pPrimitiveComponent,
static_cast<int64_t>(i));
TestEqual("number of strings", strings.Num(), 2);
TestTrue(
"contains scalar value",
strings.Contains(FString(scalarPropertyName.c_str())));
TestTrue(
"contains vec2 value",
strings.Contains(FString(vec2PropertyName.c_str())));
const FString* pScalarString =
strings.Find(FString(scalarPropertyName.c_str()));
if (pScalarString) {
TestEqual(
"scalar value",
*pScalarString,
FString(std::to_string(scalarValues[i]).c_str()));
}
const FString* pVec2String =
strings.Find(FString(vec2PropertyName.c_str()));
if (pVec2String) {
std::string expected(
"X=" + std::to_string(vec2Values[i][0]) +
" Y=" + std::to_string(vec2Values[i][1]));
TestEqual("vec2 value", *pVec2String, FString(expected.c_str()));
}
}
});
});
});
PRAGMA_ENABLE_DEPRECATION_WARNINGS
}