英文:
SwiftUI path — a curve to connect two lines smoothly
问题
我有两条带有SwiftUI路径的线(参见图像)。我想用一个完美平滑的弧线将它们连接起来,使它看起来像[这个][1]图像中的对话框尾巴。
我在努力使它们平滑连接。正如你在我的图像中所看到的,它几乎完美,但是第一个线条和弧线之间的连接(右侧)不完美。
你有什么想法我做错了什么吗?我甚至在纸上画了出来,也看不出哪个值不正确。
[![进入图像描述][2]][2]
```swift
结构体 SpeechBubbleTail: Shape {
私有 let 半径: CGFloat
init(半径: CGFloat = 10) {
self.半径 = 半径
}
函数 路径(in rect: CGRect) -> Path {
路径 { path in
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX + 半径, y: rect.maxY - 半径))
path.addArc(
center: CGPoint(x: rect.minX + ((半径 / 2) * 1.5), y: rect.maxY - (半径 * 1.5)),
radius: (半径 / 2),
startAngle: Angle(degrees: 45),
endAngle: Angle(degrees: 180),
clockwise: false
)
path.addLine(to: CGPoint(x: rect.minX + ((半径 / 2) * 0.5), y: rect.minY))
}
}
}
<details>
<summary>英文:</summary>
I have two lines with a SwiftUI Path (see image). I want to connect these with a perfect smooth arc so it looks like the speech bubble tail in [this][1] image.
I'm struggling to get it to connect smoothly. As you can see in my image, it's almost perfect but the first connection between the line and the arc (on the right) isn't perfect.
Any ideas what I'm doing wrong? I even drew this out on paper and I can't see which value isn't correct.
[![enter image description here][2]][2]
```swift
struct SpeechBubbleTail: Shape {
private let radius: CGFloat
init(radius: CGFloat = 10) {
self.radius = radius
}
func path(in rect: CGRect) -> Path {
Path { path in
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
path.addLine(to: CGPoint(x: rect.minX + radius, y: rect.maxY - radius))
path.addArc(
center: CGPoint(x: rect.minX + ((radius / 2) * 1.5), y: rect.maxY - (radius * 1.5)),
radius: (radius / 2),
startAngle: Angle(degrees: 45),
endAngle: Angle(degrees: 180),
clockwise: false
)
path.addLine(to: CGPoint(x: rect.minX + ((radius / 2) * 0.5), y: rect.minY))
}
}
}
答案1
得分: 1
让我们将 radius
重命名为 diameter
,因为你在使用 radius / 2
作为半径...
所以你有两条线,你想用一个圆弧连接它们。
- 从
(x: rect.maxX, y: rect.minY)
到(x: rect.minX + diameter, y: rect.maxY - diameter)
的对角线,以及, - 在 x =
rect.minX + diameter / 4
处的垂直线
观察:圆的中心 不能 在 (x: rect.minX + ((diameter / 2) * 1.5), y: rect.maxY - (diameter * 1.5)
处。
在 Desmos 上演示
突出显示的点是对角线的结束点。圆根本不经过它。
不过,有一个方便的 addArc(tangent1End:tangent2End:radius:transform:)
API,它接受两条线和一个半径,并生成一个同时切线的圆!
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
// addArc 会自动绘制这条线,所以你甚至不需要自己绘制它
// path.addLine(to: CGPoint(x: rect.minX + diameter, y: rect.maxY - diameter))
path.addArc(
// tangent1End 是当你延伸它们时两条线的交点
tangent1End: CGPoint(x: rect.minX + diameter / 4, y: rect.maxY - diameter / 4),
tangent2End: CGPoint(x: rect.minX + ((diameter / 2) * 0.5), y: rect.minY),
radius: diameter / 2)
path.addLine(to: CGPoint(x: rect.minX + ((diameter / 2) * 0.5), y: rect.minY))
这个 帖子 上有一个非常好的图示,展示了这个重载函数的工作原理。
还可以参考 Math.SE 上的 这个帖子,了解其中的数学原理。
英文:
Let us rename radius
to diameter
instead, since you used radius / 2
as the radius...
So you have two lines that you want to join with a circular arc.
- a diagonal line from
(x: rect.maxX, y: rect.minY)
to(x: rect.minX + diameter, y: rect.maxY - diameter)
, and, - a vertical line at x =
rect.minX + diameter / 4
Observation: The centre of the circle cannot be at (x: rect.minX + ((diameter / 2) * 1.5), y: rect.maxY - (diameter * 1.5)
.
Demo on Desmos
The point highlighted is where the diagonal line ends. The circle does not go through it at all.
<hr>
Don't worry though, there is a convenient addArc(tangent1End:tangent2End:radius:transform:)
API that takes 2 lines and a radius, and produces a circle that is tangent to both!
path.move(to: CGPoint(x: rect.maxX, y: rect.minY))
// addArc will draw this line automatically, so you don't even need to draw it yourself
// path.addLine(to: CGPoint(x: rect.minX + diameter, y: rect.maxY - diameter))
path.addArc(
// tangent1End is the intersection of the two lines when you extend them
tangent1End: CGPoint(x: rect.minX + diameter / 4, y: rect.maxY - diameter / 4),
tangent2End: CGPoint(x: rect.minX + ((diameter / 2) * 0.5), y: rect.minY),
radius: diameter / 2)
path.addLine(to: CGPoint(x: rect.minX + ((diameter / 2) * 0.5), y: rect.minY))
This post has a very nice figure showing how this overload works.
See also this post on Math.SE for the mathematics behind this.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论