import { Vector2Like } from "@here/harp-geoutils" ; import { assert } from "@here/harp-utils" ; import * as THREE from "three" ; import { MAX_FOV_RAD , MIN_FOV_RAD } from "./FovCalculation" ; function isCenteredProjection ( principalPoint ) { return principalPoint . x === 0 && principalPoint . y === 0 ; } param focalLength param ppOffset param viewportSide returns function computePosSideFov ( focalLength , ppOffset , viewportSide ) { assert ( focalLength > 0 , "Focal length must be larger than 0" ) ; return Math . atan ( ( ( 1 - ppOffset ) * viewportSide * 0.5 ) / focalLength ) ; } param focalLength param ppOffset param viewportSide returns function computeFov ( focalLength , ppOffset , viewportSide ) { assert ( focalLength > 0 , "Focal length must be larger than 0" ) ; return ppOffset === 0 ? 2 * Math . atan ( ( 0.5 * viewportSide ) / focalLength ) : computePosSideFov ( focalLength , ppOffset , viewportSide ) + computePosSideFov ( focalLength , - ppOffset , viewportSide ) ; } /**
 * For off-center projections, fovs are asymmetric. In that case, the camera saves some of the side
 * fovs to save some computations. All values are in radians.
 */ interface Fovs { top : number ; right : number ; horizontal : number ; } function getFovs ( camera ) { return camera . userData . fovs ; } /**
 * Saves camera vertical fov and focal length. For off-center projections, saves side fovs as well.
 */ function setCameraParams ( camera , ppalPoint , focalLength , viewportHeight , verticalFov ) { const viewportWidth = viewportHeight * camera . aspect ; let hFov = computeFov ( focalLength , ppalPoint . x , viewportWidth ) ; if ( hFov < MIN_FOV_RAD || hFov > MAX_FOV_RAD ) { hFov = THREE . MathUtils . clamp ( hFov , MIN_FOV_RAD , MAX_FOV_RAD ) ; const focalLength = computeFocalLengthFromFov ( hFov , viewportWidth , ppalPoint . x ) ; verticalFov = computeFov ( focalLength , ppalPoint . y , viewportHeight ) ; } camera . fov = THREE . MathUtils . radToDeg ( verticalFov ) ; if ( isCenteredProjection ( ppalPoint ) ) { delete camera . userData . fovs ; } else { const width = viewportHeight * camera . aspect ; camera . userData . fovs = { top : computePosSideFov ( focalLength , ppalPoint . y , viewportHeight ) , right : computePosSideFov ( focalLength , ppalPoint . x , width ) , horizontal : hFov } as Fovs ; } camera . userData . focalLength = focalLength ; } beta param fov param viewportSide param ppOffset returns function computeFocalLengthFromFov ( fov , viewportSide , ppOffset ) { const halfSide = viewportSide / 2 ; const ppCentered = ppOffset === 0 ; if ( ppCentered ) { return halfSide / Math . tan ( fov / 2 ) ; } const eps = 1e-6 ; const ppOffsetSq = ppOffset ** 2 ; if ( Math . abs ( fov - Math . PI / 2 ) < eps ) { return halfSide * Math . sqrt ( 1 - ppOffsetSq ) ; } const tanFov = Math . tan ( fov ) ; const sign = Math . sign ( tanFov ) ; const sqrt = Math . sqrt ( 1 + tanFov ** 2 * ( 1 - ppOffsetSq ) ) ; const f = ( halfSide * ( 1 + sign * sqrt ) ) / tanFov ; assert ( f >= 0 , "Focal length must be larger than 0" ) ; return f ; } export namespace CameraUtils { beta param camera returns export function getFocalLength ( camera ) { return camera . userData ?. focalLength ; } remarks beta param camera param focalLength param viewportHeight returns export function setFocalLength ( camera , focalLength , viewportHeight ) { const ppalPoint = getPrincipalPoint ( camera ) ; const vFov = computeFov ( focalLength , ppalPoint . y , viewportHeight ) ; if ( vFov < MIN_FOV_RAD || vFov > MAX_FOV_RAD ) { setVerticalFov ( camera , vFov , viewportHeight ) ; } else { setCameraParams ( camera , ppalPoint , focalLength , viewportHeight , vFov ) ; } return getFocalLength ( camera ) ! ; } param camera returns export function getVerticalFov ( camera ) { return THREE . MathUtils . degToRad ( camera . fov ) ; } remarks beta param camera param verticalFov - Vertical field of view in radians. It'll be clamped to
     *                      [ MIN_FOV_RAD ,  MAX_FOV_RAD ].
     *  param viewportHeight returns export function setVerticalFov ( camera , verticalFov , viewportHeight ) { verticalFov = THREE . MathUtils . clamp ( verticalFov , MIN_FOV_RAD , MAX_FOV_RAD ) ; const ppalPoint = getPrincipalPoint ( camera ) ; const focalLength = computeFocalLengthFromFov ( verticalFov , viewportHeight , ppalPoint . y ) ; setCameraParams ( camera , ppalPoint , focalLength , viewportHeight , verticalFov ) ; return getVerticalFov ( camera ) ; } beta param focalLength - Focal length in pixels (see  setVerticalFov )
     *  param distance param worldSize return export function convertWorldToScreenSize ( focalLength , distance , worldSize ) { return ( focalLength * worldSize ) / distance ; } beta param focalLength - Focal length in pixels (see  setVerticalFov )
     *  param distance param screenSize return export function convertScreenToWorldSize ( focalLength , distance , screenSize ) { return ( distance * screenSize ) / focalLength ; } beta see https remarks param camera param result returns export function getPrincipalPoint ( camera , result = new THREE . Vector2 ( ) ) { result . x = - camera . projectionMatrix . elements [ 8 ] ; result . y = - camera . projectionMatrix . elements [ 9 ] ; return result ; } beta see getPrincipalPoint param camera param ndcCoords export function setPrincipalPoint ( camera , ndcCoords ) { const height = 1 ; const width = camera . aspect ; const maxNdcCoord = 1 - 1e-6 ; camera . setViewOffset ( width , height , ( - THREE . MathUtils . clamp ( ndcCoords . x , - maxNdcCoord , maxNdcCoord ) * width ) / 2 , ( THREE . MathUtils . clamp ( ndcCoords . y , - maxNdcCoord , maxNdcCoord ) * height ) / 2 , width , height ) ; } param camera returns export function getHorizontalFov ( camera ) { return ( getFovs ( camera ) ?. horizontal ?? 2 * Math . atan ( Math . tan ( THREE . MathUtils . degToRad ( camera . fov ) / 2 ) * camera . aspect ) ) ; } beta remarks param camera returns export function getTopFov ( camera ) { return getFovs ( camera ) ?. top ?? THREE . MathUtils . degToRad ( camera . fov / 2 ) ; } see CameraUtils . getTopFov beta param camera returns export function getBottomFov ( camera ) { return THREE . MathUtils . degToRad ( camera . fov ) - getTopFov ( camera ) ; } see CameraUtils . getTopFov beta param camera returns export function getRightFov ( camera ) { return getFovs ( camera ) ?. right ?? getHorizontalFov ( camera ) / 2 ; } see CameraUtils . getTopFov beta param camera returns export function getLeftFov ( camera ) { return getFovs ( camera ) ?. right !== undefined ? getHorizontalFov ( camera ) - getRightFov ( camera ) : getHorizontalFov ( camera ) / 2 ; } }