Skip to content

Commit f168105

Browse files
authored
Merge pull request #64 from RougeWare/feature/Scaling
`Rectangle` & `TwoDimensional` can now be scaled!
2 parents d91b866 + 7bd8fca commit f168105

File tree

9 files changed

+1880
-12
lines changed

9 files changed

+1880
-12
lines changed

.github/workflows/swift.yml renamed to .github/workflows/iOS.yml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
name: Swift
1+
name: iOS
22

3-
on: [push, pull_request]
3+
on: [pull_request]
44

55
jobs:
66
build:
@@ -10,10 +10,6 @@ jobs:
1010

1111
steps:
1212
- uses: actions/checkout@v1
13-
- name: Build
14-
run: swift build -v
15-
- name: Run tests
16-
run: swift test -v
1713
- name: Generate iOS xcodeproj
1814
run: swift package generate-xcodeproj
1915
- name: Run iOS tests

.github/workflows/macOS.yml

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
name: macOS
2+
3+
on: [pull_request]
4+
5+
jobs:
6+
build:
7+
8+
timeout-minutes: 5
9+
runs-on: macOS-latest
10+
11+
steps:
12+
- uses: actions/checkout@v1
13+
- name: Build
14+
run: swift build -v
15+
- name: Run tests
16+
run: swift test -v

README.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,22 @@
22

33
A set of Swift utilities for dealing with rectangles, including a way to generically build your own!
44

5+
This package includes new types such as `IntRect` and `UIntPoint`, conveniences for doing math with various points in rectangles, centering and scaling, generic protocols to unify math across all rectangular types, conveniences for measuring and placing rectangles, and much more.
6+
7+
Who knew there was so much to be done with rectangles?
8+
9+
10+
11+
## Thoroughly Tested ##
12+
13+
Over 2,000 test assertions prove that this library works as it says it does
14+
15+
16+
17+
## Battle Hardened ##
18+
19+
This library was created for enterprise-scale applications, and is being used by multiple corporations in production today.
20+
521

622

723
## SwiftUI ##

Sources/RectangleTools/Synthesized Conveniences/TwoDimensional Extensions.swift

Lines changed: 43 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,10 @@ public extension TwoDimensional where Length: BinaryFloatingPoint {
7979

8080

8181
/// The ratio of the X dimension to the Y dimension
82-
func aspectRatio() -> CGFloat {
83-
return abs(CGFloat(measurementX) / CGFloat(measurementY))
82+
func aspectRatio() -> CGFloat
83+
where Self.Length: MultiplicativeArithmetic
84+
{
85+
CGFloat(aspectRatioDoingGenericMathWithLengthType())
8486
}
8587
}
8688

@@ -89,8 +91,8 @@ public extension TwoDimensional where Length: BinaryFloatingPoint {
8991
public extension TwoDimensional where Length == Decimal {
9092

9193
/// The ratio of the X dimension to the Y dimension
92-
func aspectRatio() -> Length {
93-
return abs(measurementX / measurementY)
94+
func aspectRatio() -> Decimal {
95+
abs(measurementX / measurementY)
9496
}
9597
}
9698

@@ -163,9 +165,44 @@ public extension TwoDimensional where Length: BinaryInteger {
163165

164166

165167
/// The ratio of the X dimension to the Y dimension
166-
func aspectRatio() -> CGFloat {
167-
return abs(CGFloat(measurementX) / CGFloat(measurementY))
168+
func aspectRatio() -> CGFloat
169+
where Length: MultiplicativeArithmetic
170+
{
171+
CGFloat(aspectRatioDoingGenericMathWithLengthType())
172+
}
173+
}
174+
175+
176+
177+
public extension TwoDimensional
178+
where Length: MultiplicativeArithmetic,
179+
Length: AdditiveArithmetic,
180+
Length: Comparable,
181+
Length: ExpressibleByIntegerLiteral {
182+
183+
/// The ratio of the X dimension to the Y dimension. Wider objects result in a greater value. Square objects result in `1`
184+
///
185+
/// This specialization function is necessary because aspect ratios less than 1 cannot be represented by integers
186+
private func aspectRatioDoingGenericMathWithLengthType() -> CGFloat
187+
where Length: BinaryInteger
188+
{
189+
let raw = CGFloat(measurementX) / CGFloat(measurementY)
190+
return raw < 0
191+
? 0 - raw
192+
: raw
168193
}
194+
195+
/// The ratio of the X dimension to the Y dimension. Wider objects result in a greater value. Square objects result in `1`
196+
private func aspectRatioDoingGenericMathWithLengthType() -> Length {
197+
let raw = measurementX / measurementY
198+
return raw < 0
199+
? 0 - raw
200+
: raw
201+
}
202+
203+
204+
/// The ratio of the X dimension to the Y dimension. Wider objects result in a greater value. Square objects result in `1`
205+
func aspectRatio() -> Length { aspectRatioDoingGenericMathWithLengthType() }
169206
}
170207

171208

Sources/RectangleTools/Synthesized Conveniences/scaled.swift

Lines changed: 471 additions & 0 deletions
Large diffs are not rendered by default.

Tests/RectangleToolsTests/Test Constants.swift

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ import RectangleTools
1515
// MARK: - Test Sizes
1616

1717
enum TestSizes {
18+
19+
// MARK: Basic test sizes
1820

1921
/// ```
2022
/// ↑
@@ -190,6 +192,48 @@ enum TestSizes {
190192

191193

192194

195+
// MARK: Sizes for aspect ratio & scaling tests
196+
197+
extension CGSize {
198+
199+
// Wide
200+
201+
/// An extremely wide rectangle (`960×12`)
202+
static let extremelyWide__960_12 = CGSize(width: 960, height: 12)
203+
204+
/// A very wide rectangle (`96×12`)
205+
static let veryWide__96_12 = CGSize(width: 96, height: 12)
206+
207+
/// A somewhat wide rectangle (`18×12`)
208+
static let wide__18_12 = CGSize(width: 18, height: 12)
209+
210+
211+
// Square
212+
213+
/// A small square (`12×12`)
214+
static let squareSmall__12_12 = CGSize(width: 12, height: 12)
215+
216+
/// A medium square (`96×96`)
217+
static let squareMedium__96_96 = CGSize(width: 96, height: 96)
218+
219+
/// A large square (`960×960`)
220+
static let squareLarge__960_960 = CGSize(width: 960, height: 960)
221+
222+
223+
// Tall
224+
225+
/// A somewhat tall rectangle (`12×18`)
226+
static let tall__12_18 = CGSize(width: 12, height: 18)
227+
228+
/// A very tall rectangle (`12×96`)
229+
static let veryTall__12_96 = CGSize(width: 12, height: 96)
230+
231+
/// An extremely tall rectangle (`12×960`)
232+
static let extremelyTall__12_960 = CGSize(width: 12, height: 960)
233+
}
234+
235+
236+
193237
// MARK: - Test Points
194238

195239
enum TestPoints {
@@ -365,3 +409,11 @@ enum TestPoints {
365409
/// ```
366410
static let decimalPoint__3_n4 = DecimalPoint(x: 3, y: -4)
367411
}
412+
413+
414+
415+
// MARK: - Approximation
416+
417+
extension ExpressibleByFloatLiteral {
418+
static var approximationTolerance: Self { 0.001 }
419+
}
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
//
2+
// Testing convenience functions.swift
3+
//
4+
//
5+
// Created by Ky Leggiero on 2022-01-11.
6+
//
7+
8+
import Foundation
9+
import RectangleTools
10+
11+
12+
13+
infix operator &&= : AssignmentPrecedence
14+
infix operator ≈≈ : ComparisonPrecedence
15+
16+
17+
18+
/// Shorthand for `lhs = lhs && rhs`
19+
func &&= (lhs: inout Bool, rhs: @autoclosure () -> Bool) {
20+
if lhs, !rhs() {
21+
lhs = false
22+
}
23+
}
24+
25+
26+
27+
/// Whether the left-hand-side argument is approximately equal to the right-hand-side
28+
func ≈≈ <Value> (lhs: Value, rhs: Value) -> Bool
29+
where Value: FloatingPoint,
30+
Value: ExpressibleByFloatLiteral
31+
{
32+
abs(rhs - lhs) < .approximationTolerance
33+
}
34+
35+
36+
37+
/// Whether the left-hand-side argument is approximately equal to the right-hand-side
38+
func ≈≈ <Value> (lhs: Value, rhs: Value) -> Bool
39+
where Value: TwoDimensional,
40+
Value.Length: FloatingPoint,
41+
Value.Length: ExpressibleByFloatLiteral
42+
{
43+
lhs.measurementX ≈≈ rhs.measurementX
44+
&& lhs.measurementY ≈≈ rhs.measurementY
45+
}
46+
47+
48+
49+
/// Whether the left-hand-side argument is approximately equal to the right-hand-side
50+
func ≈≈ <Value> (lhs: Value, rhs: Value) -> Bool
51+
where Value: DualTwoDimensional,
52+
Value.FirstDimensionPair.Length: FloatingPoint,
53+
Value.FirstDimensionPair.Length: ExpressibleByFloatLiteral,
54+
Value.SecondDimensionPair.Length: FloatingPoint,
55+
Value.SecondDimensionPair.Length: ExpressibleByFloatLiteral
56+
{
57+
lhs.firstDimensionPair ≈≈ rhs.firstDimensionPair
58+
&& lhs.secondDimensionPair ≈≈ rhs.secondDimensionPair
59+
}

0 commit comments

Comments
 (0)