diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b140ab..e09a35a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [1.1.36] — 2026-02-26 + +### Fixed +- Corrected `Photography Guide` landscape composite rendering so moon occlusion aligns with shot schedule previews for eclipse phases. + +### Changed +- Bumped `apps/mobile` version to `1.1.36`. + ## [1.1.35] — 2026-02-26 ### Fixed diff --git a/apps/mobile/package.json b/apps/mobile/package.json index cb5fb70..e9d52d8 100644 --- a/apps/mobile/package.json +++ b/apps/mobile/package.json @@ -1,6 +1,6 @@ { "name": "@eclipse-timer/mobile", - "version": "1.1.35", + "version": "1.1.36", "private": true, "main": "index.js", "scripts": { diff --git a/apps/mobile/src/utils/photographyGuide.ts b/apps/mobile/src/utils/photographyGuide.ts index 8362a0e..aaf3a7e 100644 --- a/apps/mobile/src/utils/photographyGuide.ts +++ b/apps/mobile/src/utils/photographyGuide.ts @@ -473,6 +473,7 @@ export function buildLandscapeCompositeLayout( frameWidth, frameHeight, ); + const travelVector = normalizeTravelVector(input.travelVector); const rawHorizonY = anchorY + (maxSunAltitudeDeg / LANDSCAPE_VERTICAL_FOV_DEG_24MM) * frameHeight; const horizonY = clampRange(rawHorizonY, 0, frameHeight); @@ -497,8 +498,6 @@ export function buildLandscapeCompositeLayout( const rawY = anchorY - (altitudeDeltaDeg / LANDSCAPE_VERTICAL_FOV_DEG_24MM) * frameHeight; const clampedX = clampRange(rawX, minX, maxX); const clampedY = clampRange(rawY, minY, maxY); - const clampedDeltaX = clampedX - rawX; - const clampedDeltaY = clampedY - rawY; const clamped = Math.abs(clampedX - rawX) > 0.01 || Math.abs(clampedY - rawY) > 0.01; let moon: @@ -509,30 +508,23 @@ export function buildLandscapeCompositeLayout( } | undefined; if (row.showMoon) { - const moonRadius = bodyAngularRadiusDegToPixels( - sample.moon.angularRadiusDeg, - frameWidth, - frameHeight, - ); - const moonAzimuthDeltaDeg = normalizeSignedDeltaDeg(maxSunAzimuthDeg, sample.moon.azimuthDeg); - const moonAltitudeDeltaDeg = sample.moon.altitudeDeg - maxSunAltitudeDeg; - const moonX = - anchorX + - (moonAzimuthDeltaDeg / LANDSCAPE_HORIZONTAL_FOV_DEG_24MM) * frameWidth + - clampedDeltaX; - const moonY = - anchorY - - (moonAltitudeDeltaDeg / LANDSCAPE_VERTICAL_FOV_DEG_24MM) * frameHeight + - clampedDeltaY; - const centerDistance = Math.hypot(moonX - clampedX, moonY - clampedY); - const isOccluding = centerDistance <= sunRadius + moonRadius + 0.25; - if (isOccluding) { - moon = { - x: moonX, - y: moonY, - radius: moonRadius, - }; - } + const moonGeometryStageSize = Math.max(64, sunRadius * LANDSCAPE_MOON_GEOMETRY_STAGE_FACTOR); + const moonGeometry = calculatePreviewMoonGeometry({ + progress: row.progress, + kindAtLocation: input.kindAtLocation, + magnitude: input.magnitude, + contacts: input.schedule.contacts, + stageSize: moonGeometryStageSize, + sunRadius, + travelVector, + }); + const moonOffsetX = moonGeometry.moonCenterX - moonGeometryStageSize / 2; + const moonOffsetY = moonGeometry.moonCenterY - moonGeometryStageSize / 2; + moon = { + x: clampedX + moonOffsetX, + y: clampedY + moonOffsetY, + radius: moonGeometry.moonRadius, + }; } return { diff --git a/apps/mobile/tests/photography-guide.test.ts b/apps/mobile/tests/photography-guide.test.ts index 0b74506..aeac30d 100644 --- a/apps/mobile/tests/photography-guide.test.ts +++ b/apps/mobile/tests/photography-guide.test.ts @@ -257,6 +257,14 @@ describe("photography guide schedule", () => { expect(placement.sunRadius).toBeLessThan(4); expect(placement.sunRadius).toBeGreaterThan(1); expect(placement.y + placement.sunRadius).toBeLessThanOrEqual(layout.horizonY); + expect(placement.showMoon).toBe(true); + expect(placement.moon).toBeDefined(); + if (!placement.moon) continue; + const centerDistance = Math.hypot( + placement.moon.x - placement.x, + placement.moon.y - placement.y, + ); + expect(centerDistance).toBeLessThan(placement.sunRadius * 2.5); } }); });