<commit_before>//
//  BezierCurve.swift
//  BezierKit
//
//  Created by <NAME> on 2/19/17.
//  Copyright © 2017 <NAME>. All rights reserved.
//

import CoreGraphics

public typealias DistanceFunction = (_ v: CGFloat) -> CGFloat

private enum ScaleEnum {
    case constant(CGFloat)
    case function(DistanceFunction)
}

public struct Subcurve<CurveType> where CurveType: BezierCurve {
    public let t1: CGFloat
    public let t2: CGFloat
    public let curve: CurveType

    internal var canSplit: Bool {
        let mid = 0.5 * (self.t1 + self.t2)
        return mid > self.t1 && mid < self.t2
    }

    internal init(curve: CurveType) {
        self.t1 = 0.0
        self.t2 = 1.0
        self.curve = curve
    }

    internal init(t1: CGFloat, t2: CGFloat, curve: CurveType) {
        self.t1 = t1
        self.t2 = t2
        self.curve = curve
    }

    internal func split(from t1: CGFloat, to t2: CGFloat) -> Subcurve<CurveType> {
        let curve: CurveType = self.curve.split(from: t1, to: t2)
        return Subcurve<CurveType>(t1: Utils.map(t1, 0, 1, self.t1, self.t2),
                                   t2: Utils.map(t2, 0, 1, self.t1, self.t2),
                                   curve: curve)
    }

    internal func split(at t: CGFloat) -> (left: Subcurve<CurveType>, right: Subcurve<CurveType>) {
        let (left, right) = curve.split(at: t)
        let t1 = self.t1
        let t2 = self.t2
        let tSplit = Utils.map(t, 0, 1, t1, t2)
        let subcurveLeft = Subcurve<CurveType>(t1: t1, t2: tSplit, curve: left)
        let subcurveRight = Subcurve<CurveType>(t1: tSplit, t2: t2, curve: right)
        return (left: subcurveLeft, right: subcurveRight)
    }
}

extension Subcurve: Equatable where CurveType: Equatable {
    // extension exists for automatic Equatable synthesis
}

// MARK: -

extension BezierCurve {

    // MARK: -

    private var dpoints: [[CGPoint]] {
        var ret: [[CGPoint]] = []
        var p: [CGPoint] = self.points
        ret.reserveCapacity(p.count-1)
        for d in (2 ... p.count).reversed() {
            let c = d-1
            var list: [CGPoint] = []
            list.reserveCapacity(c)
            for j: Int in 0..<c {
                let dpt: CGPoint = CGFloat(c) * (p[j+1] - p[j])
                list.append(dpt)
            }
            ret.append(list)
            p = list
        }
        return ret
    }

    private var linear: Bool {
        let order = self.order
        let points = self.points
        var a = Utils.align(points, p1: points[0], p2: points[order])
        for i in 0..<a.count {
            // TODO: investigate horrible magic number usage
            if abs(a[i].y) > 0.0001 {
                return false
            }
        }
        return true
    }

    /*
     Calculates the length of this Bezier curve. Length is calculated using numerical approximation, specifically the Legendre-Gauss quadrature algorithm.
     */
    public func length() -> CGFloat {
        return Utils.length({(_ t: CGFloat) in self.derivative(t)})
    }

    // MARK: 

    // computes the extrema for each dimension
    internal func internalExtrema(includeInflection: Bool) -> [[CGFloat]] {
        var xyz: [[CGFloat]] = []
        xyz.reserveCapacity(CGPoint.dimensions)
        for d in 0..<CGPoint.dimensions {
            let mfn = {(v: CGPoint) in v[d]}
            var p: [CGFloat] = self.dpoints[0].map(mfn)
            xyz.append(Utils.droots(p))
            if includeInflection && self.order >= 3 {
                p = self.dpoints[1].map(mfn)
                xyz[d] += Utils.droots(p)
            }
            xyz[d] = xyz[d].filter({$0 >= 0 && $0 <= 1}).sorted()
        }
        return xyz
    }

    public func extrema() -> (xyz: [[CGFloat]], values: [CGFloat] ) {
        let xyz = self.internalExtrema(includeInflection: true)
        var roots = xyz.flatMap {$0}.sorted() // the roots for each dimension, flattened and sorted
        var values: [CGFloat] = []
        if !roots.isEmpty {
            values.reserveCapacity(roots.count)
            var lastInserted: CGFloat = -CGFloat.infinity
            for i in 0..<roots.count { // loop ensures (pre-sorted) roots are unique when added to values
                let v = roots[i]
                if v > lastInserted {
                    values.append(v)
                    lastInserted = v
                }
            }
        }
        return (xyz: xyz, values: values)
    }

    // MARK: -
    public func hull(_ t: CGFloat) -> [CGPoint] {
        return Utils.hull(self.points, t)
    }

    public func generateLookupTable(withSteps steps: Int = 100) -> [CGPoint] {
        assert(steps >= 0)
        var table: [CGPoint] = []
        table.reserveCapacity(steps+1)
        for i in 0 ... steps {
            let t = CGFloat(i) / CGFloat(steps)
            table.append(self.compute(t))
        }
        return table
    }
    // MARK: -<commit_msg>code quality.<commit_after>//
//  BezierCurve.swift
//  BezierKit
//
//  Created by <NAME> on 2/19/17.
//  Copyright © 2017 <NAME>. All rights reserved.
//

import CoreGraphics

public typealias DistanceFunction = (_ v: CGFloat) -> CGFloat

private enum ScaleEnum {
    case constant(CGFloat)
    case function(DistanceFunction)
}

public struct Subcurve<CurveType> where CurveType: BezierCurve {
    public let t1: CGFloat
    public let t2: CGFloat
    public let curve: CurveType

    internal var canSplit: Bool {
        let mid = 0.5 * (self.t1 + self.t2)
        return mid > self.t1 && mid < self.t2
    }

    internal init(curve: CurveType) {
        self.t1 = 0.0
        self.t2 = 1.0
        self.curve = curve
    }

    internal init(t1: CGFloat, t2: CGFloat, curve: CurveType) {
        self.t1 = t1
        self.t2 = t2
        self.curve = curve
    }

    internal func split(from t1: CGFloat, to t2: CGFloat) -> Subcurve<CurveType> {
        let curve: CurveType = self.curve.split(from: t1, to: t2)
        return Subcurve<CurveType>(t1: Utils.map(t1, 0, 1, self.t1, self.t2),
                                   t2: Utils.map(t2, 0, 1, self.t1, self.t2),
                                   curve: curve)
    }

    internal func split(at t: CGFloat) -> (left: Subcurve<CurveType>, right: Subcurve<CurveType>) {
        let (left, right) = curve.split(at: t)
        let t1 = self.t1
        let t2 = self.t2
        let tSplit = Utils.map(t, 0, 1, t1, t2)
        let subcurveLeft = Subcurve<CurveType>(t1: t1, t2: tSplit, curve: left)
        let subcurveRight = Subcurve<CurveType>(t1: tSplit, t2: t2, curve: right)
        return (left: subcurveLeft, right: subcurveRight)
    }
}

extension Subcurve: Equatable where CurveType: Equatable {
    // extension exists for automatic Equatable synthesis
}

// MARK: -

extension BezierCurve {

    // MARK: -

    private var dpoints: [[CGPoint]] {
        var ret: [[CGPoint]] = []
        var p: [CGPoint] = self.points
        ret.reserveCapacity(p.count-1)
        for d in (2 ... p.count).reversed() {
            let c = d-1
            var list: [CGPoint] = []
            list.reserveCapacity(c)
            for j: Int in 0..<c {
                let dpt: CGPoint = CGFloat(c) * (p[j+1] - p[j])
                list.append(dpt)
            }
            ret.append(list)
            p = list
        }
        return ret
    }

    private var linear: Bool {
        let order = self.order
        let points = self.points
        var a = Utils.align(points, p1: points[0], p2: points[order])
        for i in 0..<a.count {
            // TODO: investigate horrible magic number usage
            if abs(a[i].y) > 0.0001 {
                return false
            }
        }
        return true
    }

    /*
     Calculates the length of this Bezier curve. Length is calculated using numerical approximation, specifically the Legendre-Gauss quadrature algorithm.
     */
    public func length() -> CGFloat {
        return Utils.length({(_ t: CGFloat) in self.derivative(t)})
    }

    // MARK: 

    // computes the extrema for each dimension
    internal func internalExtrema(includeInflection: Bool) -> [[CGFloat]] {
        var xyz: [[CGFloat]] = []
        xyz.reserveCapacity(CGPoint.dimensions)
        for d in 0..<CGPoint.dimensions {
            let mfn = {(v: CGPoint) in v[d]}
            var p: [CGFloat] = self.dpoints[0].map(mfn)
            xyz.append(Utils.droots(p))
            if includeInflection && self.order >= 3 {
                p = self.dpoints[1].map(mfn)
                xyz[d] += Utils.droots(p)
            }
            xyz[d] = xyz[d].filter({$0 >= 0 && $0 <= 1}).sorted()
        }
        return xyz
    }

    public func extrema() -> (xyz: [[CGFloat]], values: [CGFloat] ) {
        let xyz = self.internalExtrema(includeInflection: true)
        var roots = xyz.joined().sorted() // the roots for each dimension, flattened and sorted
        var values: [CGFloat] = []
        if !roots.isEmpty {
            values.reserveCapacity(roots.count)
            var lastInserted: CGFloat = -CGFloat.infinity
            for i in 0..<roots.count { // loop ensures (pre-sorted) roots are unique when added to values
                let v = roots[i]
                if v > lastInserted {
                    values.append(v)
                    lastInserted = v
                }
            }
        }
        return (xyz: xyz, values: values)
    }

    // MARK: -
    public func hull(_ t: CGFloat) -> [CGPoint] {
        return Utils.hull(self.points, t)
    }

    public func generateLookupTable(withSteps steps: Int = 100) -> [CGPoint] {
        assert(steps >= 0)
        var table: [CGPoint] = []
        table.reserveCapacity(steps+1)
        for i in 0 ... steps {
            let t = CGFloat(i) / CGFloat(steps)
            table.append(self.compute(t))
        }
        return table
    }
    // MARK: -
{'fraction_non_alphanumeric': 0.11987829614604463, 'fraction_numerical': 0.01795131845841785, 'mean_word_length': 1.7683885457608086, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 49, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1538973', 'n_tokens_mistral': 3348, 'n_tokens_neox': 3149, 'n_words': 850}