Comments (19)
This is listing of .startPoint
and .endPoint
of curves send to PathComponent(curves: ...)
(548.9743825215003, 325.0) (341.15500052978894, 24.26896272382021)
(341.15500052978894, 24.268962723820202) (133.33561853807763, 325.0)
(133.33561853807763, 325.0) (341.15500052978894, 625.7310372761798)
(341.15500052978894, 625.7310372761798) (548.9743825215003, 325.0)`
Strange.
from bezierkit.
@typoland If I'm understanding your data correctly it looks like your issue may be with minuscule differences in the y coordinate of the ending point of your first curve and starting point of your second. They need to be exactly equal, which I'd recommend forcing one way or the other or taking an average.
24.26896272382021
versus
24.268962723820202
from bezierkit.
Oh! In the world of CGFloats it could be difficult sometimes ;) . This time I assigned values from previous curve to the next and result is the same:
(548.9743825215003, 325.0) (341.15500052978894, 24.26896272382021)
(341.15500052978894, 24.26896272382021) (133.33561853807763, 325.0)
(133.33561853807763, 325.0) (341.15500052978894, 625.7310372761798)
(341.15500052978894, 625.7310372761798) (548.9743825215003, 325.0)
This listings made by:
componentCurves.curves.forEach({print (index, $0.startingPoint, $0.endingPoint)})
from bezierkit.
I suspect those lines in Init
:
curves.forEach {
assert($0.startingPoint == temp.last!, "curves are not contiguous.")
temp += $0.points[1...]
}
...
from bezierkit.
(Sorry for spamming here, I have to learn how to use this "issues". And markdown).
from bezierkit.
it's definitely coming from this assert ... but strange you would hit this even when forcing the start and end points to be equal (I can't see how this would logically happen). Can you reproduce the issue with a code snippet I could run?
from bezierkit.
I will. Give me some time. (I'm curious, maybe it's on my side somehow)
from bezierkit.
OK. I rounded x and y of all points to third place after comma - no issue anymore.
BTW: Is it possible to automatically reverse inner PathComponent to maka a hole somehow?
from bezierkit.
BTW: Is it possible to automatically reverse inner PathComponent to maka a hole somehow?
One way you can accomplish this is not by modifying the path, but when you go to render the path you can use the .evenOdd
rule instead of .winding
.
But if you must modify the path itself so that it works with the .winding
fill rule: BezierKit has a .reversed()
method that applies to BezierCurve
, Path
, and PathComponent
which you may have seen. There is no way to apply this automatically, however one approach you could use is to find a point that you expect not to be filled, such as the center of your "hole" and test Path.contains(_ point: CGPoint, using rule: PathFillRule = .winding)
. If the result of the contains
method is wrong then you know that your hole needs to be reversed.
from bezierkit.
Super! I will try, thank you!
BTW: good job!
from bezierkit.
After almost a year I still don't know how to close a path. This is a small app showing a problem: https://github.com/typoland/HowToCloseCurveInBezierKit
from bezierkit.
After almost a year I still don't know how to close a path. This is a small app showing a problem: https://github.com/typoland/HowToCloseCurveInBezierKit
It looks like you're creating 1 component for each curve. What this means is that when you stroke the path each curve will be stroked individually. This can make discontinuities because the stroking happens on a per-component basis and does not try to make different components continuous with each other. I think that might be the source of the things you've circled as "bad".
What you probably want is one component for the inner loop of the O and one component for the outer loop of the O. I haven't tested this, but something like this:
edit: this comment was wrong. I should have run the actual app
from bezierkit.
But curvesOfO: [[ BezierCurve ]] = [[...<Outer curve curves>...], [...<Inner curve curves>...]]
and I add them in a loop
for curve in curvesOfO {
components.append(PathComponent(curves: curve))
}
Should be OK, but it isn't :(
from bezierkit.
this looks like it should work, what goes wrong in this case?
from bezierkit.
Paths are not closed. First point is not connected with a last one. It’s why I made this small app. I must close those shapes and I don’t know how.
from bezierkit.
I see what's going on now. I was wrong in my initial assessment of what was going on in your app. Here is a workaround for you.
//
// ContentView.swift
// Shared
//
// Created by Łukasz Dziedzic on 07/05/2022.
//
import SwiftUI
import BezierKit
extension BezierKit.Path {
var closedCGPath: CGPath {
let mutablePath = CGMutablePath()
self.components.forEach {
guard $0.isClosed else {
mutablePath.addPath(BezierKit.Path(components: [$0]).cgPath)
return
}
mutablePath.move(to: $0.startingPoint)
for curve in $0.curves {
let points = curve.points
switch curve.order {
case 1:
mutablePath.addLine(to: points[1])
case 2:
mutablePath.addQuadCurve(to: curve.points[2],
control: curve.points[1])
case 3:
mutablePath.addCurve(to: curve.points[3],
control1: curve.points[1],
control2: curve.points[2])
default:
break
}
}
mutablePath.closeSubpath()
}
return mutablePath
}
}
struct ContentView: View {
var path: SwiftUI.Path {
let curvesOfO: [[BezierCurve]] = [
[ CubicCurve(p0: CGPoint(x: 118.0, y: 350.0),
p1: CGPoint(x: 187.0, y: 541.0),
p2: CGPoint(x: 233.0, y: 604.0),
p3: CGPoint(x: 300.0, y: 604.0)) as BezierCurve,
CubicCurve(p0: CGPoint(x: 300.0, y: 604.0),
p1: CGPoint(x: 505.0, y: 604.0),
p2: CGPoint(x: 551.0, y: 541.0),
p3: CGPoint(x: 481.0, y: 350.0)) as BezierCurve,
CubicCurve(p0: CGPoint(x: 481.0, y: 350.0),
p1: CGPoint(x: 481.0, y: 158.0),
p2: CGPoint(x: 436.0, y: 95.0),
p3: CGPoint(x: 300.0, y: 95.0)) as BezierCurve,
CubicCurve(p0: CGPoint(x: 300.0, y: 95.0),
p1: CGPoint(x: 163.0, y: 95.0),
p2: CGPoint(x: 118.0, y: 158.0),
p3: CGPoint(x: 118.0, y: 350.0)) as BezierCurve],
[CubicCurve(p0: CGPoint(x: 618.0, y: 350.0),
p1: CGPoint(x: 702.0, y: 580.0),
p2: CGPoint(x: 590.0, y: 705.0),
p3: CGPoint(x: 300.0, y: 705.0)) as BezierCurve,
CubicCurve(p0: CGPoint(x: 300.0, y: 705.0),
p1: CGPoint(x: 177.0, y: 705.0),
p2: CGPoint(x: 65.0, y: 580.0),
p3: CGPoint(x: -18.0, y: 350.0)) as BezierCurve,
CubicCurve(p0: CGPoint(x: -18.0, y: 350.0),
p1: CGPoint(x: -18.0, y: 119.0),
p2: CGPoint(x: 93.0, y: -5.0),
p3: CGPoint(x: 300.0, y: -5.0)) as BezierCurve,
CubicCurve(p0: CGPoint(x: 300.0, y: -5.0),
p1: CGPoint(x: 506.0, y: -5.0),
p2: CGPoint(x: 618.0, y: 119.0),
p3: CGPoint(x: 618.0, y: 350.0)) as BezierCurve]]
var components = [PathComponent]()
for curve in curvesOfO {
components.append(PathComponent(curves: curve))
}
return Path(BezierKit.Path(components: components).closedCGPath)
}
var body: some View {
path.stroke(style: StrokeStyle(lineWidth: 75, lineCap: .butt, lineJoin: CGLineJoin.bevel, miterLimit: 6))
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
Group {
ContentView()
}
}
}
What's going on is that CoreGraphics did not consider the paths closed for the purpose of stroking because they didn't have a .closeSubpath()
command. I was unaware that CoreGraphics had this behavior and I try to match CoreGraphics behavior in BezierKit wherever possible. Thank you for filing the report. This is something I should fix.
from bezierkit.
Thank you!
Seems to work now. :)
(I can’t figure out what it does exactly, but maybe I don’t need it.
from bezierkit.
Basically the workaround I gave you checks if BezierKit considers the path closed, and if so adds the missing .closeSubpath()
command to the list of drawing commands to generate the CoreGraphics version of the path.
At some point I'll fix the issue so that the workaround won't be needed.
from bezierkit.
Great!
from bezierkit.
Related Issues (20)
- boundingBox vs boundingBoxOfPath follows opposite convention as CoreGraphics
- Hard to work with ends of simple, unclosed bezier path HOT 2
- Path and PathComponent hash and hashValue is simply memory address HOT 1
- Unknown references to BezierKit.min(...) and BezierKit.max(...) HOT 3
- Path.offset(distance:) hits assertion failure when called on a Path where all points are equal HOT 1
- Union of 2 overlapping paths returns an empty path HOT 4
- `union` with nonzero winding rule HOT 9
- Path.crossingRemoved() produces wrong result HOT 11
- simplifying a curve? HOT 2
- `offset` seems to treat straight & curved segments differently HOT 3
- feature request: permit separate x and y inputs for scale, outline, reduce HOT 8
- this contour crashes `crossingsRemoved` HOT 9
- `crossingsRemoved` makes these two contours disappear HOT 12
- how to quiet the SwiftLint warning? HOT 2
- `crossingsRemoved` gets confused by coincident points HOT 3
- droots can have low precision in some cases, which could affect Path.contains(_ point:)
- Newton iteration may fail to converge, producing wrong results in curve.project()
- `offset` fatalError when all control points of segments are the same HOT 3
- Proposal: Use Sylvester Matrix for finding the intersection of cubic beziers HOT 1
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
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.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from bezierkit.