From c664babebd99bab44fad851aa5987899792f5104 Mon Sep 17 00:00:00 2001
From: Richard Piazza
-
-
-
-
-
-
- A Swift implementation of the Cartesian Coordinate System. -
- -## Installation - -**GraphPoint** is distributed using the [Swift Package Manager](https://swift.org/package-manager). To install it into a project, add it as a -dependency within your `Package.swift` manifest: - -```swift -let package = Package( - ... - dependencies: [ - .package(url: "https://github.com/richardpiazza/GraphPoint.git", from: "4.0.0") - ], - ... -) -``` - -Then import **GraphPoint** wherever you'd like to use it: +A Swift implementation of the Cartesian Coordinate System. -```swift -import GraphPoint -``` +[](https://swiftpackageindex.com/richardpiazza/GraphPoint) +[](https://swiftpackageindex.com/richardpiazza/GraphPoint) ## Dependencies **GraphPoint** relies heavily on the **[Swift2D](https://github.com/richardpiazza/Swift2D)** library, which reimplements `Rect`, `Size`, and `Point` in a cross-platform, non-Foundation reliant way. -## Deprecations - -The `CoreGraphics` aliases have been deprecated and replaced by their _Cartesian_ counterparts. These type-aliases and -**GraphPointUI** will be removed in a future version. - ## Usage There are several key aspects to understand when using **GraphPoint**. @@ -73,3 +40,29 @@ cartesianFrame == Rect(origin: Point(x: -10, y: 10), size: Size(width: 10, heigh ### `CartesianPoint` A point within a `CartesianPlane`. The x & y coordinates of a `CartesianPoint` represent the offset from the planes 'origin' (0, 0). + +## Deprecations + +The `CoreGraphics` aliases have been deprecated and replaced by their _Cartesian_ counterparts. These type-aliases and +**GraphPointUI** will be removed in a future version. + +## Installation + +**GraphPoint** is distributed using the [Swift Package Manager](https://swift.org/package-manager). To install it into a project, add it as a +dependency within your `Package.swift` manifest: + +```swift +let package = Package( + ... + dependencies: [ + .package(url: "https://github.com/richardpiazza/GraphPoint.git", from: "4.0.0") + ], + ... +) +``` + +Then import **GraphPoint** wherever you'd like to use it: + +```swift +import GraphPoint +``` diff --git a/Sources/GraphPoint/Arc.swift b/Sources/GraphPoint/Arc.swift index 0f4baa9..9d97db9 100644 --- a/Sources/GraphPoint/Arc.swift +++ b/Sources/GraphPoint/Arc.swift @@ -1,11 +1,16 @@ /// Arc of a circle (a continuous length around the circumference) -public struct Arc { +public struct Arc: Hashable, Codable, Sendable { public var radius: Radius public var startingDegree: Degree public var endingDegree: Degree public var clockwise: Bool - - public init(radius: Radius = 0.0, startingDegree: Degree = 0.0, endingDegree: Degree = 0.0, clockwise: Bool = true) { + + public init( + radius: Radius = 0.0, + startingDegree: Degree = 0.0, + endingDegree: Degree = 0.0, + clockwise: Bool = true + ) { self.radius = radius self.startingDegree = startingDegree self.endingDegree = endingDegree @@ -19,37 +24,41 @@ public extension Arc { guard let point = try? CartesianPoint.make(for: radius, degree: startingDegree) else { return .zero } - + return point } - + /// The `CartesianPoint` that represents the ending point var endingPoint: CartesianPoint { guard let point = try? CartesianPoint.make(for: radius, degree: endingDegree) else { return .zero } - + return point } - + /// Calculates the point of the right angle that joins the start and end points. var pivotPoint: CartesianPoint { var pivot = CartesianPoint(x: 0, y: 0) - + if startingDegree < 90 { - pivot.x = endingPoint.x - pivot.y = startingPoint.y + pivot = pivot + .with(x: endingPoint.x) + .with(y: startingPoint.y) } else if startingDegree < 180 { - pivot.x = startingPoint.x - pivot.y = endingPoint.y + pivot = pivot + .with(x: startingPoint.x) + .with(y: endingPoint.y) } else if startingDegree < 270 { - pivot.x = endingPoint.x - pivot.y = startingPoint.y + pivot = pivot + .with(x: endingPoint.x) + .with(y: startingPoint.y) } else { - pivot.x = startingPoint.x - pivot.y = endingPoint.y + pivot = pivot + .with(x: startingPoint.x) + .with(y: endingPoint.y) } - + return pivot } } diff --git a/Sources/GraphPoint/CartesianFrame.swift b/Sources/GraphPoint/CartesianFrame.swift index c57d6b0..9c0ba35 100644 --- a/Sources/GraphPoint/CartesianFrame.swift +++ b/Sources/GraphPoint/CartesianFrame.swift @@ -14,7 +14,7 @@ public typealias CartesianFrame = Rect public extension CartesianFrame { typealias Offset = Point - + /// The _x_ & _y_ offset required to reach the cartesian origin of the plane that contains this frame. /// /// The size of the plane is irrelevant. The assumption being made is that the plane is equal to or larger than the @@ -40,7 +40,7 @@ public extension CartesianFrame { /// └────────────────────────▼───────────────────────┘ /// ``` var offsetToCartesianOrigin: Offset { - return (x <= 0) ? Offset(x: abs(x), y: y) : Offset(x: -(x), y: y) + (x <= 0) ? Offset(x: abs(x), y: y) : Offset(x: -x, y: y) } } @@ -53,27 +53,27 @@ public extension CartesianFrame { static func make(for points: [CartesianPoint]) -> CartesianFrame { var minXMaxY = Point() var maxXMinY = Point() - + // TODO: Check the logic here. Is checking == 0 needed, or could it provide false results? - - points.forEach { (point) in + + for point in points { if point.x < minXMaxY.x || minXMaxY.x == 0 { - minXMaxY.x = point.x + minXMaxY = minXMaxY.with(x: point.x) } - + if point.y > minXMaxY.y || minXMaxY.y == 0 { - minXMaxY.y = point.y + minXMaxY = minXMaxY.with(y: point.y) } - + if point.x > maxXMinY.x || maxXMinY.x == 0 { - maxXMinY.x = point.x + maxXMinY = maxXMinY.with(x: point.x) } - + if point.y < maxXMinY.y || maxXMinY.y == 0 { - maxXMinY.y = point.y + maxXMinY = maxXMinY.with(y: point.y) } } - + return CartesianFrame( origin: minXMaxY, size: Size( @@ -82,7 +82,7 @@ public extension CartesianFrame { ) ) } - + /// Identifies the minimum `CartesianFrame` that contains the provided points, accounting for any expansion needed /// when crossing an axis at a given distance (radius) from the origin. /// @@ -122,38 +122,48 @@ public extension CartesianFrame { let startQuadrant = try Quadrant(degree: arc.startingDegree, clockwise: arc.clockwise) let endQuadrant = try Quadrant(degree: arc.endingDegree, clockwise: arc.clockwise) var frame = make(for: points) - + guard startQuadrant != endQuadrant else { return frame } - + switch (startQuadrant, endQuadrant) { case (.I, .IV), (.IV, .I): let maxAxis = frame.origin.x + frame.width if maxAxis < arc.radius { - frame.size.width += (arc.radius - maxAxis) + let width = frame.size.width + (arc.radius - maxAxis) + let size = frame.size.with(width: width) + frame = frame.with(size: size) } case (.II, .I), (.I, .II): let maxAxis = frame.origin.y if maxAxis < arc.radius { - frame.origin.y += (arc.radius - maxAxis) - frame.size.height += (arc.radius - maxAxis) + let y = frame.origin.y + (arc.radius - maxAxis) + let origin = frame.origin.with(y: y) + let height = frame.size.height + (arc.radius - maxAxis) + let size = frame.size.with(height: height) + frame = frame.with(origin: origin).with(size: size) } case (.III, .II), (.II, .III): let maxAxis = abs(frame.origin.x) if maxAxis < arc.radius { - frame.origin.x -= (arc.radius - maxAxis) - frame.size.width += (arc.radius - maxAxis) + let x = frame.origin.x - (arc.radius - maxAxis) + let origin = frame.origin.with(x: x) + let width = frame.size.width + (arc.radius - maxAxis) + let size = frame.size.with(width: width) + frame = frame.with(origin: origin).with(size: size) } case (.IV, .III), (.III, .IV): let maxAxis = abs(frame.origin.y) + frame.size.height if maxAxis < arc.radius { - frame.size.height += (arc.radius - maxAxis) + let height = frame.size.height + (arc.radius - maxAxis) + let size = frame.size.with(height: height) + frame = frame.with(size: size) } default: throw GraphPointError.unhandledQuadrantTransition(startQuadrant, endQuadrant) } - + return frame } } diff --git a/Sources/GraphPoint/CartesianPlane.swift b/Sources/GraphPoint/CartesianPlane.swift index c08aeb7..3d40a6c 100644 --- a/Sources/GraphPoint/CartesianPlane.swift +++ b/Sources/GraphPoint/CartesianPlane.swift @@ -8,22 +8,16 @@ import Swift2D public typealias CartesianPlane = Rect public extension CartesianPlane { - init(size: Size) { - self.init() - origin = .zero - self.size = size - } - init(axis: Int) { - self.init() - origin = .zero - size = Size(width: axis * 2, height: axis * 2) + self.init( + size: Size(width: axis * 2, height: axis * 2) + ) } - + init(radius: Radius) { - self.init() - origin = .zero - size = Size(width: radius * 2, height: radius * 2) + self.init( + size: Size(width: radius * 2, height: radius * 2) + ) } } @@ -35,19 +29,19 @@ public extension CartesianPlane { /// projections along each axis, either in the positive or negative direction. The coordinates of the origin are always /// all zero. For example: {0,0}. var cartesianOrigin: Point { - return center + center } - + /// The length of the shortest axis found in this plane. var minimumAxis: Double { - return min(midX, midY) + min(midX, midY) } - + /// The length of the shortest axis found in this plane. var maximumAxis: Double { - return max(midX, midY) + max(midX, midY) } - + /// Converts a non-cartesian `Point` to a `CartesianPoint`. /// /// The assumption being made is that the `Point` being provided uses the standard top-left origin indexing for @@ -68,47 +62,47 @@ public extension CartesianPlane { func cartesianPoint(for point: Point) -> CartesianPoint { let origin = cartesianOrigin var cartesianPoint: CartesianPoint = .zero - + if point.x < origin.x { - cartesianPoint.x = -(origin.x - point.x) + cartesianPoint = cartesianPoint.with(x: -(origin.x - point.x)) } else if point.x > origin.x { - cartesianPoint.x = point.x - origin.x + cartesianPoint = cartesianPoint.with(x: point.x - origin.x) } - + if point.y > origin.y { - cartesianPoint.y = -(point.y - origin.y) + cartesianPoint = cartesianPoint.with(y: -(point.y - origin.y)) } else if point.y < origin.y { - cartesianPoint.y = origin.y - point.y + cartesianPoint = cartesianPoint.with(y: origin.y - point.y) } - + return cartesianPoint } - + /// Converts a `CartesianPoint` to a non-cartesian `Point`. func point(for cartesianPoint: CartesianPoint) -> Point { var point: Point = .zero - + if cartesianPoint.x >= 0.0 { - point.x = cartesianOrigin.x + cartesianPoint.x + point = point.with(x: cartesianOrigin.x + cartesianPoint.x) } else { - point.x = cartesianOrigin.x - abs(cartesianPoint.x) + point = point.with(x: cartesianOrigin.x - abs(cartesianPoint.x)) } - + if cartesianPoint.y <= 0.0 { - point.y = cartesianOrigin.y + abs(cartesianPoint.y) + point = point.with(y: cartesianOrigin.y + abs(cartesianPoint.y)) } else { - point.y = cartesianOrigin.y - cartesianPoint.y + point = point.with(y: cartesianOrigin.y - cartesianPoint.y) } - + return point } - + /// Converts a `CartesianFrame` to a non-cartesian `Rect`. func rect(for cartesianFrame: CartesianFrame) -> Rect { let origin = cartesianOrigin return Rect(origin: Point(x: origin.x + cartesianFrame.origin.x, y: origin.y - cartesianFrame.origin.y), size: cartesianFrame.size) } - + /// A `CartesianPoint` within the bounds of the plane for the given `Degree` and `maximumAxis`. func cartesianPoint(for degree: Degree, clockwise: Bool = true) throws -> CartesianPoint { try CartesianPoint.make(for: maximumAxis, degree: degree, clockwise: clockwise) diff --git a/Sources/GraphPoint/CartesianPoint.swift b/Sources/GraphPoint/CartesianPoint.swift index 8deac46..62e991c 100644 --- a/Sources/GraphPoint/CartesianPoint.swift +++ b/Sources/GraphPoint/CartesianPoint.swift @@ -22,7 +22,7 @@ public typealias CartesianPoint = Point public extension CartesianPoint { /// The minimum axis for a `CartesianPlane` that would contain this point. var minimumAxis: Double { - return max(abs(x), abs(y)) + max(abs(x), abs(y)) } } @@ -39,72 +39,88 @@ public extension CartesianPoint { guard degree >= 0.0, degree <= 360.0 else { throw GraphPointError.invalidDegree(degree) } - + guard radius >= 0.0 else { throw GraphPointError.invalidRadius(radius) } - + guard radius > 0.0 else { return .zero } - + let rightAngle: Double = 90.0 let sinRight = sin(rightAngle.radians) var rise: Double = 0.0 var run: Double = 0.0 var point: CartesianPoint = .zero - + switch clockwise { case true: if degree > 315 { rise = 360.0 - degree run = 180.0 - rightAngle - rise - point.x = (radius / sinRight) * sin(run.radians) - point.y = (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: (radius / sinRight) * sin(run.radians), + y: (radius / sinRight) * sin(rise.radians) + ) } else if degree > 270 { run = degree - 270.0 rise = 180.0 - rightAngle - run - point.x = (radius / sinRight) * sin(run.radians) - point.y = (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: (radius / sinRight) * sin(run.radians), + y: (radius / sinRight) * sin(rise.radians) + ) } else if degree > 225 { run = 270.0 - degree rise = 180.0 - rightAngle - run - point.x = -1.0 * (radius / sinRight) * sin(run.radians) - point.y = (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: -1.0 * (radius / sinRight) * sin(run.radians), + y: (radius / sinRight) * sin(rise.radians) + ) } else if degree > 180 { rise = degree - 180.0 run = 180.0 - rightAngle - rise - point.x = -1.0 * (radius / sinRight) * sin(run.radians) - point.y = (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: -1.0 * (radius / sinRight) * sin(run.radians), + y: (radius / sinRight) * sin(rise.radians) + ) } else if degree > 135 { rise = 180.0 - degree run = 180.0 - rightAngle - rise - point.x = -1.0 * (radius / sinRight) * sin(run.radians) - point.y = -1.0 * (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: -1.0 * (radius / sinRight) * sin(run.radians), + y: -1.0 * (radius / sinRight) * sin(rise.radians) + ) } else if degree > 90 { run = degree - 90.0 rise = 180.0 - rightAngle - run - point.x = -1.0 * (radius / sinRight) * sin(run.radians) - point.y = -1.0 * (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: -1.0 * (radius / sinRight) * sin(run.radians), + y: -1.0 * (radius / sinRight) * sin(rise.radians) + ) } else if degree > 45 { run = 90.0 - degree rise = 180.0 - rightAngle - run - point.x = (radius / sinRight) * sin(run.radians) - point.y = -1.0 * (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: (radius / sinRight) * sin(run.radians), + y: -1.0 * (radius / sinRight) * sin(rise.radians) + ) } else if degree >= 0 { rise = degree run = 180.0 - rightAngle - rise - point.x = (radius / sinRight) * sin(run.radians) - point.y = -1.0 * (radius / sinRight) * sin(rise.radians) + point = CartesianPoint( + x: (radius / sinRight) * sin(run.radians), + y: -1.0 * (radius / sinRight) * sin(rise.radians) + ) } case false: // TODO: Handled anti-clockwise break } - + return point } - + /// Calculates the `CartesianPoint` for a given degree and radius from the _origin_ limited by another point. /// /// Uses the **Pythagorean Theorem** to solve for the intercept: @@ -119,49 +135,65 @@ public extension CartesianPoint { guard degree >= 0.0, degree <= 360.0 else { throw GraphPointError.invalidDegree(degree) } - + guard radius >= 0.0 else { throw GraphPointError.invalidRadius(radius) } - + guard radius > 0.0 else { return .zero } - + var point = CartesianPoint() - + switch clockwise { case true: - if (degree >= 315) { - point.x = sqrt(pow(radius, 2) - pow(modifier.y, 2)) - point.y = modifier.y - } else if (degree >= 270) { - point.x = modifier.x - point.y = sqrt(pow(radius, 2) - pow(modifier.x, 2)) - } else if (degree >= 225) { - point.x = modifier.x - point.y = sqrt(pow(radius, 2) - pow(modifier.x, 2)) - } else if (degree >= 180) { - point.x = -(sqrt(pow(radius, 2) - pow(modifier.y, 2))) - point.y = modifier.y - } else if (degree >= 135) { - point.x = -(sqrt(pow(radius, 2) - pow(modifier.y, 2))) - point.y = modifier.y - } else if (degree >= 90) { - point.x = modifier.x - point.y = -(sqrt(pow(radius, 2) - pow(modifier.x, 2))) - } else if (degree >= 45) { - point.x = modifier.x - point.y = -(sqrt(pow(radius, 2) - pow(modifier.x, 2))) - } else if (degree >= 0) { - point.x = sqrt(pow(radius, 2) - pow(modifier.y, 2)) - point.y = modifier.y + if degree >= 315 { + point = CartesianPoint( + x: sqrt(pow(radius, 2) - pow(modifier.y, 2)), + y: modifier.y + ) + } else if degree >= 270 { + point = CartesianPoint( + x: modifier.x, + y: sqrt(pow(radius, 2) - pow(modifier.x, 2)) + ) + } else if degree >= 225 { + point = CartesianPoint( + x: modifier.x, + y: sqrt(pow(radius, 2) - pow(modifier.x, 2)) + ) + } else if degree >= 180 { + point = CartesianPoint( + x: -sqrt(pow(radius, 2) - pow(modifier.y, 2)), + y: modifier.y + ) + } else if degree >= 135 { + point = CartesianPoint( + x: -sqrt(pow(radius, 2) - pow(modifier.y, 2)), + y: modifier.y + ) + } else if degree >= 90 { + point = CartesianPoint( + x: modifier.x, + y: -sqrt(pow(radius, 2) - pow(modifier.x, 2)) + ) + } else if degree >= 45 { + point = CartesianPoint( + x: modifier.x, + y: -sqrt(pow(radius, 2) - pow(modifier.x, 2)) + ) + } else if degree >= 0 { + point = CartesianPoint( + x: sqrt(pow(radius, 2) - pow(modifier.y, 2)), + y: modifier.y + ) } case false: - //TODO: Determine if calculations should be modified. + // TODO: Determine if calculations should be modified. break } - + return point } } diff --git a/Sources/GraphPoint/Degree.swift b/Sources/GraphPoint/Degree.swift index 22f746d..618dc38 100644 --- a/Sources/GraphPoint/Degree.swift +++ b/Sources/GraphPoint/Degree.swift @@ -10,9 +10,9 @@ public typealias Degree = Double public extension Degree { /// Converts an angular degree to radians var radians: Radian { - return self * (.pi / 180.0) + self * (.pi / 180.0) } - + /// Calculates the angular degree for a given point. /// /// Uses the mathematical **Law of Cotangents**. @@ -24,14 +24,14 @@ public extension Degree { guard cartesianPoint != .nan else { throw GraphPointError.invalidPoint(cartesianPoint) } - + guard cartesianPoint != .zero else { throw GraphPointError.invalidPoint(cartesianPoint) } - + let degree: Degree let quadrant = Quadrant(cartesianPoint: cartesianPoint) - + switch quadrant { case .I: let midPoint = try CartesianPoint.make(for: cartesianPoint.minimumAxis, degree: 315.0) @@ -62,11 +62,11 @@ public extension Degree { degree = 90.0 - atan(cartesianPoint.x / abs(cartesianPoint.y)).degrees } } - + if !clockwise { return 360.0 - degree } - + return degree } } diff --git a/Sources/GraphPoint/GraphPointError.swift b/Sources/GraphPoint/GraphPointError.swift index 36fa927..d566a34 100644 --- a/Sources/GraphPoint/GraphPointError.swift +++ b/Sources/GraphPoint/GraphPointError.swift @@ -1,6 +1,6 @@ import Foundation -public enum GraphPointError: Swift.Error { +public enum GraphPointError: Error { case invalidPoint(_ point: CartesianPoint) case invalidDegree(_ degree: Degree) case invalidRadius(_ radius: Radius) diff --git a/Sources/GraphPoint/Quadrant.swift b/Sources/GraphPoint/Quadrant.swift index 89e4ba8..41d01a5 100644 --- a/Sources/GraphPoint/Quadrant.swift +++ b/Sources/GraphPoint/Quadrant.swift @@ -5,7 +5,7 @@ import Foundation /// The axes of a two-dimensional Cartesian system divide the plane into four infinite regions, called quadrants, each /// bounded by two half-axes. When the axes are drawn according to the mathematical custom, the numbering goes /// counter-clockwise starting from the upper right ("northeast") quadrant. -public enum Quadrant: Int, CaseIterable { +public enum Quadrant: Int, CaseIterable, Hashable, Codable, Sendable { /// Quadrant 1 /// * x: + (positive) /// * y: + (positive) @@ -33,31 +33,31 @@ public extension Quadrant { guard degree >= 0.0, degree <= 360.0 else { throw GraphPointError.invalidDegree(degree) } - + switch clockwise { case true: - if degree >= 0.0 && degree <= 90.0 { + if degree >= 0.0, degree <= 90.0 { self = .IV - } else if degree >= 90.0 && degree <= 180.0 { + } else if degree >= 90.0, degree <= 180.0 { self = .III - } else if degree >= 180.0 && degree <= 270.0 { + } else if degree >= 180.0, degree <= 270.0 { self = .II } else { self = .I } case false: - if degree >= 0.0 && degree <= 90.0 { + if degree >= 0.0, degree <= 90.0 { self = .I - } else if degree >= 90.0 && degree <= 180.0 { + } else if degree >= 90.0, degree <= 180.0 { self = .II - } else if degree >= 180.0 && degree <= 270.0 { + } else if degree >= 180.0, degree <= 270.0 { self = .III } else { self = .IV } } } - + /// Initializes a `Quadrant` that contains the point. /// /// Special conditions are used when a point rests on an axis: diff --git a/Sources/GraphPoint/Radian.swift b/Sources/GraphPoint/Radian.swift index 1e2b092..433c5ef 100644 --- a/Sources/GraphPoint/Radian.swift +++ b/Sources/GraphPoint/Radian.swift @@ -6,6 +6,6 @@ public typealias Radian = Double public extension Radian { /// Converts a radian value to angular degree var degrees: Degree { - return self * (180.0 / .pi) + self * (180.0 / .pi) } } diff --git a/Tests/GraphPointTests/CartesianFrameTests.swift b/Tests/GraphPointTests/CartesianFrameTests.swift index 4bce9ad..c51fd0e 100644 --- a/Tests/GraphPointTests/CartesianFrameTests.swift +++ b/Tests/GraphPointTests/CartesianFrameTests.swift @@ -1,35 +1,35 @@ -import XCTest @testable import GraphPoint +import XCTest class CartesianFrameTests: XCTestCase { - + func testMakeForPoints() { var point1 = CartesianPoint(x: -10, y: 10) var point2 = CartesianPoint(x: 10, y: 10) var point3 = CartesianPoint(x: -10, y: -10) var point4 = CartesianPoint(x: 10, y: -10) - + var frame = CartesianFrame.make(for: [point1, point2, point3, point4]) XCTAssertEqual(frame.origin.x, -10) XCTAssertEqual(frame.origin.y, 10) XCTAssertEqual(frame.size.width, 20) XCTAssertEqual(frame.size.height, 20) - + point1 = CartesianPoint(x: -10, y: 10) point2 = CartesianPoint(x: 50, y: 40) point3 = CartesianPoint(x: -1, y: -1) point4 = CartesianPoint(x: 12, y: -75) - + frame = CartesianFrame.make(for: [point1, point2, point3, point4]) XCTAssertEqual(frame.origin.x, -10) XCTAssertEqual(frame.origin.y, 40) XCTAssertEqual(frame.size.width, 60) XCTAssertEqual(frame.size.height, 115) } - + func testMakeForPointsArc() throws { let radius = Radius(15) - + // .I > .IV var point1 = CartesianPoint(x: 10, y: 10) var point2 = CartesianPoint(x: 10, y: -10) @@ -39,7 +39,7 @@ class CartesianFrameTests: XCTestCase { XCTAssertEqual(frame.origin.y, 10) XCTAssertEqual(frame.size.width, 5) XCTAssertEqual(frame.size.height, 20) - + // .IV > .I point1 = CartesianPoint(x: 5, y: -10) point2 = CartesianPoint(x: 7, y: 4) diff --git a/Tests/GraphPointTests/CartesianPlaneTests.swift b/Tests/GraphPointTests/CartesianPlaneTests.swift index 0e81daa..75230dc 100644 --- a/Tests/GraphPointTests/CartesianPlaneTests.swift +++ b/Tests/GraphPointTests/CartesianPlaneTests.swift @@ -1,101 +1,101 @@ -import XCTest @testable import GraphPoint import Swift2D +import XCTest class CartesianPlaneTests: XCTestCase { - + func testCartesianOrigin() { var plane = CartesianPlane(size: Size(width: 40, height: 20)) XCTAssertEqual(plane.cartesianOrigin.x, 20) XCTAssertEqual(plane.cartesianOrigin.y, 10) - + plane = CartesianPlane(axis: 6) XCTAssertEqual(plane.cartesianOrigin.x, 6) XCTAssertEqual(plane.cartesianOrigin.y, 6) - + plane = CartesianPlane(radius: 45.0) XCTAssertEqual(plane.cartesianOrigin.x, 45.0) XCTAssertEqual(plane.cartesianOrigin.y, 45.0) } - + func testMinimumAxis() { var plane = CartesianPlane(size: Size(width: 40, height: 20)) XCTAssertEqual(plane.minimumAxis, 10) - + plane = CartesianPlane(axis: 6) XCTAssertEqual(plane.minimumAxis, 6) - + plane = CartesianPlane(radius: 45.0) XCTAssertEqual(plane.minimumAxis, 45.0) } - + func testMaximumAxis() { var plane = CartesianPlane(size: Size(width: 40, height: 20)) XCTAssertEqual(plane.maximumAxis, 20) - + plane = CartesianPlane(axis: 6) XCTAssertEqual(plane.maximumAxis, 6) - + plane = CartesianPlane(radius: 45.0) XCTAssertEqual(plane.maximumAxis, 45.0) } - + func testCartesianPointForPoint() { // 100 x 100 rect {50 x 50} axes let plane = CartesianPlane(radius: 50) - + var point: Point var cartesianPoint: CartesianPoint - + point = .init(x: 20, y: 35) cartesianPoint = plane.cartesianPoint(for: point) XCTAssertEqual(cartesianPoint.x, -30) XCTAssertEqual(cartesianPoint.y, 15) - + point = .init(x: 80, y: 35) cartesianPoint = plane.cartesianPoint(for: point) XCTAssertEqual(cartesianPoint.x, 30) XCTAssertEqual(cartesianPoint.y, 15) - + point = .init(x: 20, y: 80) cartesianPoint = plane.cartesianPoint(for: point) XCTAssertEqual(cartesianPoint.x, -30) XCTAssertEqual(cartesianPoint.y, -30) - + point = .init(x: 80, y: 80) cartesianPoint = plane.cartesianPoint(for: point) XCTAssertEqual(cartesianPoint.x, 30) XCTAssertEqual(cartesianPoint.y, -30) } - + func testPointForCartesianPoint() { // 100 x 100 rect {50 x 50} axes let plane = CartesianPlane(radius: 50) - + var cartesianPoint: CartesianPoint var point: Point - + cartesianPoint = .init(x: -30, y: 15) point = plane.point(for: cartesianPoint) XCTAssertEqual(point.x, 20) XCTAssertEqual(point.y, 35) - + cartesianPoint = .init(x: 30, y: 15) point = plane.point(for: cartesianPoint) XCTAssertEqual(point.x, 80) XCTAssertEqual(point.y, 35) - + cartesianPoint = .init(x: -30, y: -30) point = plane.point(for: cartesianPoint) XCTAssertEqual(point.x, 20) XCTAssertEqual(point.y, 80) - + cartesianPoint = .init(x: 30, y: -30) point = plane.point(for: cartesianPoint) XCTAssertEqual(point.x, 80) XCTAssertEqual(point.y, 80) } - + func testRectForCartesianFrame() { // 100 x 100 rect {50 x 50} axes let plane = CartesianPlane(radius: 50) diff --git a/Tests/GraphPointTests/CartesianPointTests.swift b/Tests/GraphPointTests/CartesianPointTests.swift index f50e1b3..2f17c6b 100644 --- a/Tests/GraphPointTests/CartesianPointTests.swift +++ b/Tests/GraphPointTests/CartesianPointTests.swift @@ -1,25 +1,25 @@ -import XCTest @testable import GraphPoint +import XCTest class CartesianPointTests: XCTestCase { - + func testMinimumAxis() { var point: CartesianPoint = .init(x: 40, y: 40) XCTAssertEqual(point.minimumAxis, 40) - + point = .init(x: -50, y: 60) XCTAssertEqual(point.minimumAxis, 60) - + point = .init(x: -25, y: -90) XCTAssertEqual(point.minimumAxis, 90) - + point = .init(x: 100, y: -20) XCTAssertEqual(point.minimumAxis, 100) } - + func testMakeForDegreeRadius() throws { var point: CartesianPoint - + do { point = try .make(for: 100.0, degree: -60.0) } catch GraphPointError.invalidDegree(let degree) { @@ -27,7 +27,7 @@ class CartesianPointTests: XCTestCase { } catch { throw error } - + do { point = try .make(for: 100.0, degree: 400.0) } catch GraphPointError.invalidDegree(let degree) { @@ -35,7 +35,7 @@ class CartesianPointTests: XCTestCase { } catch { throw error } - + do { point = try .make(for: -12.0, degree: 80.0) } catch GraphPointError.invalidRadius(let radius) { @@ -43,80 +43,80 @@ class CartesianPointTests: XCTestCase { } catch { throw error } - + point = try .make(for: 0.0, degree: 0.0) XCTAssertEqual(point.x, 0.0) XCTAssertEqual(point.y, 0.0) - + point = try .make(for: 10, degree: 10.0) XCTAssertEqual(point.x, 9.848078, accuracy: 0.00001) XCTAssertEqual(point.y, -1.7364818, accuracy: 0.00001) - + point = try .make(for: 10, degree: 45.0) XCTAssertEqual(point.x, 7.071068, accuracy: 0.00001) XCTAssertEqual(point.y, -7.071068, accuracy: 0.00001) - + point = try .make(for: 10, degree: 80.0) XCTAssertEqual(point.x, 1.7364818, accuracy: 0.00001) XCTAssertEqual(point.y, -9.848078, accuracy: 0.00001) - + point = try .make(for: 10, degree: 90.0) XCTAssertEqual(point.x, 0.0) XCTAssertEqual(point.y, -10.0) - + point = try .make(for: 10, degree: 100.0) XCTAssertEqual(point.x, -1.7364818, accuracy: 0.00001) XCTAssertEqual(point.y, -9.848078, accuracy: 0.00001) - + point = try .make(for: 10, degree: 135.0) XCTAssertEqual(point.x, -7.071068, accuracy: 0.00001) XCTAssertEqual(point.y, -7.071068, accuracy: 0.00001) - + point = try .make(for: 10, degree: 170.0) XCTAssertEqual(point.x, -9.848078, accuracy: 0.00001) XCTAssertEqual(point.y, -1.7364818, accuracy: 0.00001) - + point = try .make(for: 10, degree: 180.0) XCTAssertEqual(point.x, -10.0) XCTAssertEqual(point.y, 0.0) - + point = try .make(for: 10, degree: 190.0) XCTAssertEqual(point.x, -9.848078, accuracy: 0.00001) XCTAssertEqual(point.y, 1.7364818, accuracy: 0.00001) - + point = try .make(for: 10, degree: 225.0) XCTAssertEqual(point.x, -7.071068, accuracy: 0.00001) XCTAssertEqual(point.y, 7.071068, accuracy: 0.00001) - + point = try .make(for: 10, degree: 260.0) XCTAssertEqual(point.x, -1.7364818, accuracy: 0.00001) XCTAssertEqual(point.y, 9.848078, accuracy: 0.00001) - + point = try .make(for: 10, degree: 270.0) XCTAssertEqual(point.x, 0.0) XCTAssertEqual(point.y, 10.0) - + point = try .make(for: 10, degree: 280.0) XCTAssertEqual(point.x, 1.7364818, accuracy: 0.00001) XCTAssertEqual(point.y, 9.848078, accuracy: 0.00001) - + point = try .make(for: 10, degree: 315.0) XCTAssertEqual(point.x, 7.071068, accuracy: 0.00001) XCTAssertEqual(point.y, 7.071068, accuracy: 0.00001) - + point = try .make(for: 10, degree: 350.0) XCTAssertEqual(point.x, 9.848078, accuracy: 0.00001) XCTAssertEqual(point.y, 1.7364818, accuracy: 0.00001) - + point = try .make(for: 10, degree: 360.0) XCTAssertEqual(point.x, 10.0) XCTAssertEqual(point.y, 0.0) } - + func testMakeForDegreeRadiusLimiter() throws { var modifier: CartesianPoint = .zero var point: CartesianPoint - + do { point = try .make(for: 100.0, degree: -60.0, modifier: modifier) } catch GraphPointError.invalidDegree(let degree) { @@ -124,7 +124,7 @@ class CartesianPointTests: XCTestCase { } catch { throw error } - + do { point = try .make(for: 100.0, degree: 400.0, modifier: modifier) } catch GraphPointError.invalidDegree(let degree) { @@ -132,7 +132,7 @@ class CartesianPointTests: XCTestCase { } catch { throw error } - + do { point = try .make(for: -12.0, degree: 80.0, modifier: modifier) } catch GraphPointError.invalidRadius(let radius) { @@ -140,86 +140,86 @@ class CartesianPointTests: XCTestCase { } catch { throw error } - + point = try .make(for: 0.0, degree: 0.0, modifier: modifier) XCTAssertEqual(point.x, 0.0) XCTAssertEqual(point.y, 0.0) - + modifier = .init(x: 0.0, y: 5.0) point = try .make(for: 10, degree: 10.0, modifier: modifier) XCTAssertEqual(point.x, 8.6602545, accuracy: 0.00001) XCTAssertEqual(point.y, 5.0) - + modifier = .init(x: 5.0, y: 0.0) point = try .make(for: 10, degree: 45.0, modifier: modifier) XCTAssertEqual(point.x, 5.0) XCTAssertEqual(point.y, -8.6602545, accuracy: 0.00001) - + modifier = .init(x: 5.0, y: 0.0) point = try .make(for: 10, degree: 80.0, modifier: modifier) XCTAssertEqual(point.x, 5.0) XCTAssertEqual(point.y, -8.6602545, accuracy: 0.00001) - + modifier = .init(x: 5.0, y: 0.0) point = try .make(for: 10, degree: 90.0, modifier: modifier) XCTAssertEqual(point.x, 5.0) XCTAssertEqual(point.y, -8.6602545, accuracy: 0.00001) - + modifier = .init(x: -5.0, y: 0.0) point = try .make(for: 10, degree: 100.0, modifier: modifier) XCTAssertEqual(point.x, -5.0) XCTAssertEqual(point.y, -8.6602545, accuracy: 0.00001) - + modifier = .init(x: 0.0, y: -5.0) point = try .make(for: 10, degree: 135.0, modifier: modifier) XCTAssertEqual(point.x, -8.6602545, accuracy: 0.00001) XCTAssertEqual(point.y, -5.0) - + modifier = .init(x: 0.0, y: -5.0) point = try .make(for: 10, degree: 170.0, modifier: modifier) XCTAssertEqual(point.x, -8.6602545, accuracy: 0.00001) XCTAssertEqual(point.y, -5.0) - + modifier = .init(x: 0.0, y: 5.0) point = try .make(for: 10, degree: 180.0, modifier: modifier) XCTAssertEqual(point.x, -8.6602545, accuracy: 0.00001) XCTAssertEqual(point.y, 5.0) - + modifier = .init(x: 0.0, y: 5.0) point = try .make(for: 10, degree: 190.0, modifier: modifier) XCTAssertEqual(point.x, -8.6602545, accuracy: 0.00001) XCTAssertEqual(point.y, 5.0) - + modifier = .init(x: -5.0, y: 0.0) point = try .make(for: 10, degree: 225.0, modifier: modifier) XCTAssertEqual(point.x, -5.0) XCTAssertEqual(point.y, 8.6602545, accuracy: 0.00001) - + modifier = .init(x: -5.0, y: 0.0) point = try .make(for: 10, degree: 260.0, modifier: modifier) XCTAssertEqual(point.x, -5.0) XCTAssertEqual(point.y, 8.6602545, accuracy: 0.00001) - + modifier = .init(x: 5.0, y: 0.0) point = try .make(for: 10, degree: 270.0, modifier: modifier) XCTAssertEqual(point.x, 5.0) XCTAssertEqual(point.y, 8.6602545, accuracy: 0.00001) - + modifier = .init(x: 5.0, y: 0.0) point = try .make(for: 10, degree: 280.0, modifier: modifier) XCTAssertEqual(point.x, 5.0) XCTAssertEqual(point.y, 8.6602545, accuracy: 0.00001) - + modifier = .init(x: 0.0, y: 5.0) point = try .make(for: 10, degree: 315.0, modifier: modifier) XCTAssertEqual(point.x, 8.6602545, accuracy: 0.00001) XCTAssertEqual(point.y, 5.0) - + modifier = .init(x: 0.0, y: 5.0) point = try .make(for: 10, degree: 350.0, modifier: modifier) XCTAssertEqual(point.x, 8.6602545, accuracy: 0.00001) XCTAssertEqual(point.y, 5.0) - + modifier = .init(x: 0.0, y: 5.0) point = try .make(for: 10, degree: 360.0, modifier: modifier) XCTAssertEqual(point.x, 8.6602545, accuracy: 0.00001) diff --git a/Tests/GraphPointTests/DegreeTests.swift b/Tests/GraphPointTests/DegreeTests.swift index d89a691..ccc5ca6 100644 --- a/Tests/GraphPointTests/DegreeTests.swift +++ b/Tests/GraphPointTests/DegreeTests.swift @@ -1,20 +1,20 @@ -import XCTest @testable import GraphPoint +import XCTest class DegreeTests: XCTestCase { - + func testDegreeToRadian() { var radian: Radian = Radian(0.62831853071795862) XCTAssertEqual(radian.degrees, Degree(36), accuracy: 0.01) - + radian = Radian(3.0455995447301052) XCTAssertEqual(radian.degrees, Degree(174.5), accuracy: 0.01) } - + func testMakeForPointClockwise() throws { var point: CartesianPoint var degree: Degree - + point = .nan do { degree = try Degree.make(for: point) @@ -23,7 +23,7 @@ class DegreeTests: XCTestCase { } catch { throw error } - + point = .zero do { degree = try Degree.make(for: point) @@ -32,68 +32,68 @@ class DegreeTests: XCTestCase { } catch { throw error } - + // Quadrant.I (shallow) point = .init(x: 20, y: 10) degree = try Degree.make(for: point) XCTAssertEqual(degree, 333.43494, accuracy: 0.00001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 26.565063, accuracy: 0.0001) - + // Quadrant.I (deep) point = .init(x: 5, y: 40) degree = try Degree.make(for: point) XCTAssertEqual(degree, 277.12503, accuracy: 0.0001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 82.87497, accuracy: 0.0001) - + // Quadrant.II (shallow) point = .init(x: -20, y: 40) degree = try Degree.make(for: point) XCTAssertEqual(degree, 243.43495, accuracy: 0.00001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 116.56505, accuracy: 0.00001) - + // Quadrant.II (deep) point = .init(x: -40, y: 20) degree = try Degree.make(for: point) XCTAssertEqual(degree, 206.56505, accuracy: 0.00001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 153.43495, accuracy: 0.00001) - + // Quadrant.III (shallow) point = .init(x: -45, y: -10) degree = try Degree.make(for: point) XCTAssertEqual(degree, 167.47119, accuracy: 0.00001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 192.52881, accuracy: 0.00001) - + // Quadrant.III (deep) point = .init(x: -10, y: -45) degree = try Degree.make(for: point) XCTAssertEqual(degree, 102.52881, accuracy: 0.00001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 257.4712, accuracy: 0.00001) - + // Quadrant.IV (shallow point = .init(x: 224, y: -18) degree = try Degree.make(for: point) XCTAssertEqual(degree, 4.594246, accuracy: 0.00001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 355.40576, accuracy: 0.0001) - + // Quadrant.IV (deep) point = .init(x: 18, y: -224) degree = try Degree.make(for: point) XCTAssertEqual(degree, 85.405754, accuracy: 0.00001) - + degree = try Degree.make(for: point, clockwise: false) XCTAssertEqual(degree, 274.59424, accuracy: 0.0001) } diff --git a/Tests/GraphPointTests/QuadrantTests.swift b/Tests/GraphPointTests/QuadrantTests.swift index 4259053..5569ea1 100644 --- a/Tests/GraphPointTests/QuadrantTests.swift +++ b/Tests/GraphPointTests/QuadrantTests.swift @@ -1,36 +1,36 @@ -import XCTest @testable import GraphPoint +import XCTest class QuadrantTests: XCTestCase { - + func testInitDegreeClockwise() throws { var degree: Degree var quadrant: Quadrant - + degree = 10.0 quadrant = try .init(degree: degree) XCTAssertEqual(quadrant, .IV) quadrant = try .init(degree: degree, clockwise: false) XCTAssertEqual(quadrant, .I) - + degree = 100.0 quadrant = try .init(degree: degree) XCTAssertEqual(quadrant, .III) quadrant = try .init(degree: degree, clockwise: false) XCTAssertEqual(quadrant, .II) - + degree = 190.0 quadrant = try .init(degree: degree) XCTAssertEqual(quadrant, .II) quadrant = try .init(degree: degree, clockwise: false) XCTAssertEqual(quadrant, .III) - + degree = 280.0 quadrant = try .init(degree: degree) XCTAssertEqual(quadrant, .I) quadrant = try .init(degree: degree, clockwise: false) XCTAssertEqual(quadrant, .IV) - + degree = 400.0 do { quadrant = try .init(degree: degree) @@ -40,43 +40,43 @@ class QuadrantTests: XCTestCase { throw error } } - + func testInitCartesianPoint() { var point: CartesianPoint var quadrant: Quadrant - + point = .zero quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .I) - + point = .init(x: 40, y: 40) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .I) - + point = .init(x: -50, y: 60) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .II) - + point = .init(x: -25, y: -90) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .III) - + point = .init(x: 100, y: -20) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .IV) - + point = .init(x: 45, y: 0) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .I) - + point = .init(x: 0, y: 45) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .II) - + point = .init(x: -45, y: 0) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .III) - + point = .init(x: 0, y: -45) quadrant = .init(cartesianPoint: point) XCTAssertEqual(quadrant, .IV) diff --git a/Tests/GraphPointTests/RadianTests.swift b/Tests/GraphPointTests/RadianTests.swift index b29315a..e215438 100644 --- a/Tests/GraphPointTests/RadianTests.swift +++ b/Tests/GraphPointTests/RadianTests.swift @@ -1,12 +1,12 @@ -import XCTest @testable import GraphPoint +import XCTest class RadianTests: XCTestCase { - + func testRadianToDegree() { var degree: Degree = Degree(36) XCTAssertEqual(degree.radians, Radian(0.62831853071795862)) - + degree = Degree(174.5) XCTAssertEqual(degree.radians, Radian(3.0455995447301052)) }