Skip to content

Commit

Permalink
Merge pull request #94 from hfutrell/intersection-via-implicitization
Browse files Browse the repository at this point in the history
Intersection via implicitization
  • Loading branch information
hfutrell committed May 12, 2021
2 parents 13b6bb7 + 2ec6cc4 commit 385af8c
Show file tree
Hide file tree
Showing 16 changed files with 817 additions and 46 deletions.
24 changes: 24 additions & 0 deletions BezierKit/BezierKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@
FD067AC9246F1200006DA36B /* Polynomial.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD067AC7246F1200006DA36B /* Polynomial.swift */; };
FD067ACB246F12B5006DA36B /* PolynomialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD067ACA246F12B5006DA36B /* PolynomialTests.swift */; };
FD067ACC246F12B5006DA36B /* PolynomialTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD067ACA246F12B5006DA36B /* PolynomialTests.swift */; };
FD07BC20261BC97400ED39FF /* RootFinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1D261BC97400ED39FF /* RootFinding.swift */; };
FD07BC21261BC97400ED39FF /* RootFinding.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1D261BC97400ED39FF /* RootFinding.swift */; };
FD07BC22261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */; };
FD07BC23261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */; };
FD07BC24261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */; };
FD07BC25261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */; };
FD12F1E22288CF6900404CE1 /* UtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD12F1E12288CF6900404CE1 /* UtilsTests.swift */; };
FD12F1E32288CF6900404CE1 /* UtilsTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD12F1E12288CF6900404CE1 /* UtilsTests.swift */; };
FD149EBA2135CBFF009E791D /* AugmentedGraph.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD149EB92135CBFF009E791D /* AugmentedGraph.swift */; };
Expand Down Expand Up @@ -88,6 +94,8 @@
FDC2EB4A2298735C007768FC /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2EB492298735C007768FC /* Lock.swift */; };
FDC2EB4B2298735C007768FC /* Lock.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC2EB492298735C007768FC /* Lock.swift */; };
FDC455EE211D057E00DBF2B2 /* BoundingBoxHierarchy.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC859622119274A00AF7642 /* BoundingBoxHierarchy.swift */; };
FDC6D2F82649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */; };
FDC6D2F92649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */; };
FDC7D7032111323A00A9EEF0 /* Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC7D7012111323A00A9EEF0 /* Path.swift */; };
FDC7D7042111323A00A9EEF0 /* Path.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC7D7012111323A00A9EEF0 /* Path.swift */; };
FDC7D706211288BD00A9EEF0 /* PathTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FDC7D705211288BD00A9EEF0 /* PathTests.swift */; };
Expand Down Expand Up @@ -156,6 +164,9 @@
FD06332221E03A58001181B6 /* CGPointTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CGPointTests.swift; sourceTree = "<group>"; };
FD067AC7246F1200006DA36B /* Polynomial.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Polynomial.swift; sourceTree = "<group>"; };
FD067ACA246F12B5006DA36B /* PolynomialTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PolynomialTests.swift; sourceTree = "<group>"; };
FD07BC1D261BC97400ED39FF /* RootFinding.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = RootFinding.swift; path = Library/RootFinding.swift; sourceTree = SOURCE_ROOT; };
FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = BernsteinPolynomialN.swift; path = Library/BernsteinPolynomialN.swift; sourceTree = SOURCE_ROOT; };
FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "BezierCurve+Implicitization.swift"; path = "Library/BezierCurve+Implicitization.swift"; sourceTree = SOURCE_ROOT; };
FD0F54F51DC43FFB0084CDCD /* MacDemos.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MacDemos.app; sourceTree = BUILT_PRODUCTS_DIR; };
FD0F55081DC43FFB0084CDCD /* BezierKitTestHelpers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BezierKitTestHelpers.swift; sourceTree = "<group>"; };
FD0F550A1DC43FFB0084CDCD /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
Expand Down Expand Up @@ -207,6 +218,7 @@
FDB9D7411EB28D1900413F0E /* BezierKit_MacTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BezierKit_MacTests.swift; sourceTree = "<group>"; };
FDB9D7431EB28D1900413F0E /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
FDC2EB492298735C007768FC /* Lock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Lock.swift; sourceTree = "<group>"; };
FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BezierCurve+ImplicitizationTests.swift"; sourceTree = "<group>"; };
FDC7D7012111323A00A9EEF0 /* Path.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Path.swift; sourceTree = "<group>"; };
FDC7D705211288BD00A9EEF0 /* PathTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathTests.swift; sourceTree = "<group>"; };
FDC859592118EC5600AF7642 /* DrawTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DrawTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -295,6 +307,7 @@
FD0F55081DC43FFB0084CDCD /* BezierKitTestHelpers.swift */,
FDF0664D1FFA0C9900123308 /* BezierCurveTests.swift */,
FDB6012125BBA06600BAB067 /* BezierCurve+PolynomialTests.swift */,
FDC6D2F72649D15200002BBA /* BezierCurve+ImplicitizationTests.swift */,
FDE6CD8E1EC8F9BD00FAB479 /* LineSegmentTests.swift */,
FDA727581ED5035300011871 /* CubicCurveTests.swift */,
FD40244F2110CF5100FA723C /* QuadraticCurveTests.swift */,
Expand Down Expand Up @@ -345,6 +358,9 @@
FDC859622119274A00AF7642 /* BoundingBoxHierarchy.swift */,
FDB6B3F71EAFD6DF00001C61 /* BezierCurve.swift */,
FDB6011A25BB9B3700BAB067 /* BezierCurve+Polynomial.swift */,
FD07BC1E261BC97400ED39FF /* BernsteinPolynomialN.swift */,
FD07BC1F261BC97400ED39FF /* BezierCurve+Implicitization.swift */,
FD07BC1D261BC97400ED39FF /* RootFinding.swift */,
FD5CF14B22400FCA00FE15A6 /* BezierCurve+Intersection.swift */,
FDB6B3F81EAFD6DF00001C61 /* CubicCurve.swift */,
FDB6B3FC1EAFD6DF00001C61 /* CGPoint+Overloads.swift */,
Expand Down Expand Up @@ -673,15 +689,18 @@
FD5CAEF6256C42C00081A964 /* Path+Projection.swift in Sources */,
FD4A63FF200AA50B00930E10 /* Shape.swift in Sources */,
FDB6B40D1EAFD6DF00001C61 /* CGPoint+Overloads.swift in Sources */,
FD07BC25261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */,
FD84360622B0091500AA90EF /* PathComponent+WindingCount.swift in Sources */,
FDB6B40F1EAFD6DF00001C61 /* PathComponent.swift in Sources */,
FDB6B4151EAFD6DF00001C61 /* Utils.swift in Sources */,
FD07BC21261BC97400ED39FF /* RootFinding.swift in Sources */,
FDCE99A6223C404E00597989 /* Path+Data.swift in Sources */,
FDB6011C25BB9B3700BAB067 /* BezierCurve+Polynomial.swift in Sources */,
FDC2EB4B2298735C007768FC /* Lock.swift in Sources */,
FDA03FE125D21B9C005F7795 /* Path+VectorBoolean.swift in Sources */,
FDB6B4071EAFD6DF00001C61 /* Draw.swift in Sources */,
FDB6B4131EAFD6DF00001C61 /* Types.swift in Sources */,
FD07BC23261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */,
FDB6B4031EAFD6DF00001C61 /* BezierCurve.swift in Sources */,
FDB6B4051EAFD6DF00001C61 /* CubicCurve.swift in Sources */,
FDE6CD8D1EC8F2F800FAB479 /* LineSegment.swift in Sources */,
Expand All @@ -701,15 +720,18 @@
FD5CAEF5256C42C00081A964 /* Path+Projection.swift in Sources */,
FD4A63FE200AA50B00930E10 /* Shape.swift in Sources */,
FDB6B40C1EAFD6DF00001C61 /* CGPoint+Overloads.swift in Sources */,
FD07BC24261BC97400ED39FF /* BezierCurve+Implicitization.swift in Sources */,
FD84360522B0091500AA90EF /* PathComponent+WindingCount.swift in Sources */,
FDB6B40E1EAFD6DF00001C61 /* PathComponent.swift in Sources */,
FDB6B4141EAFD6DF00001C61 /* Utils.swift in Sources */,
FD07BC20261BC97400ED39FF /* RootFinding.swift in Sources */,
FDCE99A5223C404E00597989 /* Path+Data.swift in Sources */,
FDB6011B25BB9B3700BAB067 /* BezierCurve+Polynomial.swift in Sources */,
FDC2EB4A2298735C007768FC /* Lock.swift in Sources */,
FDA03FE025D21B9C005F7795 /* Path+VectorBoolean.swift in Sources */,
FDB6B4061EAFD6DF00001C61 /* Draw.swift in Sources */,
FDB6B4121EAFD6DF00001C61 /* Types.swift in Sources */,
FD07BC22261BC97400ED39FF /* BernsteinPolynomialN.swift in Sources */,
FDB6B4021EAFD6DF00001C61 /* BezierCurve.swift in Sources */,
FDB6B4041EAFD6DF00001C61 /* CubicCurve.swift in Sources */,
FDE6CD8C1EC8F2F800FAB479 /* LineSegment.swift in Sources */,
Expand All @@ -725,6 +747,7 @@
FD4A6408200B11DF00930E10 /* PathComponentTests.swift in Sources */,
FDEF4C6121FBD75A00DCC5C2 /* BoundingBoxHierarchyTests.swift in Sources */,
FDCE99A22239806400597989 /* Path+DataTests.swift in Sources */,
FDC6D2F82649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */,
FD4A6403200ACBD200930E10 /* ShapeTests.swift in Sources */,
FD5CAF0B256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */,
FD5325E726408631002A533C /* PerformanceTests.swift in Sources */,
Expand Down Expand Up @@ -757,6 +780,7 @@
FD4A6409200B11DF00930E10 /* PathComponentTests.swift in Sources */,
FDEF4C6221FBD75A00DCC5C2 /* BoundingBoxHierarchyTests.swift in Sources */,
FDCE99A32239806400597989 /* Path+DataTests.swift in Sources */,
FDC6D2F92649D15200002BBA /* BezierCurve+ImplicitizationTests.swift in Sources */,
FD4A6404200ACBD200930E10 /* ShapeTests.swift in Sources */,
FD5CAF0C256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */,
FD5325E826408631002A533C /* PerformanceTests.swift in Sources */,
Expand Down
73 changes: 73 additions & 0 deletions BezierKit/BezierKitTests/BezierCurve+ImplicitizationTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
//
// BezierCurve+ImplicitizationTests.swift
// BezierKit
//
// Created by Holmes Futrell on 5/10/21.
// Copyright © 2021 Holmes Futrell. All rights reserved.
//

@testable import BezierKit
import XCTest

class BezierCurve_ImplicitizationTests: XCTestCase {

func testLineSegmentImplicitization() {
let lineSegment = LineSegment(p0: CGPoint(x: 1, y: 2), p1: CGPoint(x: 4, y: 3))
let implicitLine = lineSegment.implicitPolynomial
XCTAssertEqual(implicitLine.value(at: lineSegment.startingPoint), 0)
XCTAssertEqual(implicitLine.value(at: lineSegment.endingPoint), 0)
XCTAssertEqual(implicitLine.value(at: lineSegment.point(at: 0.25)), 0)
XCTAssertEqual(implicitLine.value(at: CGPoint(x: 0, y: 5)), 10)
XCTAssertEqual(implicitLine.value(at: CGPoint(x: 2, y: -1)), -10)
// check the implicit line composed with a parametric line
let otherLineSegment = LineSegment(p0: CGPoint(x: 0, y: 5), p1: CGPoint(x: 2, y: -1))
let xPolynomial = BernsteinPolynomialN(coefficients: otherLineSegment.xPolynomial.coefficients)
let yPolynomial = BernsteinPolynomialN(coefficients: otherLineSegment.yPolynomial.coefficients)
let polynomialComposedWithLine = implicitLine.value(xPolynomial, yPolynomial)
XCTAssertEqual(polynomialComposedWithLine.value(at: 0), 10)
XCTAssertEqual(polynomialComposedWithLine.value(at: 1), -10)
}

func testQuadraticCurveImplicitization() {
let quadraticCurve = QuadraticCurve(p0: CGPoint(x: 0, y: 2),
p1: CGPoint(x: 1, y: 0),
p2: CGPoint(x: 2, y: 2))
let implicitQuadratic = quadraticCurve.implicitPolynomial
XCTAssertEqual(implicitQuadratic.value(at: quadraticCurve.startingPoint), 0)
XCTAssertEqual(implicitQuadratic.value(at: quadraticCurve.endingPoint), 0)
XCTAssertEqual(implicitQuadratic.value(at: quadraticCurve.point(at: 0.25)), 0)
let valueAbove = implicitQuadratic.value(at: CGPoint(x: 1, y: 2))
let valueBelow = implicitQuadratic.value(at: CGPoint(x: 1, y: 0))
XCTAssertGreaterThan(valueAbove, 0)
XCTAssertLessThan(valueBelow, 0)
// check the implicit quadratic composed with an parametric quadratic
let otherQuadratic = QuadraticCurve(p0: CGPoint(x: 1, y: 2),
p1: CGPoint(x: 1, y: 1),
p2: CGPoint(x: 1, y: 0))
let polynomialComposedWithQuadratic = implicitQuadratic.value(otherQuadratic.xPolynomial, otherQuadratic.yPolynomial)
XCTAssertEqual(polynomialComposedWithQuadratic.value(at: 0), valueAbove)
XCTAssertEqual(polynomialComposedWithQuadratic.value(at: 0.5), 0)
XCTAssertEqual(polynomialComposedWithQuadratic.value(at: 1), valueBelow)
}

func testCubicImplicitization() {
let cubicCurve = CubicCurve(p0: CGPoint(x: 0, y: 0),
p1: CGPoint(x: 1, y: 1),
p2: CGPoint(x: 2, y: 0),
p3: CGPoint(x: 3, y: 1))
let implicitCubic = cubicCurve.implicitPolynomial
XCTAssertEqual(implicitCubic.value(at: cubicCurve.startingPoint), 0)
XCTAssertEqual(implicitCubic.value(at: cubicCurve.endingPoint), 0)
XCTAssertEqual(implicitCubic.value(at: cubicCurve.point(at: 0.25)), 0)
let valueAbove = implicitCubic.value(at: CGPoint(x: 1, y: 1))
let valueBelow = implicitCubic.value(at: CGPoint(x: 2, y: 0))
XCTAssertGreaterThan(valueAbove, 0)
XCTAssertLessThan(valueBelow, 0)
// check the implicit quadratic composed with a parametric line
let lineSegment = LineSegment(p0: CGPoint(x: 1, y: 1), p1: CGPoint(x: 2, y: 0))
let polynomialComposedWithLineSegment = implicitCubic.value(lineSegment.xPolynomial, lineSegment.yPolynomial)
XCTAssertEqual(polynomialComposedWithLineSegment.value(at: 0), valueAbove)
XCTAssertEqual(polynomialComposedWithLineSegment.value(at: 1), valueBelow)
XCTAssertEqual(polynomialComposedWithLineSegment.value(at: 0.5), 0)
}
}

0 comments on commit 385af8c

Please sign in to comment.