🅿️Vector2D
swift ⟩ type ⟩ custom ⟩ package ⟩ GeometryKit ⟩ Vector2D
// History:
// • 2024.12.09 - draft
// • 2024.12.11 - version 1.0
// Inheritance Hierarchy
// • MetricSpace -> Vector -> Vector2D -> ComplextNumber
// ---------------------
//      🅿️ Vector2D
// ---------------------
/// 通用的二維向量協定,可適用於 `CGPoint`, `CGSize` 等
///
/// ```
/// import CoreGraphics
///
/// // CGPoint + Vector2D
/// extension CGPoint: Vector2D {
///     public typealias Scalar = CGFloat
/// }
///
/// // CGSize + Vector2D
/// extension CGSize: Vector2D {
///     public typealias Scalar = CGFloat
///     public var y: CGFloat { height }
///     public init(x: CGFloat, y: CGFloat) {
///         self.init(width: x, height: y)
///     }
/// }
/// ```
public protocol Vector2D: Vector {
    
    // ⭐️ required properties
    var x: Scalar { get }
    var y: Scalar { get }
    
    // ⭐️ required initializer
    init(x: Scalar, y: Scalar)
    
}
// ------------------------------------------
//      🌀 Vector2D: Vector Operations
// ------------------------------------------
// MARK: - Vector Operations -
public extension Vector2D {
    
    /* ------- Constants ------- */
    
    /// `Self.zero = (0, 0)`
    static var zero: Self {
        return Self.init(x: 0, y: 0)
    }
    
    /// `Self.i = (1, 0)`
    static var i: Self {
        return Self.init(x: 1, y: 0)
    }
    
    /// `Self.j = (0, 1)`
    static var j: Self {
        return Self.init(x: 0, y: 1)
    }
    
    /* ------- Initializers ------- */
    
    /// convenience initializer, ex: `CGPoint(1, 2`
    init(_ x: Scalar, _ y: Scalar) {
        self.init(x: x, y: y)
    }
    
    /* ------- Geometry Properties ------- */
    
    /// 長度平方 |z|² = x² + y²
    var normSquared: Scalar {
        x * x + y * y
    }
        
    /// 長度 |z| = √(x² + y²)
    var magnitude: Scalar {
        (x * x + y * y).squareRoot()
    }
        
    /// 長度 |z|
    var norm: Scalar {
        (x * x + y * y).squareRoot()
    }
    
    /// 單位向量
    var unitVector: Self {
        precondition(self.magnitude != 0, "⛔ Zero vector can not be normalized.")
        return self / self.magnitude
    }
    
    
    /* ------- Linear Combinations ------- */
    
    /// u + v (vector addition)
    @inlinable    // 減少運算頻繁調用的開銷
    static func + (u: Self, v: Self) -> Self {
        return Self.init(x: u.x + v.x, y: u.y + v.y)
    }
    
    /// u += v (vector addition)
    static func += (u: inout Self, v: Self) {
        u = u + v
    }
    
    /// -v (additive inverse)
    static prefix func - (v: Self) -> Self {
        return Self.init(x: -v.x, y: -v.y)
    }
    
    /// u - v (vector subtraction)
    @inlinable    // 減少運算頻繁調用的開銷
    static func - (u: Self, v: Self) -> Self {
        return Self.init(x: u.x - v.x, y: u.y - v.y)
    }
    
    /// u -= v (vector subtraction)
    static func -= (u: inout Self, v: Self) {
        u = u - v
    }
    
    /* ------- Scalar Multiplication ------- */
    
    /// v * a (scalar multiplication)
    /// (a * v : default behavior provided by `Vector`)
    @inlinable    // 減少運算頻繁調用的開銷
    static func * (v: Self, a: Scalar) -> Self {
        return Self.init(x: a * v.x, y: a * v.y)
    }
    
    /// v *= a (scalar multiplicatio)
    static func *= (v: inout Self, a: Scalar) {
        v = v * a
    }
    
    // v / a (scalar multiplication)
    // default behavior provided by `Vector`
    
    /// v /= a (scalar multiplicatio)
    static func /= (v: inout Self, a: Scalar) {
        precondition(a != 0, "⛔ Division by zero is not allowed.")
        v = v / a
    }
    
    /* ------- Dot Product ------- */
        
    /// dot product
    /// u.dot(v) = u • v = u.x * v.x + u.y * v.y
    func dot(_ v: Self) -> Scalar {
        return x * v.x + y * v.y
    }
    
    /* ------- Cross Product ------- */
    
    /// cross product:
    /// u × v = u.x * v.y - u.y * v.x
    ///
    /// ```
    /// // Example:
    /// let u = CGPoint(1, 2) // u = (1, 2)
    /// let v = CGPoint(3, 4) // v = (3, 4)
    /// u.cross(v)            // u × v = -2
    /// ```
    func cross(_ v: Self) -> Scalar {
        return x * v.y - y * v.x
    }
    
}
// ---------------------------------------
//      🌀 Vector2D: Other Utilities
// ---------------------------------------
// MARK: - Utility -
public extension Vector2D {
        
    /* ------- non-proportional scale ------- */
    
    /// ```
    /// // non-proportional scale
    /// let u = CGPoint(1, 2) // u = (1, 2)
    /// let v = CGPoint(3, 4) // v = (3, 4)
    /// u.scale(v)            // (1*3, 2*4) = (3, 8)
    /// ```
    func scaled(by v: Self) -> Self {
        return Self.init(x: x * v.x, y: y * v.y)
    }
    
    /// non-proportional scale
    /// u = (a, b)
    /// v = (c, d)
    /// u.divided(by: v) = (a/c, b/d)
    func divided(by v: Self) -> Self {
        precondition(v.x != 0 && v.y != 0, "⛔ Division by zero is not allowed.")
        return Self.init(x: x / v.x, y: y / v.y)
    }
}
// ----------------------------------------------
//      🌀 Vector2D: Geometry Utilities
// ----------------------------------------------
// MARK: - Geometry -
extension Vector2D {
    
    // ⭐️ required by MetricSpace
    // p.distance(to: q)
    public func distance(to other: Self) -> Scalar {
        return (self - other).magnitude
    }
    
}
// 需要 cos(), sin(), atan2() 等等函數者放這裡
import  CoreGraphics        // for CGFloat, CGPoint , etc
// cos(), sin(), etc use CGFloat
extension Vector2D where Scalar == CGFloat {
    
    /* ------- Geometry Utilities ------- */
    
    /// 將向量旋轉某個角度 (in radians)
    /// `vector.rotated(by: angle)`
    public func rotated(by angle: Scalar) -> Self {
        let cosA = cos(angle)
        let sinA = sin(angle)
        // transformed by rotation matrix
        return Self.init(
            x: x * cosA - y * sinA,
            y: x * sinA + y * cosA
        )
    }
    
    /// u 到 v 的有向角(in radians),
    /// 範圍:-𝜋 < θ <= 𝜋
    public func angle(to v: Self) -> Scalar {
        
        // dot = |u||v|cosθ
        let dot = self.dot(v)
        // u ⨉ v = |u||v|sinθ
        let area = self.cross(v)
        
        // |u||v|
        let mn = self.magnitude * v.magnitude
        
        precondition(mn != 0,
            "⛔ Angle to/from zero vector is not defined."
        )
        
        // (cosθ, sinθ)
        let (c, s) = (dot/mn, area/mn)
        
        // atan2(y, x)
        return atan2(s, c)
    }
    
    /* ------- Polar Coordinates ------- */
    
    // cos(x), sin(x) -> Foundation framework
    
    /// polar form: `Self.polar(radius: 2, angle: .pi/3)`
    public static func polar(radius: Scalar, angle: Scalar) -> Self {
        let (r, a) = (radius, angle)
        return Self.init(x: r * cos(a), y: r * sin(a))
    }
    
    /// convert to CGPoint: `v.point`
    public var point: CGPoint { CGPoint(x: x, y: y) }
    
    /* ------- Frame related  ------- */
    
    /// vector's origin: `v.origin == Self.zero`
    public var origin: CGPoint { .zero }
    
    /// convert to CGSize: `v.size`
    public var size  : CGSize  {  CGSize(width: x, height: y) }
}- Vector:comformed by Vector2D 
- UpArrowShape uses Vector2D. 
- used in Drag gesture to add drag offset. 
History
// 封存日期:2020.10.10
//
// 封存記錄:
// 1. 將 CGFloat 改為 associatedtype Field
// 2. 將 Conforming Types 搬到獨立的檔案:🌀 CoreGraphics + Vector2D
// 3. 將牽涉到此協定的 type constraint 
//    `T: Vector2D` 改為 `T: Vector where T.Field == CGFloat`
// -----------------------------------------
/*
 * ⭐️ Conforming Types:
 *    - CGPoint, CGVector, CGSize
 */
import CoreGraphics  // for CGFloat
import Foundation    // for String(format:)
// ⭐️ define custom operators
infix operator ×  : MultiplicationPrecedence  // cross (determinant)
infix operator •  : MultiplicationPrecedence  // dot   (• : opt + 8)
infix operator ** : MultiplicationPrecedence  // non-proportional scale
infix operator **=: MultiplicationPrecedence
public protocol Vector2D: ExpressibleByArrayLiteral, CustomStringConvertible {
    
    // x, y coordinates
    var x: CGFloat { get }
    var y: CGFloat { get }
    
    // initializer
    init(x: CGFloat, y: CGFloat)
    
    // vector addition
    static func + (u: Self, v: Self) -> Self
    // additive inverse
    static prefix func - (u: Self) -> Self
}
// default behaviors
extension Vector2D {
    
    /* ------- Constants ------- */
    
    public static var i: Self { .init(x: 1, y: 0) }
    public static var j: Self { .init(x: 0, y: 1) }
    
    /* ------- Initializers ------- */
    
    // ExpressibleByArrayLiteral
    /// Example:
    /// - `let p: CGPoint = [1, 2]`
    public init(arrayLiteral elements: CGFloat...) {
        self.init(x: elements[0], y: elements[1])
    }
    
    /// # convenience initializer
    /// Example:
    /// - `let p = CGPoint(1, 2)`
    public init(_ x: CGFloat, _ y: CGFloat) { self.init(x: x, y: y) }
    
    /* ------- Linear Combinations ------- */
    
    /// u + v
    public static func + (u: Self, v: Self) -> Self {
        .init(u.x + v.x, u.y + v.y)
    }
    /// -v (additive inverse)
    public static prefix func - (v: Self) -> Self {
        .init(-v.x, -v.y)
    }
    
    /// # vector subtraction
    /// `u - v == u + (-v)`
    public static func - (u: Self, v: Self) -> Self { 
        u + (-v)
    }
    
    /* ------- Scalar Multiplication ------- */
    
    /// a * v
    public static func * (a: CGFloat, v: Self) -> Self {
        .init(a * v.x, a * v.y)
    }
    /// v * a
    public static func * (v: Self, a: CGFloat) -> Self {
        a * v
    }
    /// v / a
    public static func / (v: Self, a: CGFloat) -> Self {
        (1/a) * v
    }
    
    /* ------- Dot Product, Cross Product ------- */
    
    /// # cross product: u × v
    public static func × (u: Self, v: Self) -> CGFloat {
        u.x * v.y - u.y * v.x  // x1 y2 - x2 y1
    }
    /// # dot product: u • v
    public static func • (u: Self, v: Self) -> CGFloat {
        u.x * v.x + u.y * v.y  // x1 x2 + y1 y2
    }
    
    /* ------- Complex Number ------- */
    
    /// multiplication: u * v
    public static func * (u: Self, v: Self) -> Self {
        let (a,b,c,d) = (u.x, u.y, v.x, v.y)       // u = a + bi, v = a - bi
        return .init(a * c - b * d, a * d + b * c) // uv = (ac-bd) + (ad+bc)i
    }
    
    /// multiplication: u *= v
    public static func *= (u: inout Self, v: Self) { u = u * v }
    
    /* ------- Other Operations ------- */
    
    /// # Non-proportional scale
    /// If `u = [a,b], v = [c,d]`, then `u ** v = [ac, bd]`
    public static func ** (u: Self, v: Self) -> Self {
        .init(u.x * v.x, u.y * v.y)
    }
    
}
// CustomStringConvertible
extension Vector2D {
    public var description: String {
        "(\(String(format: "%.2f", x)), \(String(format: "%.2f", y)))"
    }
}
/* 
 * 🅿️ Vector2D Conformance
 * - CGPoint
 * - CGVector
 * - CGSize
 */
// 🌀CGPoint + Vector2D
extension CGPoint: Vector2D {}
// 🌀CGSize + Vector2D
extension CGSize: Vector2D {
    public var x: CGFloat { width }
    public var y: CGFloat { height }
    public init(x: CGFloat, y: CGFloat) { 
        self.init(width: x, height: y) 
    }
}
// 🌀CGVector + Vector2D
extension CGVector: Vector2D {
    public var x: CGFloat { dx }
    public var y: CGFloat { dy }
    public init(x: CGFloat, y: CGFloat) { 
        self.init(dx: x, dy: y) 
    }
}- 👉 GitHub ⟩ Vector2D (https://github.com/lochiwei/Vector2D) 
- 👉 replit 
/*
 * ⭐️ 為了配合 Swift 5.0 (repl.it),函數的回傳記得要用「return」!
 */
import CoreGraphics
// ⭐️ define custom operators
infix operator ×  : MultiplicationPrecedence  // cross (determinant)
infix operator •  : MultiplicationPrecedence  // dot   (• : opt + 8)
infix operator ** : MultiplicationPrecedence  // non-proportional scale
infix operator **=: MultiplicationPrecedence
// 🅿️ Vector2D
public protocol Vector2D: ExpressibleByArrayLiteral {
    
    associatedtype Field: FloatingPoint     // support +,-,*,/
    
    // x, y coordinates
    var x: Field { get }
    var y: Field { get }
    
    // initializer
    init(x: Field, y: Field)
    
    // vector addition: u + v
    static func + (u: Self, v: Self) -> Self
    // additive inverse: -v
    static prefix func - (u: Self) -> Self
    
    // scalar multiplication: a * v
    // has default implementation in extension
}
// default behaviors
extension Vector2D {
    
    /* ------- Constants ------- */
    
    public static var i: Self { return Self.init(x: 1, y: 0) }
    public static var j: Self { return Self.init(x: 0, y: 1) }
    
    /* ------- Initializers ------- */
    
    // ExpressibleByArrayLiteral
    /// Example:
    /// - `let p: CGPoint = [1, 2]`
    public init(arrayLiteral elements: Field...) {
        var a = elements + [0, 0]   // padding 0's
        self.init(x: a[0], y: a[1])
    }
    
    /// # convenience initializer
    /// Example:
    /// - `let p = CGPoint(1, 2)`
    public init(_ x: Field, _ y: Field) { 
        self.init(x: x, y: y) 
    }
    
    /* ------- Linear Combinations ------- */
    
    /// u + v
    public static func + (u: Self, v: Self) -> Self {
        return Self.init(x: u.x + v.x, y: u.y + v.y)
    }
    /// -v (additive inverse)
    public static prefix func - (v: Self) -> Self {
        return Self.init(x: -v.x, y: -v.y)
    }
    
    /// # vector subtraction
    /// `u - v == u + (-v)`
    public static func - (u: Self, v: Self) -> Self { 
        return u + (-v)
    }
    
    /* ------- Scalar Multiplication ------- */
    
    /// a * v
    public static func * (a: Field, v: Self) -> Self {
        return Self.init(x: a * v.x, y: a * v.y)
    }
    /// v * a
    public static func * (v: Self, a: Field) -> Self {
        return a * v
    }
    /// v / a
    public static func / (v: Self, a: Field) -> Self {
        return Self.init(x: v.x / a, y: v.y / a)
    }
    
    /* ------- Dot Product, Cross Product ------- */
    
    /// # cross product: u × v
    public static func × (u: Self, v: Self) -> Field {
        return u.x * v.y - u.y * v.x  // x1 y2 - x2 y1
    }
    /// # dot product: u • v
    public static func • (u: Self, v: Self) -> Field {
        return u.x * v.x + u.y * v.y  // x1 x2 + y1 y2
    }
    
    /* ------- Complex Number ------- */
    
    /// multiplication: u * v
    public static func * (u: Self, v: Self) -> Self {
        let (a,b,c,d) = (u.x, u.y, v.x, v.y)       // u = a + bi, v = a - bi
        return Self.init(x: a * c - b * d, y: a * d + b * c) // uv = (ac-bd) + (ad+bc)i
    }
    
    /// multiplication: u *= v
    public static func *= (u: inout Self, v: Self) { 
        u = u * v
    }
    
    /* ------- Other Operations ------- */
    
    /// # Non-proportional scale
    /// If `u = [a,b], v = [c,d]`, then `u ** v = [ac, bd]`
    public static func ** (u: Self, v: Self) -> Self {
        return Self.init(x: u.x * v.x, y: u.y * v.y)
    }
    
}
extension Vector2D where Field == CGFloat {
    
    /* ------- Polar Coordinates ------- */
    
    // .polar(r, a)
    public static func polar(_ r: Field, _ a: Field) -> Self {
        Self.init(x: r * cos(a), y: r * sin(a))
    }
    
}// 2020.10.10 + vec.point (Vector2D -> CGPoint)
//
// ---------------------
//      🅿️ Vector2D
// ---------------------
import SwiftUI
// ⭐️ define custom operators
infix operator ×  : MultiplicationPrecedence  // cross (determinant)
infix operator •  : MultiplicationPrecedence  // dot   (• : opt + 8)
infix operator ** : MultiplicationPrecedence  // non-proportional scale
infix operator **=: MultiplicationPrecedence
// 🅿️ Vector2D
public protocol Vector2D: ExpressibleByArrayLiteral, Rectangular {
    
    associatedtype Field: FloatingPoint     // support +,-,*,/
    
    // x, y coordinates
    var x: Field { get }
    var y: Field { get }
    
    // initializer
    init(x: Field, y: Field)
    
    // vector addition: u + v
    // (default implementation provided)
    static func + (u: Self, v: Self) -> Self
    
    // additive inverse: -v
    // (default implementation provided)
    static prefix func - (u: Self) -> Self
}
// MARK: - Vector2D protocol extension -
// default behaviors
extension Vector2D {
    
    /* ------- Constants ------- */
    
    public static var i: Self { return Self.init(x: 1, y: 0) }
    public static var j: Self { return Self.init(x: 0, y: 1) }
    
    /* ------- Initializers ------- */
    
    /// make `Vector2D` conform to `ExpressibleByArrayLiteral`
    ///
    /// Example:
    /// ```
    /// let p: CGPoint = [1, 2]
    /// ```
    public init(arrayLiteral elements: Field...) {
        let a = elements + [0, 0]   // padding 0's
        self.init(x: a[0], y: a[1])
    }
    
    /// convenience initializer
    ///
    /// example:
    /// ```
    /// let p = CGPoint(1, 2)
    /// ```
    public init(_ x: Field, _ y: Field) {
        self.init(x: x, y: y)
    }
    
    /* ------- Linear Combinations ------- */
    
    /// u + v
    public static func + (u: Self, v: Self) -> Self {
        return Self.init(x: u.x + v.x, y: u.y + v.y)
    }
    /// -v (additive inverse)
    public static prefix func - (v: Self) -> Self {
        return Self.init(x: -v.x, y: -v.y)
    }
    
    /// vector subtraction
    /// `u - v == u + (-v)`
    public static func - (u: Self, v: Self) -> Self {
        return u + (-v)
    }
    
    /* ------- Scalar Multiplication ------- */
    
    /// a * v
    public static func * (a: Field, v: Self) -> Self {
        return Self.init(x: a * v.x, y: a * v.y)
    }
    /// v * a
    public static func * (v: Self, a: Field) -> Self {
        return a * v
    }
    /// v / a
    public static func / (v: Self, a: Field) -> Self {
        return Self.init(x: v.x / a, y: v.y / a)
    }
    
    /* ------- Dot Product, Cross Product ------- */
    
    /// cross product: `u × v`
    public static func × (u: Self, v: Self) -> Field {
        return u.x * v.y - u.y * v.x  // x1 y2 - x2 y1
    }
    /// dot product: `u • v`
    public static func • (u: Self, v: Self) -> Field {
        return u.x * v.x + u.y * v.y  // x1 x2 + y1 y2
    }
    
    /* ------- Complex Number ------- */
    
    /// complex multiplication: `u * v`
    public static func * (u: Self, v: Self) -> Self {
        let (a,b,c,d) = (u.x, u.y, v.x, v.y)       // u = a + bi, v = a - bi
        return Self.init(x: a * c - b * d, y: a * d + b * c) // uv = (ac-bd) + (ad+bc)i
    }
    
    /// complex multiplication: u *= v
    public static func *= (u: inout Self, v: Self) {
        u = u * v
    }
    
    /* ------- Other Operations ------- */
    
    /// (non-proportional scale)
    /// if `u = [a,b], v = [c,d]`, then `u ** v = [ac, bd]`
    public static func ** (u: Self, v: Self) -> Self {
        return Self.init(x: u.x * v.x, y: u.y * v.y)
    }
    
}
// MARK: - Field == CGFloat -
extension Vector2D where Field == CGFloat {
    
    /* ------- Polar Coordinates ------- */
    
    /// polar form of a 2D vector
    /// - Parameters:
    ///   - r: radius
    ///   - a: angle (in radian)
    /// - Returns: `Self`: the conforming type
    public static func polar(_ r: Field, _ a: Field) -> Self {
        Self.init(x: r * cos(a), y: r * sin(a))
    }
    
    /* ------- Vector2D to CGPoint ------- */
    
    /// turn a `Vector2D` into `CGPoint`
    ///
    /// Example:
    /// ```
    /// let size = CGSize(width: 20, height: 30)
    /// let p = size.point      // CGPoint(x: 20, y: 30)
    /// ```
    public var point: CGPoint { CGPoint(x: x, y: y) }
    
    /* ------- `Rectangular` conformance ------- */
    
    // automatically conforms to `Rectangular`
    public var origin: CGPoint { .zero }
    public var size  : CGSize  {  CGSize(width: x, height: y) }
}
// MARK: - Conforming Types -
// 🌀CGPoint + Vector2D
extension CGPoint: Vector2D {}
// 🌀CGSize + Vector2D
extension CGSize: Vector2D {
    public var x: CGFloat { width }
    public var y: CGFloat { height }
    public init(x: CGFloat, y: CGFloat) {
        self.init(width: x, height: y)
    }
}
// 🌀CGVector + Vector2D
extension CGVector: Vector2D {
    public var x: CGFloat { dx }
    public var y: CGFloat { dy }
    public init(x: CGFloat, y: CGFloat) {
        self.init(dx: x, dy: y)
    }
}
// 🌀UnitPoint + Vector2D
@available(iOS 13, macOS 10.15, *)
extension UnitPoint: Vector2D {}// 2020.10.10 + vec.point (Vector2D -> CGPoint)
// 2020.03.09 + operator "u ÷ v", "u ÷= v", "u += v"
// ---------------------
//      🅿️ Vector2D
// ---------------------
import SwiftUI
// ⭐️ define custom operators
infix operator ×  : MultiplicationPrecedence  // cross (determinant)
infix operator •  : MultiplicationPrecedence  // dot   (• : opt + 8)
infix operator ** : MultiplicationPrecedence  // non-proportional scale
infix operator **=: MultiplicationPrecedence
// 2022.03.09
// (a,b) ÷ (c,d) == (a/c, b/d)
infix operator ÷  : MultiplicationPrecedence 
infix operator ÷= : MultiplicationPrecedence
// 🅿️ Vector2D
public protocol Vector2D: ExpressibleByArrayLiteral, Rectangular {
    
    associatedtype Field: FloatingPoint     // support +,-,*,/
    
    // x, y coordinates
    var x: Field { get }
    var y: Field { get }
    
    // initializer
    init(x: Field, y: Field)
    
    // vector addition: u + v
    // (default implementation provided)
    static func + (u: Self, v: Self) -> Self
    
    // additive inverse: -v
    // (default implementation provided)
    static prefix func - (u: Self) -> Self
}
// MARK: - Vector2D protocol extension -
// default behaviors
extension Vector2D {
    
    /* ------- Constants ------- */
    
    public static var i: Self { return Self.init(x: 1, y: 0) }
    public static var j: Self { return Self.init(x: 0, y: 1) }
    
    /* ------- Initializers ------- */
    
    /// make `Vector2D` conform to `ExpressibleByArrayLiteral`
    ///
    /// Example:
    /// ```
    /// let p: CGPoint = [1, 2]
    /// ```
    public init(arrayLiteral elements: Field...) {
        let a = elements + [0, 0]   // padding 0's
        self.init(x: a[0], y: a[1])
    }
    
    /// convenience initializer
    ///
    /// example:
    /// ```
    /// let p = CGPoint(1, 2)
    /// ```
    public init(_ x: Field, _ y: Field) {
        self.init(x: x, y: y)
    }
    
    /* ------- Linear Combinations ------- */
    
    /// u + v
    public static func + (u: Self, v: Self) -> Self {
        return Self.init(x: u.x + v.x, y: u.y + v.y)
    }
    
    // 2022.03.09
    /// u += v
    public static func += (u: inout Self, v: Self) {
        u = u + v
    }
    
    /// -v (additive inverse)
    public static prefix func - (v: Self) -> Self {
        return Self.init(x: -v.x, y: -v.y)
    }
    
    /// vector subtraction
    /// `u - v == u + (-v)`
    public static func - (u: Self, v: Self) -> Self {
        return u + (-v)
    }
    
    /* ------- Scalar Multiplication ------- */
    
    /// a * v
    public static func * (a: Field, v: Self) -> Self {
        return Self.init(x: a * v.x, y: a * v.y)
    }
    /// v * a
    public static func * (v: Self, a: Field) -> Self {
        return a * v
    }
    /// v / a
    public static func / (v: Self, a: Field) -> Self {
        return Self.init(x: v.x / a, y: v.y / a)
    }
    
    /* ------- Dot Product, Cross Product ------- */
    
    /// cross product: `u × v`
    public static func × (u: Self, v: Self) -> Field {
        return u.x * v.y - u.y * v.x  // x1 y2 - x2 y1
    }
    /// dot product: `u • v`
    public static func • (u: Self, v: Self) -> Field {
        return u.x * v.x + u.y * v.y  // x1 x2 + y1 y2
    }
    
    /* ------- Complex Number ------- */
    
    /// complex multiplication: `u * v`
    public static func * (u: Self, v: Self) -> Self {
        let (a,b,c,d) = (u.x, u.y, v.x, v.y)       // u = a + bi, v = a - bi
        return Self.init(x: a * c - b * d, y: a * d + b * c) // uv = (ac-bd) + (ad+bc)i
    }
    
    /// complex multiplication: u *= v
    public static func *= (u: inout Self, v: Self) {
        u = u * v
    }
    
    /* ------- non-proportional scale ------- */
    
    /// `(a,b) ** (c,d) == (ac, bd)`
    public static func ** (u: Self, v: Self) -> Self {
        return Self.init(x: u.x * v.x, y: u.y * v.y)
    }
    
    // 2022.03.09
    /// `(a,b) ÷ (c,d) == (a/c, b/d)`
    public static func ÷ (u: Self, v: Self) -> Self {
        return Self.init(x: u.x / v.x, y: u.y / v.y)
    }
    
    /// `(a,b) ÷= (c,d): (a,b) => (a/c, b/d)`
    public static func ÷= (u: inout Self, v: Self) {
        u = u ÷ v
    }
    
}
// MARK: - Field == CGFloat -
extension Vector2D where Field == CGFloat {
    
    /* ------- Polar Coordinates ------- */
    
    /// polar form of a 2D vector
    /// - Parameters:
    ///   - r: radius
    ///   - a: angle (in radian)
    /// - Returns: `Self`: the conforming type
    public static func polar(_ r: Field, _ a: Field) -> Self {
        Self.init(x: r * cos(a), y: r * sin(a))
    }
    
    /* ------- Vector2D to CGPoint ------- */
    
    /// turn a `Vector2D` into `CGPoint`
    ///
    /// Example:
    /// ```
    /// let size = CGSize(width: 20, height: 30)
    /// let p = size.point      // CGPoint(x: 20, y: 30)
    /// ```
    public var point: CGPoint { CGPoint(x: x, y: y) }
    
    /* ------- `Rectangular` conformance ------- */
    
    // automatically conforms to `Rectangular`
    public var origin: CGPoint { .zero }
    public var size  : CGSize  {  CGSize(width: x, height: y) }
}
// MARK: - Conforming Types -
// 🌀CGPoint + Vector2D
extension CGPoint: Vector2D {}
// 🌀CGSize + Vector2D
extension CGSize: Vector2D {
    public var x: CGFloat { width }
    public var y: CGFloat { height }
    public init(x: CGFloat, y: CGFloat) {
        self.init(width: x, height: y)
    }
}
// 🌀CGVector + Vector2D
extension CGVector: Vector2D {
    public var x: CGFloat { dx }
    public var y: CGFloat { dy }
    public init(x: CGFloat, y: CGFloat) {
        self.init(dx: x, dy: y)
    }
}
// 🌀UnitPoint + Vector2D
@available(iOS 13, macOS 10.15, *)
extension UnitPoint: Vector2D {}Last updated
Was this helpful?