import { lonLatToWorldTile } from '../../utils/projection' import { worldToScreen, type CameraState } from '../camera/camera' import { type MapLayer, type LayerRenderContext } from './mapLayer' import { type MapScene } from '../renderer/mapRenderer' import { type ScreenPoint } from './trackLayer' import { type OrienteeringCourseControl, type OrienteeringCourseFinish, type OrienteeringCourseLeg, type OrienteeringCourseStart, } from '../../utils/orienteeringCourse' export interface ProjectedCourseLeg { fromKind: OrienteeringCourseLeg['fromKind'] toKind: OrienteeringCourseLeg['toKind'] from: ScreenPoint to: ScreenPoint } export interface ProjectedCourseStart { label: string point: ScreenPoint headingDeg: number | null } export interface ProjectedCourseControl { label: string sequence: number point: ScreenPoint } export interface ProjectedCourseFinish { label: string point: ScreenPoint } export interface ProjectedCourseLayers { starts: ProjectedCourseStart[] controls: ProjectedCourseControl[] finishes: ProjectedCourseFinish[] legs: ProjectedCourseLeg[] } function buildVectorCamera(scene: MapScene): CameraState { return { centerWorldX: scene.exactCenterWorldX, centerWorldY: scene.exactCenterWorldY, viewportWidth: scene.viewportWidth, viewportHeight: scene.viewportHeight, visibleColumns: scene.visibleColumns, rotationRad: scene.rotationRad, } } export class CourseLayer implements MapLayer { projectPoint(point: { point: { lon: number; lat: number } }, scene: MapScene, camera: CameraState): ScreenPoint { const worldPoint = lonLatToWorldTile(point.point, scene.zoom) return worldToScreen(camera, worldPoint, false) } projectStarts(starts: OrienteeringCourseStart[], scene: MapScene, camera: CameraState): ProjectedCourseStart[] { return starts.map((start) => ({ label: start.label, point: this.projectPoint(start, scene, camera), headingDeg: start.headingDeg, })) } projectControls(controls: OrienteeringCourseControl[], scene: MapScene, camera: CameraState): ProjectedCourseControl[] { return controls.map((control) => ({ label: control.label, sequence: control.sequence, point: this.projectPoint(control, scene, camera), })) } projectFinishes(finishes: OrienteeringCourseFinish[], scene: MapScene, camera: CameraState): ProjectedCourseFinish[] { return finishes.map((finish) => ({ label: finish.label, point: this.projectPoint(finish, scene, camera), })) } projectLegs(legs: OrienteeringCourseLeg[], scene: MapScene, camera: CameraState): ProjectedCourseLeg[] { return legs.map((leg) => ({ fromKind: leg.fromKind, toKind: leg.toKind, from: worldToScreen(camera, lonLatToWorldTile(leg.fromPoint, scene.zoom), false), to: worldToScreen(camera, lonLatToWorldTile(leg.toPoint, scene.zoom), false), })) } projectCourse(scene: MapScene): ProjectedCourseLayers | null { const course = scene.course if (!course) { return null } const camera = buildVectorCamera(scene) return { starts: this.projectStarts(course.layers.starts, scene, camera), controls: this.projectControls(course.layers.controls, scene, camera), finishes: this.projectFinishes(course.layers.finishes, scene, camera), legs: this.projectLegs(course.layers.legs, scene, camera), } } draw(_context: LayerRenderContext): void {} }