import { clamp , nearlyEquals } from '@mathigon/fermat' ; import { Angle } from './angle' ; import { Line } from './line' ; import { ORIGIN , Point } from './point' ; import { GeoShape , rad , TransformMatrix , TWO_PI } from './utilities' ; /** An arc segment of a circle, with given center, start point and angle. */ export class Arc implements GeoShape { readonly type : string = 'arc' ; constructor ( readonly c , readonly start , readonly angle ) { } get radius ( ) { return Point . distance ( this . c , this . start ) ; } get end ( ) { return this . start . rotate ( this . angle , this . c ) ; } get startAngle ( ) { return rad ( this . start , this . c ) ; } contract ( p ) { return new ( < any > this . constructor ) ( this . c , this . at ( p / 2 ) , this . angle * ( 1 - p ) ) ; } get minor ( ) : this { if ( this . angle <= Math . PI ) return this ; return new ( < any > this . constructor ) ( this . c , this . end , TWO_PI - this . angle ) ; } get major ( ) : this { if ( this . angle >= Math . PI ) return this ; return new ( < any > this . constructor ) ( this . c , this . end , TWO_PI - this . angle ) ; } get center ( ) { return this . at ( 0.5 ) ; } project ( p ) { const start = this . startAngle ; const end = start + this . angle ; let angle = rad ( p , this . c ) ; if ( end > TWO_PI && angle < end - TWO_PI ) angle += TWO_PI ; angle = clamp ( angle , start , end ) ; return this . c . shift ( this . radius , 0 ) . rotate ( angle , this . c ) ; } at ( t ) { return this . start . rotate ( this . angle * t , this . c ) ; } contains ( p ) { return p . equals ( this . project ( p ) ) ; } transform ( m ) { return new ( < any > this . constructor ) ( this . c . transform ( m ) , this . start . transform ( m ) , this . angle ) ; } /** Rotates this arc by a given angle (in radians), optionally around point `c`. */ rotate ( a , c = ORIGIN ) { if ( nearlyEquals ( a , 0 ) ) return this ; return new ( < any > this . constructor ) ( this . c . rotate ( a , c ) , this . start . rotate ( a , c ) , this . angle ) ; } reflect ( l ) { return new ( < any > this . constructor ) ( this . c . reflect ( l ) , this . start . reflect ( l ) , this . angle ) ; } scale ( sx , sy = sx ) { return new ( < any > this . constructor ) ( this . c . scale ( sx , sy ) , this . start . scale ( sx , sy ) , this . angle ) ; } shift ( x , y = x ) { return new ( < any > this . constructor ) ( this . c . shift ( x , y ) , this . start . shift ( x , y ) , this . angle ) ; } translate ( p ) { return this . shift ( p . x , p . y ) ; } equals ( ) { return false ; } } export class Sector extends Arc { readonly type = 'sector' ; contains ( p ) { return Point . distance ( p , this . c ) <= this . radius && new Angle ( this . start , this . c , p ) . rad <= this . angle ; } }