Giter Site home page Giter Site logo

bezierkit's People

Contributors

ceylo avatar hfutrell avatar kateinoigakukun avatar pedrovgs avatar vincentspitale avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bezierkit's Issues

`crossingsRemoved` makes these two contours disappear

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:

Screen Shot 2021-01-17 at 11 19 20 AM

Union of 2 overlapping paths returns an empty path

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.

Path and PathComponent hash and hashValue is simply memory address

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.

droots can have low precision in some cases, which could affect Path.contains(_ point:)

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)
    }

`offset` seems to treat straight & curved segments differently

All curves

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.

Screen Shot 2020-12-17 at Dec 17  10 39 30 AM

Screen Shot 2020-12-17 at Dec 17  10 39 36 AM

All straights

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:

Screen Shot 2020-12-17 at Dec 17  10 39 16 AM

Screen Shot 2020-12-17 at Dec 17  10 39 20 AM

Mix of curves and straights

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.

Screen Shot 2020-12-17 at Dec 17  10 37 24 AM

Screen Shot 2020-12-17 at Dec 17  10 37 30 AM

`crossingsRemoved` gets confused by coincident points

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:

Screen Shot 2021-01-21 at Jan 21  12 30 48 PM

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 } =
[]

Screen Shot 2021-01-21 at Jan 21  12 44 53 PM

Proposal: Use Sylvester Matrix for finding the intersection of cubic beziers

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)?

Impossible to make closed PathComponent

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.

Hard to work with ends of simple, unclosed bezier path

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:

  1. Create the polyline as a path going from the center of one box to the center of the next.
  2. Create paths for the boxes at the head and tail of the line.
  3. Subtract the paths of the boxes from the line, removing the part of the line where it intersects the boxes.
  4. Create paths for arrowheads at the ends of the line path, using the derivative of the path at its tail and head for angles for the arrowheads.
  5. Outline the path and the paths for the arrowheads
  6. Perform a union on the path and the arrowhead paths so they can be drawn or manipulated further as a single graphics entity.

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?

`union` with nonzero winding rule

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.

  1. Is there a way to invoke union so that it takes account of nonzero winding?
  2. Is there a way to test the winding count of a Path? (I see there is an internal windingCount property)
  3. Is there a way to combine two Path objects into a new Path without applying any Boolean processing?

Screen Shot 2020-08-05 at Aug 05  10 56 12 AM

Screen Shot 2020-08-05 at Aug 05  11 20 53 AM

simplifying a curve?

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.

Screen Shot 2020-09-04 at Sep 04  4 43 09 PM

Screen Shot 2020-09-04 at Sep 04  4 43 14 PM

Screen Shot 2020-09-04 at Sep 04  4 43 33 PM

this contour crashes `crossingsRemoved`

Screen Shot 2021-01-15 at Jan 15  1 44 57 PM

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.

Path.crossingRemoved() produces wrong result

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 🙏

Newton iteration may fail to converge, producing wrong results in curve.project()

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)
    }

how to quiet the SwiftLint warning?

Screen Shot 2021-01-20 at Jan 20  3 35 09 PM

Since I upgraded to the current version of BezierKit I’m getting this warning. I installed SwiftLint as a package and added it to the BezierKit target as shown below, but the warning persists.

What else is to be done?

Screen Shot 2021-01-20 at Jan 20  3 36 01 PM

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.