mirror of
https://github.com/TelegramMessenger/Telegram-iOS.git
synced 2026-07-05 19:28:46 +02:00
126 lines
3.9 KiB
Swift
126 lines
3.9 KiB
Swift
import Swift2D
|
|
|
|
/// A cartesian-based struct that describes the relationship of any particular `Point` to the _origin_ of a `Rect`.
|
|
public struct VectorPoint {
|
|
public enum Sign: String {
|
|
case plus = "+"
|
|
case minus = "-"
|
|
}
|
|
|
|
public typealias Offset = (sign: Sign, multiplier: Double)
|
|
|
|
public var x: Offset
|
|
public var y: Offset
|
|
|
|
public init(x: Offset, y: Offset) {
|
|
self.x = x
|
|
self.y = y
|
|
}
|
|
|
|
/// Initializes a `VectorPoint` for a given `Point` container in the provided `Rect`.
|
|
public init(point: Point, in rect: Rect) {
|
|
let radius = rect.size.maxRadius
|
|
let cartesianPoint = Self.cartesianPoint(for: point, in: rect)
|
|
|
|
if cartesianPoint.x < 0 {
|
|
x = (.minus, abs(cartesianPoint.x) / radius)
|
|
} else {
|
|
x = (.plus, cartesianPoint.x / radius)
|
|
}
|
|
|
|
if cartesianPoint.y < 0 {
|
|
y = (.plus, abs(cartesianPoint.y) / radius)
|
|
} else {
|
|
y = (.minus, cartesianPoint.y / radius)
|
|
}
|
|
}
|
|
}
|
|
|
|
// MARK: - CustomStringConvertible
|
|
|
|
extension VectorPoint: CustomStringConvertible {
|
|
public var description: String {
|
|
"VectorPoint(x: (\(x.sign.rawValue), \(x.multiplier)), y: (\(y.sign.rawValue), \(y.multiplier)))"
|
|
}
|
|
}
|
|
|
|
// MARK: - Equatable
|
|
|
|
extension VectorPoint: Equatable {
|
|
public static func == (lhs: VectorPoint, rhs: VectorPoint) -> Bool {
|
|
guard lhs.x.sign == rhs.x.sign else {
|
|
return false
|
|
}
|
|
guard lhs.x.multiplier == rhs.x.multiplier else {
|
|
return false
|
|
}
|
|
guard lhs.y.sign == rhs.y.sign else {
|
|
return false
|
|
}
|
|
guard lhs.y.multiplier == rhs.y.multiplier else {
|
|
return false
|
|
}
|
|
|
|
return true
|
|
}
|
|
}
|
|
|
|
// MARK: -
|
|
|
|
public extension VectorPoint {
|
|
/// Translates the provided point within the `Rect` from using the top-left
|
|
/// as the _origin_, to using the center as the _origin_.
|
|
///
|
|
/// For example: Given `Rect(x: 0, y: 0, width: 100, height: 100)`, the point
|
|
/// `Point(x: 25, y: 25)` would translate to `Point(x: -25, y: 25)`.
|
|
static func cartesianPoint(for point: Point, in rect: Rect) -> Point {
|
|
let origin = Point(x: rect.size.width / 2.0, y: rect.size.height / 2.0)
|
|
var cartesianPoint: Point = .zero
|
|
|
|
if point.x < origin.x {
|
|
cartesianPoint = cartesianPoint.x(-(origin.x - point.x))
|
|
} else if point.x > origin.x {
|
|
cartesianPoint = cartesianPoint.x(point.x - origin.x)
|
|
}
|
|
|
|
if point.y > origin.y {
|
|
cartesianPoint = cartesianPoint.y(-(point.y - origin.y))
|
|
} else if point.y < origin.y {
|
|
cartesianPoint = cartesianPoint.y(origin.y - point.y)
|
|
}
|
|
|
|
return cartesianPoint
|
|
}
|
|
}
|
|
|
|
// MARK: - Instance Functionality
|
|
|
|
public extension VectorPoint {
|
|
/// Calculates the `Point` for this instance in the specified `Rect`.
|
|
func translate(to rect: Rect) -> Point {
|
|
translate(to: rect.size)
|
|
}
|
|
|
|
/// Calculates the `Point` in the desired output size
|
|
func translate(to outputSize: Size) -> Point {
|
|
let center = outputSize.center
|
|
let radius = outputSize.minRadius
|
|
|
|
switch (x.sign, y.sign) {
|
|
case (.plus, .plus):
|
|
return Point(x: center.x + (radius * x.multiplier), y: center.y + (radius * y.multiplier))
|
|
case (.plus, .minus):
|
|
return Point(x: center.x + (radius * x.multiplier), y: center.y - (radius * y.multiplier))
|
|
case (.minus, .plus):
|
|
return Point(x: center.x - (radius * x.multiplier), y: center.y + (radius * y.multiplier))
|
|
case (.minus, .minus):
|
|
return Point(x: center.x - (radius * x.multiplier), y: center.y - (radius * y.multiplier))
|
|
}
|
|
}
|
|
}
|
|
|
|
public extension VectorPoint {
|
|
var coreGraphicsDescription: String {
|
|
"CGPoint(x: center.x \(x.sign.rawValue) (radius * \(x.multiplier)), y: center.y \(y.sign.rawValue) (radius * \(y.multiplier)))"
|
|
}
|
|
}
|