import has from 'lodash/has' ; import each from 'lodash/each' ; import clamp from 'lodash/clamp' ; import isArray from 'lodash/isArray' ; import every from 'lodash/every' ; export function radiansToDegrees ( value ) { return value * 180 / Math . PI ; } ; export function degreesToRadians ( value ) { return value * Math . PI / 180 ; } ; /** Checks whether an object conforms to the GeometricalPoint interface */ export function isGeoPoint ( object ) { return has ( object , 'x' ) && has ( object , 'y' ) ; } ; /** Checks whether an object conforms to the GeometricalVector interface */ export function isGeoVector ( object ) { return has ( object , 'x2' ) && has ( object , 'y1' ) && has ( object , 'x2' ) && has ( object , 'y2' ) ; } ; /** Checks whether an object conforms to the GeometricalVector interface */ export function isGeoAngle ( object ) { return has ( object , 'vectors' ) && object . vectors . length === 2 && each ( object . vectors , isGeoVector ) ; } ; export function isSingleGeoObject ( object ) { return isGeoPoint ( object ) || isGeoVector ( object ) || isGeoAngle ( object ) ; } ; export function isCompositeGeoObject ( object ) { return isArray ( object ) && every ( object , isSingleGeoObject ) ; } ; export function isGeoObject ( object ) { return isSingleGeoObject ( object ) || isCompositeGeoObject ( object ) ; } ; export function isBehind ( point , line ) { return ( ( line . x2 - line . x1 ) * ( point . y - line . y1 ) - ( line . y2 - line . y1 ) * ( point . x - line . x1 ) ) > 0 ; } ; export function getSegmentLength ( { x1 , x2 , y1 , y2 } ) { return ( x2 - x1 ) ** 2 + ( y2 - y1 ) ** 2 ; } ; return { number } see https export function calculateDistanceBetweenTwoPoints ( A , B ) { return Math . sqrt ( Math . pow ( B . x - A . x , 2 ) + Math . pow ( B . y - A . y , 2 ) ) ; } ; return { number } see https see https export function calculateAngleBetweenPoints ( A , B , C ) { const AB = calculateDistanceBetweenTwoPoints ( A , B ) ; const BC = calculateDistanceBetweenTwoPoints ( B , C ) ; const AC = calculateDistanceBetweenTwoPoints ( A , C ) ; return Math . acos ( ( BC * BC + AB * AB - AC * AC ) / ( 2 * BC * AB ) ) ; } ; return { number } see https see https see https see http export function calculateAngleBetweenTwoVectors ( line1 , line2 ) { const { x1 , x2 , y1 , y2 } = line1 ; const { x1 : x3 , x2 : x4 , y1 : y3 , y2 : y4 } = line2 ; const dx1 = x2 - x1 ; const dy1 = y2 - y1 ; const dx2 = x4 - x3 ; const dy2 = y4 - y3 ; const d = dx1 * dx2 + dy1 * dy2 ; const l2 = ( dx1 ** 2 + dy1 ** 2 ) * ( dx2 ** 2 + dy2 ** 2 ) ; return Math . acos ( d / Math . sqrt ( l2 ) ) ; } ; export function calculateAngle ( { vectors : [ v1 , v2 ] } ) { return calculateAngleBetweenTwoVectors ( v1 , v2 ) ; } /** Rotate a point in a 2-D plane given an origin and an angle */ export function rotatePointAroundOrigin ( /**
 * The central point (the origin around which the second point will be rotated)
 */ { x : cx , y : cy } , { x , y } , angleInRadians ) { const cos = Math . cos ( angleInRadians ) ; const sin = Math . sin ( angleInRadians ) ; const nx = ( cos * ( x - cx ) ) + ( sin * ( y - cy ) ) + cx ; const ny = ( cos * ( y - cy ) ) - ( sin * ( x - cx ) ) + cy ; return { x : nx , y : ny } ; } export interface Rect { top : number ; left : number ; bottom : number ; right : number ; } export const isPointWithinRect = ( { x , y } , { top , left , bottom , right } ) => { return ( clamp ( x , left , right ) === x && clamp ( y , top , bottom ) === y ) ; } ; export const getSlope = ( { x1 , y1 , x2 , y2 } ) => ( y2 - y1 ) / ( x2 - x1 ) ; export const getYInterceptEquation = ( vector ) => { const { x1 , y1 } = vector ; return ( x ) => getSlope ( vector ) * ( x - x1 ) + y1 ; } ; export const isPointInLine = ( { x , y } , vector ) => { const getY = getYInterceptEquation ( vector ) ; return getY ( x ) === y ; } ; export const isPointInSegment = ( point , vector ) => { const { x1 , y1 , x2 , y2 } = vector ; const maxY = Math . max ( y1 , y2 ) ; const minY = Math . min ( y1 , y2 ) ; const maxX = Math . max ( x1 , x2 ) ; const minX = Math . min ( x1 , x2 ) ; return ( point . x >= minX && point . x <= maxX && point . y >= minY && point . y <= maxY ) && isPointInLine ( point , vector ) ; } ; export const getABCForLine = ( { x1 , y1 , x2 , y2 } ) => { const A = y2 - y1 ; const B = x1 - x2 ; const C = ( A * x1 ) + ( B * y1 ) ; return { A , B , C } ; } ; export const getIntersectionPoint = ( vector1 , vector2 ) => { const { A : A1 , B : B1 , C : C1 } = getABCForLine ( vector1 ) ; const { A : A2 , B : B2 , C : C2 } = getABCForLine ( vector2 ) ; const det = A1 * B2 - A2 * B1 ; if ( det === 0 ) { return undefined ; } else { const x = ( B2 * C1 - B1 * C2 ) / det ; const y = ( A1 * C2 - A2 * C1 ) / det ; return { x , y } ; } } ; export const getVectorPoints = ( { x1 , y1 , x2 , y2 } ) : [ GeoPoint , GeoPoint ] => { return [ { x : x1 , y : y1 } , { x : x2 , y : y2 } , ] ; } ; export const createVectorFromPoints = ( point1 , point2 ) : GeoVector => { return { x1 : point1 . x , y1 : point1 . y , x2 : point2 . x , y2 : point2 . y , } ; } ; export const getMidpoint = ( { x1 , y1 , x2 , y2 } ) : GeoPoint => { return { x : ( x1 + x2 ) / 2 , y : ( y1 + y2 ) / 2 , } ; } ; export const createAngleFromVectors = ( vector1 , vector2 ) : GeoAngle => { return { vectors : [ vector1 , vector2 ] , } ; } ; export const createPerpendicular = ( { x1 , y1 , x2 , y2 } , point ) : GeoVector => { const k = ( ( y2 - y1 ) * ( point . x - x1 ) - ( x2 - x1 ) * ( point . y - y1 ) ) / ( ( y2 - y1 ) ** 2 + ( x2 - x1 ) ** 2 ) ; const x = point . x - k * ( y2 - y1 ) ; const y = point . y + k * ( x2 - x1 ) ; return createVectorFromPoints ( point , { x , y } ) ; } ; export const createParallel = ( vector , origin , x2 ) : GeoVector => { const slope = getSlope ( vector ) ; const intercept = origin . y - ( slope * origin . x ) ; const y2 = ( slope * x2 ) + intercept ; return createVectorFromPoints ( origin , { x : x2 , y : y2 } ) ; } ; export const createHorizontalLine = ( { x , y } , x2 ) : GeoVector => ( { x1 : x , y1 : y , x2 , y2 : y } ) ; export const composeGeoObject = ( ... objects ) : CompositeGeoObject => objects ;