1. WHS Rule 3.1b — ferdig, testet (117/117), rullet ut... nei, venter fortsatt (se under). 2. round.tee_name_snapshot-synk — ferdig, scratch-verifisert. 3. Optimistisk versjonssjekk for samtidig hull-redigering — ferdig bygget, og jeg fant og rettet en reell UX-bug underveis (en fullskjerm-feilvisning i stedet for en liten banner) som ellers ville gjort funksjonen verre enn ingenting. Alt er dokumentert i ADR-056/057 og CHANGELOG punkt 65–66. Deploy — rekkefølgen har betydning (migrasjonen må kjøre først, siden ny kode leser version-kolonnen): # 1. Migrasjon mot ekte teecup_db docker exec teeoff_db psql -U teeoff_admin -d teecup_db -f /opt/teecup/062_round_hole_version.sql # 2. Backend docker compose build teecup_api docker compose up -d teecup_api # 3. Frontend docker compose build teecup_frontend docker compose up -d teecup_frontend Og fortsatt uavklart fra tidligere: datakorreksjonen for din spesifikke runde UPDATE round SET tee_name_snapshot = '55' WHERE id = '520f9681-6e7f-49bf-8504-9ab223874285';
33 lines
1.3 KiB
TypeScript
33 lines
1.3 KiB
TypeScript
export type LatLng = { lat: number; lng: number }
|
|
|
|
/**
|
|
* Storsirkel-avstand mellom to koordinater, i meter. Ren klient-side
|
|
* beregning -- ingen Mapbox-kall (ADR-048 kostnadskontroll-invariant B).
|
|
*/
|
|
export function haversineMeters(a: LatLng, b: LatLng): number {
|
|
const R = 6371000
|
|
const toRad = (d: number) => (d * Math.PI) / 180
|
|
const dLat = toRad(b.lat - a.lat)
|
|
const dLng = toRad(b.lng - a.lng)
|
|
const h =
|
|
Math.sin(dLat / 2) ** 2 +
|
|
Math.cos(toRad(a.lat)) * Math.cos(toRad(b.lat)) * Math.sin(dLng / 2) ** 2
|
|
return 2 * R * Math.asin(Math.sqrt(h))
|
|
}
|
|
|
|
/**
|
|
* Retningsvinkel (kompassgrader, 0-360, 0 = nord) fra a til b. Brukes til å
|
|
* rotere slagmålings-kartet slik at "opp på skjermen" følger spillerens
|
|
* egen gangretning på hullet, uten å trenge lagrede green-koordinater --
|
|
* se bearingForShotMap() i shot-measurement-sheet.tsx.
|
|
*/
|
|
export function bearingDegrees(a: LatLng, b: LatLng): number {
|
|
const toRad = (d: number) => (d * Math.PI) / 180
|
|
const toDeg = (r: number) => (r * 180) / Math.PI
|
|
const lat1 = toRad(a.lat)
|
|
const lat2 = toRad(b.lat)
|
|
const dLng = toRad(b.lng - a.lng)
|
|
const y = Math.sin(dLng) * Math.cos(lat2)
|
|
const x = Math.cos(lat1) * Math.sin(lat2) - Math.sin(lat1) * Math.cos(lat2) * Math.cos(dLng)
|
|
return (toDeg(Math.atan2(y, x)) + 360) % 360
|
|
}
|