/** 
 | 
 * @author Yi Shen(https://github.com/pissang) 
 | 
 */ 
 | 
  
 | 
import * as vec2 from './vector'; 
 | 
import * as curve from './curve'; 
 | 
  
 | 
const mathMin = Math.min; 
 | 
const mathMax = Math.max; 
 | 
const mathSin = Math.sin; 
 | 
const mathCos = Math.cos; 
 | 
const PI2 = Math.PI * 2; 
 | 
  
 | 
const start = vec2.create(); 
 | 
const end = vec2.create(); 
 | 
const extremity = vec2.create(); 
 | 
  
 | 
/** 
 | 
 * 从顶点数组中计算出最小包围盒,写入`min`和`max`中 
 | 
 */ 
 | 
export function fromPoints(points: ArrayLike<number>[], min: vec2.VectorArray, max: vec2.VectorArray) { 
 | 
    if (points.length === 0) { 
 | 
        return; 
 | 
    } 
 | 
    let p = points[0]; 
 | 
    let left = p[0]; 
 | 
    let right = p[0]; 
 | 
    let top = p[1]; 
 | 
    let bottom = p[1]; 
 | 
  
 | 
    for (let i = 1; i < points.length; i++) { 
 | 
        p = points[i]; 
 | 
        left = mathMin(left, p[0]); 
 | 
        right = mathMax(right, p[0]); 
 | 
        top = mathMin(top, p[1]); 
 | 
        bottom = mathMax(bottom, p[1]); 
 | 
    } 
 | 
  
 | 
    min[0] = left; 
 | 
    min[1] = top; 
 | 
    max[0] = right; 
 | 
    max[1] = bottom; 
 | 
} 
 | 
  
 | 
export function fromLine( 
 | 
    x0: number, y0: number, x1: number, y1: number, 
 | 
    min: vec2.VectorArray, max: vec2.VectorArray 
 | 
) { 
 | 
    min[0] = mathMin(x0, x1); 
 | 
    min[1] = mathMin(y0, y1); 
 | 
    max[0] = mathMax(x0, x1); 
 | 
    max[1] = mathMax(y0, y1); 
 | 
} 
 | 
  
 | 
const xDim: number[] = []; 
 | 
const yDim: number[] = []; 
 | 
/** 
 | 
 * 从三阶贝塞尔曲线(p0, p1, p2, p3)中计算出最小包围盒,写入`min`和`max`中 
 | 
 */ 
 | 
export function fromCubic( 
 | 
    x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, x3: number, y3: number, 
 | 
    min: vec2.VectorArray, max: vec2.VectorArray 
 | 
) { 
 | 
    const cubicExtrema = curve.cubicExtrema; 
 | 
    const cubicAt = curve.cubicAt; 
 | 
    let n = cubicExtrema(x0, x1, x2, x3, xDim); 
 | 
    min[0] = Infinity; 
 | 
    min[1] = Infinity; 
 | 
    max[0] = -Infinity; 
 | 
    max[1] = -Infinity; 
 | 
  
 | 
    for (let i = 0; i < n; i++) { 
 | 
        const x = cubicAt(x0, x1, x2, x3, xDim[i]); 
 | 
        min[0] = mathMin(x, min[0]); 
 | 
        max[0] = mathMax(x, max[0]); 
 | 
    } 
 | 
    n = cubicExtrema(y0, y1, y2, y3, yDim); 
 | 
    for (let i = 0; i < n; i++) { 
 | 
        const y = cubicAt(y0, y1, y2, y3, yDim[i]); 
 | 
        min[1] = mathMin(y, min[1]); 
 | 
        max[1] = mathMax(y, max[1]); 
 | 
    } 
 | 
  
 | 
    min[0] = mathMin(x0, min[0]); 
 | 
    max[0] = mathMax(x0, max[0]); 
 | 
    min[0] = mathMin(x3, min[0]); 
 | 
    max[0] = mathMax(x3, max[0]); 
 | 
  
 | 
    min[1] = mathMin(y0, min[1]); 
 | 
    max[1] = mathMax(y0, max[1]); 
 | 
    min[1] = mathMin(y3, min[1]); 
 | 
    max[1] = mathMax(y3, max[1]); 
 | 
} 
 | 
  
 | 
/** 
 | 
 * 从二阶贝塞尔曲线(p0, p1, p2)中计算出最小包围盒,写入`min`和`max`中 
 | 
 */ 
 | 
export function fromQuadratic( 
 | 
    x0: number, y0: number, x1: number, y1: number, x2: number, y2: number, 
 | 
    min: vec2.VectorArray, max: vec2.VectorArray 
 | 
) { 
 | 
    const quadraticExtremum = curve.quadraticExtremum; 
 | 
    const quadraticAt = curve.quadraticAt; 
 | 
    // Find extremities, where derivative in x dim or y dim is zero 
 | 
    const tx = 
 | 
        mathMax( 
 | 
            mathMin(quadraticExtremum(x0, x1, x2), 1), 0 
 | 
        ); 
 | 
    const ty = 
 | 
        mathMax( 
 | 
            mathMin(quadraticExtremum(y0, y1, y2), 1), 0 
 | 
        ); 
 | 
  
 | 
    const x = quadraticAt(x0, x1, x2, tx); 
 | 
    const y = quadraticAt(y0, y1, y2, ty); 
 | 
  
 | 
    min[0] = mathMin(x0, x2, x); 
 | 
    min[1] = mathMin(y0, y2, y); 
 | 
    max[0] = mathMax(x0, x2, x); 
 | 
    max[1] = mathMax(y0, y2, y); 
 | 
} 
 | 
  
 | 
/** 
 | 
 * 从圆弧中计算出最小包围盒,写入`min`和`max`中 
 | 
 */ 
 | 
export function fromArc( 
 | 
    x: number, y: number, rx: number, ry: number, startAngle: number, endAngle: number, anticlockwise: boolean, 
 | 
    min: vec2.VectorArray, max: vec2.VectorArray 
 | 
) { 
 | 
    const vec2Min = vec2.min; 
 | 
    const vec2Max = vec2.max; 
 | 
  
 | 
    const diff = Math.abs(startAngle - endAngle); 
 | 
  
 | 
  
 | 
    if (diff % PI2 < 1e-4 && diff > 1e-4) { 
 | 
        // Is a circle 
 | 
        min[0] = x - rx; 
 | 
        min[1] = y - ry; 
 | 
        max[0] = x + rx; 
 | 
        max[1] = y + ry; 
 | 
        return; 
 | 
    } 
 | 
  
 | 
    start[0] = mathCos(startAngle) * rx + x; 
 | 
    start[1] = mathSin(startAngle) * ry + y; 
 | 
  
 | 
    end[0] = mathCos(endAngle) * rx + x; 
 | 
    end[1] = mathSin(endAngle) * ry + y; 
 | 
  
 | 
    vec2Min(min, start, end); 
 | 
    vec2Max(max, start, end); 
 | 
  
 | 
    // Thresh to [0, Math.PI * 2] 
 | 
    startAngle = startAngle % (PI2); 
 | 
    if (startAngle < 0) { 
 | 
        startAngle = startAngle + PI2; 
 | 
    } 
 | 
    endAngle = endAngle % (PI2); 
 | 
    if (endAngle < 0) { 
 | 
        endAngle = endAngle + PI2; 
 | 
    } 
 | 
  
 | 
    if (startAngle > endAngle && !anticlockwise) { 
 | 
        endAngle += PI2; 
 | 
    } 
 | 
    else if (startAngle < endAngle && anticlockwise) { 
 | 
        startAngle += PI2; 
 | 
    } 
 | 
    if (anticlockwise) { 
 | 
        const tmp = endAngle; 
 | 
        endAngle = startAngle; 
 | 
        startAngle = tmp; 
 | 
    } 
 | 
  
 | 
    // const number = 0; 
 | 
    // const step = (anticlockwise ? -Math.PI : Math.PI) / 2; 
 | 
    for (let angle = 0; angle < endAngle; angle += Math.PI / 2) { 
 | 
        if (angle > startAngle) { 
 | 
            extremity[0] = mathCos(angle) * rx + x; 
 | 
            extremity[1] = mathSin(angle) * ry + y; 
 | 
  
 | 
            vec2Min(min, extremity, min); 
 | 
            vec2Max(max, extremity, max); 
 | 
        } 
 | 
    } 
 | 
} 
 |