@@ -38,6 +38,10 @@ class MainActivity : ComponentActivity(), MessageClient.OnMessageReceivedListene
3838 PREVIEW ,
3939 }
4040
41+ private enum class LiveScenarioModel {
42+ GIBRALTAR_2027_TOTAL ,
43+ }
44+
4145 private data class LiveRenderPayload (
4246 val showMoon : Boolean ,
4347 val moonRadiusNorm : Float ,
@@ -85,6 +89,7 @@ class MainActivity : ComponentActivity(), MessageClient.OnMessageReceivedListene
8589 private var activePreviewSessionId: String? = null
8690 private var previewProgressNorm = 0f
8791 private var debugOverlayEnabled = false
92+ private var activeLiveScenarioModel: LiveScenarioModel ? = null
8893 private var connectedPhoneNodeId: String? = null
8994 private var lastSentPreviewScrubProgressNorm = Float .NaN
9095 private var lastSentPreviewScrubElapsedRealtimeMs = 0L
@@ -379,22 +384,87 @@ class MainActivity : ComponentActivity(), MessageClient.OnMessageReceivedListene
379384 longitudeDeg = location.longitude,
380385 epochMillis = nowMs,
381386 )
382- val localGeometry = LocalSunMoonCalculator .calculateLiveGeometry(
383- latitudeDeg = location.latitude,
384- longitudeDeg = location.longitude,
385- epochMillis = nowMs,
386- )
387- val payload = LiveRenderPayload (
388- showMoon = localGeometry.showMoon,
389- moonRadiusNorm = localGeometry.moonRadiusNorm,
390- moonCenterXNorm = localGeometry.moonCenterXNorm,
391- moonCenterYNorm = localGeometry.moonCenterYNorm,
392- )
387+ val payload = calculateScenarioLivePayload(nowMs) ? : run {
388+ val localGeometry = LocalSunMoonCalculator .calculateLiveGeometry(
389+ latitudeDeg = location.latitude,
390+ longitudeDeg = location.longitude,
391+ epochMillis = nowMs,
392+ )
393+ LiveRenderPayload (
394+ showMoon = localGeometry.showMoon,
395+ moonRadiusNorm = localGeometry.moonRadiusNorm,
396+ moonCenterXNorm = localGeometry.moonCenterXNorm,
397+ moonCenterYNorm = localGeometry.moonCenterYNorm,
398+ )
399+ }
393400 latestLocalLivePayload = payload
394401 renderLivePayload(payload)
395402 clearStatusMessage()
396403 }
397404
405+ private fun calculateScenarioLivePayload (nowMs : Long ): LiveRenderPayload ? {
406+ return when (activeLiveScenarioModel) {
407+ LiveScenarioModel .GIBRALTAR_2027_TOTAL -> {
408+ val eventSpanMs = GIBRALTAR_2027_C4_UTC_MS - GIBRALTAR_2027_C1_UTC_MS
409+ if (eventSpanMs <= 0L ) {
410+ return null
411+ }
412+
413+ val showMoon = nowMs in GIBRALTAR_2027_C1_UTC_MS .. GIBRALTAR_2027_C4_UTC_MS
414+ if (! showMoon) {
415+ return LiveRenderPayload (
416+ showMoon = false ,
417+ moonRadiusNorm = 0f ,
418+ moonCenterXNorm = 0.5f ,
419+ moonCenterYNorm = 0.5f ,
420+ )
421+ }
422+
423+ val progressNorm = ((nowMs - GIBRALTAR_2027_C1_UTC_MS ).toDouble() / eventSpanMs.toDouble())
424+ .coerceIn(0.0 , 1.0 )
425+ .toFloat()
426+ val c2ProgressNorm = ((GIBRALTAR_2027_C2_UTC_MS - GIBRALTAR_2027_C1_UTC_MS ).toDouble() / eventSpanMs.toDouble())
427+ .coerceIn(0.0 , 1.0 )
428+ .toFloat()
429+ val maxProgressNorm = ((GIBRALTAR_2027_MAX_UTC_MS - GIBRALTAR_2027_C1_UTC_MS ).toDouble() / eventSpanMs.toDouble())
430+ .coerceIn(0.0 , 1.0 )
431+ .toFloat()
432+ val c3ProgressNorm = ((GIBRALTAR_2027_C3_UTC_MS - GIBRALTAR_2027_C1_UTC_MS ).toDouble() / eventSpanMs.toDouble())
433+ .coerceIn(0.0 , 1.0 )
434+ .toFloat()
435+
436+ val moonRadiusNorm = GIBRALTAR_2027_TOTAL_MOON_RADIUS_NORM
437+ val moonClosestOffsetNorm = 0f
438+ val externalTouchAxisOffsetNorm = GIBRALTAR_2027_SUN_RADIUS_NORM + moonRadiusNorm
439+ val internalTouchAxisOffsetNorm = abs(GIBRALTAR_2027_SUN_RADIUS_NORM - moonRadiusNorm)
440+ val anchors = listOf (
441+ MotionAnchor (0f , - externalTouchAxisOffsetNorm),
442+ MotionAnchor (c2ProgressNorm, - internalTouchAxisOffsetNorm),
443+ MotionAnchor (maxProgressNorm, 0f ),
444+ MotionAnchor (c3ProgressNorm, internalTouchAxisOffsetNorm),
445+ MotionAnchor (1f , externalTouchAxisOffsetNorm),
446+ ).sortedBy { it.progressNorm }
447+
448+ val axisOffsetNorm = interpolatePreviewAxisOffset(progressNorm, anchors)
449+ val moonOffsetXNorm =
450+ axisOffsetNorm * GIBRALTAR_2027_TRAVEL_VECTOR_X_NORM - moonClosestOffsetNorm * GIBRALTAR_2027_TRAVEL_VECTOR_Y_NORM
451+ val moonOffsetYNorm =
452+ axisOffsetNorm * GIBRALTAR_2027_TRAVEL_VECTOR_Y_NORM + moonClosestOffsetNorm * GIBRALTAR_2027_TRAVEL_VECTOR_X_NORM
453+ val moonCenterXNorm = (0.5f + moonOffsetXNorm).coerceIn(0f , 1f )
454+ val moonCenterYNorm = (0.5f + moonOffsetYNorm).coerceIn(0f , 1f )
455+
456+ LiveRenderPayload (
457+ showMoon = true ,
458+ moonRadiusNorm = moonRadiusNorm,
459+ moonCenterXNorm = moonCenterXNorm,
460+ moonCenterYNorm = moonCenterYNorm,
461+ )
462+ }
463+
464+ null -> null
465+ }
466+ }
467+
398468 private fun renderLivePayload (payload : LiveRenderPayload ) {
399469 if (renderMode != RenderMode .LIVE ) {
400470 logInfo(
@@ -869,9 +939,12 @@ class MainActivity : ComponentActivity(), MessageClient.OnMessageReceivedListene
869939 val data = sourceIntent?.data
870940 if (data == null || ! data.scheme.equals(DEEP_LINK_SCHEME , ignoreCase = true )) {
871941 activeDeepLinkLabel = null
942+ activeLiveScenarioModel = null
872943 return
873944 }
874945
946+ activeLiveScenarioModel = parseLiveScenarioModel(data)
947+
875948 parseDebugOverlayEnabled(data)?.let { enabled ->
876949 setDebugOverlayEnabled(
877950 enabled = enabled,
@@ -883,6 +956,17 @@ class MainActivity : ComponentActivity(), MessageClient.OnMessageReceivedListene
883956 activeDeepLinkLabel = label
884957 }
885958
959+ private fun parseLiveScenarioModel (uri : Uri ): LiveScenarioModel ? {
960+ val scenario = uri.getQueryParameter(" scenario" )?.trim()?.lowercase()
961+ return when (scenario) {
962+ " gibraltar-between-c1-c3" ,
963+ " gibraltar-max" ,
964+ -> LiveScenarioModel .GIBRALTAR_2027_TOTAL
965+
966+ else -> null
967+ }
968+ }
969+
886970 private fun setDebugOverlayEnabled (
887971 enabled : Boolean ,
888972 source : String ,
@@ -969,5 +1053,16 @@ class MainActivity : ComponentActivity(), MessageClient.OnMessageReceivedListene
9691053 private const val PREVIEW_ROTARY_SENSITIVITY = 0.025f
9701054 private const val PREVIEW_SCRUB_MIN_SEND_INTERVAL_MS = 25L
9711055 private const val PREVIEW_PROGRESS_EPSILON = 0.001f
1056+
1057+ // Canonical 2027 Gibraltar total-eclipse profile sourced from the shared engine output.
1058+ private const val GIBRALTAR_2027_SUN_RADIUS_NORM = 0.24f
1059+ private const val GIBRALTAR_2027_TOTAL_MOON_RADIUS_NORM = 0.25333333f
1060+ private const val GIBRALTAR_2027_TRAVEL_VECTOR_X_NORM = - 0.13866234f
1061+ private const val GIBRALTAR_2027_TRAVEL_VECTOR_Y_NORM = 0.9903397f
1062+ private val GIBRALTAR_2027_C1_UTC_MS : Long = Instant .parse(" 2027-08-02T07:41:13.164Z" ).toEpochMilli()
1063+ private val GIBRALTAR_2027_C2_UTC_MS : Long = Instant .parse(" 2027-08-02T08:45:48.130Z" ).toEpochMilli()
1064+ private val GIBRALTAR_2027_MAX_UTC_MS : Long = Instant .parse(" 2027-08-02T08:48:00.130Z" ).toEpochMilli()
1065+ private val GIBRALTAR_2027_C3_UTC_MS : Long = Instant .parse(" 2027-08-02T08:50:18.022Z" ).toEpochMilli()
1066+ private val GIBRALTAR_2027_C4_UTC_MS : Long = Instant .parse(" 2027-08-02T10:01:33.400Z" ).toEpochMilli()
9721067 }
9731068}
0 commit comments