test(step097): add A1 renderer regression entry points

This commit is contained in:
tei
2026-09-26 09:15:10 +09:00
parent be5b9080ed
commit d0ced72351
7 changed files with 422 additions and 28 deletions

View File

@@ -55,6 +55,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
private var navSeaPbfLayerVisibility = emptyList<NavSeaPbfLayerVisibility>()
private var retainedCacheEnabled = true
private var step093Mode = false
private var step097Topology: Step097StencilFixture.Topology? = null
private var step093Topology = Step093Topology.BOTTOM_CONTINUOUS_TOP
private var step093Variant = Step093Variant.DEFAULT
private var step093StartVisible = true
@@ -63,8 +64,9 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
private val step093Handler = Handler(Looper.getMainLooper())
private val step093DiagnosticsPoll = object : Runnable {
override fun run() {
if (step093Mode && this@ParticleCoreLayerValidationActivity::maplibreMap.isInitialized) {
refreshStep093Diagnostics(log = false)
if ((step093Mode || step097Topology != null) && this@ParticleCoreLayerValidationActivity::maplibreMap.isInitialized) {
if (step097Topology != null) refreshStep097Diagnostics(log = false)
else refreshStep093Diagnostics(log = false)
step093Handler.postDelayed(this, STEP093_DIAGNOSTICS_INTERVAL_MS)
}
}
@@ -107,6 +109,8 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
navSeaPbfRenderEnabled = savedInstanceState?.getBoolean(STATE_NAVSEA_PBF_RENDER_ENABLED, true) ?: true
retainedCacheEnabled = savedInstanceState?.getBoolean(STATE_RETAINED_CACHE_ENABLED, true) ?: true
step093Mode = savedInstanceState?.getBoolean(STATE_STEP093_MODE, false) ?: false
step097Topology = savedInstanceState?.getString(STATE_STEP097_TOPOLOGY)
?.let { value -> Step097StencilFixture.Topology.values().firstOrNull { it.name == value } }
step093Topology = savedInstanceState?.getString(STATE_STEP093_TOPOLOGY)
?.let { value -> Step093Topology.values().firstOrNull { it.name == value } }
?: Step093Topology.BOTTOM_CONTINUOUS_TOP
@@ -145,7 +149,8 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
updateNavSeaPbfButtonState()
updatePbfModeButtonState()
updateRetainedCacheButtonState()
if (step093Mode) loadStep093Style(configureBeforeStyle = false)
if (step097Topology != null) loadStep097StencilStyle()
else if (step093Mode) loadStep093Style(configureBeforeStyle = false)
else loadValidationStyle(active = active, enabled = enabled, reason = "INITIAL")
}
@@ -317,7 +322,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
}
private fun activateRealWeather(anchor: android.view.View?) {
if (isPbfMatrixMode() || step093Mode) leaveRealWeatherMode()
if (isPbfMatrixMode() || step093Mode || step097Topology != null) leaveRealWeatherMode()
realWeatherMenuAnchor = anchor ?: findViewById(R.id.validationMenuRealWeather)
if (realWeatherMode) {
if (realWeatherTuningMenu == null) showRealWeatherTuning(realWeatherMenuAnchor!!) else dismissRealWeatherTuning()
@@ -349,6 +354,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
private fun leaveRealWeatherMode() {
step093Mode = false
step097Topology = null
step093Handler.removeCallbacks(step093DiagnosticsPoll)
dismissRealWeatherTuning()
weatherRuntime?.dispose()
@@ -446,6 +452,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
menu.add(0, 13, 13, "CAMERA NEXT")
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")
setOnMenuItemClickListener { item ->
when (item.itemId) {
in Step093Topology.values().indices -> applyStep093Scene(Step093Topology.values()[item.itemId])
@@ -455,6 +462,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
13 -> applyStep093CameraPreset()
14 -> refreshStep093Diagnostics(log = true)
15 -> applyStep093Scene(Step093Topology.BOTTOM_CONTINUOUS_TOP)
16 -> showStep097StencilMenu(anchor)
}
true
}
@@ -462,6 +470,70 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
}
}
private fun showStep097StencilMenu(anchor: android.view.View) {
PopupMenu(this, anchor).apply {
Step097StencilFixture.Topology.values().forEachIndexed { index, topology ->
menu.add(0, index, index, "${topology.name} · same source / same tiles")
}
menu.add(0, 10, 10, "REBUILD CURRENT")
menu.add(0, 11, 11, "READ DIAGNOSTICS")
setOnMenuItemClickListener { item ->
when (item.itemId) {
in Step097StencilFixture.Topology.values().indices ->
applyStep097StencilScene(Step097StencilFixture.Topology.values()[item.itemId])
10 -> if (step097Topology != null) loadStep097StencilStyle()
11 -> if (step097Topology != null) refreshStep097Diagnostics(log = true)
}
true
}
show()
}
}
private fun applyStep097StencilScene(topology: Step097StencilFixture.Topology) {
leaveRealWeatherMode()
step097Topology = topology
retainedCacheEnabled = true
maplibreMap.setRetainedUnderlayEnabled(true)
updateRetainedCacheButtonState()
loadStep097StencilStyle()
}
private fun loadStep097StencilStyle() {
val topology = step097Topology ?: return
styleReady = false
val epoch = ++styleLoadEpoch
status.text = "STEP-097 · ${topology.name} · LOADING"
val accepted = maplibreMap.setRenderSegmentPlan(Step097StencilFixture.planJson(topology))
Log.i(TAG, "STEP097_STENCIL_PLAN topology=${topology.name} accepted=$accepted beforeStyle=true")
maplibreMap.setStyle(Style.Builder().fromJson(Step097StencilFixture.styleJson())) {
if (step097Topology != topology || epoch != styleLoadEpoch) return@setStyle
styleReady = true
maplibreMap.moveCamera(CameraUpdateFactory.newCameraPosition(
CameraPosition.Builder().target(LatLng(0.0, 0.0)).zoom(2.0).build()
))
status.text = statusText()
startStep093DiagnosticsPolling()
refreshStep097Diagnostics(log = true)
Log.i(TAG, "STEP097_STENCIL_READY topology=${topology.name} source=step097-shared-polygon")
}
}
private fun refreshStep097Diagnostics(log: Boolean) {
val topology = step097Topology ?: return
val snapshot = JSONObject(maplibreMap.getRenderSegmentDiagnostics())
diagnostics.text = buildString {
append("STEP-097 ${topology.name} valid=${snapshot.optBoolean("valid")} fallback=${snapshot.optBoolean("fallback")} topology=${snapshot.optLong("topologyRevision")} reason=${snapshot.optString("lastReason")}\n")
val segments = snapshot.optJSONArray("segments")
for (index in 0 until (segments?.length() ?: 0)) {
val segment = segments?.optJSONObject(index) ?: continue
val cache = segment.optJSONObject("cache")
append("$index ${segment.optString("strategy")} ${cache?.optString("cacheState")} build=${cache?.optLong("build")} reuse=${cache?.optLong("reuse")}\n")
}
}
if (log) Log.i(TAG, "STEP097_STENCIL_DIAGNOSTICS ${diagnostics.text.toString().replace('\n', ' ')}")
}
private fun showStep093MutationMenu(anchor: android.view.View) {
val actions = arrayOf(
"CONTINUOUS ADD", "CONTINUOUS REORDER", "BOTTOM ADD", "BOTTOM REORDER",
@@ -845,7 +917,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
}
private fun enterPbfMatrix() {
if (realWeatherMode || step093Mode) leaveRealWeatherMode()
if (realWeatherMode || step093Mode || step097Topology != null) leaveRealWeatherMode()
if (!isPbfMatrixMode()) {
preRealWeatherVisuals = ParticleVisuals(particleCount, lineWidth, particleLength, particleOpacity, trailOpacity, trailFade)
particleCount = REAL_WEATHER_PARTICLE_COUNT
@@ -1558,6 +1630,9 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
}
private fun statusText(): String {
step097Topology?.let { topology ->
return "STEP-097 · ${topology.name} · SAME SOURCE STENCIL · CACHE ${if (retainedCacheEnabled) "ON" else "OFF"}"
}
if (step093Mode) {
return "STEP-093 · ${step093Topology.label} · ${step093Variant.name} · " +
"CACHE ${if (retainedCacheEnabled) "ON" else "OFF"}"
@@ -1769,7 +1844,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
""".trimIndent()
}
override fun onStart() { super.onStart(); mapView.onStart(); if (step093Mode) startStep093DiagnosticsPolling() }
override fun onStart() { super.onStart(); mapView.onStart(); 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() }
@@ -1799,6 +1874,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
outState.putBoolean(STATE_NAVSEA_PBF_RENDER_ENABLED, navSeaPbfRenderEnabled)
outState.putBoolean(STATE_RETAINED_CACHE_ENABLED, retainedCacheEnabled)
outState.putBoolean(STATE_STEP093_MODE, step093Mode)
outState.putString(STATE_STEP097_TOPOLOGY, step097Topology?.name)
outState.putString(STATE_STEP093_TOPOLOGY, step093Topology.name)
outState.putString(STATE_STEP093_VARIANT, step093Variant.name)
super.onSaveInstanceState(outState)
@@ -1835,6 +1911,7 @@ class ParticleCoreLayerValidationActivity : AppCompatActivity() {
private const val STATE_NAVSEA_PBF_RENDER_ENABLED = "particle_validation.navsea_pbf_render_enabled"
private const val STATE_RETAINED_CACHE_ENABLED = "particle_validation.retained_cache_enabled"
private const val STATE_STEP093_MODE = "particle_validation.step093_mode"
private const val STATE_STEP097_TOPOLOGY = "particle_validation.step097_topology"
private const val STATE_STEP093_TOPOLOGY = "particle_validation.step093_topology"
private const val STATE_STEP093_VARIANT = "particle_validation.step093_variant"
private const val PARTICLE_LAYER_ID = "particle-raster-core"

View File

@@ -0,0 +1,76 @@
package org.maplibre.android.testapp.activity.particle
import org.json.JSONArray
import org.json.JSONObject
/** Offline same-source tile fixture for retained target stencil regression. */
internal object Step097StencilFixture {
enum class Topology { RR, RCR, CRR }
const val FIRST_FILL = "step097-shared-fill-a"
const val SECOND_FILL = "step097-shared-fill-b"
const val THIRD_FILL = "step097-shared-fill-c"
private const val FOURTH_FILL = "step097-shared-fill-d"
private const val SOURCE = "step097-shared-polygon"
fun styleJson(): String {
val geometry = JSONObject()
.put("type", "Polygon")
.put("coordinates", JSONArray().put(
JSONArray().put(JSONArray().put(-45).put(-35))
.put(JSONArray().put(45).put(-35))
.put(JSONArray().put(45).put(35))
.put(JSONArray().put(-45).put(35))
.put(JSONArray().put(-45).put(-35))
))
val source = JSONObject().put("type", "geojson").put("data", JSONObject()
.put("type", "Feature")
.put("properties", JSONObject())
.put("geometry", geometry))
val layers = JSONArray()
.put(JSONObject().put("id", "step097-background").put("type", "background")
.put("paint", JSONObject().put("background-color", "#15243a")))
.put(fill(FIRST_FILL, "#f94144"))
.put(fill(SECOND_FILL, "#43aa8b"))
.put(fill(THIRD_FILL, "#577590"))
.put(fill(FOURTH_FILL, "#f9c74f"))
return JSONObject()
.put("version", 8)
.put("name", "STEP-097 same-source stencil fixture")
.put("sources", JSONObject().put(SOURCE, source))
.put("layers", layers)
.toString()
}
fun planJson(topology: Topology): 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)
}
when (topology) {
Topology.RR -> {
add("RETAINED")
add("RETAINED", SECOND_FILL)
}
Topology.RCR -> {
add("RETAINED")
add("CONTINUOUS", SECOND_FILL)
add("RETAINED", THIRD_FILL)
}
Topology.CRR -> {
add("CONTINUOUS")
add("RETAINED", SECOND_FILL)
add("RETAINED", THIRD_FILL)
}
}
return JSONObject().put("schemaVersion", 1).put("segments", segments).toString()
}
private fun fill(id: String, color: String): JSONObject = JSONObject()
.put("id", id)
.put("type", "fill")
.put("source", SOURCE)
.put("paint", JSONObject().put("fill-color", color).put("fill-opacity", 0.55))
}