Skip to content

Commit 385af8c

Browse files
authored
Merge pull request #94 from hfutrell/intersection-via-implicitization
Intersection via implicitization
2 parents 13b6bb7 + 2ec6cc4 commit 385af8c

16 files changed

+817
-46
lines changed

BezierKit/BezierKit.xcodeproj/project.pbxproj

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@
1515
FD067AC9246F1200006DA36B /* Polynomial.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD067AC7246F1200006DA36B /* Polynomial.swift */; };
1616
FD067ACB246F12B5006DA36B /* PolynomialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD067ACA246F12B5006DA36B /* PolynomialTests.swift */; };
1717
FD067ACC246F12B5006DA36B /* PolynomialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD067ACA246F12B5006DA36B /* PolynomialTests.swift */; };
18+
FD07BC20261BC97400ED39FF /* RootFinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1D261BC97400ED39FF /* RootFinding.swift */; };
19+
FD07BC21261BC97400ED39FF /* RootFinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1D261BC97400ED39FF /* RootFinding.swift */; };
20+
FD07BC22261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */; };
21+
FD07BC23261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */; };
22+
FD07BC24261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */; };
23+
FD07BC25261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */; };
1824
FD12F1E22288CF6900404CE1 /* UtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD12F1E12288CF6900404CE1 /* UtilsTests.swift */; };
1925
FD12F1E32288CF6900404CE1 /* UtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD12F1E12288CF6900404CE1 /* UtilsTests.swift */; };
2026
FD149EBA2135CBFF009E791D /* AugmentedGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD149EB92135CBFF009E791D /* AugmentedGraph.swift */; };
@@ -88,6 +94,8 @@
8894
FDC2EB4A2298735C007768FC /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2EB492298735C007768FC /* Lock.swift */; };
8995
FDC2EB4B2298735C007768FC /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2EB492298735C007768FC /* Lock.swift */; };
9096
FDC455EE211D057E00DBF2B2 /* BoundingBoxHierarchy.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC859622119274A00AF7642 /* BoundingBoxHierarchy.swift */; };
97+
FDC6D2F82649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */; };
98+
FDC6D2F92649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */; };
9199
FDC7D7032111323A00A9EEF0 /* Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC7D7012111323A00A9EEF0 /* Path.swift */; };
92100
FDC7D7042111323A00A9EEF0 /* Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC7D7012111323A00A9EEF0 /* Path.swift */; };
93101
FDC7D706211288BD00A9EEF0 /* PathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC7D705211288BD00A9EEF0 /* PathTests.swift */; };
@@ -156,6 +164,9 @@
156164
FD06332221E03A58001181B6 /* CGPointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGPointTests.swift; sourceTree = "<group>"; };
157165
FD067AC7246F1200006DA36B /* Polynomial.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Polynomial.swift; sourceTree = "<group>"; };
158166
FD067ACA246F12B5006DA36B /* PolynomialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolynomialTests.swift; sourceTree = "<group>"; };
167+
FD07BC1D261BC97400ED39FF /* RootFinding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RootFinding.swift; path = Library/RootFinding.swift; sourceTree = SOURCE_ROOT; };
168+
FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BernsteinPolynomialN.swift; path = Library/BernsteinPolynomialN.swift; sourceTree = SOURCE_ROOT; };
169+
FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "BezierCurve+Implicitization.swift"; path = "Library/BezierCurve+Implicitization.swift"; sourceTree = SOURCE_ROOT; };
159170
FD0F54F51DC43FFB0084CDCD /* MacDemos.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacDemos.app; sourceTree = BUILT_PRODUCTS_DIR; };
160171
FD0F55081DC43FFB0084CDCD /* BezierKitTestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BezierKitTestHelpers.swift; sourceTree = "<group>"; };
161172
FD0F550A1DC43FFB0084CDCD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
@@ -207,6 +218,7 @@
207218
FDB9D7411EB28D1900413F0E /* BezierKit_MacTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BezierKit_MacTests.swift; sourceTree = "<group>"; };
208219
FDB9D7431EB28D1900413F0E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
209220
FDC2EB492298735C007768FC /* Lock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lock.swift; sourceTree = "<group>"; };
221+
FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BezierCurve+ImplicitizationTests.swift"; sourceTree = "<group>"; };
210222
FDC7D7012111323A00A9EEF0 /* Path.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Path.swift; sourceTree = "<group>"; };
211223
FDC7D705211288BD00A9EEF0 /* PathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathTests.swift; sourceTree = "<group>"; };
212224
FDC859592118EC5600AF7642 /* DrawTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawTests.swift; sourceTree = "<group>"; };
@@ -295,6 +307,7 @@
295307
FD0F55081DC43FFB0084CDCD /* BezierKitTestHelpers.swift */,
296308
FDF0664D1FFA0C9900123308 /* BezierCurveTests.swift */,
297309
FDB6012125BBA06600BAB067 /* BezierCurve+PolynomialTests.swift */,
310+
FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */,
298311
FDE6CD8E1EC8F9BD00FAB479 /* LineSegmentTests.swift */,
299312
FDA727581ED5035300011871 /* CubicCurveTests.swift */,
300313
FD40244F2110CF5100FA723C /* QuadraticCurveTests.swift */,
@@ -345,6 +358,9 @@
345358
FDC859622119274A00AF7642 /* BoundingBoxHierarchy.swift */,
346359
FDB6B3F71EAFD6DF00001C61 /* BezierCurve.swift */,
347360
FDB6011A25BB9B3700BAB067 /* BezierCurve+Polynomial.swift */,
361+
FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */,
362+
FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */,
363+
FD07BC1D261BC97400ED39FF /* RootFinding.swift */,
348364
FD5CF14B22400FCA00FE15A6 /* BezierCurve+Intersection.swift */,
349365
FDB6B3F81EAFD6DF00001C61 /* CubicCurve.swift */,
350366
FDB6B3FC1EAFD6DF00001C61 /* CGPoint+Overloads.swift */,
@@ -673,15 +689,18 @@
673689
FD5CAEF6256C42C00081A964 /* Path+Projection.swift in Sources */,
674690
FD4A63FF200AA50B00930E10 /* Shape.swift in Sources */,
675691
FDB6B40D1EAFD6DF00001C61 /* CGPoint+Overloads.swift in Sources */,
692+
FD07BC25261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */,
676693
FD84360622B0091500AA90EF /* PathComponent+WindingCount.swift in Sources */,
677694
FDB6B40F1EAFD6DF00001C61 /* PathComponent.swift in Sources */,
678695
FDB6B4151EAFD6DF00001C61 /* Utils.swift in Sources */,
696+
FD07BC21261BC97400ED39FF /* RootFinding.swift in Sources */,
679697
FDCE99A6223C404E00597989 /* Path+Data.swift in Sources */,
680698
FDB6011C25BB9B3700BAB067 /* BezierCurve+Polynomial.swift in Sources */,
681699
FDC2EB4B2298735C007768FC /* Lock.swift in Sources */,
682700
FDA03FE125D21B9C005F7795 /* Path+VectorBoolean.swift in Sources */,
683701
FDB6B4071EAFD6DF00001C61 /* Draw.swift in Sources */,
684702
FDB6B4131EAFD6DF00001C61 /* Types.swift in Sources */,
703+
FD07BC23261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */,
685704
FDB6B4031EAFD6DF00001C61 /* BezierCurve.swift in Sources */,
686705
FDB6B4051EAFD6DF00001C61 /* CubicCurve.swift in Sources */,
687706
FDE6CD8D1EC8F2F800FAB479 /* LineSegment.swift in Sources */,
@@ -701,15 +720,18 @@
701720
FD5CAEF5256C42C00081A964 /* Path+Projection.swift in Sources */,
702721
FD4A63FE200AA50B00930E10 /* Shape.swift in Sources */,
703722
FDB6B40C1EAFD6DF00001C61 /* CGPoint+Overloads.swift in Sources */,
723+
FD07BC24261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */,
704724
FD84360522B0091500AA90EF /* PathComponent+WindingCount.swift in Sources */,
705725
FDB6B40E1EAFD6DF00001C61 /* PathComponent.swift in Sources */,
706726
FDB6B4141EAFD6DF00001C61 /* Utils.swift in Sources */,
727+
FD07BC20261BC97400ED39FF /* RootFinding.swift in Sources */,
707728
FDCE99A5223C404E00597989 /* Path+Data.swift in Sources */,
708729
FDB6011B25BB9B3700BAB067 /* BezierCurve+Polynomial.swift in Sources */,
709730
FDC2EB4A2298735C007768FC /* Lock.swift in Sources */,
710731
FDA03FE025D21B9C005F7795 /* Path+VectorBoolean.swift in Sources */,
711732
FDB6B4061EAFD6DF00001C61 /* Draw.swift in Sources */,
712733
FDB6B4121EAFD6DF00001C61 /* Types.swift in Sources */,
734+
FD07BC22261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */,
713735
FDB6B4021EAFD6DF00001C61 /* BezierCurve.swift in Sources */,
714736
FDB6B4041EAFD6DF00001C61 /* CubicCurve.swift in Sources */,
715737
FDE6CD8C1EC8F2F800FAB479 /* LineSegment.swift in Sources */,
@@ -725,6 +747,7 @@
725747
FD4A6408200B11DF00930E10 /* PathComponentTests.swift in Sources */,
726748
FDEF4C6121FBD75A00DCC5C2 /* BoundingBoxHierarchyTests.swift in Sources */,
727749
FDCE99A22239806400597989 /* Path+DataTests.swift in Sources */,
750+
FDC6D2F82649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */,
728751
FD4A6403200ACBD200930E10 /* ShapeTests.swift in Sources */,
729752
FD5CAF0B256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */,
730753
FD5325E726408631002A533C /* PerformanceTests.swift in Sources */,
@@ -757,6 +780,7 @@
757780
FD4A6409200B11DF00930E10 /* PathComponentTests.swift in Sources */,
758781
FDEF4C6221FBD75A00DCC5C2 /* BoundingBoxHierarchyTests.swift in Sources */,
759782
FDCE99A32239806400597989 /* Path+DataTests.swift in Sources */,
783+
FDC6D2F92649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */,
760784
FD4A6404200ACBD200930E10 /* ShapeTests.swift in Sources */,
761785
FD5CAF0C256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */,
762786
FD5325E826408631002A533C /* PerformanceTests.swift in Sources */,
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
//
2+
// BezierCurve+ImplicitizationTests.swift
3+
// BezierKit
4+
//
5+
// Created by Holmes Futrell on 5/10/21.
6+
// Copyright © 2021 Holmes Futrell. All rights reserved.
7+
//
8+
9+
@testable import BezierKit
10+
import XCTest
11+
12+
class BezierCurve_ImplicitizationTests: XCTestCase {
13+
14+
func testLineSegmentImplicitization() {
15+
let lineSegment = LineSegment(p0: CGPoint(x: 1, y: 2), p1: CGPoint(x: 4, y: 3))
16+
let implicitLine = lineSegment.implicitPolynomial
17+
XCTAssertEqual(implicitLine.value(at: lineSegment.startingPoint), 0)
18+
XCTAssertEqual(implicitLine.value(at: lineSegment.endingPoint), 0)
19+
XCTAssertEqual(implicitLine.value(at: lineSegment.point(at: 0.25)), 0)
20+
XCTAssertEqual(implicitLine.value(at: CGPoint(x: 0, y: 5)), 10)
21+
XCTAssertEqual(implicitLine.value(at: CGPoint(x: 2, y: -1)), -10)
22+
// check the implicit line composed with a parametric line
23+
let otherLineSegment = LineSegment(p0: CGPoint(x: 0, y: 5), p1: CGPoint(x: 2, y: -1))
24+
let xPolynomial = BernsteinPolynomialN(coefficients: otherLineSegment.xPolynomial.coefficients)
25+
let yPolynomial = BernsteinPolynomialN(coefficients: otherLineSegment.yPolynomial.coefficients)
26+
let polynomialComposedWithLine = implicitLine.value(xPolynomial, yPolynomial)
27+
XCTAssertEqual(polynomialComposedWithLine.value(at: 0), 10)
28+
XCTAssertEqual(polynomialComposedWithLine.value(at: 1), -10)
29+
}
30+
31+
func testQuadraticCurveImplicitization() {
32+
let quadraticCurve = QuadraticCurve(p0: CGPoint(x: 0, y: 2),
33+
p1: CGPoint(x: 1, y: 0),
34+
p2: CGPoint(x: 2, y: 2))
35+
let implicitQuadratic = quadraticCurve.implicitPolynomial
36+
XCTAssertEqual(implicitQuadratic.value(at: quadraticCurve.startingPoint), 0)
37+
XCTAssertEqual(implicitQuadratic.value(at: quadraticCurve.endingPoint), 0)
38+
XCTAssertEqual(implicitQuadratic.value(at: quadraticCurve.point(at: 0.25)), 0)
39+
let valueAbove = implicitQuadratic.value(at: CGPoint(x: 1, y: 2))
40+
let valueBelow = implicitQuadratic.value(at: CGPoint(x: 1, y: 0))
41+
XCTAssertGreaterThan(valueAbove, 0)
42+
XCTAssertLessThan(valueBelow, 0)
43+
// check the implicit quadratic composed with an parametric quadratic
44+
let otherQuadratic = QuadraticCurve(p0: CGPoint(x: 1, y: 2),
45+
p1: CGPoint(x: 1, y: 1),
46+
p2: CGPoint(x: 1, y: 0))
47+
let polynomialComposedWithQuadratic = implicitQuadratic.value(otherQuadratic.xPolynomial, otherQuadratic.yPolynomial)
48+
XCTAssertEqual(polynomialComposedWithQuadratic.value(at: 0), valueAbove)
49+
XCTAssertEqual(polynomialComposedWithQuadratic.value(at: 0.5), 0)
50+
XCTAssertEqual(polynomialComposedWithQuadratic.value(at: 1), valueBelow)
51+
}
52+
53+
func testCubicImplicitization() {
54+
let cubicCurve = CubicCurve(p0: CGPoint(x: 0, y: 0),
55+
p1: CGPoint(x: 1, y: 1),
56+
p2: CGPoint(x: 2, y: 0),
57+
p3: CGPoint(x: 3, y: 1))
58+
let implicitCubic = cubicCurve.implicitPolynomial
59+
XCTAssertEqual(implicitCubic.value(at: cubicCurve.startingPoint), 0)
60+
XCTAssertEqual(implicitCubic.value(at: cubicCurve.endingPoint), 0)
61+
XCTAssertEqual(implicitCubic.value(at: cubicCurve.point(at: 0.25)), 0)
62+
let valueAbove = implicitCubic.value(at: CGPoint(x: 1, y: 1))
63+
let valueBelow = implicitCubic.value(at: CGPoint(x: 2, y: 0))
64+
XCTAssertGreaterThan(valueAbove, 0)
65+
XCTAssertLessThan(valueBelow, 0)
66+
// check the implicit quadratic composed with a parametric line
67+
let lineSegment = LineSegment(p0: CGPoint(x: 1, y: 1), p1: CGPoint(x: 2, y: 0))
68+
let polynomialComposedWithLineSegment = implicitCubic.value(lineSegment.xPolynomial, lineSegment.yPolynomial)
69+
XCTAssertEqual(polynomialComposedWithLineSegment.value(at: 0), valueAbove)
70+
XCTAssertEqual(polynomialComposedWithLineSegment.value(at: 1), valueBelow)
71+
XCTAssertEqual(polynomialComposedWithLineSegment.value(at: 0.5), 0)
72+
}
73+
}

0 commit comments

Comments
 (0)