feat: add v2 multi-plane field ingress
This commit is contained in:
@@ -94,6 +94,23 @@ particle::ParticleFieldPayloadBundle v2Payload(std::optional<std::vector<char>>
|
||||
return {.scalar = std::move(scalar), .vector = std::move(vector), .validity = std::move(validity)};
|
||||
}
|
||||
|
||||
std::string v2HostMetadata(const int index, const bool scalar, const bool vector, const char* semantics = "VELOCITY") {
|
||||
std::string result = "{\"schema\":\"maplibre-particle-field/v2\",\"fieldId\":\"v2-host-" +
|
||||
std::to_string(index) + "\",\"generation\":" + std::to_string(index + 1) +
|
||||
",\"validTime\":" + std::to_string(100 + index) +
|
||||
",\"grid\":{\"width\":2,\"height\":1},\"bounds\":{\"west\":0,\"south\":0,\"east\":1,\"north\":1},\"validity\":{\"encoding\":\"uint8\",\"byteLength\":2}";
|
||||
if (scalar) result += ",\"scalar\":{\"encoding\":\"float32-le\",\"byteLength\":8,\"noData\":-9999}";
|
||||
if (vector) result += std::string(",\"vector\":{\"layout\":\"interleaved-uv\",\"encoding\":\"float32-le\",\"byteLength\":16,\"noData\":-9999,\"semantics\":\"") + semantics + "\"}";
|
||||
return result + "}";
|
||||
}
|
||||
|
||||
std::string v2LegacyCompatibleHostMetadata(const int index) {
|
||||
return "{\"schema\":\"maplibre-particle-field/v2\",\"fieldId\":\"v2-compatible-t" +
|
||||
std::to_string(index) + "\",\"generation\":" + std::to_string(index + 1) +
|
||||
",\"validTime\":" + std::to_string(1704067200000ULL + index * 3600000ULL) +
|
||||
",\"grid\":{\"width\":16,\"height\":16},\"bounds\":{\"west\":-180,\"south\":-85,\"east\":180,\"north\":85},\"validity\":{\"encoding\":\"uint8\",\"byteLength\":256},\"vector\":{\"layout\":\"interleaved-uv\",\"encoding\":\"float32-le\",\"byteLength\":2048,\"noData\":-9999,\"semantics\":\"VELOCITY\"}}";
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
using namespace mbgl;
|
||||
@@ -545,6 +562,73 @@ TEST(Source, HostFieldSubmissionBuildsOneCoreOwnedTimeline) {
|
||||
EXPECT_EQ(source.impl().timeline->frame().t0Index, 2u);
|
||||
}
|
||||
|
||||
TEST(Source, HostFieldV2BundleUsesTheSameTimelineIngress) {
|
||||
SourceTest test;
|
||||
style::RasterArraySource source{"host-submission"};
|
||||
source.setObserver(&test.styleObserver);
|
||||
source.loadDescription(*test.fileSource);
|
||||
const auto valid = std::vector<char>{1, 1};
|
||||
const auto scalarT0 = floatBytes({2.0f, 3.0f});
|
||||
const auto scalarT1 = floatBytes({2.5f, 3.5f});
|
||||
const auto vectorT0 = floatBytes({1.0f, 0.0f, 0.0f, 1.0f});
|
||||
const auto vectorT1 = floatBytes({0.5f, 0.0f, 0.0f, 1.0f});
|
||||
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(0, true, false), v2Payload(scalarT0, std::nullopt, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedPendingInitialWindow);
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(1, true, false), v2Payload(scalarT1, std::nullopt, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::InitialWindowReady);
|
||||
EXPECT_TRUE(source.impl().field->hasScalar());
|
||||
EXPECT_FALSE(source.impl().field->hasVector());
|
||||
|
||||
EXPECT_TRUE(source.clearHostFields());
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(2, false, true), v2Payload(std::nullopt, vectorT0, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedPendingInitialWindow);
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(3, false, true), v2Payload(std::nullopt, vectorT1, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::InitialWindowReady);
|
||||
EXPECT_TRUE(source.impl().field->hasVector());
|
||||
EXPECT_EQ(source.impl().field->vectorSemantics, particle::VectorSemantics::Velocity);
|
||||
|
||||
EXPECT_TRUE(source.clearHostFields());
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(4, true, true, "DIRECTION"), v2Payload(scalarT0, vectorT0, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedPendingInitialWindow);
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(5, true, true, "DIRECTION"), v2Payload(scalarT1, vectorT1, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::InitialWindowReady);
|
||||
EXPECT_EQ(source.impl().field->vectorSemantics, particle::VectorSemantics::Direction);
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(6, true, true), v2Payload(scalarT1, vectorT1, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedIncompatibleSnapshot);
|
||||
|
||||
EXPECT_TRUE(source.clearHostFields());
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(7, false, true),
|
||||
particle::ParticleFieldPayloadBundle{.scalar = std::nullopt,
|
||||
.vector = vectorT0,
|
||||
.validity = std::nullopt}),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedAdapter);
|
||||
EXPECT_EQ(source.submitHostField(v2HostMetadata(8, false, false), v2Payload(std::nullopt, std::nullopt, valid)),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedAdapter);
|
||||
}
|
||||
|
||||
TEST(Source, HostFieldLegacyAndCompatibleV2VectorOnlyShareOneTimeline) {
|
||||
SourceTest test;
|
||||
style::RasterArraySource source{"host-submission"};
|
||||
source.setObserver(&test.styleObserver);
|
||||
source.loadDescription(*test.fileSource);
|
||||
const auto legacyBytes = fixtureBytes("uniform-east", "field.f32");
|
||||
const std::vector<char> legacyPayload(legacyBytes.begin(), legacyBytes.end());
|
||||
const std::vector<char> validity(16 * 16, 1);
|
||||
const auto northBytes = fixtureBytes("uniform-north", "field.f32");
|
||||
const std::vector<char> nextPayload(northBytes.begin(), northBytes.end());
|
||||
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(0), legacyPayload),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedPendingInitialWindow);
|
||||
EXPECT_EQ(source.submitHostField(v2LegacyCompatibleHostMetadata(1),
|
||||
v2Payload(std::nullopt, nextPayload, validity)),
|
||||
style::RasterArrayHostFieldSubmitResult::InitialWindowReady);
|
||||
ASSERT_TRUE(source.impl().timeline);
|
||||
EXPECT_EQ(source.impl().timeline->size(), 2u);
|
||||
EXPECT_EQ(source.impl().field->vectorSemantics, particle::VectorSemantics::Velocity);
|
||||
EXPECT_EQ(source.impl().nextField->vectorSemantics, particle::VectorSemantics::Velocity);
|
||||
}
|
||||
|
||||
TEST(Source, HostFieldClearAndTimestampSeekAreFailClosed) {
|
||||
SourceTest test;
|
||||
style::RasterArraySource source{"host-submission"};
|
||||
|
||||
Reference in New Issue
Block a user