diagnostics: add STEP-099 render source readiness audit
This commit is contained in:
@@ -4,6 +4,7 @@ import android.graphics.Color
|
||||
import android.os.Bundle
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import android.os.SystemClock
|
||||
import android.text.InputType
|
||||
import android.util.Log
|
||||
import android.widget.Button
|
||||
@@ -23,7 +24,10 @@ import org.maplibre.android.maps.MapLibreMap
|
||||
import org.maplibre.android.maps.Style
|
||||
import org.maplibre.android.maps.WeatherRuntime
|
||||
import org.maplibre.android.style.layers.PaintPropertyValue
|
||||
import org.maplibre.android.style.sources.GeoJsonSource
|
||||
import org.maplibre.android.testapp.R
|
||||
import org.maplibre.geojson.Feature
|
||||
import org.maplibre.geojson.Point
|
||||
|
||||
/** Android OpenGL host for the formal raster-array to raster-particle fixture path. */
|
||||
class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
@@ -57,6 +61,75 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
private var retainedCacheEnabled = true
|
||||
private var step093Mode = false
|
||||
private var step097Topology: Step097StencilFixture.Topology? = null
|
||||
private var step099Scenario: Step099ReadinessFixture.Scenario? = null
|
||||
private var step099Tick = 0L
|
||||
private var step099LastOverallLoaded: Boolean? = null
|
||||
private var step099FalseSinceMs: Long? = null
|
||||
private var step099FalseWindowCount = 0L
|
||||
private var step099FalseWindowTotalMs = 0L
|
||||
private var step099FalseWindowMaxMs = 0L
|
||||
private var step099Running = false
|
||||
private val step099Handler = Handler(Looper.getMainLooper())
|
||||
private val step099ReadinessTransitionPoll = object : Runnable {
|
||||
override fun run() {
|
||||
if (step099Running && step099Scenario != null && this@ParticleCoreLayerValidationActivity::maplibreMap.isInitialized && styleReady) {
|
||||
val now = SystemClock.elapsedRealtime()
|
||||
val snapshot = JSONObject(maplibreMap.getRenderSegmentDiagnostics())
|
||||
val loaded = snapshot.optBoolean("renderOrchestratorLoaded")
|
||||
val previous = step099LastOverallLoaded
|
||||
if (previous == null || previous != loaded) {
|
||||
var falseWindowMs: Long? = null
|
||||
if (!loaded) {
|
||||
step099FalseSinceMs = now
|
||||
} else {
|
||||
falseWindowMs = step099FalseSinceMs?.let { start ->
|
||||
(now - start).also { duration ->
|
||||
step099FalseWindowCount += 1
|
||||
step099FalseWindowTotalMs += duration
|
||||
step099FalseWindowMaxMs = maxOf(step099FalseWindowMaxMs, duration)
|
||||
}
|
||||
}
|
||||
step099FalseSinceMs = null
|
||||
}
|
||||
Log.i(
|
||||
TAG,
|
||||
"STEP099_LOADED_TRANSITION elapsedMs=${now} from=${previous} to=${loaded} " +
|
||||
"falseWindowMs=${falseWindowMs ?: -1} source=${snapshot.optJSONObject("lastMutation")?.optString("sourceId")}"
|
||||
)
|
||||
step099LastOverallLoaded = loaded
|
||||
}
|
||||
}
|
||||
if (step099Running) step099Handler.postDelayed(this, STEP099_STATE_SAMPLE_INTERVAL_MS)
|
||||
}
|
||||
}
|
||||
private val step099DiagnosticsPoll = object : Runnable {
|
||||
override fun run() {
|
||||
val scenario = step099Scenario ?: return
|
||||
if (!step099Running) return
|
||||
if (this@ParticleCoreLayerValidationActivity::maplibreMap.isInitialized && styleReady) {
|
||||
step099Tick += 1
|
||||
when (scenario) {
|
||||
Step099ReadinessFixture.Scenario.T2_GEOJSON_1HZ -> {
|
||||
val sourceId = if (step099Tick % 2L == 0L) {
|
||||
Step099ReadinessFixture.DYNAMIC_SOURCE
|
||||
} else {
|
||||
Step099ReadinessFixture.DYNAMIC_SOURCE_B
|
||||
}
|
||||
updateStep099GeoJson(sourceId, step099Tick)
|
||||
if (step099Tick % 2L == 0L) refreshStep099Diagnostics(log = true)
|
||||
}
|
||||
Step099ReadinessFixture.Scenario.T4_RCR -> {
|
||||
if (step099Tick % 2L == 0L) {
|
||||
updateStep099GeoJson(Step099ReadinessFixture.DYNAMIC_SOURCE, step099Tick)
|
||||
refreshStep099Diagnostics(log = true)
|
||||
}
|
||||
}
|
||||
else -> if (step099Tick % 2L == 0L) refreshStep099Diagnostics(log = true)
|
||||
}
|
||||
}
|
||||
if (step099Running) step099Handler.postDelayed(this, STEP099_TICK_INTERVAL_MS)
|
||||
}
|
||||
}
|
||||
private var step093Topology = Step093Topology.BOTTOM_CONTINUOUS_TOP
|
||||
private var step093Variant = Step093Variant.DEFAULT
|
||||
private var step093StartVisible = true
|
||||
@@ -454,6 +527,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
menu.add(0, 14, 14, "READ DIAGNOSTICS")
|
||||
menu.add(0, 15, 15, "RESET DEFAULT A")
|
||||
menu.add(0, 16, 16, "STEP-097 SAME SOURCE STENCIL")
|
||||
menu.add(0, 17, 17, "STEP-099 READINESS")
|
||||
setOnMenuItemClickListener { item ->
|
||||
when (item.itemId) {
|
||||
in Step093Topology.values().indices -> applyStep093Scene(Step093Topology.values()[item.itemId])
|
||||
@@ -464,6 +538,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
14 -> refreshStep093Diagnostics(log = true)
|
||||
15 -> applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP)
|
||||
16 -> showStep097StencilMenu(anchor)
|
||||
17 -> showStep099Menu(anchor)
|
||||
}
|
||||
true
|
||||
}
|
||||
@@ -491,7 +566,145 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun showStep099Menu(anchor: android.view.View) {
|
||||
PopupMenu(this, anchor).apply {
|
||||
Step099ReadinessFixture.Scenario.values().forEachIndexed { index, scenario ->
|
||||
menu.add(0, index, index, scenario.label)
|
||||
}
|
||||
menu.add(0, 10, 10, "STOP / RETURN TO DEFAULT")
|
||||
setOnMenuItemClickListener { item ->
|
||||
if (item.itemId in Step099ReadinessFixture.Scenario.values().indices) {
|
||||
applyStep099Scenario(Step099ReadinessFixture.Scenario.values()[item.itemId])
|
||||
} else if (item.itemId == 10) {
|
||||
stopStep099Scenario()
|
||||
loadValidationStyle(active, enabled, "STEP099_EXIT")
|
||||
}
|
||||
true
|
||||
}
|
||||
show()
|
||||
}
|
||||
}
|
||||
|
||||
private fun applyStep099Scenario(scenario: Step099ReadinessFixture.Scenario) {
|
||||
stopStep093DiagnosticsPolling()
|
||||
step093Mode = false
|
||||
step097Topology = null
|
||||
step099Scenario = scenario
|
||||
step099Running = true
|
||||
step099Tick = 0L
|
||||
step099LastOverallLoaded = null
|
||||
step099FalseSinceMs = null
|
||||
step099FalseWindowCount = 0L
|
||||
step099FalseWindowTotalMs = 0L
|
||||
step099FalseWindowMaxMs = 0L
|
||||
timeWindowMode = false
|
||||
productionFeedMode = false
|
||||
hostSubmissionMode = false
|
||||
realWeatherMode = false
|
||||
weatherRuntime?.dispose()
|
||||
weatherRuntime = null
|
||||
step099Handler.removeCallbacksAndMessages(null)
|
||||
val accepted = maplibreMap.setRenderSegmentPlan(Step099ReadinessFixture.planJson(scenario))
|
||||
styleReady = false
|
||||
val epoch = ++styleLoadEpoch
|
||||
status.text = "STEP-099 · ${scenario.label} · LOADING"
|
||||
Log.i(TAG, "STEP099_SCENARIO_START scenario=${scenario.name} planAccepted=$accepted")
|
||||
maplibreMap.setStyle(Style.Builder().fromJson(Step099ReadinessFixture.styleJson(scenario))) {
|
||||
if (!step099Running || step099Scenario != scenario || epoch != styleLoadEpoch) return@setStyle
|
||||
styleReady = true
|
||||
status.text = "STEP-099 · ${scenario.label}"
|
||||
refreshStep099Diagnostics(log = true)
|
||||
step099Handler.post(step099ReadinessTransitionPoll)
|
||||
step099Handler.post(step099DiagnosticsPoll)
|
||||
maplibreMap.moveCamera(CameraUpdateFactory.newCameraPosition(
|
||||
CameraPosition.Builder().target(LatLng(28.0, 135.0)).zoom(3.0).build()
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
private fun stopStep099Scenario() {
|
||||
step099Running = false
|
||||
step099Handler.removeCallbacksAndMessages(null)
|
||||
val previous = step099Scenario
|
||||
step099Scenario = null
|
||||
if (previous != null) {
|
||||
val average = if (step099FalseWindowCount == 0L) 0 else step099FalseWindowTotalMs / step099FalseWindowCount
|
||||
val open = step099FalseSinceMs?.let { SystemClock.elapsedRealtime() - it } ?: 0L
|
||||
Log.i(TAG, "STEP099_AGGREGATE scenario=${previous.name} falseWindowCount=$step099FalseWindowCount " +
|
||||
"falseWindowAvgMs=$average falseWindowMaxMs=$step099FalseWindowMaxMs openFalseWindowMs=$open")
|
||||
}
|
||||
step099LastOverallLoaded = null
|
||||
step099FalseSinceMs = null
|
||||
}
|
||||
|
||||
private fun updateStep099GeoJson(sourceId: String, tick: Long) {
|
||||
val source = maplibreMap.style?.getSourceAs<GeoJsonSource>(sourceId) ?: return
|
||||
val offset = (tick % 20L) * 0.12
|
||||
val longitude = if (sourceId == Step099ReadinessFixture.DYNAMIC_SOURCE) 135.0 + offset else 136.0 - offset
|
||||
val latitude = if (sourceId == Step099ReadinessFixture.DYNAMIC_SOURCE) 28.0 + offset * 0.3 else 29.0 - offset * 0.3
|
||||
source.setGeoJson(Feature.fromGeometry(Point.fromLngLat(longitude, latitude)))
|
||||
Log.i(TAG, "STEP099_SOURCE_UPDATE scenario=${step099Scenario?.name} sourceId=$sourceId tick=$tick")
|
||||
}
|
||||
|
||||
private fun refreshStep099Diagnostics(log: Boolean) {
|
||||
if (!this::maplibreMap.isInitialized || !styleReady) return
|
||||
val snapshot = JSONObject(maplibreMap.getRenderSegmentDiagnostics())
|
||||
val sources = snapshot.optJSONArray("sources")
|
||||
val sourceSummary = buildList {
|
||||
for (index in 0 until (sources?.length() ?: 0)) {
|
||||
val source = sources?.optJSONObject(index) ?: continue
|
||||
add("${source.optString("sourceId")}:${source.optString("sourceType")}:" +
|
||||
"${source.optBoolean("enabled")}/${source.optBoolean("isLoaded")}" +
|
||||
" tiles=${source.opt("tileCount")}/${source.opt("incompleteTileCount")}/${source.opt("loadedTileCount")}" +
|
||||
" fade=${source.optBoolean("hasFadingTiles")}")
|
||||
}
|
||||
}
|
||||
val segments = snapshot.optJSONArray("segments")
|
||||
val segmentSummary = buildList {
|
||||
for (index in 0 until (segments?.length() ?: 0)) {
|
||||
val segment = segments?.optJSONObject(index) ?: continue
|
||||
val dependencies = segment.optJSONArray("dependentSourceIds")
|
||||
val dependencyText = buildList {
|
||||
for (dependencyIndex in 0 until (dependencies?.length() ?: 0)) {
|
||||
add(dependencies?.optString(dependencyIndex).orEmpty())
|
||||
}
|
||||
}.joinToString(",")
|
||||
val cache = segment.optJSONObject("cache")
|
||||
val cacheText = if (cache == null) {
|
||||
"cache=-"
|
||||
} else {
|
||||
"cache=${cache.optString("cacheState")}@${cache.optLong("contentRevision")}" +
|
||||
" b=${cache.optLong("build")} r=${cache.optLong("reuse")}" +
|
||||
" i=${cache.optLong("invalidation")}/${cache.optString("lastInvalidationReason")}"
|
||||
}
|
||||
add("${segment.optInt("segmentIndex")}:${segment.optString("strategy")}" +
|
||||
"[${segment.optInt("beginIndex")},${segment.optInt("endExclusive")})" +
|
||||
" deps=[$dependencyText] $cacheText")
|
||||
}
|
||||
}
|
||||
val mutation = snapshot.optJSONObject("lastMutation")
|
||||
val affectedSegments = mutation?.optJSONArray("affectedSegmentIndices")
|
||||
val affectedText = buildList {
|
||||
for (index in 0 until (affectedSegments?.length() ?: 0)) {
|
||||
add(affectedSegments?.optInt(index).toString())
|
||||
}
|
||||
}.joinToString(",")
|
||||
val message = "scenario=${step099Scenario?.name} overall=${snapshot.optBoolean("renderOrchestratorLoaded")} " +
|
||||
"style=${snapshot.optBoolean("styleLoaded")} image=${snapshot.optBoolean("imageManagerLoaded")} " +
|
||||
"sprite=${snapshot.optBoolean("spriteLoaded")} fade=${snapshot.optBoolean("hasFadingTiles")} " +
|
||||
"rev=${snapshot.optLong("contentRevision")} sources=${sourceSummary.joinToString(";")} " +
|
||||
"last=${mutation?.optLong("sequence")}/${mutation?.optString("sourceId")}/${mutation?.optString("reason")}" +
|
||||
" affected=[$affectedText] scope=${mutation?.optString("dependencyScope")} " +
|
||||
"fast=${snapshot.optBoolean("fastPathActive")}/${snapshot.optBoolean("fastPathEligible")}" +
|
||||
"/${snapshot.optString("fastPathFallbackReason")}" +
|
||||
" h=${snapshot.optLong("fastPathHit")} m=${snapshot.optLong("fastPathMiss")}" +
|
||||
" full=${snapshot.optLong("fullCpuFrame")} segments=${segmentSummary.joinToString(";")}"
|
||||
diagnostics.text = "STEP-099 $message"
|
||||
if (log) Log.i(TAG, "STEP099_AGGREGATE_SAMPLE $message")
|
||||
}
|
||||
|
||||
private fun applyStep097StencilScene(topology: Step097StencilFixture.Topology) {
|
||||
stopStep099Scenario()
|
||||
leaveRealWeatherMode()
|
||||
step097Topology = topology
|
||||
retainedCacheEnabled = true
|
||||
@@ -630,6 +843,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
variant: Step093Variant = Step093Variant.DEFAULT,
|
||||
configureBeforeStyle: Boolean = false
|
||||
) {
|
||||
stopStep099Scenario()
|
||||
leaveRealWeatherMode()
|
||||
step093Mode = true
|
||||
step093Topology = topology
|
||||
@@ -720,6 +934,10 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
step093Handler.post(step093DiagnosticsPoll)
|
||||
}
|
||||
|
||||
private fun stopStep093DiagnosticsPolling() {
|
||||
step093Handler.removeCallbacks(step093DiagnosticsPoll)
|
||||
}
|
||||
|
||||
private fun refreshStep093Diagnostics(log: Boolean) {
|
||||
val snapshot = maplibreMap.retainedUnderlayDiagnostics
|
||||
val cacheCount = (if (snapshot.bottomPresent) 1 else 0) + (if (snapshot.topPresent) 1 else 0)
|
||||
@@ -1145,6 +1363,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
}
|
||||
|
||||
private fun loadValidationStyle(active: Boolean, enabled: Boolean, reason: String = "STYLE_CHANGE") {
|
||||
if (step099Scenario != null) stopStep099Scenario()
|
||||
step097V4GoldenReady = false
|
||||
if (pureParticleMode) {
|
||||
loadPureParticleStyle(active, enabled, reason)
|
||||
@@ -1904,11 +2123,37 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
override fun onStart() { super.onStart(); mapView.onStart(); if (step093Mode || step097Topology != null) startStep093DiagnosticsPolling() }
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
mapView.onStart()
|
||||
if (step099Scenario != null) {
|
||||
step099Running = true
|
||||
step099LastOverallLoaded = null
|
||||
step099FalseSinceMs = null
|
||||
step099Handler.removeCallbacksAndMessages(null)
|
||||
if (styleReady) {
|
||||
step099Handler.post(step099ReadinessTransitionPoll)
|
||||
step099Handler.post(step099DiagnosticsPoll)
|
||||
}
|
||||
} else if (step093Mode || step097Topology != null) startStep093DiagnosticsPolling()
|
||||
}
|
||||
override fun onResume() { super.onResume(); mapView.onResume() }
|
||||
override fun onPause() { mapView.onPause(); super.onPause() }
|
||||
override fun onStop() { step093Handler.removeCallbacks(step093DiagnosticsPoll); mapView.onStop(); super.onStop() }
|
||||
override fun onDestroy() { step093Handler.removeCallbacks(step093DiagnosticsPoll); weatherRuntime?.dispose(); weatherRuntime = null; mapView.onDestroy(); super.onDestroy() }
|
||||
override fun onStop() {
|
||||
step093Handler.removeCallbacks(step093DiagnosticsPoll)
|
||||
step099Running = false
|
||||
step099Handler.removeCallbacksAndMessages(null)
|
||||
mapView.onStop()
|
||||
super.onStop()
|
||||
}
|
||||
override fun onDestroy() {
|
||||
step093Handler.removeCallbacks(step093DiagnosticsPoll)
|
||||
stopStep099Scenario()
|
||||
weatherRuntime?.dispose()
|
||||
weatherRuntime = null
|
||||
mapView.onDestroy()
|
||||
super.onDestroy()
|
||||
}
|
||||
override fun onLowMemory() { super.onLowMemory(); mapView.onLowMemory() }
|
||||
|
||||
override fun onSaveInstanceState(outState: Bundle) {
|
||||
@@ -1978,6 +2223,8 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
|
||||
private const val WEATHER_COLOR_LAYER_ID = "weather-color-real"
|
||||
private const val PARTICLE_SOURCE_ID = "particle-fixture"
|
||||
private const val STEP093_DIAGNOSTICS_INTERVAL_MS = 1000L
|
||||
private const val STEP099_STATE_SAMPLE_INTERVAL_MS = 200L
|
||||
private const val STEP099_TICK_INTERVAL_MS = 500L
|
||||
private const val STEP093_WEATHER_LAYER_ID = WEATHER_COLOR_LAYER_ID
|
||||
private const val STEP093_PARTICLE_LAYER_ID = PARTICLE_LAYER_ID
|
||||
private const val STEP093_BOTTOM_BACKGROUND_ID = "step093-bottom-background"
|
||||
|
||||
@@ -0,0 +1,141 @@
|
||||
package org.maplibre.android.testapp.activity.particle
|
||||
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
|
||||
/** STEP-099 offline readiness/invalidation fixtures. Diagnostics only; no renderer semantics are changed. */
|
||||
internal object Step099ReadinessFixture {
|
||||
enum class Scenario(val label: String) {
|
||||
T1_STATIC("T1 STATIC"),
|
||||
T2_GEOJSON_1HZ("T2 GEOJSON 1HZ"),
|
||||
T3_PERMANENT_UNREADY("T3 PERMANENT UNREADY"),
|
||||
T4_RCR("T4 R-C-R")
|
||||
}
|
||||
|
||||
const val PARTICLE_SOURCE = "particle-fixture"
|
||||
const val STATIC_SOURCE = "step099-static"
|
||||
const val DYNAMIC_SOURCE = "step099-dynamic"
|
||||
const val DYNAMIC_SOURCE_B = "step099-dynamic-b"
|
||||
const val UNREADY_SOURCE = "step099-unready-raster-array"
|
||||
|
||||
const val STATIC_LAYER = "step099-static-fill"
|
||||
const val WEATHER_LAYER = "step099-weather"
|
||||
const val PARTICLE_LAYER = "step099-particle"
|
||||
const val DYNAMIC_LAYER = "step099-dynamic-circle"
|
||||
const val DYNAMIC_LAYER_B = "step099-dynamic-circle-b"
|
||||
const val UPPER_STATIC_LAYER = "step099-static-upper-fill"
|
||||
|
||||
fun styleJson(scenario: Scenario): String {
|
||||
val sources = JSONObject()
|
||||
.put(PARTICLE_SOURCE, JSONObject()
|
||||
.put("type", "raster-array")
|
||||
.put("fixture", "uniform-east")
|
||||
.put("metadata", "asset://integration/particle-fixtures/uniform-east/metadata.json")
|
||||
.put("field", "asset://integration/particle-fixtures/uniform-east/field.f32"))
|
||||
.put(STATIC_SOURCE, geoJsonSource(
|
||||
"""{"type":"Polygon","coordinates":[[[112,0],[158,0],[158,56],[112,56],[112,0]]]}"""
|
||||
))
|
||||
|
||||
if (scenario == Scenario.T2_GEOJSON_1HZ || scenario == Scenario.T4_RCR) {
|
||||
sources.put(DYNAMIC_SOURCE, geoJsonSource(
|
||||
"""{"type":"Point","coordinates":[135.0,28.0]}"""
|
||||
))
|
||||
}
|
||||
if (scenario == Scenario.T2_GEOJSON_1HZ) {
|
||||
sources.put(DYNAMIC_SOURCE_B, geoJsonSource(
|
||||
"""{"type":"Point","coordinates":[136.0,29.0]}"""
|
||||
))
|
||||
}
|
||||
if (scenario == Scenario.T3_PERMANENT_UNREADY) {
|
||||
// A valid host-submission RasterArraySource with no submitted field is intentionally isLoaded=false.
|
||||
// It has no layer on purpose: STEP-099 verifies whether a globally present but unrelated Source
|
||||
// can still hold RenderOrchestrator::isLoaded() false.
|
||||
sources.put(UNREADY_SOURCE, JSONObject()
|
||||
.put("type", "raster-array")
|
||||
.put("host-field-submission", true))
|
||||
}
|
||||
|
||||
val layers = JSONArray()
|
||||
.put(JSONObject()
|
||||
.put("id", "step099-background")
|
||||
.put("type", "background")
|
||||
.put("paint", JSONObject().put("background-color", "#0b2942")))
|
||||
.put(JSONObject()
|
||||
.put("id", STATIC_LAYER)
|
||||
.put("type", "fill")
|
||||
.put("source", STATIC_SOURCE)
|
||||
.put("paint", JSONObject()
|
||||
.put("fill-color", "#176b87")
|
||||
.put("fill-opacity", 0.58)))
|
||||
.put(JSONObject()
|
||||
.put("id", WEATHER_LAYER)
|
||||
.put("type", "weather-color")
|
||||
.put("source", PARTICLE_SOURCE)
|
||||
.put("paint", JSONObject().put("weather-color-opacity", 0.32)))
|
||||
.put(JSONObject()
|
||||
.put("id", PARTICLE_LAYER)
|
||||
.put("type", "raster-particle")
|
||||
.put("source", PARTICLE_SOURCE)
|
||||
.put("paint", JSONObject()
|
||||
.put("raster-particle-active", true)
|
||||
.put("raster-particle-particle-count", 1024)))
|
||||
|
||||
if (scenario == Scenario.T2_GEOJSON_1HZ || scenario == Scenario.T4_RCR) {
|
||||
layers.put(JSONObject()
|
||||
.put("id", DYNAMIC_LAYER)
|
||||
.put("type", "circle")
|
||||
.put("source", DYNAMIC_SOURCE)
|
||||
.put("paint", JSONObject()
|
||||
.put("circle-radius", 12)
|
||||
.put("circle-color", "#ffcc00")
|
||||
.put("circle-opacity", 0.95)))
|
||||
}
|
||||
if (scenario == Scenario.T2_GEOJSON_1HZ) {
|
||||
layers.put(JSONObject()
|
||||
.put("id", DYNAMIC_LAYER_B)
|
||||
.put("type", "circle")
|
||||
.put("source", DYNAMIC_SOURCE_B)
|
||||
.put("paint", JSONObject()
|
||||
.put("circle-radius", 10)
|
||||
.put("circle-color", "#ff6600")
|
||||
.put("circle-opacity", 0.90)))
|
||||
}
|
||||
layers.put(JSONObject()
|
||||
.put("id", UPPER_STATIC_LAYER)
|
||||
.put("type", "fill")
|
||||
.put("source", STATIC_SOURCE)
|
||||
.put("paint", JSONObject().put("fill-color", "#d3a640").put("fill-opacity", 0.38)))
|
||||
|
||||
return JSONObject()
|
||||
.put("version", 8)
|
||||
.put("name", "STEP-099 Source Readiness Diagnostics")
|
||||
.put("sources", sources)
|
||||
.put("layers", layers)
|
||||
.toString()
|
||||
}
|
||||
|
||||
fun planJson(scenario: Scenario): String {
|
||||
val segments = JSONArray()
|
||||
fun add(strategy: String, start: String? = null) {
|
||||
val segment = JSONObject().put("strategy", strategy)
|
||||
if (start != null) segment.put("startLayerId", start)
|
||||
segments.put(segment)
|
||||
}
|
||||
|
||||
add("RETAINED")
|
||||
add("CONTINUOUS", WEATHER_LAYER)
|
||||
add("RETAINED", if (scenario == Scenario.T2_GEOJSON_1HZ || scenario == Scenario.T4_RCR) DYNAMIC_LAYER else UPPER_STATIC_LAYER)
|
||||
|
||||
return JSONObject()
|
||||
.put("schemaVersion", 1)
|
||||
.put("segments", segments)
|
||||
.toString()
|
||||
}
|
||||
|
||||
private fun geoJsonSource(geometryJson: String): JSONObject = JSONObject()
|
||||
.put("type", "geojson")
|
||||
.put("data", JSONObject()
|
||||
.put("type", "Feature")
|
||||
.put("properties", JSONObject())
|
||||
.put("geometry", JSONObject(geometryJson)))
|
||||
}
|
||||
Reference in New Issue
Block a user