teecup/frontend/lib/hole-geometry.test.ts

81 lines
3.4 KiB
TypeScript
Raw Permalink Normal View History

import { describe, expect, it } from "vitest"
import { midpoint, projectOntoAxis } from "./hole-geometry"
// Testrigg: en rein nord-sør-akse (tee i sør, green 200 m rett nord) --
// lett å regne fasit for. 111_320 m per breddegrad er samme tilnærming
// som geo.test.ts allerede bruker.
const METERS_PER_DEGREE_LAT = 111_320
const tee = { lat: 59.9, lng: 10.75 }
const green = { lat: 59.9 + 200 / METERS_PER_DEGREE_LAT, lng: 10.75 }
describe("projectOntoAxis", () => {
it("punktet på start (tee) gir alongPercent=0, crossMeters≈0", () => {
const { alongPercent, crossMeters } = projectOntoAxis(tee, green, tee)
expect(alongPercent).toBeCloseTo(0, 3)
expect(crossMeters).toBeCloseTo(0, 3)
})
it("punktet på slutt (green) gir alongPercent=100, crossMeters≈0", () => {
const { alongPercent, crossMeters } = projectOntoAxis(tee, green, green)
expect(alongPercent).toBeCloseTo(100, 0)
expect(crossMeters).toBeCloseTo(0, 1)
})
it("midtpunktet på aksen gir alongPercent≈50, crossMeters≈0", () => {
const mid = midpoint(tee, green)
const { alongPercent, crossMeters } = projectOntoAxis(tee, green, mid)
expect(alongPercent).toBeCloseTo(50, 0)
expect(crossMeters).toBeCloseTo(0, 1)
})
it("et punkt rett øst for midtpunktet gir riktig crossMeters mot høyre", () => {
// Aksen peker rett nord (bearing 0) -- et punkt rett øst for et punkt
// PÅ aksen skal derfor ligge til HØYRE (positiv cross), på samme
// langs-posisjon (alongPercent uendret).
const mid = midpoint(tee, green)
const offsetEast = { lat: mid.lat, lng: mid.lng + 20 / (METERS_PER_DEGREE_LAT * Math.cos((mid.lat * Math.PI) / 180)) }
const { alongPercent, crossMeters } = projectOntoAxis(tee, green, offsetEast)
expect(alongPercent).toBeCloseTo(50, 0)
expect(crossMeters).toBeGreaterThan(19)
expect(crossMeters).toBeLessThan(21)
})
it("et punkt rett vest for midtpunktet gir negativ crossMeters (venstre)", () => {
const mid = midpoint(tee, green)
const offsetWest = { lat: mid.lat, lng: mid.lng - 20 / (METERS_PER_DEGREE_LAT * Math.cos((mid.lat * Math.PI) / 180)) }
const { crossMeters } = projectOntoAxis(tee, green, offsetWest)
expect(crossMeters).toBeLessThan(-19)
expect(crossMeters).toBeGreaterThan(-21)
})
it("et punkt bak tee (før start) gir negativ alongPercent", () => {
const behindTee = { lat: tee.lat - 50 / METERS_PER_DEGREE_LAT, lng: tee.lng }
const { alongPercent } = projectOntoAxis(tee, green, behindTee)
expect(alongPercent).toBeLessThan(0)
})
it("et punkt forbi green gir alongPercent > 100", () => {
const beyondGreen = { lat: green.lat + 50 / METERS_PER_DEGREE_LAT, lng: green.lng }
const { alongPercent } = projectOntoAxis(tee, green, beyondGreen)
expect(alongPercent).toBeGreaterThan(100)
})
it("axisStart == axisEnd degraderer grasiøst (ingen NaN/deling på null)", () => {
const { alongPercent, crossMeters } = projectOntoAxis(tee, tee, green)
expect(Number.isFinite(alongPercent)).toBe(true)
expect(Number.isFinite(crossMeters)).toBe(true)
})
})
describe("midpoint", () => {
it("midtpunktet av et punkt med seg selv er punktet selv", () => {
expect(midpoint(tee, tee)).toEqual(tee)
})
it("midtpunktet ligger halvveis mellom to punkt", () => {
const m = midpoint(tee, green)
expect(m.lat).toBeCloseTo((tee.lat + green.lat) / 2, 10)
expect(m.lng).toBeCloseTo((tee.lng + green.lng) / 2, 10)
})
})