# Vector2D

[swift](/ios/swift.md) ⟩ [type](/ios/swift/type.md) ⟩ [custom](/ios/custom.md) ⟩ [package](/ios/custom/package.md) ⟩ [GeometryKit](/ios/custom/package/geometrykit.md) ⟩ Vector2D&#x20;

{% hint style="info" %}

{% endhint %}

{% tabs %}
{% tab title=" 💾 程式" %}

````swift
// 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) }
}
````

{% endtab %}

{% tab title="📗 參考" %}

* [x] [Vector Algebra with Protocols](https://www.objc.io/blog/2018/11/29/vector-calculus-with-protocols/) - objc
  {% endtab %}

{% tab title="👥  相關 " %}

* [Vector](/ios/custom/package/geometrykit/vector.md)：comformed by <mark style="color:purple;">Vector2D</mark>
* [🔰 Floating Point](/ios/swift/type/category/basic/numbers/floating-point.md)
* [🌀 CGPoint](/ios/swift/scope/framework/built-in-frameworks/core-graphics/cgpoint.md)
* [🌀 CGVector](/ios/swift/scope/framework/built-in-frameworks/core-graphics/cgvector.md)
* [🌀 CGSize](/ios/swift/scope/framework/built-in-frameworks/core-graphics/cgsize.md)
  {% endtab %}

{% tab title="🗣 討論" %}

* [Mathematical operations on CGPoint in Swift](https://stackoverflow.com/questions/66000086/mathematical-operations-on-cgpoint-in-swift/70334764#70334764)
  {% endtab %}

{% tab title="⬇️ 應用" %}

* [UpArrowShape](/ios/swiftui/view/view/.dimension/uparrowshape.md) uses Vector2D.
* [Polygon](/ios/swiftui/shapes/shape/polygon.md)
* used in [Drag](/ios/swiftui/gestures/drag.md) gesture to add drag offset.
  {% endtab %}
  {% endtabs %}

## History

{% tabs %}
{% tab title="✏️ " %}

* 2020.09.30：➕  **CGRect** conforms to Vector2D  &#x20;
* 2020.10.08：➕  **unit vectors**: Vector2D.**i**, Vector2D.**j**, **v / a** (scalar **division**)
* 2020.10.10： ➊ 使用 associatedtype **Field**&#x20;
* 2020.10.22：➕  .**polar**(r, a) (conditional conformance)

#### Versions

1. 2020.10.10
2. 2022.02.09
3. 2022.03.09
   {% endtab %}

{% tab title="1" %}

```swift
// 封存日期：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) 
    }
}
```

{% endtab %}

{% tab title="2" %}

* :point\_right: GitHub ⟩ [Vector2D](https://github.com/lochiwei/Vector2D) (<https://github.com/lochiwei/Vector2D>)
* :point\_right: [replit](https://replit.com/@pegasusroe/Vector2D#Vector2D.swift)

```swift
/*
 * ⭐️ 為了配合 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))
    }
    
}
```

{% endtab %}

{% tab title="3" %}

````swift
// 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 {}
````

{% endtab %}

{% tab title="4" %}

````swift
// 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 {}
````

{% endtab %}
{% endtabs %}


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://lochiwei.gitbook.io/ios/custom/package/geometrykit/vector2d.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
