Fikser to ting rapportert fra ekte produksjonsskjermbilde: (1) kun nærmeste hindring ble vist -- target-distance.tsx viser nå ALLE hindringer, sortert nærmest først, uavhengig av om et diagram kan tegnes. (2) Nytt hull-diagram (hole-diagram-view.tsx) plasserer hindringer og spiller i 2D langs en fast tee->green-akse, tee nederst/ green øverst konsistent uansett gangretning. Ny geometri-modul frontend/lib/hole-geometry.ts (projectOntoAxis, bygget på eksisterende haversineMeters/bearingDegrees) med 10 enhetstester som beviser matematikken riktig før noe visuelt ble bygget. Verifisert i scratch mot presist kjente syntetiske koordinater -- alle tall og posisjoner stemte eksakt med håndregnede fasitverdier. Midlertidig hånd-kodet visning, venter på V0-eksport for den polerte versjonen (samme mønster som FlagPlantSheet/PlayerImportPanel). Ingen migrasjon, ingen backend-endring. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
39 lines
1.8 KiB
TypeScript
39 lines
1.8 KiB
TypeScript
import { type LatLng, bearingDegrees, haversineMeters } from "./geo"
|
|
|
|
/**
|
|
* Projiserer et vilkårlig punkt ned på en fast akse (typisk tee->green),
|
|
* for et hull-diagram der "langs hullet" og "til siden" skal vises
|
|
* uavhengig av spillerens gangretning -- ren klientberegning, ingen
|
|
* Mapbox-kall (samme ADR-048-kostnadskontroll-prinsipp som geo.ts).
|
|
*
|
|
* `alongPercent`: 0 ved axisStart, 100 ved axisEnd -- IKKE klippet her
|
|
* (kan bli <0 eller >100 hvis punktet ligger bak start/forbi slutt),
|
|
* klipping skjer kun ved selve visningen.
|
|
* `crossMeters`: avstand til siden av aksen. Positiv = til høyre for
|
|
* aksens retning (sett fra axisStart mot axisEnd), negativ = venstre --
|
|
* samme klokke-positive konvensjon som bearingDegrees.
|
|
*/
|
|
export function projectOntoAxis(
|
|
axisStart: LatLng,
|
|
axisEnd: LatLng,
|
|
point: LatLng,
|
|
): { alongPercent: number; crossMeters: number } {
|
|
const axisLength = haversineMeters(axisStart, axisEnd)
|
|
if (axisLength === 0) {
|
|
return { alongPercent: 0, crossMeters: haversineMeters(axisStart, point) }
|
|
}
|
|
const axisBearing = bearingDegrees(axisStart, axisEnd)
|
|
const pointDistance = haversineMeters(axisStart, point)
|
|
const pointBearing = bearingDegrees(axisStart, point)
|
|
// Normaliser vinkeldifferansen til (-180, 180] før trigonometri.
|
|
const angleDiff = (((pointBearing - axisBearing + 540) % 360) - 180) * (Math.PI / 180)
|
|
const along = pointDistance * Math.cos(angleDiff)
|
|
const cross = pointDistance * Math.sin(angleDiff)
|
|
return { alongPercent: (along / axisLength) * 100, crossMeters: cross }
|
|
}
|
|
|
|
/** Midtpunkt mellom to koordinater (enkel plan-tilnærming -- presist nok
|
|
* på hull-skala, samme antakelse som resten av geo.ts). */
|
|
export function midpoint(a: LatLng, b: LatLng): LatLng {
|
|
return { lat: (a.lat + b.lat) / 2, lng: (a.lng + b.lng) / 2 }
|
|
}
|