Skip to content

Commit 428ced0

Browse files
authored
Merge pull request #52 from RougeWare/develop
Sync develop into master
2 parents d601b68 + 8e0abf8 commit 428ced0

File tree

4 files changed

+202
-1
lines changed

4 files changed

+202
-1
lines changed

Sources/RectangleTools/Synthesized Conveniences/Rectangle Extensions.swift

Lines changed: 82 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ public extension Rectangle
217217

218218

219219

220-
// MARK: -
220+
// MARK: - Repositioning
221221

222222
public extension Rectangle where Self.Length: ExpressibleByIntegerLiteral {
223223

@@ -380,3 +380,84 @@ public extension Rectangle
380380
y: self.minY)
381381
}
382382
}
383+
384+
385+
386+
// MARK: - Combination
387+
388+
public extension Rectangle
389+
where Length: Comparable,
390+
Length: AdditiveArithmetic
391+
{
392+
/// Returns the smallest rectangle which encompasses both this and the given one
393+
///
394+
/// ```
395+
/// │ │ │
396+
/// │ │ ┌────┐ │ ┏━━━━━━━━┯━━━━┓
397+
/// │ │ │ │ │ ┃ ┃
398+
/// │ .union(with: │ └────┘ ) == │ ┃ └ ─ ─┨
399+
/// │ ┌──────┐ │ │ ┠─ ─ ─ ┐ ┃
400+
/// │ └──────┘ │ │ ┗━━━━━━┷━━━━━━┛
401+
/// │ │ │
402+
/// ┼───────────────── ┼───────────────── ┼─────────────────
403+
/// ```
404+
///
405+
/// - Parameter other: The other rectangle which will be encompassed in the result
406+
func union(with other: Self) -> Self {
407+
return Self.init(
408+
minX: min(self.minX, other.minX),
409+
minY: min(self.minY, other.minY),
410+
maxX: max(self.maxX, other.maxX),
411+
maxY: max(self.maxY, other.maxY)
412+
)
413+
}
414+
}
415+
416+
417+
418+
public extension MutableRectangle
419+
where Length: Comparable,
420+
Length: AdditiveArithmetic
421+
{
422+
/// Converts this rectangle into the smallest rectangle which encompasses both this and the given one
423+
///
424+
/// ```
425+
/// │ │ │
426+
/// │ │ ┌────┐ │ ┏━━━━━━━━┯━━━━┓
427+
/// │ │ │ │ │ ┃ ┃
428+
/// │ .formUnion(with: │ └────┘ ) -> │ ┃ └ ─ ─┨
429+
/// │ ┌──────┐ │ │ ┠─ ─ ─ ┐ ┃
430+
/// │ └──────┘ │ │ ┗━━━━━━┷━━━━━━┛
431+
/// │ │ │
432+
/// ┼───────────────── ┼───────────────── ┼─────────────────
433+
/// ```
434+
///
435+
/// - Parameter other: The other rectangle which will be encompassed in the result
436+
mutating func formUnion(with other: Self) {
437+
let template = self.union(with: other)
438+
self.origin = template.origin
439+
self.size = template.size
440+
}
441+
}
442+
443+
444+
445+
public extension Collection
446+
where Element: Rectangle,
447+
Element.Length: Comparable,
448+
Element.Length: AdditiveArithmetic
449+
{
450+
/// Returns the smallest rectangle which encompasses all rectangles in a collection
451+
///
452+
/// See also: `Rectangle.union(with:)`
453+
func grandUnion() -> Element? {
454+
guard let first = self.first else {
455+
return nil
456+
}
457+
458+
return dropFirst()
459+
.reduce(into: first) { grandUnion, rectangle in
460+
grandUnion = grandUnion.union(with: rectangle)
461+
}
462+
}
463+
}

Tests/LinuxMain.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,4 +19,5 @@ tests += SizePositionTests.allTests
1919
tests += TwoDimensionalMeasurementTests.allTests
2020
tests += FourSidedTests.allTests
2121
tests += Rectangle_Edgewise_Init_Tests.allTests
22+
tests += Rectangle_Combination_Tests.allTests
2223
XCTMain(tests)
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
//
2+
// Rectangle Combination Tests.swift
3+
// RectangleTools
4+
//
5+
// Created by Ben Leggiero on 2020-08-05.
6+
// Copyright © 2019 Ben Leggiero BH-1-PS.
7+
//
8+
9+
import XCTest
10+
import RectangleTools
11+
12+
13+
14+
final class Rectangle_Combination_Tests: XCTestCase {
15+
16+
/// ```
17+
/// ↑
18+
/// │
19+
/// 6│
20+
/// 5│
21+
/// 4│
22+
/// 3│ ┏━━━━━━━━┓
23+
/// 2│ ┗━━━━━━━━┛
24+
/// 1│
25+
/// ←┼──────────────────→
26+
/// ↓ 1 2 3 4 5 6
27+
/// ```
28+
let rect__1_2__3_1 = DecimalRectangle(x: 1, y: 2, width: 3, height: 1)
29+
30+
/// ```
31+
/// ↑
32+
/// │
33+
/// 6│ ┏━━━━━┓
34+
/// 5│ ┃ ┃
35+
/// 4│ ┗━━━━━┛
36+
/// 3│
37+
/// 2│
38+
/// 1│
39+
/// ←┼──────────────────→
40+
/// ↓ 1 2 3 4 5 6
41+
/// ```
42+
let rect__4_4__2_2 = DecimalRectangle(x: 4, y: 4, width: 2, height: 2)
43+
44+
/// ```
45+
/// ↑
46+
/// │
47+
/// 6│
48+
/// 5│ ┏━━┓
49+
/// 4│ ┃ ┃
50+
/// 3│ ┗━━┛
51+
/// 2│
52+
/// 1│
53+
/// ←┼──────────────────→
54+
/// ↓ 1 2 3 4 5 6
55+
/// ```
56+
let rect__2_3__2_2 = DecimalRectangle(x: 2, y: 3, width: 2, height: 2)
57+
58+
59+
func test_union_with() {
60+
let union = rect__1_2__3_1.union(with: rect__4_4__2_2)
61+
62+
XCTAssertEqual(union.origin.x, 1)
63+
XCTAssertEqual(union.origin.y, 2)
64+
XCTAssertEqual(union.size.width, 5)
65+
XCTAssertEqual(union.size.height, 4)
66+
67+
let union2 = union.union(with: rect__2_3__2_2)
68+
69+
XCTAssertEqual(union2.origin.x, 1)
70+
XCTAssertEqual(union2.origin.y, 2)
71+
XCTAssertEqual(union2.size.width, 5)
72+
XCTAssertEqual(union2.size.height, 4)
73+
}
74+
75+
76+
func test_formUnion_with() {
77+
var union = rect__1_2__3_1
78+
union.formUnion(with: rect__4_4__2_2)
79+
80+
XCTAssertEqual(union.origin.x, 1)
81+
XCTAssertEqual(union.origin.y, 2)
82+
XCTAssertEqual(union.size.width, 5)
83+
XCTAssertEqual(union.size.height, 4)
84+
85+
union.formUnion(with: rect__2_3__2_2)
86+
87+
XCTAssertEqual(union.origin.x, 1)
88+
XCTAssertEqual(union.origin.y, 2)
89+
XCTAssertEqual(union.size.width, 5)
90+
XCTAssertEqual(union.size.height, 4)
91+
}
92+
93+
94+
func test_grandUnion() {
95+
for _ in (1...5) {
96+
let grandUnion = [
97+
rect__1_2__3_1,
98+
rect__2_3__2_2,
99+
rect__4_4__2_2,
100+
]
101+
.shuffled()
102+
.grandUnion()
103+
?? .init(origin: .zero, size: .zero)
104+
105+
XCTAssertEqual(grandUnion.origin.x, 1)
106+
XCTAssertEqual(grandUnion.origin.y, 2)
107+
XCTAssertEqual(grandUnion.size.width, 5)
108+
XCTAssertEqual(grandUnion.size.height, 4)
109+
}
110+
}
111+
112+
113+
static let allTests = [
114+
("test_union_with", test_union_with),
115+
("test_formUnion_with", test_formUnion_with),
116+
("test_grandUnion", test_grandUnion),
117+
]
118+
}

Tests/RectangleToolsTests/XCTestManifests.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ public func allTests() -> [XCTestCaseEntry] {
1919
testCase(TwoDimensionalMeasurementTests.allTests),
2020
testCase(FourSidedTests.allTests),
2121
testCase(Rectangle_Edgewise_Init_Tests.allTests),
22+
testCase(Rectangle_Combination_Tests.allTests),
2223
]
2324
}
2425
#endif

0 commit comments

Comments
 (0)