Skip to content

Commit

Permalink
Merge pull request #77 from hfutrell/0.8.0-release
Browse files Browse the repository at this point in the history
0.8.0 release
  • Loading branch information
hfutrell authored Nov 25, 2020
2 parents fcc5751 + 165818a commit 38b45b3
Show file tree
Hide file tree
Showing 20 changed files with 740 additions and 187 deletions.
1 change: 0 additions & 1 deletion .swift-version

This file was deleted.

3 changes: 2 additions & 1 deletion BezierKit.podspec
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,12 @@

Pod::Spec.new do |s|
s.name = "BezierKit"
s.version = "0.7.1"
s.version = "0.8.0"
s.summary = "comprehensive Bezier Path library written in Swift"
s.homepage = "https://github.com/hfutrell/BezierKit"
s.license = "MIT"
s.author = { "Holmes Futrell" => "[email protected]" }
s.swift_version = "5.3"

s.ios.deployment_target = "10.0"
s.osx.deployment_target = "10.12"
Expand Down
44 changes: 32 additions & 12 deletions BezierKit/BezierKit.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,12 @@
FD4A6404200ACBD200930E10 /* ShapeTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4A6400200ACB8900930E10 /* ShapeTests.swift */; };
FD4A6408200B11DF00930E10 /* PathComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4A6405200B11DA00930E10 /* PathComponentTests.swift */; };
FD4A6409200B11DF00930E10 /* PathComponentTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD4A6405200B11DA00930E10 /* PathComponentTests.swift */; };
FD5CAEF5256C42C00081A964 /* Path+Projection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CAEF4256C42C00081A964 /* Path+Projection.swift */; };
FD5CAEF6256C42C00081A964 /* Path+Projection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CAEF4256C42C00081A964 /* Path+Projection.swift */; };
FD5CAF04256C92B90081A964 /* Path+ProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CAF03256C92B90081A964 /* Path+ProjectionTests.swift */; };
FD5CAF05256C92B90081A964 /* Path+ProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CAF03256C92B90081A964 /* Path+ProjectionTests.swift */; };
FD5CAF0B256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CAF0A256C92DB0081A964 /* PathComponent+ProjectionTests.swift */; };
FD5CAF0C256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CAF0A256C92DB0081A964 /* PathComponent+ProjectionTests.swift */; };
FD5CF14C22400FCA00FE15A6 /* BezierCurve+Intersection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CF14B22400FCA00FE15A6 /* BezierCurve+Intersection.swift */; };
FD5CF14D22400FCA00FE15A6 /* BezierCurve+Intersection.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD5CF14B22400FCA00FE15A6 /* BezierCurve+Intersection.swift */; };
FD6D9C9F21BEE75C008652C5 /* TransformableTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = FD6D9C9E21BEE75C008652C5 /* TransformableTests.swift */; };
Expand Down Expand Up @@ -156,6 +162,9 @@
FD4A63FD200AA50B00930E10 /* Shape.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = Shape.swift; path = Library/Shape.swift; sourceTree = SOURCE_ROOT; };
FD4A6400200ACB8900930E10 /* ShapeTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ShapeTests.swift; sourceTree = "<group>"; };
FD4A6405200B11DA00930E10 /* PathComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PathComponentTests.swift; sourceTree = "<group>"; };
FD5CAEF4256C42C00081A964 /* Path+Projection.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Path+Projection.swift"; sourceTree = "<group>"; };
FD5CAF03256C92B90081A964 /* Path+ProjectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Path+ProjectionTests.swift"; sourceTree = "<group>"; };
FD5CAF0A256C92DB0081A964 /* PathComponent+ProjectionTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "PathComponent+ProjectionTests.swift"; sourceTree = "<group>"; };
FD5CF14B22400FCA00FE15A6 /* BezierCurve+Intersection.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "BezierCurve+Intersection.swift"; sourceTree = "<group>"; };
FD6D9C9E21BEE75C008652C5 /* TransformableTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransformableTests.swift; sourceTree = "<group>"; };
FD80FF8922B1CEE00018C592 /* LockTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -275,9 +284,11 @@
FD40244F2110CF5100FA723C /* QuadraticCurveTests.swift */,
FD4A6400200ACB8900930E10 /* ShapeTests.swift */,
FD4A6405200B11DA00930E10 /* PathComponentTests.swift */,
FD5CAF0A256C92DB0081A964 /* PathComponent+ProjectionTests.swift */,
FD05111720153EAE000D035E /* BoundingBoxTests.swift */,
FDC7D705211288BD00A9EEF0 /* PathTests.swift */,
FDCE99A12239806400597989 /* Path+DataTests.swift */,
FD5CAF03256C92B90081A964 /* Path+ProjectionTests.swift */,
FDC859592118EC5600AF7642 /* DrawTests.swift */,
FD6D9C9E21BEE75C008652C5 /* TransformableTests.swift */,
FD26915B238B628B002036A6 /* ReversibleTests.swift */,
Expand Down Expand Up @@ -312,24 +323,25 @@
FDB6B3F61EAFD6DF00001C61 /* Library */ = {
isa = PBXGroup;
children = (
FD149EB92135CBFF009E791D /* AugmentedGraph.swift */,
FDC859622119274A00AF7642 /* BoundingBoxHierarchy.swift */,
FDB6B3F71EAFD6DF00001C61 /* BezierCurve.swift */,
FD5CF14B22400FCA00FE15A6 /* BezierCurve+Intersection.swift */,
FDB6B3FE1EAFD6DF00001C61 /* QuadraticCurve.swift */,
FDB6B3F81EAFD6DF00001C61 /* CubicCurve.swift */,
FDE6CD8B1EC8F2F800FAB479 /* LineSegment.swift */,
FDB6B3F91EAFD6DF00001C61 /* Draw.swift */,
FDB6B3FC1EAFD6DF00001C61 /* CGPoint+Overloads.swift */,
FDB6B3FF1EAFD6DF00001C61 /* Types.swift */,
FDB6B4001EAFD6DF00001C61 /* Utils.swift */,
FD4A63FD200AA50B00930E10 /* Shape.swift */,
FDB6B3F91EAFD6DF00001C61 /* Draw.swift */,
FDE6CD8B1EC8F2F800FAB479 /* LineSegment.swift */,
FDC2EB492298735C007768FC /* Lock.swift */,
FDC7D7012111323A00A9EEF0 /* Path.swift */,
FDCE99A4223C404E00597989 /* Path+Data.swift */,
FD5CAEF4256C42C00081A964 /* Path+Projection.swift */,
FDB6B3FD1EAFD6DF00001C61 /* PathComponent.swift */,
FD84360422B0091500AA90EF /* PathComponent+WindingCount.swift */,
FD149EB92135CBFF009E791D /* AugmentedGraph.swift */,
FDC859622119274A00AF7642 /* BoundingBoxHierarchy.swift */,
FDC2EB492298735C007768FC /* Lock.swift */,
FD067AC7246F1200006DA36B /* Polynomial.swift */,
FDB6B3FE1EAFD6DF00001C61 /* QuadraticCurve.swift */,
FD4A63FD200AA50B00930E10 /* Shape.swift */,
FDB6B3FF1EAFD6DF00001C61 /* Types.swift */,
FDB6B4001EAFD6DF00001C61 /* Utils.swift */,
);
path = Library;
sourceTree = "<group>";
Expand Down Expand Up @@ -488,7 +500,7 @@
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 0830;
LastUpgradeCheck = 1100;
LastUpgradeCheck = 1210;
ORGANIZATIONNAME = "Holmes Futrell";
TargetAttributes = {
FD0F54F41DC43FFB0084CDCD = {
Expand Down Expand Up @@ -638,6 +650,7 @@
FD5CF14D22400FCA00FE15A6 /* BezierCurve+Intersection.swift in Sources */,
FDC7D7042111323A00A9EEF0 /* Path.swift in Sources */,
FDC859642119274A00AF7642 /* BoundingBoxHierarchy.swift in Sources */,
FD5CAEF6256C42C00081A964 /* Path+Projection.swift in Sources */,
FD4A63FF200AA50B00930E10 /* Shape.swift in Sources */,
FDB6B40D1EAFD6DF00001C61 /* CGPoint+Overloads.swift in Sources */,
FD84360622B0091500AA90EF /* PathComponent+WindingCount.swift in Sources */,
Expand All @@ -663,6 +676,7 @@
FD5CF14C22400FCA00FE15A6 /* BezierCurve+Intersection.swift in Sources */,
FDC7D7032111323A00A9EEF0 /* Path.swift in Sources */,
FDC455EE211D057E00DBF2B2 /* BoundingBoxHierarchy.swift in Sources */,
FD5CAEF5256C42C00081A964 /* Path+Projection.swift in Sources */,
FD4A63FE200AA50B00930E10 /* Shape.swift in Sources */,
FDB6B40C1EAFD6DF00001C61 /* CGPoint+Overloads.swift in Sources */,
FD84360522B0091500AA90EF /* PathComponent+WindingCount.swift in Sources */,
Expand All @@ -683,10 +697,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FD5CAF04256C92B90081A964 /* Path+ProjectionTests.swift in Sources */,
FD4A6408200B11DF00930E10 /* PathComponentTests.swift in Sources */,
FDEF4C6121FBD75A00DCC5C2 /* BoundingBoxHierarchyTests.swift in Sources */,
FDCE99A22239806400597989 /* Path+DataTests.swift in Sources */,
FD4A6403200ACBD200930E10 /* ShapeTests.swift in Sources */,
FD5CAF0B256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */,
FDF0664E1FFA0C9900123308 /* BezierCurveTests.swift in Sources */,
FD06332321E03A58001181B6 /* CGPointTests.swift in Sources */,
FD12F1E22288CF6900404CE1 /* UtilsTests.swift in Sources */,
Expand All @@ -710,10 +726,12 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
FD5CAF05256C92B90081A964 /* Path+ProjectionTests.swift in Sources */,
FD4A6409200B11DF00930E10 /* PathComponentTests.swift in Sources */,
FDEF4C6221FBD75A00DCC5C2 /* BoundingBoxHierarchyTests.swift in Sources */,
FDCE99A32239806400597989 /* Path+DataTests.swift in Sources */,
FD4A6404200ACBD200930E10 /* ShapeTests.swift in Sources */,
FD5CAF0C256C92DB0081A964 /* PathComponent+ProjectionTests.swift in Sources */,
FDF0664F1FFA0C9900123308 /* BezierCurveTests.swift in Sources */,
FD06332421E03A58001181B6 /* CGPointTests.swift in Sources */,
FD12F1E32288CF6900404CE1 /* UtilsTests.swift in Sources */,
Expand Down Expand Up @@ -790,6 +808,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
Expand Down Expand Up @@ -852,6 +871,7 @@
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
Expand Down Expand Up @@ -1060,7 +1080,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = BezierKit_MacTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.12;
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = "com.HolmesFutrell.BezierKit-MacTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
Expand All @@ -1075,7 +1095,7 @@
COMBINE_HIDPI_IMAGES = YES;
INFOPLIST_FILE = BezierKit_MacTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/../Frameworks @loader_path/../Frameworks";
MACOSX_DEPLOYMENT_TARGET = 10.12;
MACOSX_DEPLOYMENT_TARGET = 10.15;
PRODUCT_BUNDLE_IDENTIFIER = "com.HolmesFutrell.BezierKit-MacTests";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_SWIFT3_OBJC_INFERENCE = Default;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1210"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1210"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1210"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1210"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1100"
LastUpgradeVersion = "1210"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
16 changes: 15 additions & 1 deletion BezierKit/BezierKitTests/CubicCurveTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -288,13 +288,27 @@ class CubicCurveTests: XCTestCase {
XCTAssertEqual(p7.t, t, accuracy: epsilon)
}

func testProjectRealWorldIssue() {
// this issue occurred when using the Bezier Clipping approach
// to root solving due to some kind of issue with the limits of precision
// one idea is to look at the .split() functions and make sure there are no cracks
// another idea is to look at the start and end points and actually require the call to produce a solution
let epsilon: CGFloat = 1.0e-5
let c = CubicCurve(p0: CGPoint(x: 100, y: 25),
p1: CGPoint(x: 10, y: 90),
p2: CGPoint(x: 50, y: 185),
p3: CGPoint(x: 170, y: 175))
let t = c.project(CGPoint(x: 8.3359375, y: -49.10546875)).t
XCTAssertEqual(t, 0.0575491, accuracy: epsilon)
}

func testProjectPerformance() {
let c = CubicCurve(p0: CGPoint(x: -1, y: -1),
p1: CGPoint(x: 3, y: 1),
p2: CGPoint(x: -3, y: 1),
p3: CGPoint(x: 1, y: -1))
self.measure {
// roughly 0.060 -Onone, 0.007 with -Ospeed
// roughly 0.029 -Onone, 0.004 with -Ospeed
for theta in stride(from: 0, to: 2*Double.pi, by: 0.01) {
_ = c.project(CGPoint(x: cos(theta), y: sin(theta)))
}
Expand Down
62 changes: 62 additions & 0 deletions BezierKit/BezierKitTests/Path+ProjectionTests.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
//
// Path+ProjectionTests.swift
// BezierKit
//
// Created by Holmes Futrell on 11/23/20.
// Copyright © 2020 Holmes Futrell. All rights reserved.
//

@testable import BezierKit
import XCTest

#if canImport(CoreGraphics)
import CoreGraphics

class PathProjectionTests: XCTestCase {
func testProjection() {
XCTAssertNil(Path().project(CGPoint.zero), "projection requires non-empty path.")
let triangle1 = { () -> Path in
let cgPath = CGMutablePath()
cgPath.addLines(between: [CGPoint(x: 0, y: 2),
CGPoint(x: 2, y: 4),
CGPoint(x: 0, y: 4)])
cgPath.closeSubpath()
return Path(cgPath: cgPath)
}()
let triangle2 = { () -> Path in
let cgPath = CGMutablePath()
cgPath.addLines(between: [CGPoint(x: 2, y: 1),
CGPoint(x: 3, y: 1),
CGPoint(x: 3, y: 2)])
cgPath.closeSubpath()
return Path(cgPath: cgPath)
}()
let square = Path(rect: CGRect(x: 3, y: 3, width: 1, height: 1))
let path = Path(components: triangle1.components + triangle2.components + square.components)
let projection = path.project(CGPoint(x: 2, y: 2))
XCTAssertEqual(projection?.location, IndexedPathLocation(componentIndex: 1, elementIndex: 2, t: 0.5))
XCTAssertEqual(projection?.point, CGPoint(x: 2.5, y: 1.5))
}
func testPointIsWithinDistanceOfBoundary() {

let circleCGPath = CGMutablePath()
circleCGPath.addEllipse(in: CGRect(origin: CGPoint(x: -1.0, y: -1.0), size: CGSize(width: 2.0, height: 2.0)))

let circlePath = Path(cgPath: circleCGPath) // a circle centered at origin with radius 1

let d = CGFloat(0.1)
let p1 = CGPoint(x: -3.0, y: 0.0)
let p2 = CGPoint(x: -0.9, y: 0.9)
let p3 = CGPoint(x: 0.75, y: 0.75)
let p4 = CGPoint(x: 0.5, y: 0.5)

XCTAssertFalse(circlePath.pointIsWithinDistanceOfBoundary(p1, distance: d)) // no, path bounding box isn't even within that distance
XCTAssertFalse(circlePath.pointIsWithinDistanceOfBoundary(p2, distance: d)) // no, within bounding box, but no individual curves are within that distance
XCTAssertTrue(circlePath.pointIsWithinDistanceOfBoundary(p3, distance: d)) // yes, one of the curves that makes up the circle is within that distance
XCTAssertTrue(circlePath.pointIsWithinDistanceOfBoundary(p3, distance: CGFloat(10.0))) // yes, so obviously within that distance implementation should early return yes
XCTAssertFalse(circlePath.pointIsWithinDistanceOfBoundary(p4, distance: d)) // no, we are inside the path but too far from the boundary

}
}

#endif
Loading

0 comments on commit 38b45b3

Please sign in to comment.