SwiftUI路径 - 一条平滑连接两条线的曲线

3

我有两条带有SwiftUI路径的线(见图像)。我想用一个完美平滑的弧线将它们连接起来,就像this图像中的对话气泡尾巴一样。

我在努力使其连接得更顺畅。正如您在我的图像中所看到的,它几乎完美,但是线和弧线之间的第一个连接(右侧)不完美。

有什么想法我做错了什么吗?我甚至在纸上画出来,也看不出哪个值不正确。

enter image description here

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个回答

2
让我们将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上进行演示。

enter image description here

强调的重点是对角线的终点。圆形根本不经过它。
不过别担心,有一个方便的addArc(tangent1End:tangent2End:radius:transform:) API,它接受两条线和一个半径,并生成一个同时与两者相切的圆!
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))

这个帖子有一张非常好的图表,展示了这种过载是如何工作的。

还可以参考 Math.SE 上的这篇帖子,了解背后的数学原理。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接