๐ ฟ๏ธRectangular
// 2021.11.24 + conform : ๐CGPoint + ๐
ฟ๏ธ Rectangular
// 2021.11.25 / fix : rect.inscribedSquare
// + property : rect.unitSquare (CGRect)
// + conform : ๐UnitPoint + ๐
ฟ๏ธ Rectangular
// 2022.03.09 + subscript: rect[point]
// ------------------------
// ๐
ฟ๏ธ Rectangular
// ------------------------
import SwiftUI
// ๐
ฟ๏ธ Rectangular
public protocol Rectangular {
var origin: CGPoint { get }
var size : CGSize { get }
}
// default behaviors
extension Rectangular {
// MARK: - Bounds -
/// the bounds (x-coordinates) of the range of width
public var boundsX: (CGFloat, CGFloat) {
let x1 = origin.x
let x2 = x1 + size.width
return (x1, x2)
}
/// the bounds (y-coordinates) of the range of height
public var boundsY: (CGFloat, CGFloat) {
let y1 = origin.y
let y2 = y1 + size.height
return (y1, y2)
}
// MARK: - Coordinates -
/// lower bound (x-coordinate) of the width
public var minX: CGFloat {
return min(boundsX.0, boundsX.1)
}
/// upper bound (x-coordinate) of the width
public var maxX: CGFloat {
return max(boundsX.0, boundsX.1)
}
/// midpoint (x-coordinate) of the width
public var midX: CGFloat {
origin.x + size.width / 2
}
/// lower bound (y-coordinate) of the height
public var minY: CGFloat {
return min(boundsY.0, boundsY.1)
}
/// upper bound (y-coordinate) of the height
public var maxY: CGFloat {
return max(boundsY.0, boundsY.1)
}
/// midpoint (y-coordinate) of the height
public var midY: CGFloat {
origin.y + size.height / 2
}
// MARK: - Points -
// 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 corner points of a rect
public var corners: [CGPoint] { [bottomLeft, bottomRight, topRight, topLeft] }
/// a point relative to the rect
/// ```
/// rect[1,0] == rect.topRight
/// rect[0,1] == rect.bottomLeft
/// ```
public subscript(_ s: CGFloat, _ t: CGFloat) -> CGPoint {
let x = minX + s * abs(width)
let y = minY + t * abs(height)
return CGPoint(x: x, y: y)
}
// 2022.03.09
/// relative point in rect.
/// ```
/// rect[point]
/// ```
public subscript<V: Vector2D>(_ v: V) -> CGPoint where V.Field == CGFloat {
let x = minX + v.x * abs(width)
let y = minY + v.y * abs(height)
return CGPoint(x: x, y: y)
}
// MARK: - Dimensions -
// โ ๏ธ abs() ็่จญๅฎๅฐๅทฒ็ถๆ width ๅฑฌๆง็้กๅฅๆ่ฉฒ็กๆโ๏ธ
public var width : CGFloat { abs(size.width) }
public var height : CGFloat { abs(size.height) }
public var minSide: CGFloat { min(abs(width), abs(height)) }
public var maxSide: CGFloat { max(abs(width), abs(height)) }
public var aspectRatio: CGFloat { abs(width/height) }
// MARK: - Rect -
/// unit square of conforming type
public static var unitSquare: CGRect {
CGRect(origin: [0.0, 0.0], size: [1.0, 1.0])
}
public var rect: CGRect {
CGRect(origin: origin, size: size)
}
public var boundingSquare: CGRect {
let d = maxSide / 2
let x = midX - d
let y = midY - d
return CGRect(x: x, y: y, width: maxSide, height: maxSide)
}
public var inscribedSquare: CGRect {
let d = minSide / 2
let x = midX - d
let y = midY - d
return CGRect(x: x, y: y, width: minSide, height: minSide)
}
}
// MARK: - Conforming Types -
// ๐CGRect + ๐
ฟ๏ธ Rectangular
extension CGRect: Rectangular { }
// ๐GeometryProxy + Rectangular
@available(iOS 13, macOS 10.15, *)
extension GeometryProxy: Rectangular {
public var origin: CGPoint { .zero }
}
// the following conforms to `Rectangular` automatically
// ๐CGSize + ๐
ฟ๏ธ Rectangular
// ๐CGPoint + ๐
ฟ๏ธ Rectangular
// ๐UnitPoint + ๐
ฟ๏ธ Rectangular
History
2021.11.15
2022.03.09
2020.10.11๏ผ๐ฃ ๆฐๅ ๅ ฅใ
2020.10.12๏ผโ .rect, .boundingSquare
2020.10.22๏ผ
โ๏ธ .minSide, .maxSide ๅ ๅ ฅ abs(), ้ฟๅ ๆไบๅๅฅ็ width, height ๆ่ฒ ๅผ
โ .aspectRatio (width / height)
โ .inscribedSquare
//
// Rectangular.swift
// -----------------
// 1.0.0: 2021/11/18
// 1.0.1: 2021/11/24 + ๐CGPoint + ๐
ฟ๏ธ Rectangular
// 1.0.2: 2021/11/25 - fix `inscribedSquare` bug
//
import SwiftUI
// ๐
ฟ๏ธ Rectangular
public protocol Rectangular {
var origin: CGPoint { get }
var size : CGSize { get }
}
// default behaviors
extension Rectangular {
// MARK: - Bounds -
/// the bounds (x-coordinates) of the range of width
public var boundsX: (CGFloat, CGFloat) {
let x1 = origin.x
let x2 = x1 + size.width
return (x1, x2)
}
/// the bounds (y-coordinates) of the range of height
public var boundsY: (CGFloat, CGFloat) {
let y1 = origin.y
let y2 = y1 + size.height
return (y1, y2)
}
// MARK: - Coordinates -
/// lower bound (x-coordinate) of the width
public var minX: CGFloat {
return min(boundsX.0, boundsX.1)
}
/// upper bound (x-coordinate) of the width
public var maxX: CGFloat {
return max(boundsX.0, boundsX.1)
}
/// midpoint (x-coordinate) of the width
public var midX: CGFloat {
origin.x + size.width / 2
}
/// lower bound (y-coordinate) of the height
public var minY: CGFloat {
return min(boundsY.0, boundsY.1)
}
/// upper bound (y-coordinate) of the height
public var maxY: CGFloat {
return max(boundsY.0, boundsY.1)
}
/// midpoint (y-coordinate) of the height
public var midY: CGFloat {
origin.y + size.height / 2
}
// MARK: - Points -
// 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 corner points of a rect
public var corners: [CGPoint] { [bottomLeft, bottomRight, topRight, topLeft] }
/// a point relative to the rectangle's size (width, height)
///
/// ```
/// rect[1,0] == rect.topRight
/// rect[0,1] == rect.bottomLeft
/// ```
public subscript(_ s: CGFloat, _ t: CGFloat) -> CGPoint {
let x = minX + s * abs(width)
let y = minY + t * abs(height)
return CGPoint(x: x, y: y)
}
// MARK: - Dimensions -
public var width : CGFloat { abs(size.width) } // โ ๏ธ abs() ็่จญๅฎๅฐๅทฒ็ถๆ width ๅฑฌๆง็้กๅฅๆ่ฉฒ็กๆโ๏ธ
public var height : CGFloat { abs(size.height) }
public var minSide: CGFloat { min(abs(width), abs(height)) }
public var maxSide: CGFloat { max(abs(width), abs(height)) }
public var aspectRatio: CGFloat { abs(width/height) }
// MARK: - Rect -
public var rect: CGRect {
CGRect(origin: origin, size: size)
}
public var boundingSquare: CGRect {
let d = maxSide / 2
let x = midX - d
let y = midY - d
return CGRect(x: x, y: y, width: maxSide, height: maxSide)
}
public var inscribedSquare: CGRect {
let d = minSide / 2
let x = midX - d
let y = midY - d
return CGRect(x: x, y: y, width: minSide, height: minSide)
}
}
// MARK: - Conforming Types -
// ๐CGRect + ๐
ฟ๏ธ Rectangular
extension CGRect: Rectangular { }
// ๐CGSize + ๐
ฟ๏ธ Rectangular
extension CGSize: Rectangular {
public var origin: CGPoint { .zero }
public var size : CGSize { self }
}
// ๐CGPoint + ๐
ฟ๏ธ Rectangular
extension CGPoint: Rectangular {
public var origin: CGPoint { .zero }
public var size : CGSize { CGSize(width: x, height: y) }
}
// ๐GeometryProxy + ๐
ฟ๏ธ Rectangular
extension GeometryProxy: Rectangular {
public var origin: CGPoint { .zero }
}
// [2021]
// 11.18
// 11.24 + ๐CGPoint + ๐
ฟ๏ธ Rectangular
// 11.25 - fix `inscribedSquare`,
// + Self.unitSquare
// + ๐UnitPoint + ๐
ฟ๏ธ Rectangular
// 2022.02.22 (r) unitSquare: minor edit
// ------------------------
// ๐
ฟ๏ธ Rectangular
// ------------------------
import SwiftUI
// ๐
ฟ๏ธ Rectangular
public protocol Rectangular {
var origin: CGPoint { get }
var size : CGSize { get }
}
// default behaviors
extension Rectangular {
// MARK: - Bounds -
/// the bounds (x-coordinates) of the range of width
public var boundsX: (CGFloat, CGFloat) {
let x1 = origin.x
let x2 = x1 + size.width
return (x1, x2)
}
/// the bounds (y-coordinates) of the range of height
public var boundsY: (CGFloat, CGFloat) {
let y1 = origin.y
let y2 = y1 + size.height
return (y1, y2)
}
// MARK: - Coordinates -
/// lower bound (x-coordinate) of the width
public var minX: CGFloat {
return min(boundsX.0, boundsX.1)
}
/// upper bound (x-coordinate) of the width
public var maxX: CGFloat {
return max(boundsX.0, boundsX.1)
}
/// midpoint (x-coordinate) of the width
public var midX: CGFloat {
origin.x + size.width / 2
}
/// lower bound (y-coordinate) of the height
public var minY: CGFloat {
return min(boundsY.0, boundsY.1)
}
/// upper bound (y-coordinate) of the height
public var maxY: CGFloat {
return max(boundsY.0, boundsY.1)
}
/// midpoint (y-coordinate) of the height
public var midY: CGFloat {
origin.y + size.height / 2
}
// MARK: - Points -
// 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 corner points of a rect
public var corners: [CGPoint] { [bottomLeft, bottomRight, topRight, topLeft] }
/// a point relative to the rectangle's size (width, height)
///
/// ```
/// rect[1,0] == rect.topRight
/// rect[0,1] == rect.bottomLeft
/// ```
public subscript(_ s: CGFloat, _ t: CGFloat) -> CGPoint {
let x = minX + s * abs(width)
let y = minY + t * abs(height)
return CGPoint(x: x, y: y)
}
// MARK: - Dimensions -
// โ ๏ธ abs() ็่จญๅฎๅฐๅทฒ็ถๆ width ๅฑฌๆง็้กๅฅๆ่ฉฒ็กๆโ๏ธ
public var width : CGFloat { abs(size.width) }
public var height : CGFloat { abs(size.height) }
public var minSide: CGFloat { min(abs(width), abs(height)) }
public var maxSide: CGFloat { max(abs(width), abs(height)) }
public var aspectRatio: CGFloat { abs(width/height) }
// MARK: - Rect -
/// unit square of conforming type
public static var unitSquare: CGRect {
CGRect(origin: .zero, size: .init(width: 1, height: 1))
}
public var rect: CGRect {
CGRect(origin: origin, size: size)
}
public var boundingSquare: CGRect {
let d = maxSide / 2
let x = midX - d
let y = midY - d
return CGRect(x: x, y: y, width: maxSide, height: maxSide)
}
public var inscribedSquare: CGRect {
let d = minSide / 2
let x = midX - d
let y = midY - d
return CGRect(x: x, y: y, width: minSide, height: minSide)
}
}
// MARK: - Conforming Types -
// ๐CGRect + ๐
ฟ๏ธ Rectangular
extension CGRect: Rectangular { }
// ๐GeometryProxy + Rectangular
@available(iOS 13, macOS 10.15, *)
extension GeometryProxy: Rectangular {
public var origin: CGPoint { .zero }
}
// the following conforms to `Rectangular` automatically
// ๐CGSize + ๐
ฟ๏ธ Rectangular
// ๐CGPoint + ๐
ฟ๏ธ Rectangular
// ๐UnitPoint + ๐
ฟ๏ธ Rectangular
Last updated