USB-Meter / USB Meter / Model / Measurements.swift
1 contributor
126 lines | 3.752kb
//
//  Measurements.swift
//  USB Meter
//
//  Created by Bogdan Timofte on 07/05/2020.
//  Copyright © 2020 Bogdan Timofte. All rights reserved.
//

import Foundation
import CoreGraphics

class Measurements : ObservableObject {

    class Measurement : ObservableObject {
        struct Point : Identifiable , Hashable {
            var id : Int
            var timestamp: Date
            var value: Double
            func point() -> CGPoint {
                return CGPoint(x: timestamp.timeIntervalSince1970, y: value)
            }
        }

        var points: [Point] = []
        var context = ChartContext()

        func removeValue(index: Int) {
            points.remove(at: index)
            context.reset()
            for point in points {
                context.include( point: point.point() )
            }
            self.objectWillChange.send()
        }

        func addPoint(timestamp: Date, value: Double) {
            let newPoint = Measurement.Point(id: points.count, timestamp: timestamp, value: value)
            points.append(newPoint)
            context.include( point: newPoint.point() )
            self.objectWillChange.send()
        }
        
        func reset() {
            points.removeAll()
            context.reset()
            self.objectWillChange.send()
        }

        func trim(before cutoff: Date) {
            points = points
                .filter { $0.timestamp >= cutoff }
                .enumerated()
                .map { index, point in
                    Measurement.Point(id: index, timestamp: point.timestamp, value: point.value)
                }
            context.reset()
            for point in points {
                context.include(point: point.point())
            }
            self.objectWillChange.send()
        }
    }
    
    @Published var power = Measurement()
    @Published var voltage = Measurement()
    @Published var current = Measurement()

    private var lastPointTimestamp = 0
    
    private var itemsInSum: Double = 0
    private var powerSum: Double = 0
    private var voltageSum: Double = 0
    private var currentSum: Double = 0

    func reset() {
        power.reset()
        voltage.reset()
        current.reset()
        lastPointTimestamp = 0
        itemsInSum = 0
        powerSum = 0
        voltageSum = 0
        currentSum = 0
        self.objectWillChange.send()
    }
    
    func remove(at idx: Int) {
        power.removeValue(index: idx)
        voltage.removeValue(index: idx)
        current.removeValue(index: idx)
        self.objectWillChange.send()
    }

    func trim(before cutoff: Date) {
        power.trim(before: cutoff)
        voltage.trim(before: cutoff)
        current.trim(before: cutoff)
        self.objectWillChange.send()
    }


        
    func addValues(timestamp: Date, power: Double, voltage: Double, current: Double) {
        let valuesTimestamp = timestamp.timeIntervalSinceReferenceDate.intValue
        if lastPointTimestamp == 0 {
            lastPointTimestamp = valuesTimestamp
        }
        if lastPointTimestamp == valuesTimestamp {
            itemsInSum += 1
            powerSum += power
            voltageSum += voltage
            currentSum += current
        }
        else {
            self.power.addPoint( timestamp: timestamp, value: powerSum / itemsInSum )
            self.voltage.addPoint( timestamp: timestamp, value: voltageSum / itemsInSum )
            self.current.addPoint( timestamp: timestamp, value: currentSum / itemsInSum )
            lastPointTimestamp = valuesTimestamp
            itemsInSum = 1
            powerSum = power
            voltageSum = voltage
            currentSum = current
        }
        self.objectWillChange.send()
    }
}