fix: expose V4 velocity component color binding
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
@@ -118,7 +118,7 @@ class WeatherRuntimeBridgeModule(private val context: ReactApplicationContext) :
|
||||
@ReactMethod override fun setEncodedForecastPlaybackSpeed(reactTag: Double, speed: Double, promise: Promise) { if(!speed.isFinite() || speed <= 0 || speed > Float.MAX_VALUE) return reject(promise,"INVALID_ARGUMENT","invalid encoded playback speed"); command(reactTag,promise) { it.setEncodedForecastPlaybackSpeed(speed.toFloat()) } }
|
||||
@ReactMethod override fun setEncodedColorBinding(reactTag: Double, fieldKey: String, semanticID: Double, groupID: Double, expectedValueClass: String, expectedUnitID: Double, promise: Promise) {
|
||||
if (!validEncodedId(fieldKey) || !validUInt16(semanticID, true) || !validUInt16(groupID, false) || !validUInt16(expectedUnitID, false)) return reject(promise,"INVALID_ARGUMENT","invalid encoded color binding selector")
|
||||
val valueClass = when (expectedValueClass) { "SCALAR" -> 0; "DIRECTION_ANGLE" -> 2; else -> return reject(promise,"INVALID_ARGUMENT","invalid encoded color binding valueClass") }
|
||||
val valueClass = when (expectedValueClass) { "SCALAR" -> 0; "VELOCITY_COMPONENT" -> 1; "DIRECTION_ANGLE" -> 2; else -> return reject(promise,"INVALID_ARGUMENT","invalid encoded color binding valueClass") }
|
||||
command(reactTag,promise) { it.setEncodedColorBinding(fieldKey, semanticID.toInt(), groupID.toInt(), valueClass, expectedUnitID.toInt()) }
|
||||
}
|
||||
@ReactMethod override fun setEncodedParticleBinding(reactTag: Double, fieldKey: String, mode: String, uSemanticID: Double, uGroupID: Double, vSemanticID: Double, vGroupID: Double, directionSemanticID: Double, directionGroupID: Double, expectedUnitID: Double, promise: Promise) {
|
||||
|
||||
@@ -29,7 +29,7 @@ export const FieldRuntime = {
|
||||
payloadRefs.vectorFileUri ?? "",
|
||||
),
|
||||
submitEncodedField: (reactTag: number, fieldKey: string, metadata: EncodedFieldRuntimeMetadata, contract: ResolvedFieldProfileContractInput, qbinFileUri: string): Promise<EncodedFieldSubmitResult> => { encodedString(fieldKey, "fieldKey"); encodedString(metadata.fieldID, "fieldID"); uint(metadata.generation, "generation", MAX_SAFE, true); uint(metadata.dataVersion, "dataVersion"); if (typeof qbinFileUri !== "string" || !(qbinFileUri.startsWith("/") || qbinFileUri.startsWith("file://"))) return Promise.reject(new Error("qbinFileUri must be an absolute local path or file:// URI")); return nativeBridge().submitEncodedField(reactTag, fieldKey, metadata.fieldID, metadata.generation, metadata.dataVersion, encodedContractJson(contract), qbinFileUri); },
|
||||
setEncodedColorBinding: (reactTag: number, binding: EncodedColorBindingInput): Promise<CommandResult> => { encodedString(binding.fieldKey, "fieldKey"); uint(binding.semanticID, "semanticID", 0xffff, true); uint(binding.groupID, "groupID", 0xffff); uint(binding.expectedUnitID, "expectedUnitID", 0xffff); if (!["SCALAR", "DIRECTION_ANGLE"].includes(binding.expectedValueClass)) return Promise.reject(new Error("invalid encoded color binding valueClass")); return nativeBridge().setEncodedColorBinding(reactTag, binding.fieldKey, binding.semanticID, binding.groupID, binding.expectedValueClass, binding.expectedUnitID); },
|
||||
setEncodedColorBinding: (reactTag: number, binding: EncodedColorBindingInput): Promise<CommandResult> => { encodedString(binding.fieldKey, "fieldKey"); uint(binding.semanticID, "semanticID", 0xffff, true); uint(binding.groupID, "groupID", 0xffff); uint(binding.expectedUnitID, "expectedUnitID", 0xffff); if (!["SCALAR", "VELOCITY_COMPONENT", "DIRECTION_ANGLE"].includes(binding.expectedValueClass)) return Promise.reject(new Error("invalid encoded color binding valueClass")); return nativeBridge().setEncodedColorBinding(reactTag, binding.fieldKey, binding.semanticID, binding.groupID, binding.expectedValueClass, binding.expectedUnitID); },
|
||||
setEncodedParticleBinding: (reactTag: number, binding: EncodedParticleBindingInput): Promise<CommandResult> => { encodedString(binding.fieldKey, "fieldKey"); uint(binding.expectedUnitID, "expectedUnitID", 0xffff); const inactive = { semanticID: 0, groupID: 0 }; const valid = (plane: { semanticID: number; groupID: number }) => { uint(plane.semanticID, "selector semanticID", 0xffff, true); uint(plane.groupID, "selector groupID", 0xffff); }; let u = inactive, v = inactive, direction = inactive; if (binding.mode === "VECTOR_COMPONENTS" && binding.uPlane && binding.vPlane && !binding.directionPlane) { u = binding.uPlane; v = binding.vPlane; valid(u); valid(v); } else if (binding.mode === "DIRECTION_ANGLE" && binding.directionPlane && !binding.uPlane && !binding.vPlane) { direction = binding.directionPlane; valid(direction); } else return Promise.reject(new Error("encoded particle binding requires exactly U/V or direction selector; inactive ABI slots are zero")); return nativeBridge().setEncodedParticleBinding(reactTag, binding.fieldKey, binding.mode, u.semanticID, u.groupID, v.semanticID, v.groupID, direction.semanticID, direction.groupID, binding.expectedUnitID); },
|
||||
setEncodedForecastTime: (reactTag: number, timestampMs: number): Promise<CommandResult> => { uint(timestampMs, "forecast timestamp"); return nativeBridge().setEncodedForecastTime(reactTag, timestampMs); },
|
||||
setEncodedForecastPlaybackState: (reactTag: number, playback: "PLAY" | "PAUSE"): Promise<CommandResult> => nativeBridge().setEncodedForecastPlaybackState(reactTag, playback),
|
||||
|
||||
@@ -9,7 +9,7 @@ export type EncodedFieldRuntimeMetadata = Readonly<{ fieldID: string; generation
|
||||
export type RequiredPlaneContractInput = Readonly<{ semanticID: number; valueClass: "SCALAR" | "VELOCITY_COMPONENT" | "DIRECTION_ANGLE" | "VALIDITY"; unitID: number; groupID: number; component: "NONE" | "U_EAST" | "V_NORTH" | "W_UP"; requiredFlag: boolean }>;
|
||||
/** Frozen V4 JSON field names match ResolvedFieldProfileContract exactly. */
|
||||
export type ResolvedFieldProfileContractInput = Readonly<{ contractSchemaVersion: number; profileID: string; profileVersion: number; allowAdditionalPlanes: boolean; sharedValidityRequired: boolean; timeRelation: "ANY" | "VALID_GTE_REFERENCE" | "VALID_EQ_REFERENCE"; requiredPlanes: readonly RequiredPlaneContractInput[] }>;
|
||||
export type EncodedColorBindingInput = Readonly<{ fieldKey: string; semanticID: number; groupID: number; expectedValueClass: "SCALAR" | "DIRECTION_ANGLE"; expectedUnitID: number }>;
|
||||
export type EncodedColorBindingInput = Readonly<{ fieldKey: string; semanticID: number; groupID: number; expectedValueClass: "SCALAR" | "VELOCITY_COMPONENT" | "DIRECTION_ANGLE"; expectedUnitID: number }>;
|
||||
export type EncodedParticleBindingInput = Readonly<{ fieldKey: string; mode: "VECTOR_COMPONENTS" | "DIRECTION_ANGLE"; uPlane?: Readonly<{ semanticID: number; groupID: number }>; vPlane?: Readonly<{ semanticID: number; groupID: number }>; directionPlane?: Readonly<{ semanticID: number; groupID: number }>; expectedUnitID: number }>;
|
||||
export type FieldPayloadRefs = Readonly<
|
||||
{ validityFileUri: string } & (
|
||||
|
||||
@@ -1435,7 +1435,7 @@ jni::jint NativeMapView::submitRasterArraySourceEncodedField(JNIEnv& env, const
|
||||
}
|
||||
jni::jint NativeMapView::clearRasterArraySourceEncodedField(JNIEnv& env,const jni::String& sourceId,const jni::String& fieldKey) { auto* s=dynamic_cast<mbgl::style::RasterArraySource*>(map->getStyle().getSource(jni::Make<std::string>(env,sourceId))); if(!s)return 0; return s->clearEncodedField(jni::Make<std::string>(env,fieldKey)) ? 1 : -1; }
|
||||
jni::jint NativeMapView::clearAllRasterArraySourceEncodedFields(JNIEnv& env,const jni::String& sourceId) { auto* s=dynamic_cast<mbgl::style::RasterArraySource*>(map->getStyle().getSource(jni::Make<std::string>(env,sourceId))); if(!s)return 0; s->clearAllEncodedFields(); return 1; }
|
||||
jni::jint NativeMapView::setRasterArraySourceEncodedColorBinding(JNIEnv& env, const jni::String& sourceId, const jni::String& fieldKey, jni::jint semanticID, jni::jint groupID, jni::jint valueClass, jni::jint unitID) { auto* s=dynamic_cast<mbgl::style::RasterArraySource*>(map->getStyle().getSource(jni::Make<std::string>(env,sourceId))); if(!s)return 0; if(semanticID<=0||semanticID>UINT16_MAX||groupID<0||groupID>UINT16_MAX||unitID<0||unitID>UINT16_MAX||(valueClass!=0&&valueClass!=2))return -1; s->setColorBinding({jni::Make<std::string>(env,fieldKey),{static_cast<uint16_t>(semanticID),static_cast<uint16_t>(groupID)},static_cast<mbgl::particle::FieldValueClass>(valueClass),static_cast<uint16_t>(unitID)}); return 1; }
|
||||
jni::jint NativeMapView::setRasterArraySourceEncodedColorBinding(JNIEnv& env, const jni::String& sourceId, const jni::String& fieldKey, jni::jint semanticID, jni::jint groupID, jni::jint valueClass, jni::jint unitID) { auto* s=dynamic_cast<mbgl::style::RasterArraySource*>(map->getStyle().getSource(jni::Make<std::string>(env,sourceId))); if(!s)return 0; if(semanticID<=0||semanticID>UINT16_MAX||groupID<0||groupID>UINT16_MAX||unitID<0||unitID>UINT16_MAX||(valueClass<0||valueClass>2))return -1; s->setColorBinding({jni::Make<std::string>(env,fieldKey),{static_cast<uint16_t>(semanticID),static_cast<uint16_t>(groupID)},static_cast<mbgl::particle::FieldValueClass>(valueClass),static_cast<uint16_t>(unitID)}); return 1; }
|
||||
jni::jint NativeMapView::setRasterArraySourceEncodedParticleBinding(JNIEnv& env, const jni::String& sourceId, const jni::String& fieldKey, jni::jint mode, jni::jint uSemanticID, jni::jint uGroupID, jni::jint vSemanticID, jni::jint vGroupID, jni::jint directionSemanticID, jni::jint directionGroupID, jni::jint unitID) { auto* s=dynamic_cast<mbgl::style::RasterArraySource*>(map->getStyle().getSource(jni::Make<std::string>(env,sourceId))); if(!s)return 0; const auto valid=[](jni::jint semantic,jni::jint group){return semantic>0&&semantic<=UINT16_MAX&&group>=0&&group<=UINT16_MAX;}; const auto inactive=[](jni::jint semantic,jni::jint group){return semantic==0&&group==0;}; if(unitID<0||unitID>UINT16_MAX)return -1; mbgl::particle::ParticleBinding binding; binding.fieldKey=jni::Make<std::string>(env,fieldKey); binding.expectedUnitID=static_cast<uint16_t>(unitID); if(mode==0&&valid(uSemanticID,uGroupID)&&valid(vSemanticID,vGroupID)&&inactive(directionSemanticID,directionGroupID)){binding.mode=mbgl::particle::ParticleBindingMode::VectorComponents;binding.uPlane={static_cast<uint16_t>(uSemanticID),static_cast<uint16_t>(uGroupID)};binding.vPlane={static_cast<uint16_t>(vSemanticID),static_cast<uint16_t>(vGroupID)};} else if(mode==1&&inactive(uSemanticID,uGroupID)&&inactive(vSemanticID,vGroupID)&&valid(directionSemanticID,directionGroupID)){binding.mode=mbgl::particle::ParticleBindingMode::DirectionAngle;binding.directionPlane={static_cast<uint16_t>(directionSemanticID),static_cast<uint16_t>(directionGroupID)};} else return -1; s->setParticleBinding(std::move(binding)); return 1; }
|
||||
jni::jint NativeMapView::setRasterArraySourceEncodedForecastTime(JNIEnv& env,const jni::String& sourceId,jni::jlong timestamp) { auto* s=dynamic_cast<mbgl::style::RasterArraySource*>(map->getStyle().getSource(jni::Make<std::string>(env,sourceId))); if(!s)return 0; return timestamp>=0&&s->setRequestedForecastTime(static_cast<uint64_t>(timestamp))?1:-1; }
|
||||
jni::jint NativeMapView::setRasterArraySourceEncodedForecastPlaybackState(JNIEnv& env,const jni::String& sourceId,jni::jboolean playing) { auto* s=dynamic_cast<mbgl::style::RasterArraySource*>(map->getStyle().getSource(jni::Make<std::string>(env,sourceId))); if(!s)return 0; s->setForecastPlaybackState(playing ? mbgl::particle::ForecastPlaybackState::Playing : mbgl::particle::ForecastPlaybackState::Paused); return 1; }
|
||||
|
||||
@@ -209,6 +209,17 @@ TEST(ParticleFieldBinding, FailsClosedAndSupportsDirectionAngle) {
|
||||
particle::EncodedFieldStore store;
|
||||
submit(store, "weather.wind", makeFrame("wind", Base, 1, "0"));
|
||||
submit(store, "weather.wind", makeFrame("wind", Base + Hour, 1, "1"));
|
||||
const particle::ColorBinding velocityComponent{"weather.wind", {1, 7, particle::FieldComponent::UEast},
|
||||
particle::FieldValueClass::VelocityComponent,
|
||||
particle::FieldUnitMetersPerSecond};
|
||||
const auto velocityProjection = particle::BindingProjectionResolver::resolve(store, velocityComponent, Base);
|
||||
ASSERT_TRUE(velocityProjection.accepted());
|
||||
EXPECT_EQ(velocityProjection.projection->t0PlaneStorage,
|
||||
velocityProjection.projection->t0Frame->planes.front().storage);
|
||||
const particle::ColorBinding validity{"weather.wind", {900, 0, particle::FieldComponent::None},
|
||||
particle::FieldValueClass::Validity, particle::FieldUnitNone};
|
||||
EXPECT_EQ(particle::BindingProjectionResolver::resolve(store, validity, Base).error,
|
||||
particle::BindingProjectionError::InvalidBinding);
|
||||
EXPECT_EQ(particle::BindingProjectionResolver::resolve(store, color(""), Base).error, particle::BindingProjectionError::InvalidBinding);
|
||||
EXPECT_EQ(particle::BindingProjectionResolver::resolve(store, color("missing"), Base).error, particle::BindingProjectionError::FieldSeriesMissing);
|
||||
EXPECT_EQ(particle::BindingProjectionResolver::resolve(store, color("weather.wind"), Base + 2 * Hour).error, particle::BindingProjectionError::WindowUnavailable);
|
||||
|
||||
Reference in New Issue
Block a user