# CGRect

## 目前版本

{% tabs %}
{% tab title="🌀  CGRect" %}

```swift
/*
 * ⭐️ required: 
 *    - 🅿️ Rectangular
 */

import SwiftUI       // for CGRect

// 🌀CGRect + Rectangular
extension CGRect: Rectangular { }

// 🌀CGRect + convenience inits
extension CGRect {
    
    /// CGRect(x,y,w,h)
    public init(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) {
        self.init(x: x, y: y, width: width, height: height)
    }
    
    /// rect from one corner to another.
    /// `CGRect(from: A, to: B)`
    public init(from p1: CGPoint, to p2: CGPoint) {
        let x = p1.x
        let y = p1.y
        let w = p2.x - p1.x
        let h = p2.y - p1.y
        self.init(x: x, y: y, width: w, height: h)
    }
    
    /// rect with center and corner.
    /// - `CGRect(center: A, corner: B)`
    public init(center: CGPoint, corner: CGPoint) {
        let x = corner.x
        let y = corner.y
        let dx = center.x - corner.x
        let dy = center.y - corner.y
        self.init(x: x, y: y, width: 2 * dx, height: 2 * dy)
    }
    
    /* ------ Modifiers -------- */
    
    /// - turn a `CGRect` into `Path` 
    public var path: Path { Path(self) }
    
}
```

{% endtab %}

{% tab title="💈 範例" %}

```swift
import SwiftUI
// ⭐️ required: 🌀CGPoint+Vector2D, 🌀CGRect

// points
let A = CGPoint(40, 40)
let B = CGPoint(80, 70)

// rects
let rect1 = CGRect(from: A, to: B)       // origin: (40,40), size:(30,40)
let rect2 = CGRect(center: A, corner: B) // origin: ( 0,10), size:(60,80)
    
// instance members
rect1.point(0.5, 0.5)  // (60, 55)
rect2.point(1,1)       // (80, 70)
rect2.bottomRight      // (80, 70)
rect2.corners          // [(0,70), (80,70), (80,10), (0,10)]

// subscript
let p    = CGPoint(1,2)                       // 🌀CGPoint
let size = CGSize(20, 20)                     // 🌀CGSize
let rect = CGRect(origin: p, size: size / 2)  // 🌀CGSize + 🅿️Vector2D

rect[ 0, 0]   // (  1,   2)
rect[ 1, 0]   // ( 11,   2)
rect[ 0, 1]   // (  1,  12)
rect[ 2, 1]   // ( 21,  12)
rect[-2,-2]   // (-19, -18)
```

{% endtab %}

{% tab title="👨‍🦳 " %}

* [🌀 Rectangular](https://lochiwei.gitbook.io/ios/custom/package/geometrykit/frame)
  {% endtab %}

{% tab title="👶 " %}

* [🌀 GeometryProxy](https://lochiwei.gitbook.io/ios/swiftui/view/measure/geometryproxy/geometryproxy)
  {% endtab %}

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

* [🌀 GeometryProxy](https://lochiwei.gitbook.io/ios/swiftui/view/measure/geometryproxy/geometryproxy)
* [📦  GeometryReader](https://lochiwei.gitbook.io/ios/swiftui/view/measure/geometryreader)
* [Calling Types As Functions](https://lochiwei.gitbook.io/ios/features/callasfunction)
  {% endtab %}

{% tab title="🍎 " %}

* CoreGraphics  ⟩  [CGRect](https://developer.apple.com/documentation/coregraphics/cgrect)
* CoreGraphics  ⟩  [CGPoint](https://developer.apple.com/documentation/coregraphics/cgpoint?language=occ)
  {% endtab %}

{% tab title="✏️  紀錄" %}

* 2020.09.30：➕ added .**path**&#x20;
* 2020.10.08：\
  ➕ .**maxSide** \
  ✏️ ~~minLength~~ ➝ **minSide**\
  ➕ **CGRect**(x, y, w, h)\
  ➕ **subscript**: rect\[x, y]
  {% endtab %}
  {% endtabs %}

## 修改記錄

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

* 2020.09.30：➕ added .**path**&#x20;
* 2020.10.08：\
  ➕ .**maxSide** \
  ✏️ ~~minLength~~ ➝ **minSide**\
  ➕ **CGRect**(x, y, w, h)\
  ➕ **subscript**: rect\[x, y]
* ➊ 2020.10.11：將大部分的功能移至 [Rectangular](https://lochiwei.gitbook.io/ios/custom/package/geometrykit/frame)
  {% endtab %}

{% tab title="➊" %}

```swift
// 封存日期：2020.10.11
// 修改內容：
// 1. 將大部分的功能移至 Rectangular
// 2. 移除對 Vector2D 的依賴
// ------------------------------------

/*
 * ⭐️ required: 
 *    - 🅿️ Vector2D
 */

import SwiftUI       // for CGRect
import VectorSpace   // for 🅿️ Vector2D

// 🌀CGRect
extension CGRect {
    
    /* ------- ⭐️ Points ------- */
    
    /// # Key Points of a CGRect
    /// - Example: `.top`, `.bottom`, `.center`, ...
    public enum KeyPoint: CaseIterable {
        case topLeft, top, topRight
        case left, center, right
        case bottomLeft, bottom, bottomRight
    }
    
    // `rect.point(at: .top) == rect.top`
    public func point(at position: KeyPoint) -> CGPoint {
        switch position {
        case .topLeft    : return topLeft
        case .top        : return top
        case .topRight   : return topRight
        case .left       : return left
        case .center     : return center
        case .right      : return right
        case .bottomLeft : return bottomLeft
        case .bottom     : return bottom
        case .bottomRight: return bottomRight
        }
    }
    
    // rect.top, ...
    public var top        : CGPoint { CGPoint(x: midX, y: minY) }
    public var bottom     : CGPoint { CGPoint(x: midX, y: maxY) }
    public var left       : CGPoint { CGPoint(x: minX, y: midY) }
    public var right      : CGPoint { CGPoint(x: maxX, y: midY) }
    public var center     : CGPoint { CGPoint(x: midX, y: midY) }
    public var bottomLeft : CGPoint { CGPoint(x: minX, y: maxY) }
    public var bottomRight: CGPoint { CGPoint(x: maxX, y: maxY) }
    public var topLeft    : CGPoint { CGPoint(x: minX, y: minY) }
    public var topRight   : CGPoint { CGPoint(x: maxX, y: minY) }
    
    /// 4 corners of a rect
    public var corners: [CGPoint] { [bottomLeft, bottomRight, topRight, topLeft] }
    
    /// # Relative Point
    ///   a point relative to the rectangle's width and height
    /// ## Examples
    /// - `rect.point(0,0) == rect.topLeft`
    /// - `rect.point(1,1) == rect.bottomRight`
    public func point(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
        let u = topRight - topLeft                     // 🅿️ Vector2D
        let v = bottomLeft - topLeft
        let w = x * u + y * v
        return topLeft + w  
    }
    
    /// ## Examples
    ///    - `rect[1,0] == rect.topRight`
    ///    - `rect[0,1] == rect.bottomLeft`
    public subscript(_ x: CGFloat, _ y: CGFloat) -> CGPoint {
        point(x, y)
    }
    
    /* ------- ⭐️ Dimensions ------- */
    
    /// side length of the rect.
    public var minSide: CGFloat { min(width, height) }
    public var maxSide: CGFloat { max(width, height) }
    
    /* ------- ⭐️ Initializers ------- */
    
    /// CGRect(x,y,w,h)
    public init(_ x: CGFloat, _ y: CGFloat, _ width: CGFloat, _ height: CGFloat) {
        self.init(x: x, y: y, width: width, height: height)
    }
    
    /// draws a `CGRect` from a corner to another corner.
    /// `CGRect(from: A, to: B)`
    public init(from p1: CGPoint, to p2: CGPoint) {
        let x = min(p1.x, p2.x)
        let y = min(p1.y, p2.y)
        let w = abs(p1.x - p2.x)
        let h = abs(p1.y - p2.y)
        self.init(x: x, y: y, width: w, height: h)
    }
    
    /// draws a `CGRect` with center and a corner.
    /// - `CGRect(center: A, corner: B)`
    public init(center p1: CGPoint, corner p2: CGPoint) {
        self.init(from: p2, to: 2 * p1 - p2)             // 🅿️ Vector2D
    }
    
    /* ------ Modifiers -------- */
    
    /// - turn a `CGRect` into `Path` 
    public var path: Path { Path(self) }
    
}
```

{% endtab %}
{% endtabs %}
