hfutrell / bezierkit Goto Github PK
View Code? Open in Web Editor NEWBezier curves and paths in Swift for building vector applications
License: MIT License
Bezier curves and paths in Swift for building vector applications
License: MIT License
Text:
path.components.map { $0.curves } =
[[BezierKit.CubicCurve(p0: (28.0, 14.0), p1: (32.0, 21.0), p2: (33.0, 42.0), p3: (30.0, 53.0)), BezierKit.CubicCurve(p0: (30.0, 53.0), p1: (19.0, 32.0), p2: (22.0, 26.0), p3: (28.0, 14.0))], [BezierKit.CubicCurve(p0: (42.0, 38.0), p1: (42.0, 53.0), p2: (36.0, 53.0), p3: (27.0, 53.0)), BezierKit.CubicCurve(p0: (27.0, 53.0), p1: (19.0, 40.0), p2: (29.0, 32.0), p3: (42.0, 38.0))]]
path.crossingsRemoved().components.map { $0.curves } =
[]
Visual:
Let consider the 2 following UIBezierPath:
let p1 = UIBezierPath()
p1.move(to: CGPoint(x: 160.30770651563628, y: 827.7553004653367))
p1.addCurve(to: CGPoint(x: 110.26942663248718, y: 568.5268524837642), controlPoint1: CGPoint(x: 181.33161356383755, y: 737.7466984152248), controlPoint2: CGPoint(x: 164.05060972624904, y: 653.3356412085424))
p1.addCurve(to: CGPoint(x: 68.86790851824688, y: 559.2578558910238), controlPoint1: CGPoint(x: 101.39627582752009, y: 554.534576214393), controlPoint2: CGPoint(x: 82.86018478761805, y: 550.3847050860568))
p1.addCurve(to: CGPoint(x: 59.59891192550654, y: 600.6593740052641), controlPoint1: CGPoint(x: 54.875632248875704, y: 568.1310066959909), controlPoint2: CGPoint(x: 50.725761120539445, y: 586.667097735893))
p1.addCurve(to: CGPoint(x: 101.88038125865839, y: 814.1080420111522), controlPoint1: CGPoint(x: 105.11513351206828, y: 672.4349541994575), controlPoint2: CGPoint(x: 119.06082214735332, y: 740.5542794564268))
p1.addCurve(to: CGPoint(x: 124.27041466005505, y: 850.1453338667334), controlPoint1: CGPoint(x: 98.11179489803564, y: 830.2423023675684), controlPoint2: CGPoint(x: 108.13615430363883, y: 846.3767475061106))
p1.addCurve(to: CGPoint(x: 160.30770651563628, y: 827.7553004653367), controlPoint1: CGPoint(x: 140.40467501647126, y: 853.9139202273561), controlPoint2: CGPoint(x: 156.53912015501353, y: 843.889560821753))
and
let p2 = UIBezierPath()
p2.move(to: CGPoint(x: 110.01560660410875, y: 568.1334199999095))
p2.addCurve(to: CGPoint(x: -34.46691786355873, y: 426.72807843882487), controlPoint1: CGPoint(x: 64.94829801467844, y: 499.45942595887277), controlPoint2: CGPoint(x: 20.78869552632778, y: 454.67344613026177))
p2.addCurve(to: CGPoint(x: -69.07061390857123, y: 474.860094579322), controlPoint1: CGPoint(x: -65.01464367993249, y: 411.2786538880151), controlPoint2: CGPoint(x: -93.44515961076199, y: 450.82408423410607))
p2.addLine(to: CGPoint(x: 63.869824962902115, y: 605.9541384664693))
p2.addCurve(to: CGPoint(x: 110.01560660410875, y: 568.1334199999095), controlPoint1: CGPoint(x: 89.4862743247028, y: 631.2148038093562), controlPoint2: CGPoint(x: 129.75430800678396, y: 598.2114411849384))
If we create 2 Paths and perform a union,
let path1 = Path(cgPath: p1.cgPath)
let path2 = Path(cgPath: p2.cgPath)
let final = path1.union(path2)
the final
Path is Empty while the 2 Paths are overlapping.
this means that Swift classes that depend on Hashable such as Set
will fail to locate instances that are identical but do not share the same address, such as independent copies.
A good unit test of this behavior is to make a Path, add it to a Set
, make a copy using Path.copy(using: CGAffineTransform.identity)
and see if Set.contains()
still locates it.
Here is an example where droots gets low precision in 0.11.0
The unit test that demonstrates this issue was removed because it is somewhat low priority and represents a longstanding issue.
func testDrootsCubicWorldIssue4() {
// this test was failing due to round-off it seems
let roots = drootsCubicTestHelper(117.11706850363589,
39.0399142482629,
-2.3525217329734005e-06,
-2.352663614146877e-06)
let filtered = roots.filter { $0 >= 0 && $0 <= 1 }
XCTAssertEqual(filtered.count, 1)
XCTAssertEqual(filtered.first!, CGFloat(0.999858), accuracy: 1.0e-5)
}
The answer is gets for the root is 0.9997828474060952
which is incorrect in the 4th digit.
There was another related unit test that failed for the same reason:
func testCrossingsRemovedFifthRealWorldCase() {
// this test fails for the same reason that
// `testDrootsCubicWorldIssue4` fails
// the path doesn't have any self-intersections
// but the `contains` call gives the wrong results
let cgPath = CGMutablePath()
cgPath.move(to: CGPoint(x: -45.58408505173276, y: 4384.210079234615))
cgPath.addCurve(to: CGPoint(x: 519.756427723393, y: 4384.14765017776),
control1: CGPoint(x: 110.51314747385496, y: 4228.07836809298),
control2: CGPoint(x: 363.6247165817579, y: 4228.050417652172))
cgPath.addCurve(to: CGPoint(x: 519.8188567802481, y: 4949.488162952885),
control1: CGPoint(x: 675.8881388650282, y: 4540.244882703348),
control2: CGPoint(x: 675.9160893058358, y: 4793.356451811251))
cgPath.addCurve(to: CGPoint(x: 501.53832994006814, y: 4967.769608589276),
control1: CGPoint(x: 513.7155041887056, y: 4955.5928615872745),
control2: CGPoint(x: 507.6055609674461, y: 4961.702072477192))
cgPath.addCurve(to: CGPoint(x: -63.802186103924214, y: 4967.783798079717),
control1: CGPoint(x: 345.4277755233733, y: 5123.887999645149),
control2: CGPoint(x: 92.31620495194895, y: 5123.894352496412))
cgPath.addCurve(to: CGPoint(x: -63.81637559436501, y: 4402.443282035724),
control1: CGPoint(x: -219.92057715979726, y: 4811.673243663022),
control2: CGPoint(x: -219.9269300110598, y: 4558.561673091597))
cgPath.addCurve(to: CGPoint(x: -45.58408505173276, y: 4384.210079234615),
control1: CGPoint(x: -57.725037285805456, y: 4396.351638460308),
control2: CGPoint(x: -51.63917972581493, y: 4390.2665134127255))
let path = Path(cgPath: cgPath)
let result = path.crossingsRemoved()
// seems to fail because we get the wrnog results here:
// we get the right results with 1.0e-5
// let curve = path.components[0].curves[0]
// let point = curve.point(at: 0.5) - 1.0e-7 * curve.normal(at: 0.5)
// XCTAssertFalse(path.contains(point))
XCTAssertEqual(path, result)
}
Here’s an example of a capital O showing what happens when offset(10)
is applied: each on-curve point is shifted in the offset direction by 10 units.
Here’s an example of the same offset(10)
applied to a capital H. In this case, the points are only moving 5 units from their original positions:
Now here’s a capital D with offset(10)
. Whereas the O was only made of curves, and the H only made of straights, this combines both. The result is that the straight segments are moving only half the distance, so certain segments that should be parallel are not. For instance, the top and bottom edges are no longer horizontal.
Not sure why but this namespacing doesn't work if you just pull in the Library folder into a project!
Your library is great - thanks so much for making it!
Currently — am I wrong? — these operations only seem to accept a single distance
argument that represents a distance in both x and y. It would be useful to be able to pass separate distances in x and y for these operations.
Without detracting from your success with #81, I discovered a case that still fails with that patch:
path.components.map { $0.curves } =
[[BezierKit.LineSegment(p0: (100.0, 585.0), p1: (100.0, 585.0)), BezierKit.LineSegment(p0: (100.0, 585.0), p1: (225.0, 585.0)), BezierKit.LineSegment(p0: (225.0, 585.0), p1: (100.0, 680.0)), BezierKit.LineSegment(p0: (100.0, 680.0), p1: (100.0, 585.0))], [BezierKit.LineSegment(p0: (260.0, 392.0), p1: (260.0, 585.0)), BezierKit.LineSegment(p0: (260.0, 585.0), p1: (160.0, 680.0)), BezierKit.LineSegment(p0: (160.0, 680.0), p1: (260.0, 392.0))]]
path.crossingsRemoved().components.map { $0.curves } =
[]
Looks like:
The bugaboo is that we have two points sitting atop each other at (100,585). There is no value of the discriminant that will cure this problem (so it deserves to be considered a distinct issue, I think).
In this case the “crossing” has zero area, so the “removal” (based on behavior of other crossing-removal algorithms I’ve used) should mean that the coincident points are collapsed into a single point.
For that matter, there doesn’t even need to be an actual geometric overlap for the operation to fail. A simpler example:
path.components.map { $0.curves } =
[[BezierKit.LineSegment(p0: (290.0, 467.0), p1: (290.0, 467.0)), BezierKit.LineSegment(p0: (290.0, 467.0), p1: (394.0, 467.0)), BezierKit.LineSegment(p0: (394.0, 467.0), p1: (290.0, 579.0)), BezierKit.LineSegment(p0: (290.0, 579.0), p1: (290.0, 467.0))]]
path.crossingsRemoved().components.map { $0.curves } =
[]
This can happen when you have a shape made up of curves when the shape is a height and width of 0. The generated outline path will be a group of points where every point is equal.
The assertion hit is "curves are not contiguous." in PathComponent.init(curves:)
this can be really confusing, and probably resulted from BezierKit originally only having a boundingBox
method which behaved like CoreGraphics boundingBoxOfPath
. Therefore when BezierKit added boundingBoxOfPath
it chose the wrong convention.
I want to suggest an improvement of intersection finding algorithm - I have a working solution in C++ and ObjC based on this paper: https://mat.polsl.pl/sjpam/zeszyty/z6/Silesian_J_Pure_Appl_Math_v6_i1_str_155-176.pdf which can be ported to swift.
The solution uses Jenkins-Traub polynomial (9) solving method by Chris Sweeny which requires complex number math.
Question before I start making the PR: do authors of this library consider adding either Eigen C++ template library or swift-numerics library as a dependency (to have complex number math in place)?
Hi, maybe this is not a issue, but I don't know make closed PathComponent
. I have var curves : [CubicCurve]
array where last.endingPoint == first.startPoint
. I expect to get closed PathComponent
, form PathComponent(curves: curves)
but I receive "curves are not contiguous."
error.
I very much like what you are doing with BezierKit and would like to use it for a new project. I plan to draw graphs (boxes connected by lines). The path between boxes will be connected by polylines (converted to BezierKit Paths) and I want to add arrowheads where the path intersects with the box at either end. This seems like it ought to be easy:
Unfortunately, I run into problems at step 3, as the boolean operations only seem to work on closed paths, and the polyline is, in its simplest case a single straight line segment— it might be composed of many segments or other bezier curves, but it is not a closed path. If I first outline the path, the subtraction works as expected, but then I can't simply compute the locations of the path's ends and derivatives to know where to place the arrowheads. I can compute the intersections of the box paths with the line paths, but there doesn't appear to be any way to simply use the PathIntersection
or IndexedPathLocation
objects to split the path at the intersection points.
As I said, this seems like it ought to be easy. Am I missing something?
Suppose I’d like to reduce
a list of Path
objects into a single Path
with overlaps removed, but winding preserved.
In example A
, the crossbar overlaps the sides. If I convert this to an array of Path
and reduce
into a new Path
using union
, I get the right result.
In example Q
, however, the same approach doesn’t work: union
will remove the overlap correctly from the Q
tail, but it will also remove the inner contour entirely.
union
so that it takes account of nonzero winding?Path
? (I see there is an internal windingCount
property)Path
objects into a new Path
without applying any Boolean processing?Suppose I delete the marked point on the glyph below. Currently I get the glyph in the second pic, which is not wrong. But it would be more useful to get something closer to the glyph in the third pic (where the remaining Bézier handles have been adjusted to approximate the curve that existed before.).
The question: is there a way to accomplish this in BezierKit? I’m not sure how to characterize this operation. I suppose it would be a sort of curve simplification, where the remaining BCPs are adjusted to produce the curve that’s the closest fit to the one that was there before.
I am making a Path
using this contour as a component and passing it through crossingsRemoved()
. The two off-curve points are key. Once the upper point gets one unit to the right of the lower point, it triggers this assertion in addNeighbor
.
Hey @hfutrell
I randomly get some invalid results from Path.crossingsRemoved(accuracy: 1)
I haven't identified any simple repeatable use case for now.
So here us a dump of a case where it happens. Note that I've used the method you mentioned here (Not sure this issue is linked with issue #64 btw).
Original Path:
component 0: curves = [BezierKit.CubicCurve(p0: (-230.0, 679.0), p1: (-242.0, 611.0), p2: (-245.0, 540.0), p3: (-244.0, 445.0)), BezierKit.CubicCurve(p0: (-244.0, 445.0), p1: (-244.0, 423.0), p2: (-261.0, 405.0), p3: (-284.0, 405.0)), BezierKit.CubicCurve(p0: (-284.0, 405.0), p1: (-306.0, 405.0), p2: (-324.0, 422.0), p3: (-324.0, 445.0)), BezierKit.CubicCurve(p0: (-324.0, 445.0), p1: (-325.0, 543.0), p2: (-321.0, 618.0), p3: (-309.0, 692.0)), BezierKit.CubicCurve(p0: (-309.0, 692.0), p1: (-306.0, 714.0), p2: (-285.0, 729.0), p3: (-263.0, 725.0)), BezierKit.CubicCurve(p0: (-263.0, 725.0), p1: (-241.0, 721.0), p2: (-227.0, 701.0), p3: (-230.0, 679.0))]
component 1: curves = [BezierKit.CubicCurve(p0: (-244.0, 446.0), p1: (-244.0, 434.0), p2: (-243.0, 421.0), p3: (-243.0, 405.0)), BezierKit.CubicCurve(p0: (-243.0, 405.0), p1: (-243.0, 402.0), p2: (-243.0, 399.0), p3: (-243.0, 395.0)), BezierKit.CubicCurve(p0: (-243.0, 395.0), p1: (-243.0, 390.0), p2: (-243.0, 388.0), p3: (-243.0, 385.0)), BezierKit.CubicCurve(p0: (-243.0, 385.0), p1: (-243.0, 378.0), p2: (-242.0, 372.0), p3: (-242.0, 366.0)), BezierKit.CubicCurve(p0: (-242.0, 366.0), p1: (-240.0, 239.0), p2: (-237.0, 179.0), p3: (-232.0, 123.0)), BezierKit.CubicCurve(p0: (-232.0, 123.0), p1: (-230.0, 101.0), p2: (-246.0, 81.0), p3: (-268.0, 79.0)), BezierKit.CubicCurve(p0: (-268.0, 79.0), p1: (-290.0, 77.0), p2: (-310.0, 93.0), p3: (-312.0, 115.0)), BezierKit.CubicCurve(p0: (-312.0, 115.0), p1: (-317.0, 174.0), p2: (-319.0, 235.0), p3: (-322.0, 364.0)), BezierKit.CubicCurve(p0: (-322.0, 364.0), p1: (-322.0, 370.0), p2: (-323.0, 376.0), p3: (-323.0, 384.0)), BezierKit.CubicCurve(p0: (-323.0, 384.0), p1: (-323.0, 386.0), p2: (-323.0, 389.0), p3: (-323.0, 394.0)), BezierKit.CubicCurve(p0: (-323.0, 394.0), p1: (-323.0, 398.0), p2: (-323.0, 401.0), p3: (-323.0, 403.0)), BezierKit.CubicCurve(p0: (-323.0, 403.0), p1: (-323.0, 420.0), p2: (-324.0, 432.0), p3: (-324.0, 444.0)), BezierKit.CubicCurve(p0: (-324.0, 444.0), p1: (-324.0, 466.0), p2: (-307.0, 484.0), p3: (-285.0, 485.0)), BezierKit.CubicCurve(p0: (-285.0, 485.0), p1: (-263.0, 485.0), p2: (-245.0, 468.0), p3: (-244.0, 446.0))]
component 2: curves = [BezierKit.CubicCurve(p0: (-269.0, 159.0), p1: (-125.0, 146.0), p2: (30.0, 150.0), p3: (221.0, 169.0)), BezierKit.CubicCurve(p0: (221.0, 169.0), p1: (243.0, 171.0), p2: (263.0, 155.0), p3: (265.0, 133.0)), BezierKit.CubicCurve(p0: (265.0, 133.0), p1: (267.0, 111.0), p2: (251.0, 91.0), p3: (229.0, 89.0)), BezierKit.CubicCurve(p0: (229.0, 89.0), p1: (33.0, 70.0), p2: (-127.0, 66.0), p3: (-276.0, 79.0)), BezierKit.CubicCurve(p0: (-276.0, 79.0), p1: (-298.0, 81.0), p2: (-314.0, 100.0), p3: (-312.0, 122.0)), BezierKit.CubicCurve(p0: (-312.0, 122.0), p1: (-310.0, 144.0), p2: (-291.0, 161.0), p3: (-269.0, 159.0))]
component 3: curves = [BezierKit.CubicCurve(p0: (220.0, 169.0), p1: (239.0, 171.0), p2: (251.0, 173.0), p3: (259.0, 176.0)), BezierKit.CubicCurve(p0: (259.0, 176.0), p1: (261.0, 177.0), p2: (262.0, 177.0), p3: (262.0, 178.0)), BezierKit.CubicCurve(p0: (262.0, 178.0), p1: (263.0, 178.0), p2: (263.0, 178.0), p3: (263.0, 178.0)), BezierKit.CubicCurve(p0: (263.0, 178.0), p1: (262.0, 178.0), p2: (262.0, 177.0), p3: (262.0, 177.0)), BezierKit.CubicCurve(p0: (262.0, 177.0), p1: (259.0, 174.0), p2: (256.0, 169.0), p3: (256.0, 164.0)), BezierKit.CubicCurve(p0: (256.0, 164.0), p1: (257.0, 186.0), p2: (276.0, 203.0), p3: (298.0, 202.0)), BezierKit.CubicCurve(p0: (298.0, 202.0), p1: (320.0, 201.0), p2: (337.0, 182.0), p3: (336.0, 160.0)), BezierKit.CubicCurve(p0: (336.0, 160.0), p1: (335.0, 144.0), p2: (328.0, 130.0), p3: (317.0, 119.0)), BezierKit.CubicCurve(p0: (317.0, 119.0), p1: (309.0, 111.0), p2: (299.0, 106.0), p3: (287.0, 101.0)), BezierKit.CubicCurve(p0: (287.0, 101.0), p1: (272.0, 95.0), p2: (254.0, 92.0), p3: (230.0, 89.0)), BezierKit.CubicCurve(p0: (230.0, 89.0), p1: (208.0, 87.0), p2: (188.0, 103.0), p3: (185.0, 124.0)), BezierKit.CubicCurve(p0: (185.0, 124.0), p1: (183.0, 146.0), p2: (199.0, 166.0), p3: (220.0, 169.0))]
component 4: curves = [BezierKit.CubicCurve(p0: (256.0, 163.0), p1: (257.0, 210.0), p2: (257.0, 247.0), p3: (258.0, 331.0)), BezierKit.CubicCurve(p0: (258.0, 331.0), p1: (259.0, 434.0), p2: (260.0, 480.0), p3: (261.0, 537.0)), BezierKit.CubicCurve(p0: (261.0, 537.0), p1: (263.0, 613.0), p2: (266.0, 680.0), p3: (271.0, 745.0)), BezierKit.CubicCurve(p0: (271.0, 745.0), p1: (273.0, 767.0), p2: (292.0, 783.0), p3: (314.0, 782.0)), BezierKit.CubicCurve(p0: (314.0, 782.0), p1: (336.0, 780.0), p2: (352.0, 761.0), p3: (351.0, 739.0)), BezierKit.CubicCurve(p0: (351.0, 739.0), p1: (346.0, 676.0), p2: (343.0, 610.0), p3: (341.0, 535.0)), BezierKit.CubicCurve(p0: (341.0, 535.0), p1: (340.0, 478.0), p2: (339.0, 433.0), p3: (338.0, 330.0)), BezierKit.CubicCurve(p0: (338.0, 330.0), p1: (337.0, 246.0), p2: (337.0, 208.0), p3: (336.0, 161.0)), BezierKit.CubicCurve(p0: (336.0, 161.0), p1: (336.0, 139.0), p2: (317.0, 122.0), p3: (295.0, 122.0)), BezierKit.CubicCurve(p0: (295.0, 122.0), p1: (273.0, 122.0), p2: (256.0, 141.0), p3: (256.0, 163.0))]
component 5: curves = [BezierKit.CubicCurve(p0: (271.0, 747.0), p1: (270.0, 734.0), p2: (277.0, 721.0), p3: (287.0, 716.0)), BezierKit.CubicCurve(p0: (287.0, 716.0), p1: (290.0, 714.0), p2: (292.0, 713.0), p3: (294.0, 713.0)), BezierKit.CubicCurve(p0: (294.0, 713.0), p1: (294.0, 713.0), p2: (294.0, 713.0), p3: (294.0, 713.0)), BezierKit.CubicCurve(p0: (294.0, 713.0), p1: (294.0, 713.0), p2: (294.0, 713.0), p3: (294.0, 713.0)), BezierKit.CubicCurve(p0: (294.0, 713.0), p1: (272.0, 713.0), p2: (254.0, 731.0), p3: (254.0, 753.0)), BezierKit.CubicCurve(p0: (254.0, 753.0), p1: (254.0, 775.0), p2: (272.0, 793.0), p3: (294.0, 793.0)), BezierKit.CubicCurve(p0: (294.0, 793.0), p1: (306.0, 793.0), p2: (316.0, 791.0), p3: (326.0, 785.0)), BezierKit.CubicCurve(p0: (326.0, 785.0), p1: (343.0, 776.0), p2: (353.0, 758.0), p3: (351.0, 737.0)), BezierKit.CubicCurve(p0: (351.0, 737.0), p1: (348.0, 715.0), p2: (328.0, 700.0), p3: (306.0, 702.0)), BezierKit.CubicCurve(p0: (306.0, 702.0), p1: (284.0, 705.0), p2: (269.0, 725.0), p3: (271.0, 747.0))]
component 6: curves = [BezierKit.CubicCurve(p0: (292.0, 713.0), p1: (247.0, 715.0), p2: (198.0, 709.0), p3: (136.0, 697.0)), BezierKit.CubicCurve(p0: (136.0, 697.0), p1: (114.0, 692.0), p2: (93.0, 706.0), p3: (89.0, 728.0)), BezierKit.CubicCurve(p0: (89.0, 728.0), p1: (84.0, 750.0), p2: (98.0, 771.0), p3: (120.0, 775.0)), BezierKit.CubicCurve(p0: (120.0, 775.0), p1: (188.0, 789.0), p2: (243.0, 795.0), p3: (296.0, 793.0)), BezierKit.CubicCurve(p0: (296.0, 793.0), p1: (318.0, 792.0), p2: (335.0, 774.0), p3: (334.0, 751.0)), BezierKit.CubicCurve(p0: (334.0, 751.0), p1: (333.0, 729.0), p2: (315.0, 712.0), p3: (292.0, 713.0))]
component 7: curves = [BezierKit.CubicCurve(p0: (136.0, 697.0), p1: (-13.0, 667.0), p2: (-147.0, 614.0), p3: (-270.0, 539.0)), BezierKit.CubicCurve(p0: (-270.0, 539.0), p1: (-289.0, 527.0), p2: (-314.0, 533.0), p3: (-325.0, 552.0)), BezierKit.CubicCurve(p0: (-325.0, 552.0), p1: (-337.0, 571.0), p2: (-331.0, 596.0), p3: (-312.0, 607.0)), BezierKit.CubicCurve(p0: (-312.0, 607.0), p1: (-181.0, 687.0), p2: (-38.0, 743.0), p3: (120.0, 775.0)), BezierKit.CubicCurve(p0: (120.0, 775.0), p1: (142.0, 780.0), p2: (163.0, 766.0), p3: (167.0, 744.0)), BezierKit.CubicCurve(p0: (167.0, 744.0), p1: (172.0, 722.0), p2: (158.0, 701.0), p3: (136.0, 697.0))]
component 8: curves = [BezierKit.CubicCurve(p0: (-269.0, 539.0), p1: (-285.0, 530.0), p2: (-299.0, 522.0), p3: (-324.0, 510.0)), BezierKit.CubicCurve(p0: (-324.0, 510.0), p1: (-325.0, 510.0), p2: (-336.0, 505.0), p3: (-339.0, 503.0)), BezierKit.CubicCurve(p0: (-339.0, 503.0), p1: (-344.0, 501.0), p2: (-349.0, 498.0), p3: (-353.0, 496.0)), BezierKit.CubicCurve(p0: (-353.0, 496.0), p1: (-354.0, 496.0), p2: (-354.0, 496.0), p3: (-355.0, 495.0)), BezierKit.CubicCurve(p0: (-355.0, 495.0), p1: (-375.0, 485.0), p2: (-399.0, 493.0), p3: (-409.0, 513.0)), BezierKit.CubicCurve(p0: (-409.0, 513.0), p1: (-419.0, 533.0), p2: (-411.0, 557.0), p3: (-391.0, 567.0)), BezierKit.CubicCurve(p0: (-391.0, 567.0), p1: (-390.0, 567.0), p2: (-389.0, 567.0), p3: (-389.0, 568.0)), BezierKit.CubicCurve(p0: (-389.0, 568.0), p1: (-384.0, 570.0), p2: (-379.0, 573.0), p3: (-373.0, 575.0)), BezierKit.CubicCurve(p0: (-373.0, 575.0), p1: (-370.0, 577.0), p2: (-359.0, 582.0), p3: (-359.0, 582.0)), BezierKit.CubicCurve(p0: (-359.0, 582.0), p1: (-336.0, 593.0), p2: (-324.0, 599.0), p3: (-313.0, 607.0)), BezierKit.CubicCurve(p0: (-313.0, 607.0), p1: (-294.0, 619.0), p2: (-269.0, 613.0), p3: (-257.0, 595.0)), BezierKit.CubicCurve(p0: (-257.0, 595.0), p1: (-245.0, 576.0), p2: (-251.0, 551.0), p3: (-269.0, 539.0))]
component 9: curves = [BezierKit.CubicCurve(p0: (-350.0, 564.0), p1: (-347.0, 562.0), p2: (-346.0, 561.0), p3: (-344.0, 560.0)), BezierKit.CubicCurve(p0: (-344.0, 560.0), p1: (-344.0, 560.0), p2: (-343.0, 559.0), p3: (-343.0, 559.0)), BezierKit.CubicCurve(p0: (-343.0, 559.0), p1: (-342.0, 559.0), p2: (-342.0, 559.0), p3: (-342.0, 558.0)), BezierKit.CubicCurve(p0: (-342.0, 558.0), p1: (-341.0, 558.0), p2: (-341.0, 558.0), p3: (-340.0, 557.0)), BezierKit.CubicCurve(p0: (-340.0, 557.0), p1: (-339.0, 559.0), p2: (-339.0, 559.0), p3: (-326.0, 527.0)), BezierKit.CubicCurve(p0: (-326.0, 527.0), p1: (-326.0, 504.0), p2: (-344.0, 487.0), p3: (-366.0, 487.0)), BezierKit.CubicCurve(p0: (-366.0, 487.0), p1: (-388.0, 487.0), p2: (-406.0, 504.0), p3: (-406.0, 527.0)), BezierKit.CubicCurve(p0: (-406.0, 527.0), p1: (-393.0, 494.0), p2: (-393.0, 494.0), p3: (-392.0, 496.0)), BezierKit.CubicCurve(p0: (-392.0, 496.0), p1: (-391.0, 495.0), p2: (-391.0, 495.0), p3: (-391.0, 495.0)), BezierKit.CubicCurve(p0: (-391.0, 495.0), p1: (-390.0, 495.0), p2: (-390.0, 495.0), p3: (-390.0, 495.0)), BezierKit.CubicCurve(p0: (-390.0, 495.0), p1: (-390.0, 495.0), p2: (-391.0, 495.0), p3: (-391.0, 495.0)), BezierKit.CubicCurve(p0: (-391.0, 495.0), p1: (-392.0, 496.0), p2: (-394.0, 497.0), p3: (-396.0, 499.0)), BezierKit.CubicCurve(p0: (-396.0, 499.0), p1: (-414.0, 512.0), p2: (-418.0, 536.0), p3: (-405.0, 555.0)), BezierKit.CubicCurve(p0: (-405.0, 555.0), p1: (-393.0, 573.0), p2: (-368.0, 577.0), p3: (-350.0, 564.0))]
component 10: curves = [BezierKit.CubicCurve(p0: (-326.0, 552.0), p1: (-317.0, 550.0), p2: (-309.0, 546.0), p3: (-299.0, 539.0)), BezierKit.CubicCurve(p0: (-299.0, 539.0), p1: (-294.0, 536.0), p2: (-279.0, 526.0), p3: (-278.0, 525.0)), BezierKit.CubicCurve(p0: (-278.0, 525.0), p1: (-259.0, 513.0), p2: (-254.0, 488.0), p3: (-267.0, 470.0)), BezierKit.CubicCurve(p0: (-267.0, 470.0), p1: (-279.0, 451.0), p2: (-304.0, 446.0), p3: (-322.0, 459.0)), BezierKit.CubicCurve(p0: (-322.0, 459.0), p1: (-325.0, 460.0), p2: (-339.0, 470.0), p3: (-342.0, 472.0)), BezierKit.CubicCurve(p0: (-342.0, 472.0), p1: (-344.0, 473.0), p2: (-345.0, 474.0), p3: (-347.0, 475.0)), BezierKit.CubicCurve(p0: (-347.0, 475.0), p1: (-347.0, 475.0), p2: (-347.0, 475.0), p3: (-347.0, 475.0)), BezierKit.CubicCurve(p0: (-347.0, 475.0), p1: (-347.0, 475.0), p2: (-347.0, 475.0), p3: (-347.0, 475.0)), BezierKit.CubicCurve(p0: (-347.0, 475.0), p1: (-368.0, 481.0), p2: (-381.0, 502.0), p3: (-375.0, 524.0)), BezierKit.CubicCurve(p0: (-375.0, 524.0), p1: (-370.0, 545.0), p2: (-348.0, 558.0), p3: (-326.0, 552.0))]
component 11: curves = [BezierKit.CubicCurve(p0: (-278.0, 525.0), p1: (-278.0, 525.0), p2: (-227.0, 491.0), p3: (-214.0, 482.0)), BezierKit.CubicCurve(p0: (-214.0, 482.0), p1: (-190.0, 467.0), p2: (-171.0, 454.0), p3: (-153.0, 443.0)), BezierKit.CubicCurve(p0: (-153.0, 443.0), p1: (-111.0, 416.0), p2: (-76.0, 396.0), p3: (-44.0, 381.0)), BezierKit.CubicCurve(p0: (-44.0, 381.0), p1: (-24.0, 372.0), p2: (-15.0, 348.0), p3: (-25.0, 328.0)), BezierKit.CubicCurve(p0: (-25.0, 328.0), p1: (-34.0, 308.0), p2: (-58.0, 299.0), p3: (-78.0, 309.0)), BezierKit.CubicCurve(p0: (-78.0, 309.0), p1: (-113.0, 325.0), p2: (-151.0, 347.0), p3: (-196.0, 375.0)), BezierKit.CubicCurve(p0: (-196.0, 375.0), p1: (-215.0, 387.0), p2: (-234.0, 400.0), p3: (-258.0, 416.0)), BezierKit.CubicCurve(p0: (-258.0, 416.0), p1: (-272.0, 425.0), p2: (-322.0, 459.0), p3: (-322.0, 459.0)), BezierKit.CubicCurve(p0: (-322.0, 459.0), p1: (-341.0, 471.0), p2: (-346.0, 496.0), p3: (-333.0, 514.0)), BezierKit.CubicCurve(p0: (-333.0, 514.0), p1: (-321.0, 533.0), p2: (-296.0, 538.0), p3: (-278.0, 525.0))]
component 12: curves = [BezierKit.CubicCurve(p0: (-45.0, 382.0), p1: (-40.0, 380.0), p2: (-36.0, 378.0), p3: (-30.0, 375.0)), BezierKit.CubicCurve(p0: (-30.0, 375.0), p1: (-28.0, 374.0), p2: (-22.0, 372.0), p3: (-23.0, 372.0)), BezierKit.CubicCurve(p0: (-23.0, 372.0), p1: (-20.0, 371.0), p2: (-18.0, 370.0), p3: (-16.0, 369.0)), BezierKit.CubicCurve(p0: (-16.0, 369.0), p1: (-4.0, 363.0), p2: (4.0, 360.0), p3: (12.0, 356.0)), BezierKit.CubicCurve(p0: (12.0, 356.0), p1: (33.0, 346.0), p2: (51.0, 339.0), p3: (67.0, 331.0)), BezierKit.CubicCurve(p0: (67.0, 331.0), p1: (113.0, 309.0), p2: (148.0, 290.0), p3: (180.0, 270.0)), BezierKit.CubicCurve(p0: (180.0, 270.0), p1: (198.0, 257.0), p2: (204.0, 233.0), p3: (192.0, 214.0)), BezierKit.CubicCurve(p0: (192.0, 214.0), p1: (179.0, 196.0), p2: (155.0, 190.0), p3: (136.0, 202.0)), BezierKit.CubicCurve(p0: (136.0, 202.0), p1: (108.0, 221.0), p2: (75.0, 238.0), p3: (32.0, 259.0)), BezierKit.CubicCurve(p0: (32.0, 259.0), p1: (17.0, 266.0), p2: (0.0, 274.0), p3: (-20.0, 283.0)), BezierKit.CubicCurve(p0: (-20.0, 283.0), p1: (-28.0, 287.0), p2: (-37.0, 290.0), p3: (-48.0, 296.0)), BezierKit.CubicCurve(p0: (-48.0, 296.0), p1: (-50.0, 296.0), p2: (-53.0, 297.0), p3: (-55.0, 299.0)), BezierKit.CubicCurve(p0: (-55.0, 299.0), p1: (-55.0, 299.0), p2: (-61.0, 301.0), p3: (-63.0, 302.0)), BezierKit.CubicCurve(p0: (-63.0, 302.0), p1: (-69.0, 305.0), p2: (-73.0, 307.0), p3: (-77.0, 308.0)), BezierKit.CubicCurve(p0: (-77.0, 308.0), p1: (-97.0, 317.0), p2: (-107.0, 341.0), p3: (-98.0, 361.0)), BezierKit.CubicCurve(p0: (-98.0, 361.0), p1: (-89.0, 381.0), p2: (-65.0, 391.0), p3: (-45.0, 382.0))]
component 13: curves = [BezierKit.CubicCurve(p0: (180.0, 269.0), p1: (181.0, 269.0), p2: (182.0, 268.0), p3: (183.0, 267.0)), BezierKit.CubicCurve(p0: (183.0, 267.0), p1: (188.0, 264.0), p2: (194.0, 261.0), p3: (201.0, 256.0)), BezierKit.CubicCurve(p0: (201.0, 256.0), p1: (201.0, 256.0), p2: (215.0, 247.0), p3: (219.0, 245.0)), BezierKit.CubicCurve(p0: (219.0, 245.0), p1: (239.0, 233.0), p2: (253.0, 223.0), p3: (265.0, 213.0)), BezierKit.CubicCurve(p0: (265.0, 213.0), p1: (282.0, 199.0), p2: (285.0, 174.0), p3: (271.0, 157.0)), BezierKit.CubicCurve(p0: (271.0, 157.0), p1: (257.0, 140.0), p2: (232.0, 137.0), p3: (215.0, 151.0)), BezierKit.CubicCurve(p0: (215.0, 151.0), p1: (205.0, 159.0), p2: (194.0, 166.0), p3: (177.0, 177.0)), BezierKit.CubicCurve(p0: (177.0, 177.0), p1: (173.0, 179.0), p2: (159.0, 188.0), p3: (159.0, 188.0)), BezierKit.CubicCurve(p0: (159.0, 188.0), p1: (151.0, 193.0), p2: (145.0, 197.0), p3: (140.0, 200.0)), BezierKit.CubicCurve(p0: (140.0, 200.0), p1: (138.0, 201.0), p2: (137.0, 202.0), p3: (136.0, 203.0)), BezierKit.CubicCurve(p0: (136.0, 203.0), p1: (118.0, 215.0), p2: (112.0, 239.0), p3: (125.0, 258.0)), BezierKit.CubicCurve(p0: (125.0, 258.0), p1: (137.0, 276.0), p2: (161.0, 282.0), p3: (180.0, 269.0))]
component 14: curves = [BezierKit.CubicCurve(p0: (204.0, 199.0), p1: (207.0, 206.0), p2: (207.0, 207.0), p3: (209.0, 210.0)), BezierKit.CubicCurve(p0: (209.0, 210.0), p1: (220.0, 229.0), p2: (244.0, 236.0), p3: (263.0, 225.0)), BezierKit.CubicCurve(p0: (263.0, 225.0), p1: (283.0, 214.0), p2: (289.0, 189.0), p3: (278.0, 170.0)), BezierKit.CubicCurve(p0: (278.0, 170.0), p1: (279.0, 171.0), p2: (279.0, 171.0), p3: (279.0, 172.0)), BezierKit.CubicCurve(p0: (279.0, 172.0), p1: (279.0, 172.0), p2: (279.0, 172.0), p3: (279.0, 172.0)), BezierKit.CubicCurve(p0: (279.0, 172.0), p1: (279.0, 172.0), p2: (279.0, 172.0), p3: (279.0, 171.0)), BezierKit.CubicCurve(p0: (279.0, 171.0), p1: (278.0, 170.0), p2: (278.0, 168.0), p3: (277.0, 166.0)), BezierKit.CubicCurve(p0: (277.0, 166.0), p1: (268.0, 146.0), p2: (244.0, 137.0), p3: (224.0, 146.0)), BezierKit.CubicCurve(p0: (224.0, 146.0), p1: (204.0, 155.0), p2: (195.0, 178.0), p3: (204.0, 199.0))]
component 15: curves = [BezierKit.CubicCurve(p0: (-293.0, 721.0), p1: (-267.0, 762.0), p2: (-228.0, 789.0), p3: (-176.0, 803.0)), BezierKit.CubicCurve(p0: (-176.0, 803.0), p1: (-155.0, 808.0), p2: (-133.0, 796.0), p3: (-127.0, 774.0)), BezierKit.CubicCurve(p0: (-127.0, 774.0), p1: (-122.0, 753.0), p2: (-134.0, 731.0), p3: (-156.0, 725.0)), BezierKit.CubicCurve(p0: (-156.0, 725.0), p1: (-188.0, 717.0), p2: (-210.0, 701.0), p3: (-225.0, 679.0)), BezierKit.CubicCurve(p0: (-225.0, 679.0), p1: (-236.0, 660.0), p2: (-261.0, 654.0), p3: (-280.0, 666.0)), BezierKit.CubicCurve(p0: (-280.0, 666.0), p1: (-298.0, 678.0), p2: (-304.0, 702.0), p3: (-293.0, 721.0))]
component 16: curves = [BezierKit.CubicCurve(p0: (-177.0, 803.0), p1: (-133.0, 815.0), p2: (-89.0, 818.0), p3: (-33.0, 817.0)), BezierKit.CubicCurve(p0: (-33.0, 817.0), p1: (-11.0, 816.0), p2: (6.0, 798.0), p3: (6.0, 776.0)), BezierKit.CubicCurve(p0: (6.0, 776.0), p1: (5.0, 754.0), p2: (-13.0, 737.0), p3: (-35.0, 737.0)), BezierKit.CubicCurve(p0: (-35.0, 737.0), p1: (-84.0, 738.0), p2: (-120.0, 735.0), p3: (-155.0, 725.0)), BezierKit.CubicCurve(p0: (-155.0, 725.0), p1: (-177.0, 720.0), p2: (-199.0, 732.0), p3: (-205.0, 753.0)), BezierKit.CubicCurve(p0: (-205.0, 753.0), p1: (-210.0, 775.0), p2: (-198.0, 797.0), p3: (-177.0, 803.0))]
component 17: curves = [BezierKit.CubicCurve(p0: (-34.0, 817.0), p1: (-5.0, 817.0), p2: (19.0, 817.0), p3: (67.0, 818.0)), BezierKit.CubicCurve(p0: (67.0, 818.0), p1: (133.0, 819.0), p2: (160.0, 819.0), p3: (194.0, 818.0)), BezierKit.CubicCurve(p0: (194.0, 818.0), p1: (216.0, 817.0), p2: (233.0, 798.0), p3: (232.0, 776.0)), BezierKit.CubicCurve(p0: (232.0, 776.0), p1: (231.0, 754.0), p2: (212.0, 737.0), p3: (190.0, 738.0)), BezierKit.CubicCurve(p0: (190.0, 738.0), p1: (159.0, 739.0), p2: (133.0, 739.0), p3: (68.0, 738.0)), BezierKit.CubicCurve(p0: (68.0, 738.0), p1: (20.0, 737.0), p2: (-5.0, 737.0), p3: (-34.0, 737.0)), BezierKit.CubicCurve(p0: (-34.0, 737.0), p1: (-57.0, 737.0), p2: (-74.0, 755.0), p3: (-74.0, 777.0)), BezierKit.CubicCurve(p0: (-74.0, 777.0), p1: (-74.0, 800.0), p2: (-56.0, 817.0), p3: (-34.0, 817.0))]
component 18: curves = [BezierKit.CubicCurve(p0: (194.0, 818.0), p1: (229.0, 816.0), p2: (257.0, 796.0), p3: (280.0, 762.0)), BezierKit.CubicCurve(p0: (280.0, 762.0), p1: (292.0, 743.0), p2: (287.0, 718.0), p3: (269.0, 706.0)), BezierKit.CubicCurve(p0: (269.0, 706.0), p1: (250.0, 694.0), p2: (225.0, 699.0), p3: (213.0, 717.0)), BezierKit.CubicCurve(p0: (213.0, 717.0), p1: (208.0, 726.0), p2: (203.0, 731.0), p3: (198.0, 735.0)), BezierKit.CubicCurve(p0: (198.0, 735.0), p1: (195.0, 737.0), p2: (192.0, 738.0), p3: (190.0, 738.0)), BezierKit.CubicCurve(p0: (190.0, 738.0), p1: (168.0, 739.0), p2: (151.0, 758.0), p3: (152.0, 780.0)), BezierKit.CubicCurve(p0: (152.0, 780.0), p1: (153.0, 802.0), p2: (172.0, 819.0), p3: (194.0, 818.0))]
Resulting Path:
component 0: curves = [BezierKit.CubicCurve(p0: (-242.7048464180748, 555.1771373807451), p1: (-243.42071156036235, 538.3183050343076), p2: (-243.85245293148537, 520.7631006313234), p3: (-244.04990918035318, 502.30220184637574)), BezierKit.CubicCurve(p0: (-244.04990918035318, 502.30220184637574), p1: (-231.7251494835195, 494.0386451098102), p2: (-219.4828559441881, 485.7958233459765), p3: (-214.0, 482.0)), BezierKit.CubicCurve(p0: (-214.0, 482.0), p1: (-190.0, 467.0), p2: (-171.0, 454.0), p3: (-153.0, 443.0)), BezierKit.CubicCurve(p0: (-153.0, 443.0), p1: (-113.57235196659968, 417.6536548356712), p2: (-80.31351119290451, 398.4761169310476), p3: (-49.91434078882551, 383.81281784108467)), BezierKit.CubicCurve(p0: (-49.91434078882551, 383.81281784108467), p1: (-48.256762379039984, 383.32985915538274), p2: (-46.61533465921372, 382.7269005966463), p3: (-45.0, 382.0)), BezierKit.CubicCurve(p0: (-45.0, 382.0), p1: (-40.0, 380.0), p2: (-36.0, 378.0), p3: (-30.0, 375.0)), BezierKit.CubicCurve(p0: (-30.0, 375.0), p1: (-28.0, 374.0), p2: (-22.0, 372.0), p3: (-23.0, 372.0)), BezierKit.CubicCurve(p0: (-23.0, 372.0), p1: (-20.0, 371.0), p2: (-18.0, 370.0), p3: (-16.0, 369.0)), BezierKit.CubicCurve(p0: (-16.0, 369.0), p1: (-4.0, 363.0), p2: (4.0, 360.0), p3: (12.0, 356.0)), BezierKit.CubicCurve(p0: (12.0, 356.0), p1: (33.0, 346.0), p2: (51.0, 339.0), p3: (67.0, 331.0)), BezierKit.CubicCurve(p0: (67.0, 331.0), p1: (113.0, 309.0), p2: (148.0, 290.0), p3: (180.0, 270.0)), BezierKit.CubicCurve(p0: (180.0, 270.0), p1: (181.77901447807565, 268.71515621027874), p2: (183.44081071492155, 267.32286236609684), p3: (184.97959612864216, 265.8385653525094)), BezierKit.CubicCurve(p0: (184.97959612864216, 265.8385653525094), p1: (189.5598615691778, 263.1952583846162), p2: (194.9002705922668, 260.3569495769522), p3: (201.0, 256.0)), BezierKit.CubicCurve(p0: (201.0, 256.0), p1: (201.0, 256.0), p2: (215.0, 247.0), p3: (219.0, 245.0)), BezierKit.CubicCurve(p0: (219.0, 245.0), p1: (227.77031876233895, 239.73780874259666), p2: (235.38686015678235, 234.86020994115842), p3: (242.18692402657078, 230.19855367406512)), BezierKit.CubicCurve(p0: (242.18692402657078, 230.19855367406512), p1: (247.1199497303487, 230.38482208680261), p2: (252.12642416612897, 229.62942053258706), p3: (256.94790961428265, 227.84807612189257)), BezierKit.CubicCurve(p0: (256.94790961428265, 227.84807612189257), p1: (257.2164610185148, 254.60244271605063), p2: (257.46525371413315, 286.08131198718957), p3: (258.0, 331.0)), BezierKit.CubicCurve(p0: (258.0, 331.0), p1: (259.0, 434.0), p2: (260.0, 480.0), p3: (261.0, 537.0)), BezierKit.CubicCurve(p0: (261.0, 537.0), p1: (262.59814157455685, 597.7293798331593), p2: (264.8347972721954, 652.712132558583), p3: (268.220185075935, 705.5197840574061)), BezierKit.CubicCurve(p0: (268.220185075935, 705.5197840574061), p1: (252.0608377575346, 695.7882085749465), p2: (231.8173428516103, 698.1111664964208), p3: (218.88881500271162, 710.0882602449426)), BezierKit.CubicCurve(p0: (218.88881500271162, 710.0882602449426), p1: (193.90439733744492, 707.3506076383935), p2: (166.89175102688512, 702.9638948660113), p3: (136.8185833666551, 697.1582323624708)), BezierKit.CubicCurve(p0: (136.8185833666551, 697.1582323624708), p1: (136.54717435829534, 697.102353196791), p2: (136.27420858699207, 697.0498561067259), p3: (136.0, 697.0)), BezierKit.CubicCurve(p0: (136.0, 697.0), p1: (135.35570722014236, 696.8535698227596), p2: (134.712272112157, 696.7234354110924), p3: (134.07009656098558, 696.6093204691006)), BezierKit.CubicCurve(p0: (134.07009656098558, 696.6093204691006), p1: (-3.2178229499304254, 668.7608541191655), p2: (-127.7637593278102, 621.3551034330992), p3: (-242.7048464180748, 555.1771373807451))]
component 1: curves = [BezierKit.CubicCurve(p0: (-243.0012122122419, 405.9677785469315), p1: (-243.00040959717086, 405.64640343661983), p2: (-243.0, 405.32381611406606), p3: (-243.0, 405.0)), BezierKit.CubicCurve(p0: (-243.0, 405.0), p1: (-243.0, 402.0), p2: (-243.0, 399.0), p3: (-243.0, 395.0)), BezierKit.CubicCurve(p0: (-243.0, 395.0), p1: (-243.0, 390.0), p2: (-243.0, 388.0), p3: (-243.0, 385.0)), BezierKit.CubicCurve(p0: (-243.0, 385.0), p1: (-243.0, 378.0), p2: (-242.0, 372.0), p3: (-242.0, 366.0)), BezierKit.CubicCurve(p0: (-242.0, 366.0), p1: (-240.38503852802143, 263.4499465293619), p2: (-238.11805191704912, 204.5855773713073), p3: (-234.6725424279648, 156.23753496138895)), BezierKit.CubicCurve(p0: (-234.6725424279648, 156.23753496138895), p1: (-107.38556967896513, 147.22684143468666), p2: (29.777193971488916, 151.0362669928679), p3: (193.41884264277, 166.3376661785078)), BezierKit.CubicCurve(p0: (193.41884264277, 166.3376661785078), p1: (188.58015663424897, 169.52254272978132), p2: (183.18750239165857, 172.996321981868), p3: (177.0, 177.0)), BezierKit.CubicCurve(p0: (177.0, 177.0), p1: (173.0, 179.0), p2: (159.0, 188.0), p3: (159.0, 188.0)), BezierKit.CubicCurve(p0: (159.0, 188.0), p1: (151.81284014712202, 192.49197490804877), p2: (146.23990738020717, 196.17683627311592), p3: (141.55609494265158, 199.0545840952015)), BezierKit.CubicCurve(p0: (141.55609494265158, 199.0545840952015), p1: (139.66820011659203, 199.87554383038707), p2: (137.81137783083045, 200.85597189631756), p3: (136.0, 202.0)), BezierKit.CubicCurve(p0: (136.0, 202.0), p1: (108.0, 221.0), p2: (75.0, 238.0), p3: (32.0, 259.0)), BezierKit.CubicCurve(p0: (32.0, 259.0), p1: (17.0, 266.0), p2: (0.0, 274.0), p3: (-20.0, 283.0)), BezierKit.CubicCurve(p0: (-20.0, 283.0), p1: (-28.0, 287.0), p2: (-37.0, 290.0), p3: (-48.0, 296.0)), BezierKit.CubicCurve(p0: (-48.0, 296.0), p1: (-50.0, 296.0), p2: (-53.0, 297.0), p3: (-55.0, 299.0)), BezierKit.CubicCurve(p0: (-55.0, 299.0), p1: (-55.0, 299.0), p2: (-61.0, 301.0), p3: (-63.0, 302.0)), BezierKit.CubicCurve(p0: (-63.0, 302.0), p1: (-69.0, 305.0), p2: (-73.0, 307.0), p3: (-77.0, 308.0)), BezierKit.CubicCurve(p0: (-77.0, 308.0), p1: (-79.07686283880575, 308.9345882774626), p2: (-81.04589169633121, 310.0309275268457), p3: (-82.89700853509468, 311.2677418912434)), BezierKit.CubicCurve(p0: (-82.89700853509468, 311.2677418912434), p1: (-116.54494896847837, 327.0565396874017), p2: (-153.09004202674086, 348.3004705944165), p3: (-196.0, 375.0)), BezierKit.CubicCurve(p0: (-196.0, 375.0), p1: (-210.86839285020864, 384.3905639053949), p2: (-225.73678570041727, 394.39350760566003), p3: (-243.0012122122419, 405.9677785469315))]
Super thanks for your support 🙏
As in tittle... sometimes happens, bcps
are on points, points have same coordinates.
Example project: on github
this is a longstanding issue, here is a unit test demonstrating it:
func testDegree5RealWorldIssue() {
// this case may return a non-root because Newton iteration
// does not converge
let polynomial = BernsteinPolynomial5(b0: -68686.64586343056,
b1: 102389.02112160496,
b2: -163207.59913132348,
b3: 177077.4933777841,
b4: -108411.70135107233,
b5: 57838.81668210728)
let roots = findDistinctRootsInUnitInterval(of: polynomial)
XCTAssertEqual(roots.count, 1)
XCTAssertEqual(roots[0], 0.44454, accuracy: 1.0e-5)
}
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.