Zum Inhalt

apple/PhysarumApp/Sources/Capture/CaptureMath.swift

import Foundation
import CoreMedia

/// Ports src/lib/filename.ts slug rules: lowercase, strip diacritics,
/// non-alphanumeric runs → single hyphen, trim hyphens, empty → "preset".
func captureSlug(_ input: String) -> String {
    let folded = input.lowercased()
        .folding(options: .diacriticInsensitive, locale: Locale(identifier: "en_US_POSIX"))
    var out = ""
    var lastHyphen = false
    for scalar in folded.unicodeScalars {
        let c = Character(scalar)
        if c.isASCII && (c.isLetter || c.isNumber) {
            out.append(c); lastHyphen = false
        } else if !lastHyphen {
            out.append("-"); lastHyphen = true
        }
    }
    while out.hasPrefix("-") { out.removeFirst() }
    while out.hasSuffix("-") { out.removeLast() }
    return out.isEmpty ? "preset" : out
}

private let timestampFormatter: DateFormatter = {
    let f = DateFormatter()
    f.locale = Locale(identifier: "en_US_POSIX")
    f.dateFormat = "yyyyMMdd-HHmmss"
    return f
}()

/// `physarum-<preset-slug>-<YYYYMMDD-HHmmss>.<ext>`
func captureFilename(presetName: String, date: Date, ext: String) -> String {
    "physarum-\(captureSlug(presetName))-\(timestampFormatter.string(from: date)).\(ext)"
}

/// Even-rounded export dimensions for a width/height aspect at a given long edge.
/// aspectWH >= 1 → width is the long edge; < 1 (portrait) → height is the long edge.
func exportDimensions(aspectWH: Double, longEdge: Int) -> (w: Int, h: Int) {
    func even(_ v: Int) -> Int { max(2, v - (v % 2)) }
    if aspectWH >= 1 {
        return (even(longEdge), even(Int((Double(longEdge) / aspectWH).rounded())))
    } else {
        return (even(Int((Double(longEdge) * aspectWH).rounded())), even(longEdge))
    }
}

func clipFrameCount(durationSeconds: Int, fps: Int) -> Int { max(1, durationSeconds) * max(1, fps) }

func clipPresentationTime(frameIndex: Int, fps: Int) -> CMTime {
    CMTime(value: CMTimeValue(frameIndex), timescale: CMTimeScale(max(1, fps)))
}