Skip to content

Commit 67f3571

Browse files
committed
feat: create new a 3D primitive called Size3D
1 parent b0345a7 commit 67f3571

3 files changed

Lines changed: 441 additions & 0 deletions

File tree

Lines changed: 251 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,251 @@
1+
import Foundation
2+
3+
/// A size that describes width, height, and depth in a 3D coordinate system.
4+
@frozen public struct Size3D : Codable, Copyable, Equatable, Hashable, Sendable {
5+
6+
// MARK: - Creating a 3D size structure
7+
8+
/// Creates a size structure.
9+
@inline(__always)
10+
public init() {
11+
self.width = 0.0
12+
self.height = 0.0
13+
self.depth = 0.0
14+
}
15+
16+
/// Creates a size structure from the specified double-precision values.
17+
///
18+
/// - Parameters:
19+
/// - width: A double-precision value that specifies the width.
20+
/// - height: A double-precision value that specifies the height.
21+
/// - depth: A double-precision value that specifies the depth.
22+
@inline(__always)
23+
public init(width: Double = 0, height: Double = 0, depth: Double = 0) {
24+
self.width = width
25+
self.height = height
26+
self.depth = depth
27+
}
28+
29+
/// Creates a size structure from the specified floating-point values.
30+
///
31+
/// - Parameters:
32+
/// - width: A floating-point value that specifies the width.
33+
/// - height: A floating-point value that specifies the height.
34+
/// - depth: A floating-point value that specifies the depth.
35+
@inline(__always)
36+
public init<T>(width: T, height: T, depth: T ) where T : BinaryFloatingPoint {
37+
self.width = Double(width)
38+
self.height = Double(height)
39+
self.depth = Double(depth)
40+
}
41+
42+
/// Creates a size structure from the specified vector.
43+
///
44+
/// - Parameter xyz: A vector that contains the width, height, and depth values.
45+
@inline(__always)
46+
public init(_ xyz: Vector3D) {
47+
(width, height, depth) = (xyz.x, xyz.y, xyz.z)
48+
}
49+
50+
// MARK: - Inspecting a 3D size’s properties
51+
52+
/// The width value.
53+
public let width: Double
54+
55+
/// The height value.
56+
public let height: Double
57+
58+
/// The depth value.
59+
public let depth: Double
60+
61+
/// Accesses the width, height, or depth value at the specified index.
62+
///
63+
/// - Parameter index: The index of the value to access. Valid indices are 0, 1, and 2.
64+
/// - Returns: The width, height, or depth value at the specified index.
65+
/// - Complexity: O(1)
66+
@inline(__always)
67+
public subscript(index: Int) -> Double {
68+
get {
69+
switch index {
70+
case 0: return width
71+
case 1: return height
72+
case 2: return depth
73+
default:
74+
fatalError("Index out of range. Valid indices are 0, 1, and 2.")
75+
}
76+
}
77+
}
78+
79+
// MARK: - 3D size constants
80+
81+
/// The size structure with width, height, and depth values of one.
82+
public static let one = Size3D(width: 1, height: 1, depth: 1)
83+
84+
// MARK: - Creating derived 3D sizes
85+
86+
/// Returns the intersection of two sizes.
87+
///
88+
/// - Parameter other: The size that the function compares against.
89+
/// - Returns: A new size that is the intersection of two sizes.
90+
@inline(__always)
91+
public func intersection(_ other: Size3D) -> Size3D? {
92+
let newWidth = min(self.width, other.width)
93+
let newHeight = min(self.height, other.height)
94+
let newDepth = min(self.depth, other.depth)
95+
96+
if newWidth >= 0 && newHeight >= 0 && newDepth >= 0 {
97+
return Size3D(width: newWidth, height: newHeight, depth: newDepth)
98+
} else {
99+
return nil
100+
}
101+
}
102+
}
103+
104+
extension Size3D : ExpressibleByArrayLiteral {
105+
106+
/// Creates an instance initialized with the given elements.
107+
///
108+
/// - Parameter elements: The elements of the array literal.
109+
@inline(__always)
110+
public init(arrayLiteral elements: Double...) {
111+
precondition(elements.count == 3, "Array literal must contain exactly three elements.")
112+
(width, height, depth) = (elements[0], elements[1], elements[2])
113+
}
114+
}
115+
116+
extension Size3D : AdditiveArithmetic {
117+
118+
// MARK: - Applying arithmetic operations
119+
120+
/// The zero size.
121+
public static let zero = Size3D()
122+
123+
/// Returns a size that’s the product of a size and a scalar value.
124+
///
125+
/// - Parameters:
126+
/// - lhs: The left-hand-side value.
127+
/// - rhs: The right-hand-side scalar value.
128+
/// - Returns: The product of the size and the scalar.
129+
/// - Complexity: O(1)
130+
@inline(__always)
131+
public static func * (lhs: Size3D, rhs: Double) -> Size3D {
132+
.init(width: lhs.width * rhs, height: lhs.height * rhs, depth: lhs.depth * rhs)
133+
}
134+
135+
/// Multiplies a size and a double-precision value, and stores the result in the left-hand-side variable.
136+
///
137+
/// - Parameters:
138+
/// - lhs: The left-hand-side value.
139+
/// - rhs: The right-hand-side value.
140+
/// - Complexity: O(1)
141+
@inline(__always)
142+
public static func *= (lhs: inout Size3D, rhs: Double) {
143+
lhs = lhs * rhs
144+
}
145+
146+
/// Adds two sizes and returns the result.
147+
///
148+
/// - Parameters:
149+
/// - lhs: The first size.
150+
/// - rhs: The second size.
151+
/// - Returns: The sum of the two sizes.
152+
/// - Complexity: O(1)
153+
@inline(__always)
154+
public static func + (lhs: Size3D, rhs: Size3D) -> Size3D {
155+
.init(width: lhs.width + rhs.width, height: lhs.height + rhs.height, depth: lhs.depth + rhs.depth)
156+
}
157+
158+
/// Adds the second size to the first size and stores the result in the first size.
159+
///
160+
/// - Parameters:
161+
/// - lhs: The first size.
162+
/// - rhs: The second size.
163+
/// - Complexity: O(1)
164+
@inline(__always)
165+
public static func += (lhs: inout Size3D, rhs: Size3D) {
166+
lhs = lhs + rhs
167+
}
168+
169+
/// Subtracts one size from another and returns the result.
170+
///
171+
/// - Parameters:
172+
/// - lhs: The first size.
173+
/// - rhs: The second size.
174+
/// - Returns: The difference of the two sizes.
175+
/// - Complexity: O(1)
176+
@inline(__always)
177+
public static func - (lhs: Size3D, rhs: Size3D) -> Size3D {
178+
.init(width: lhs.width - rhs.width, height: lhs.height - rhs.height, depth: lhs.depth - rhs.depth)
179+
}
180+
181+
/// Subtracts the second size from the first size and stores the result in the first size.
182+
///
183+
/// - Parameters:
184+
/// - lhs: The first size.
185+
/// - rhs: The second size.
186+
/// - Complexity: O(1)
187+
@inline(__always)
188+
public static func -= (lhs: inout Size3D, rhs: Size3D) {
189+
lhs = lhs - rhs
190+
}
191+
192+
/// Returns a size with each element divided by a scalar value.
193+
///
194+
/// - Parameters:
195+
/// - lhs: The left-hand-side value.
196+
/// - rhs: The right-hand-side value.
197+
/// - Returns: The resulting size.
198+
/// - Complexity: O(1)
199+
@inline(__always)
200+
public static func / (lhs: Size3D, rhs: Double) -> Size3D {
201+
.init(width: lhs.width / rhs, height: lhs.height / rhs, depth: lhs.depth / rhs)
202+
}
203+
204+
/// Divides each element of the size by a scalar value and stores the result in the left-hand-side variable.
205+
///
206+
/// - Parameters:
207+
/// - lhs: The left-hand-side value.
208+
/// - rhs: The right-hand-side value.
209+
/// - Complexity: O(1)
210+
@inline(__always)
211+
public static func /= (lhs: inout Size3D, rhs: Double) {
212+
lhs = lhs / rhs
213+
}
214+
}
215+
216+
extension Size3D : Primitive3D {
217+
// MARK: - Instance properties
218+
219+
/// A Boolean value that indicates whether the vector is finite.
220+
public var isFinite: Bool {
221+
width.isFinite && height.isFinite && depth.isFinite
222+
}
223+
224+
/// A Boolean value that indicates whether the vector contains any NaN values.
225+
public var isNaN: Bool {
226+
width.isNaN || height.isNaN || depth.isNaN
227+
}
228+
229+
/// A Boolean value that indicates whether the vector is zero.
230+
public var isZero: Bool {
231+
width == 0 && height == 0 && depth == 0
232+
}
233+
234+
// MARK: - Type properties
235+
236+
/// A size with infinite values.
237+
public static var infinity: Size3D {
238+
.init(width: .infinity, height: .infinity, depth: .infinity)
239+
}
240+
241+
// MARK: - Transforming primitives
242+
243+
// Applies an affine transform.
244+
///
245+
/// - Parameter transform: The affine transform to apply.
246+
/// - Returns: A new transformed size.
247+
/// - Complexity: O(1)
248+
public func applying(_ transform: AffineTransform3D) -> Size3D {
249+
fatalError("Size3D does not support applying affine transforms.")
250+
}
251+
}

Sources/OpenSpatial/Data structures/Vector3D.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ import Foundation
4444
/// The z-element value.
4545
public let z: Double
4646

47+
/// Accesses the x, y, or z value at the specified index.
48+
///
49+
/// - Parameter index: The index of the value to access. Valid indices are 0, 1, and 2.
50+
/// - Returns: The x, y, or z value at the specified index.
51+
/// - Complexity: O(1)
52+
@inline(__always)
53+
public subscript(index: Int) -> Double {
54+
get {
55+
switch index {
56+
case 0: return x
57+
case 1: return y
58+
case 2: return z
59+
default:
60+
fatalError("Index out of range. Valid indices are 0, 1, and 2.")
61+
}
62+
}
63+
}
64+
4765
// MARK: - Geometry functions
4866

4967
/// Returns the cross product of the vector and the specified vector.

0 commit comments

Comments
 (0)