-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[GeometriaClipping] Adding Capsule2Parametric shape
- Loading branch information
Showing
10 changed files
with
274 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
92 changes: 92 additions & 0 deletions
92
Sources/GeometriaClipping/2D/Geometry/Capsule2Parametric.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
import Geometria | ||
|
||
/// A parametric geometry that is defined by line segments connecting two circular | ||
/// arcs at the end-points. | ||
public struct Capsule2Parametric<Vector: Vector2Real>: ParametricClip2Geometry, Equatable { | ||
public typealias Scalar = Vector.Scalar | ||
public typealias Simplex = Parametric2GeometrySimplex<Vector> | ||
public typealias Contour = Parametric2Contour<Vector> | ||
|
||
public var start: Vector | ||
public var startRadius: Scalar | ||
public var end: Vector | ||
public var endRadius: Scalar | ||
|
||
public var startPeriod: Period | ||
public var endPeriod: Period | ||
|
||
public var isReversed: Bool | ||
|
||
internal init( | ||
start: Vector, | ||
end: Vector, | ||
radius: Scalar, | ||
startPeriod: Period, | ||
endPeriod: Period | ||
) { | ||
self.init( | ||
start: start, | ||
startRadius: radius, | ||
end: end, | ||
endRadius: radius, | ||
startPeriod: startPeriod, | ||
endPeriod: endPeriod | ||
) | ||
} | ||
|
||
internal init( | ||
start: Vector, | ||
startRadius: Scalar, | ||
end: Vector, | ||
endRadius: Scalar, | ||
startPeriod: Period, | ||
endPeriod: Period | ||
) { | ||
self.start = start | ||
self.startRadius = startRadius | ||
self.end = end | ||
self.endRadius = endRadius | ||
self.startPeriod = startPeriod | ||
self.endPeriod = endPeriod | ||
self.isReversed = false | ||
} | ||
|
||
public func allContours() -> [Contour] { | ||
let startCircle = Circle2(center: start, radius: startRadius) | ||
let endCircle = Circle2(center: end, radius: endRadius) | ||
|
||
let tangents = startCircle.outerTangents(to: endCircle) | ||
|
||
let startArc = CircleArc2(clockwiseAngleToCenter: start, startPoint: tangents.1.start, endPoint: tangents.0.start) | ||
let endArc = CircleArc2(clockwiseAngleToCenter: end, startPoint: tangents.0.end, endPoint: tangents.1.end) | ||
|
||
let simplexes: [Simplex] = [ | ||
.circleArc2(.init(circleArc: startArc, startPeriod: 0, endPeriod: 0)), | ||
.lineSegment2(.init(lineSegment: tangents.0, startPeriod: 0, endPeriod: 0)), | ||
.circleArc2(.init(circleArc: endArc, startPeriod: 0, endPeriod: 0)), | ||
.lineSegment2(.init(lineSegment: tangents.1.reversed, startPeriod: 0, endPeriod: 0)), | ||
] | ||
|
||
let contour = Contour( | ||
normalizing: simplexes, | ||
startPeriod: startPeriod, | ||
endPeriod: endPeriod | ||
) | ||
|
||
if isReversed { | ||
return [ | ||
contour.reversed() | ||
] | ||
} else { | ||
return [ | ||
contour | ||
] | ||
} | ||
} | ||
|
||
public func reversed() -> Capsule2Parametric { | ||
var copy = self | ||
copy.isReversed = !isReversed | ||
return copy | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.
142 changes: 142 additions & 0 deletions
142
Tests/GeometriaClippingTests/2D/Geometry/Capsule2ParametricTests.swift
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
import Geometria | ||
import TestCommons | ||
import XCTest | ||
|
||
@testable import GeometriaClipping | ||
|
||
class Capsule2ParametricTests: XCTestCase { | ||
typealias Sut = Capsule2Parametric<Vector2D> | ||
let accuracy: Double = 1e-12 | ||
|
||
func testEphemeral() { | ||
let sut = Sut( | ||
start: .init(x: -150, y: -30), | ||
startRadius: 60, | ||
end: .init(x: 70, y: 80), | ||
endRadius: 100, | ||
startPeriod: 0.0, | ||
endPeriod: 1.0 | ||
) | ||
|
||
TestFixture.beginFixture { fixture in | ||
fixture.add(sut, category: "input") | ||
|
||
fixture.assertions(on: sut) | ||
.assertSimplexes( | ||
accuracy: accuracy, | ||
[ | ||
.circleArc2( | ||
.init( | ||
circleArc: .init( | ||
center: .init(x: -150.0, y: -30.0), | ||
radius: 60.00000000000001, | ||
startAngle: Angle(radians: 2.1977925247947656), | ||
sweepAngle: Angle(radians: 2.8148954755916673) | ||
), | ||
startPeriod: 0.0, | ||
endPeriod: 0.16870660664537054 | ||
) | ||
), | ||
.lineSegment2( | ||
.init( | ||
lineSegment: .init( | ||
start: .init(x: -132.2516485101565, y: -87.31488479786879), | ||
end: .init(x: 99.5805858164058, y: -15.524807996447976) | ||
), | ||
startPeriod: 0.16870660664537054, | ||
endPeriod: 0.41113094230800334 | ||
) | ||
), | ||
.circleArc2( | ||
.init( | ||
circleArc: .init( | ||
center: .init(x: 70.0, y: 80.0), | ||
radius: 100.0, | ||
startAngle: Angle(radians: -1.2704973067931533), | ||
sweepAngle: Angle(radians: 3.468289831587919) | ||
), | ||
startPeriod: 0.41113094230800334, | ||
endPeriod: 0.7575756643373672 | ||
) | ||
), | ||
.lineSegment2( | ||
.init( | ||
lineSegment: .init( | ||
start: .init(x: 11.328505092685084, y: 160.97935345099341), | ||
end: .init(x: -185.20289694438895, y: 18.58761207059606) | ||
), | ||
startPeriod: 0.7575756643373672, | ||
endPeriod: 1.0 | ||
) | ||
), | ||
] | ||
) | ||
} | ||
} | ||
|
||
func testReversed() { | ||
let sut = Sut( | ||
start: .init(x: -150, y: -30), | ||
startRadius: 60, | ||
end: .init(x: 70, y: 80), | ||
endRadius: 100, | ||
startPeriod: 0.0, | ||
endPeriod: 1.0 | ||
) | ||
|
||
TestFixture.beginFixture { fixture in | ||
fixture.add(sut, category: "input") | ||
|
||
fixture.assertions(on: sut.reversed()) | ||
.assertSimplexes( | ||
accuracy: accuracy, | ||
[ | ||
.lineSegment2( | ||
.init( | ||
lineSegment: .init( | ||
start: .init(x: -185.20289694438895, y: 18.58761207059606), | ||
end: .init(x: 11.328505092685084, y: 160.97935345099341) | ||
), | ||
startPeriod: 0.0, | ||
endPeriod: 0.24242433566263277 | ||
) | ||
), | ||
.circleArc2( | ||
.init( | ||
circleArc: .init( | ||
center: .init(x: 70.0, y: 80.0), | ||
radius: 100.0, | ||
startAngle: Angle(radians: 2.1977925247947656), | ||
sweepAngle: Angle(radians: -3.468289831587919) | ||
), | ||
startPeriod: 0.24242433566263277, | ||
endPeriod: 0.5888690576919966 | ||
) | ||
), | ||
.lineSegment2( | ||
.init( | ||
lineSegment: .init( | ||
start: .init(x: 99.5805858164058, y: -15.524807996447976), | ||
end: .init(x: -132.2516485101565, y: -87.31488479786879) | ||
), | ||
startPeriod: 0.5888690576919966, | ||
endPeriod: 0.8312933933546295 | ||
) | ||
), | ||
.circleArc2( | ||
.init( | ||
circleArc: .init( | ||
center: .init(x: -150.0, y: -30.0), | ||
radius: 60.00000000000001, | ||
startAngle: Angle(radians: 5.012688000386433), | ||
sweepAngle: Angle(radians: -2.8148954755916673) | ||
), | ||
startPeriod: 0.8312933933546295, | ||
endPeriod: 1.0 | ||
) | ||
), | ||
] | ||
) | ||
} | ||
} | ||
} |
File renamed without changes.
File renamed without changes.
File renamed without changes.