Files
MapLibreParticleLab/include/mbgl/particle/field/field_data_adapter.hpp
2026-09-04 14:51:42 +08:00

100 lines
3.0 KiB
C++

#pragma once
#include <cstdint>
#include <optional>
#include <string>
#include <vector>
namespace mbgl::particle {
// Provider-neutral description of the canonical field bytes consumed by Core.
// Provider names, URLs and transport metadata deliberately do not cross this boundary.
struct ParticleFieldDescriptor {
std::string fieldID;
std::string fieldType;
std::string displayDomain;
// Assigned by the producer before decoding. The adapter never invents a revision.
uint64_t generation = 0;
uint64_t validTime = 0;
uint32_t width = 0;
uint32_t height = 0;
double west = -180.0;
double south = -85.0;
double east = 180.0;
double north = 85.0;
float noData = -9999.0f;
uint64_t dataVersion = 0;
uint64_t byteLength = 0;
uint32_t stride = 0;
std::string layout = "interleaved-uv";
std::string encoding = "float32-le";
std::string fieldSha256;
};
struct ParticleFieldSnapshot {
std::string fieldID;
std::string fieldType;
std::string displayDomain;
uint64_t validTime = 0;
uint32_t width = 0;
uint32_t height = 0;
double west = -180.0;
double south = -85.0;
double east = 180.0;
double north = 85.0;
float noData = -9999.0f;
uint64_t dataVersion = 0;
uint64_t generation = 0;
std::string fieldSha256;
std::vector<float> velocity;
std::vector<uint8_t> valid;
bool isValid() const;
bool isTimeInterpolationCompatibleWith(const ParticleFieldSnapshot&) const;
};
inline bool fieldIdentityChanged(const ParticleFieldSnapshot& current, const ParticleFieldSnapshot& next) {
return current.generation != next.generation || current.fieldID != next.fieldID ||
current.dataVersion != next.dataVersion;
}
inline bool sameFieldGpuContent(const ParticleFieldSnapshot& current, const ParticleFieldSnapshot& next) {
return current.fieldID == next.fieldID && current.dataVersion == next.dataVersion &&
current.fieldSha256 == next.fieldSha256 && current.isTimeInterpolationCompatibleWith(next);
}
struct ParticleFieldTimeWindow {
ParticleFieldSnapshot t0;
ParticleFieldSnapshot t1;
bool isValid() const { return t0.isValid() && t1.isValid() && t0.isTimeInterpolationCompatibleWith(t1); }
};
enum class ParticleFieldAdapterError : uint8_t {
None,
InvalidDescriptor,
UnsupportedFormat,
DimensionMismatch,
PayloadSizeMismatch,
InvalidTimestampOrIdentity,
NonFiniteData,
DecodeValidationFailure,
};
const char* particleFieldAdapterErrorName(ParticleFieldAdapterError);
struct ParticleFieldAdapterResult {
std::optional<ParticleFieldSnapshot> snapshot;
ParticleFieldAdapterError error = ParticleFieldAdapterError::None;
std::string message;
explicit operator bool() const { return snapshot.has_value(); }
};
class ParticleFieldDataAdapter final {
public:
static ParticleFieldAdapterResult decode(const ParticleFieldDescriptor&, const std::vector<char>&, uint64_t generation);
};
} // namespace mbgl::particle