Skip to content

Commit

Permalink
Merge branch '0.5.8-release' into 0.5.9-release
Browse files Browse the repository at this point in the history
  • Loading branch information
hfutrell committed May 28, 2019
2 parents cb5a598 + 8ffe206 commit 3288437
Show file tree
Hide file tree
Showing 3 changed files with 28 additions and 12 deletions.
15 changes: 15 additions & 0 deletions BezierKit/BezierKitTests/PathTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,21 @@ class PathTests: XCTestCase {
)
}

func testSubtractingWinding() {
// subtracting should use .evenOdd fill, if it doesn't this test can *add* an inner square instead of doing nothing
let path = Path(cgPath: {
let cgPath = CGMutablePath()
cgPath.addRect(CGRect(x: 0, y: 0, width: 5, height: 5))
cgPath.addRect(CGRect(x: 1, y: 1, width: 3, height: 3))
return cgPath
}())
let subtractionPath = Path(cgPath: CGPath(rect: CGRect(x: 3, y: 3, width: 1, height: 1), transform: nil))
XCTAssertFalse(path.contains(subtractionPath, using: .evenOdd)) // subtractionPath exists in the path's hole, path doesn't contain it
XCTAssertFalse(path.contains(subtractionPath, using: .winding)) // but it *does* contain it using .winding rule
let result = path.subtract(subtractionPath) // since `subtract` uses .evenOdd rule it does nothing
XCTAssertEqual(result, path)
}

func testUnion() {
let expectedResult = Path(components: [PathComponent(curves:
[
Expand Down
16 changes: 8 additions & 8 deletions BezierKit/Library/AugmentedGraph.swift
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,8 @@ internal class PathLinkedListRepresentation {
let p = prev.compute(0.5)
let n = prev.normal(0.5)
let line = LineSegment(p0: p, p1: p + n)
let intersections = path.intersections(with: Path(curve: line))
let s: CGFloat = 0.5 * (intersections.map({$0.indexedPathLocation2.t}).first(where: {$0 > 0}) ?? 1.0)
let intersections = Path(curve: line).intersections(with: path)
let s: CGFloat = 0.5 * (intersections.map({$0.indexedPathLocation1.t}).sorted().first(where: {$0 > CGFloat(Utils.epsilon) }) ?? 1.0)
initialWinding = path.windingCount(p + s * n)
} else {
initialWinding = path.windingCount(startingVertex.emitPrevious().compute(0.5))
Expand Down Expand Up @@ -331,14 +331,14 @@ internal class AugmentedGraph {
case .removeCrossings:
pathComponents += nonCrossingComponents1
case .union:
pathComponents += nonCrossingComponents1.filter { path2.contains(anyPointOnComponent($0)) == false }
pathComponents += nonCrossingComponents2.filter { path1.contains(anyPointOnComponent($0)) == false }
pathComponents += nonCrossingComponents1.filter { path2.contains(anyPointOnComponent($0), using: .evenOdd) == false }
pathComponents += nonCrossingComponents2.filter { path1.contains(anyPointOnComponent($0), using: .evenOdd) == false }
case .subtract:
pathComponents += nonCrossingComponents1.filter { path2.contains(anyPointOnComponent($0)) == false }
pathComponents += nonCrossingComponents2.filter { path1.contains(anyPointOnComponent($0)) == true }
pathComponents += nonCrossingComponents1.filter { path2.contains(anyPointOnComponent($0), using: .evenOdd) == false }
pathComponents += nonCrossingComponents2.filter { path1.contains(anyPointOnComponent($0), using: .evenOdd) == true }
case .intersect:
pathComponents += nonCrossingComponents1.filter { path2.contains(anyPointOnComponent($0)) == true }
pathComponents += nonCrossingComponents2.filter { path1.contains(anyPointOnComponent($0)) == true }
pathComponents += nonCrossingComponents1.filter { path2.contains(anyPointOnComponent($0), using: .evenOdd) == true }
pathComponents += nonCrossingComponents2.filter { path1.contains(anyPointOnComponent($0), using: .evenOdd) == true }
}

// handle components that have crossings (the main algorithm)
Expand Down
9 changes: 5 additions & 4 deletions BezierKit/Library/Path.swift
Original file line number Diff line number Diff line change
Expand Up @@ -240,11 +240,11 @@ internal func windingCountImpliesContainment(_ count: Int, using rule: PathFillR
return windingCountImpliesContainment(count, using: rule)
}

@objc(containsPath:accuracy:) public func contains(_ other: Path, accuracy: CGFloat = BezierKit.defaultIntersectionAccuracy) -> Bool {
@objc(containsPath:usingRule:accuracy:) public func contains(_ other: Path, using rule: PathFillRule = .winding, accuracy: CGFloat = BezierKit.defaultIntersectionAccuracy) -> Bool {
// first, check that each component of `other` starts inside self
for component in other.components {
let p = component.startingPoint
guard self.contains(p) else {
guard self.contains(p, using: rule) else {
return false
}
}
Expand Down Expand Up @@ -295,6 +295,7 @@ internal func windingCountImpliesContainment(_ count: Int, using rule: PathFillR
var paths: [Path] = []
var componentWindingCounts: [Path: Int] = [:]
let componentsAsPaths = self.components.map { Path(components: [$0]) }
let rule: PathFillRule = .evenOdd
for component in componentsAsPaths {
let windingCount = self.windingCount(component.components[0].startingPoint, ignoring: component.components[0])
if windingCount == 0 {
Expand All @@ -314,11 +315,11 @@ internal func windingCountImpliesContainment(_ count: Int, using rule: PathFillR
}
var owner: Path?
for path in paths {
guard path.contains(component) else {
guard path.contains(component, using: rule) else {
continue
}
if owner != nil {
if owner!.contains(path) {
if owner!.contains(path, using: rule) {
owner = path
}
} else {
Expand Down

0 comments on commit 3288437

Please sign in to comment.