#pragma once #include #include #include #include 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 velocity; std::vector 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 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&, uint64_t generation); }; } // namespace mbgl::particle