function sqr ( a ) { return a * a ; } export type PointLike = Point | { x ? : number ; y : number ; } | { x : number ; y ? : number ; } ; export function point ( data ) { if ( data instanceof Point ) { return data ; } return new Point ( data . x || 0 , data . y || 0 ) ; } export class Point { public static readonly Zero = new Point ( 0 , 0 ) ; constructor ( public readonly x , public readonly y ) { } public distance ( other = Point . Zero ) { const d = this . sub ( other ) ; return Math . sqrt ( sqr ( d . x ) + sqr ( d . y ) ) ; } public sub ( other ) { const o = point ( other ) ; return new Point ( this . x - o . x , this . y - o . y ) ; } public add ( other ) { const o = point ( other ) ; return new Point ( this . x + o . x , this . y + o . y ) ; } public mul ( scalar ) { return new Point ( this . x * scalar , this . y * scalar ) ; } public div ( scalar ) { return new Point ( this . x / scalar , this . y / scalar ) ; } public equals ( other ) { const o = point ( other ) ; return this . x === o . x && this . y === o . y ; } public getPointCloserTo ( dest , dist ) { if ( this . equals ( dest ) ) return this ; var p = point ( dest ) . sub ( this ) ; const angle = Math . atan2 ( p . x , p . y ) ; var result = new Point ( this . x + Math . sin ( angle ) * dist , this . y + Math . cos ( angle ) * dist ) ; return result ; } } function turn ( p1 , p2 , p3 ) { const a = p1 . x ; const b = p1 . y ; const c = p2 . x ; const d = p2 . y ; const e = p3 . x ; const f = p3 . y ; const A = ( f - b ) * ( c - a ) ; const B = ( d - b ) * ( e - a ) ; return A > B + Number . MIN_VALUE ? 1 : A + Number . MIN_VALUE < B ? - 1 : 0 ; } export function isIntersect ( aStart , aEnd , bStart , bEnd ) { return ( turn ( aStart , bStart , bEnd ) != turn ( aEnd , bStart , bEnd ) && turn ( aStart , aEnd , bStart ) != turn ( aStart , aEnd , bEnd ) ) ; } export function scale ( clientOffset , clientSize , viewSize ) { const clientRatio = clientSize . x / clientSize . y ; const viewRatio = viewSize . x / viewSize . y ; let zoom = 1 ; if ( clientRatio < viewRatio ) zoom = viewSize . y / clientSize . y ; else zoom = viewSize . x / clientSize . x ; const clientMid = clientOffset . mul ( zoom ) . add ( clientSize . mul ( zoom / 2 ) ) ; const viewMid = viewSize . div ( 2 ) ; const clientOffset2 = viewMid . sub ( clientMid ) ; return { clientOffset : clientOffset2 , clientZoom : zoom } ; } export class Rectangle { public static ofSize ( position , size ) { return new Rectangle ( position , position . add ( size ) ) ; } constructor ( public readonly topLeft , public readonly bottomRight ) { } get size ( ) : Point { return this . bottomRight . sub ( this . topLeft ) ; } get topRight ( ) : Point { return new Point ( this . bottomRight . x , this . topLeft . y ) ; } get bottomLeft ( ) : Point { return new Point ( this . topLeft . x , this . bottomRight . y ) ; } }