import { mat4 , vec2 , vec3 } from 'gl-matrix' ; import { abs2 , abs3 , sign , v2 , v3 } from './gl-matrix-extensions' ; import { DEG2RAD } from './auxiliaries' ; import { Camera } from './camera' ; namespace ray_math { /**
     * Lots of variables that represent components of other variables or are transformed.
     * For these I (dl) prefer, e.g.,  _component or _transformation notation
     */ param ray0 param ray1 param radius returns export function rayCircleIntersection ( ray0 , ray1 , radius = 1.0 ) { const ray_direction = vec2 . subtract ( v2 ( ) , ray1 , ray0 ) ; if ( vec2 . equals ( ray_direction , vec2 . fromValues ( 0.0 , 0.0 ) ) ) { return undefined ; } /**
         * This is a default ray circle intersection with common variable names. It's math and math sometimes has no
         * meaning full variable names... (we could use twoTimesDotProductOfRayAndOrigin instead of b, but this is
         * obviously not a good idea :D).
         */ const a = vec2 . squaredLength ( ray_direction ) ; const b = 2.0 * vec2 . dot ( ray_direction , ray0 ) ; const c = vec2 . squaredLength ( ray0 ) - radius * radius ; const delta = b * b - 4.0 * a * c ; if ( delta < 0.0 ) { return undefined ; } const s = Math . sqrt ( delta ) ; const t = Math . min ( ( - b + s ) / ( 2.0 * a ) , ( - b - s ) / ( 2.0 * a ) ) ; const intersection = vec2 . scale ( v2 ( ) , ray_direction , t ) ; return vec2 . add ( intersection , intersection , ray0 ) ; } param point param edgeLength returns export function pointSquareIntersection ( point , edgeLength = 1.0 ) { const a = abs2 ( v2 ( ) , point ) ; if ( a [ 0 ] >= a [ 1 ] ) { return vec2 . fromValues ( sign ( point [ 0 ] ) * edgeLength , point [ 1 ] / a [ 0 ] * edgeLength ) ; } return vec2 . fromValues ( point [ 0 ] / a [ 1 ] * edgeLength , sign ( point [ 1 ] ) * edgeLength ) ; } param ray0 param ray1 returns export function raySquareIntersection ( ray0 , ray1 , halfLength = 1.0 ) { const vertices = [ vec2 . fromValues ( - halfLength , + halfLength ) , vec2 . fromValues ( - halfLength , - halfLength ) , vec2 . fromValues ( + halfLength , - halfLength ) , vec2 . fromValues ( + halfLength , + halfLength ) ] ; const intersections = new Array < number > ( ) ; for ( let i = 0 ; i < 4 ; ++ i ) { const intersection = rayLineIntersection ( ray0 , ray1 , vertices [ i ] , vertices [ ( i + 1 ) % 4 ] ) ; if ( intersection ) { intersections . push ( intersection [ 1 ] ) ; } } return intersections ; } param ray0 param ray1 param line0 param line1 returns export function rayLineIntersection ( ray0 , ray1 , line0 , line1 ) { const p = ray0 ; const r = vec2 . sub ( v2 ( ) , ray1 , ray0 ) ; const q = line0 ; const s = vec2 . sub ( v2 ( ) , line1 , line0 ) ; const cross_rs = vec2 . cross ( v3 ( ) , r , s ) [ 2 ] ; if ( cross_rs === 0.0 ) { return undefined ; } const qp = vec2 . sub ( v2 ( ) , q , p ) ; const u = vec2 . cross ( v3 ( ) , qp , vec2 . scale ( v2 ( ) , r , 1.0 / cross_rs ) ) [ 2 ] ; const t = vec2 . cross ( v3 ( ) , qp , vec2 . scale ( v2 ( ) , s , 1.0 / cross_rs ) ) [ 2 ] ; if ( u < 0.0 || u > 1.0 || t < 0.0 ) { return undefined ; } return [ vec2 . add ( v2 ( ) , q , vec2 . scale ( v2 ( ) , s , u ) ) , t ] ; } param ray0 param ray1 param origin param normal returns export function rayPlaneIntersection ( ray0 , ray1 , origin = vec3 . fromValues ( 0.0 , 0.0 , 0.0 ) , normal = vec3 . fromValues ( 0.0 , 1.0 , 0.0 ) ) { const ray_direction = vec3 . normalize ( v3 ( ) , vec3 . subtract ( v3 ( ) , ray1 , ray0 ) ) ; const rdDotN = vec3 . dot ( ray_direction , normal ) ; if ( vec3 . equals ( ray_direction , [ 0 , 0 , 0 ] ) || rdDotN >= 0.0 ) { return undefined ; } const t = vec3 . dot ( vec3 . subtract ( v3 ( ) , origin , ray0 ) , normal ) / rdDotN ; return vec3 . add ( v3 ( ) , vec3 . scale ( v3 ( ) , ray_direction , t ) , ray0 ) ; } param ray0 param ray1 param origin param radius returns export function raySphereIntersection ( ray0 , ray1 , origin = vec3 . fromValues ( 0.0 , 0.0 , 0.0 ) , radius = 1.0 ) { const rayOriginToSphereCenter = vec3 . subtract ( v3 ( ) , ray0 , origin ) ; const ray_direction = vec3 . normalize ( v3 ( ) , vec3 . subtract ( v3 ( ) , ray1 , ray0 ) ) ; const dot_term = vec3 . dot ( ray_direction , rayOriginToSphereCenter ) ; const t = dot_term * dot_term - vec3 . squaredLength ( rayOriginToSphereCenter ) + radius * radius ; if ( t <= 0.0 ) { return undefined ; } return vec3 . add ( v3 ( ) , ray0 , vec3 . scale ( v3 ( ) , ray_direction , - dot_term - Math . sqrt ( t ) ) ) ; } param ray0 param ray1 param radius returns export function rayPlaneIntersection_tube ( ray0 , ray1 , radius = 1.0 ) { const intersection = rayPlaneIntersection ( ray0 , ray1 ) ; if ( intersection !== undefined && vec3 . length ( intersection ) < radius ) { return intersection ; } const ray0_xz = vec2 . fromValues ( ray0 [ 0 ] , ray0 [ 2 ] ) ; const ray1_xz = vec2 . fromValues ( ray1 [ 0 ] , ray1 [ 2 ] ) ; const intersection2 = rayCircleIntersection ( ray0_xz , ray1_xz , radius ) ; return intersection2 ? vec3 . fromValues ( intersection2 [ 0 ] , 0.0 , intersection2 [ 1 ] ) : undefined ; } param point param halfLength returns export function isPointWithinSquare ( point , halfLength = 1.0 ) { const p_abs = abs2 ( v2 ( ) , point ) ; return p_abs [ 0 ] <= halfLength && p_abs [ 1 ] <= halfLength ; } param viewProjection param point returns export function isPointWithinNDC ( viewProjection , point ) { const p_transformed = vec3 . transformMat4 ( v3 ( ) , point , viewProjection ) ; const p_abs = abs3 ( v3 ( ) , p_transformed ) ; return p_abs [ 0 ] <= 1.0 && p_abs [ 1 ] <= 1.0 && p_transformed [ 2 ] >= 0.0 && p_transformed [ 2 ] <= 1.0 ; } param ray0 param ray1 param point returns export function distancePointToRay ( ray0 , ray1 , point ) { const ray_direction = vec3 . subtract ( v3 ( ) , ray1 , ray0 ) ; const ray_length = vec3 . squaredLength ( ray_direction ) ; if ( ray_length === 0.0 ) { return 0.0 ; } const eyeToPoint = vec3 . subtract ( v3 ( ) , point , ray0 ) ; const theta = vec3 . dot ( eyeToPoint , ray_direction ) ; return theta / ray_length ; } param camera param point returns export function eyeWithPointInView ( camera , point ) { const ray_direction = vec3 . subtract ( v3 ( ) , camera . center , camera . eye ) ; const ray_normalized = vec3 . normalize ( v3 ( ) , ray_direction ) ; const ortho_v = vec3 . normalize ( v3 ( ) , vec3 . cross ( v3 ( ) , ray_normalized , camera . up ) ) ; const ortho_u = vec3 . normalize ( v3 ( ) , vec3 . cross ( v3 ( ) , ortho_v , ray_normalized ) ) ; const distance = distancePointToRay ( camera . eye , camera . center , point ) ; const closest = vec3 . add ( v3 ( ) , camera . eye , vec3 . scale ( v3 ( ) , ray_direction , distance ) ) ; const t = vec3 . subtract ( v3 ( ) , point , closest ) ; const part_v = Math . abs ( vec3 . dot ( t , ortho_v ) ) / camera . aspect ; const part_u = Math . abs ( vec3 . dot ( t , ortho_u ) ) ; const part_max = Math . max ( part_v , part_u ) ; const a = part_max / Math . tan ( camera . fovy * DEG2RAD * 0.5 ) ; return vec3 . subtract ( v3 ( ) , closest , vec3 . scale ( v3 ( ) , ray_normalized , a ) ) ; } } export = ray_math ;