Last active
November 10, 2021 03:30
-
-
Save wildthink/5b8eb62b843666b5a8e7a4f69e7ede15 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// CompoundUnit.swift | |
// | |
// Created by Jason Jobe on 11/7/21. | |
// | |
// https://github.com/ole/Ampere | |
import Foundation | |
public protocol CompoundUnitProtocol: Dimension { | |
associatedtype Numerator: Unit | |
associatedtype Denominator: Unit | |
init(symbol: String?, _: Numerator, per: Denominator) | |
} | |
public final class CompoundUnit<Numerator: Unit, Denominator: Unit>: Dimension, CompoundUnitProtocol { | |
public typealias Numerator = Numerator | |
public typealias Denominator = Denominator | |
public override class func baseUnit() -> Self { | |
.init(symbol: nil, Numerator.anyBaseUnit(), per: Denominator.anyBaseUnit()) | |
} | |
public private(set) var numerator: Numerator | |
public private(set) var denominator: Denominator | |
public var defaultSymbol: String { | |
"\(numerator.symbol)/\(denominator.symbol)" | |
} | |
public required init(symbol: String? = nil, _ num: Numerator, per den: Denominator) { | |
self.numerator = num | |
self.denominator = den | |
super.init(symbol: symbol ?? "\(num.symbol)/\(den.symbol)", | |
converter: UnitConverterLinear(coefficient: num.coefficient/den.coefficient)) | |
} | |
public override func isEqual(_ object: Any?) -> Bool { | |
guard let other = object as? Self else { | |
return false | |
} | |
return self === other || | |
(self.symbol == other.symbol | |
&& self.numerator == other.numerator | |
&& self.denominator == other.denominator) | |
} | |
required public init?(coder: NSCoder) { | |
return nil | |
} | |
} | |
public extension Unit { | |
@objc class func anyBaseUnit() -> Self { | |
Self(symbol: String(describing: self).lowercased()) | |
} | |
@objc var coefficient: Double { | |
1.0 | |
} | |
} | |
extension Dimension { | |
@objc public override class func anyBaseUnit() -> Self { | |
baseUnit() | |
} | |
@objc public override var coefficient: Double { | |
(converter as? UnitConverterLinear)?.coefficient ?? 1.0 | |
} | |
} | |
public extension Double { | |
func callAsFunction <R: CompoundUnitProtocol>(_ num: R.Numerator, per dem: R.Denominator) -> Measurement<R> { | |
Measurement(value: self, unit: R(symbol: nil, num, per: dem)) | |
} | |
} | |
public extension Int { | |
func callAsFunction <R: CompoundUnitProtocol>(_ num: R.Numerator, per dem: R.Denominator) -> Measurement<R> { | |
Measurement(value: Double(self), unit: R(symbol: nil, num, per: dem)) | |
} | |
} | |
public extension Measurement where UnitType: CompoundUnitProtocol { | |
/// Returns a new measurement created by converting to the specified unit. | |
/// | |
/// - parameter otherUnit: A unit of the same `CompoundUnit`. | |
/// - returns: A converted measurement. | |
/// | |
func converted(to num: UnitType.Numerator, per dem: UnitType.Denominator) -> Self { | |
return self.converted(to: CompoundUnit(symbol: nil, num, per: dem) as! UnitType) | |
} | |
/// Converts the measurement to the specified unit. | |
/// | |
/// - parameter otherUnit: A unit of the same `CompoundUnit`. | |
mutating func convert(to num: UnitType.Numerator, per dem: UnitType.Denominator) { | |
self.convert(to: CompoundUnit(symbol: nil, num, per: dem) as! UnitType) | |
} | |
} | |
public func / <LU: Unit, RU: Unit> (lhs: Measurement<LU>, rhs: Measurement<RU>) | |
-> Measurement<CompoundUnit<LU, RU>> { | |
Measurement(lhs.value / rhs.value, CompoundUnit(lhs.unit, per: rhs.unit)) | |
} | |
public func * <LU: Unit, RU: Dimension> (lhs: Measurement<CompoundUnit<LU, RU>>, rhs: Measurement<RU>) | |
-> Measurement<LU> { | |
let rhv = rhs.converted(to: lhs.unit.denominator) | |
return Measurement(lhs.value * rhv.value, lhs.unit.numerator) | |
} | |
func / <A: Unit, C: Unit>(lhs: A, rhs: C) -> CompoundUnit<A, C> { | |
CompoundUnit<A, C>(symbol: nil, lhs, per: rhs) | |
} | |
extension Measurement: ExpressibleByFloatLiteral { | |
public init(floatLiteral value: FloatLiteralType) { | |
self = Measurement(value: value, unit: UnitType.anyBaseUnit()) | |
} | |
} | |
extension Measurement: ExpressibleByIntegerLiteral { | |
public init(integerLiteral value: Int) { | |
self = Measurement(value: Double(value), unit: UnitType.anyBaseUnit()) | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public typealias UnitVelocity = CompoundUnit<UnitLength, UnitDuration> | |
public typealias Velocity = Measurement<UnitVelocity> | |
//public typealias Velocity = Measurement<CompoundUnit<UnitLength, UnitDuration>> | |
extension UnitVelocity { | |
static let mps: UnitVelocity = baseUnit() | |
static let mph: UnitVelocity = .init(symbol: "mph", .miles, per: .hours) | |
static let kph: UnitVelocity = .init(symbol: "kph", .kilometers, per: .hours) | |
} | |
func demo_vel() { | |
let s1_mph: Measurement<UnitSpeed> = .init(value: 60, unit: .milesPerHour) | |
let s2_kph: Measurement<UnitSpeed> = .init(value: 60, unit: .kilometersPerHour) | |
let v1_mph: Velocity = 60(.mph) // .init(value: 60, unit: .mph) | |
let v2_kph: Velocity = 96.56(.kph) | |
// let uv: Unit = UnitVelocity(.kilometers, per: .hours) | |
let v3: Velocity = 55(.kilometers, per: .hour) | |
let v4: Velocity = 88(.meters, per: .hour) | |
print (v3, v4.converted(to: .meters, per: .seconds)) | |
print (s1_mph, s1_mph.converted(to: .kilometersPerHour)) | |
print (s1_mph.unit.coefficient, s2_kph.unit.coefficient) | |
print (s1_mph.unit.coefficient/s2_kph.unit.coefficient) | |
// print ("mph", UnitVelocity.mph.coefficient, UnitVelocity.kph.coefficient) | |
print (v1_mph, v1_mph * 2, v1_mph / 3) | |
print (v1_mph, v1_mph.converted(to: .kph)) | |
print (v2_kph, v2_kph.converted(to: .mph)) | |
print (v2_kph, v2_kph.converted(to: .meters, per: .hours)) | |
print (v2_kph, v2_kph.converted(to: .mps)) | |
// v2_kph.converted(to: .meters, per: .hour) | |
print (String(describing: Velocity.self)) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment