SwiftUI路径 — 一条曲线,用于平滑连接两条线。

huangapple go评论69阅读模式
英文:

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&#39;m struggling to get it to connect smoothly. As you can see in my image, it&#39;s almost perfect but the first connection between the line and the arc (on the right) isn&#39;t perfect.

Any ideas what I&#39;m doing wrong? I even drew this out on paper and I can&#39;t see which value isn&#39;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) -&gt; 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 上演示

SwiftUI路径 — 一条曲线,用于平滑连接两条线。

突出显示的点是对角线的结束点。圆根本不经过它。


不过,有一个方便的 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

SwiftUI路径 — 一条曲线,用于平滑连接两条线。

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&#39;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.

huangapple
  • 本文由 发表于 2023年6月22日 13:10:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76528754.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定