SwiftUI之深入解析三角函数和三角公式的应用

一、基本术语

  • 三角是关于直角三角形的边和角之间的关系,可以给它们取个随意的名字,以确保我们都能理解对方,这些名称并不相关,可以选择任意名称,本文名称定义如下:

在这里插入图片描述

  • 直角三角形:或者简单的直角三角形,它是一个三角形,其中有一个角是 90 度;
    • Hypotenuse(斜边):它是直角三角形中最大的边,也是对着直角的边;
    • Leg:任意边,这不是斜边;
    • Opposed Leg:相对于其中一个角度,它是没有“接触”它的那个,在上图中, leg(a) 与 𝝰(alpha) 相反,leg(b) 与 𝝱(beta) 相反;
    • Adjacent Leg:相对于其中一个角,它是接触它的那个角,在上图中,leg(a) 毗邻 𝝱(beta),leg(g) 毗邻𝝰(alpha)。

二、度和弧度

  • 我们都知道度,如果我告诉你,给我一个 90 度的角,你可能马上就知道该怎么做。但如果我说,给一个 1.5708 弧度的角,那么你还知道怎么做吗?其实,它们都指向同一个角,角度和弧度是测量它们的两种不同尺度,这两个单元之间的转换非常简单:

在这里插入图片描述

  • π 是 Pi 的符号,如果需要从角度转换到弧度,那么需要:

在这里插入图片描述

  • 将弧度转换为角度:

在这里插入图片描述

  • 如下所示,是一个可以创建的扩展,以便在两个单位之间转换:
extension Double {
    var asDegrees: Double { return self * 180 / .pi }
    var asRadians: Double { return self * .pi / 180 }
}

let radAngle: Double = 2.0
print("radAngle radians= \(radAngle.asDegrees) degrees") 

let degAngle: Double = 180
print("degAngle degrees = \(degAngle.asRadians) radians") 
  • SwiftUI 有一个名为 Angle 的类型,带有一些方便的初始化式和计算属性:
let a = Angle(degrees: 180) // Create an angle using degrees
let b = Angle(radians: 2.3456) // Create an angle using radians
        
print("\(a.radians) radians = \(a.degrees) degrees")
print("\(b.radians) radians = \(b.degrees) degrees")
  • 为什么会复杂化呢?degrees 不是更容易使用吗?也许对我们来说是这样,但数学上,弧度是有意义的,如果你有兴趣了解原因,可以浏览参考:Why Radians?。我们需要知道弧度,因为在 Swift 中的三角函数需要用弧度来指定角度。

三、三角函数的作用

  • 正如我们看到的,给定一个直角三角形,可以从其他三角形推导出一些值。例如,如果知道斜边和其中一个角,就可以得到腿和其他角的大小。如果知道两条边,你就能得到斜边和角等。
  • 我们为什么需要这个呢?如果开始考虑三角形的顶点(A, B 和 C),在你的视图中作为 CGPoints,那么一切都比较清晰了。给定两个 CGPoint,可以计算从一个到另一个的方向(角度)(例如,对一个视图旋转效果很有用)。给定两个点的 x、y 坐标,可以得到它们之间的距离(斜边),给定一个 CGPoint 的距离和方向,可以获得第二个 CGPoint 坐标等。
  • 三角函数的另一个应用,是当你需要一个函数来平滑一个效果,一个距离,一个颜色,或者任何可以用数字表示的东西。

四、正弦,余弦和正切是什么?

  • 除了三个基本的三角函数之外,还应该知道反函数(反正弦,反余弦和反正切)。例如,如果一个角度 𝝱 的正弦值为 x,那么 x 的反正弦值为 𝝱:

在这里插入图片描述

  • 根据勾股定理,斜边的平方等于两条边的平方和:

在这里插入图片描述

在这里插入图片描述

  • 由这些公式,我们可以推断出其余的一切,当需要某个没有的值时,看看其他知道的值,然后选择正确的公式就行了。对于任何值,需要知道两条边,或者一条边和一个角,所有的计算组合都在下表中,如下图所示:

在这里插入图片描述
在这里插入图片描述

  • 这就是我们需要的全部数学,让我们看看如何获得两个 CGPoint 之间的距离和方向,然后给定一个点坐标,一个距离和一个方向的情况下,如何计算第二个点。我们要用它们来画一个多边形,来看看到如何应用相同的想法,以绘制一个形状,如花朵显示在文章的顶部,最后使用 sin() 函数来平滑值的输入或输出。

五、角度和方向

  • 如果你有两个任意的点,我们称它们为 pt1 和 pt2,我们将得到这两个点之间的距离和方向:

在这里插入图片描述

  • 使用 SwiftUI,这段代码将得到两点之间的方向和距离:
func getDistanceAndDirection(_ pt1: CGPoint, _ pt2: CGPoint) -> (distance: CGFloat, angle: Angle) {
    let a = pt2.y - pt1.y // calculate leg a
    let b = pt2.x - pt1.x // calculate leg b
    
    var alpha = atan2(a, b) // calculate angle
    let s = sin(alpha) // sine of the angle
    let h = (a == 0 ? abs(b) : (a / s)) // calculate hypotenuse, and prevent divide by zero

    alpha = alpha < 0 ? alpha + (.pi * 2) : alpha // make sure angles are returned as positive values
    
    return (h, Angle(radians: Double(alpha)))
}
  • 看这两点构成的三角形,距离与三角形的斜边相匹配,用 arctan 计算角度。
  • 在给定的方向和角度下获得第二个点:
    • 如果知道一个点的坐标 (pt1),给定一个方向和长度,那么如何获得第二个点 (pt2)?

在这里插入图片描述

    • 在这个例子中,创建一个形状来绘制一条线,给定一个 CGPoint,一个角度和一个距离:
Line(pt1: CGPoint(x: 100, y: 300), direction: Angle(degrees: 25), length: 300)
                .stroke(Color.blue, lineWidth: 2)
                .frame(width: 400, height: 400)
struct Line: Shape {
    let pt1: CGPoint
    let direction: Angle
    let length: CGFloat
    
    func path(in rect: CGRect) -> Path {
        let x = pt1.x + length * CGFloat(cos(direction.radians))
        let y = pt1.y - length * CGFloat(sin(direction.radians))
        
        let pt2 = CGPoint(x: x, y: y)
        
        var p = Path()
        
        p.move(to: pt1)
        p.addLine(to: pt2)
                
        return p
    }
}

六、绘制一个多边形

  • 接下来,来创建一个形状来绘制一个正多边形,这里将使用一个七边多边形,代码几乎类似,可以创建任意数量的边:

在这里插入图片描述

  • 一个多边形有许多顶点,想要得到相应的坐标,这样就可以画出连接它们的线。如下图所示,所有顶点到圆周中心的距离都相同:

在这里插入图片描述

  • 如前所述,在两点之间,您总是可以创建一个直角三角形。在某些情况下,会形成一个三角形,其中一条边的长度为 0,而另一条边的长度为斜边,想象一个三角形,其中一条边收缩,直到它的长度为零。在这种情况下,正弦值为 0,余弦值为 1,反之亦然。三角函数可以很好地处理这个问题,其中一种情况,就是顶部的顶点(90 度角),cos(90) = 0 sin(90) = 1:

在这里插入图片描述

  • 如果我们定义了多边形的中心和周长的半径,就可以得到所有的顶点,每个顶点的角度由多边形的边数决定。三角函数的美妙之处在于,它们可以处理大于 90 度的角,(在某些情况下)返回负值,这很好地满足了我们的绘图要求。例如,在上面的第二个三角形中,余弦值是负的,这意味着顶点的 x 坐标将小于圆周中心的 x 坐标,正是需要的:
struct PolygonShape: Shape {
    var sides: Int
    
    func path(in rect: CGRect) -> Path {        
        // hypotenuse (we make it fit inside the available rect
        let h = Double(min(rect.size.width, rect.size.height)) / 2.0
        
        // center
        let c = CGPoint(x: rect.size.width / 2.0, y: rect.size.height / 2.0)
        
        var path = Path()
                
        for i in 0..<sides {
            let angle = (Double(i) * (360.0 / Double(sides))) * Double.pi / 180

            // Calculate vertex position
            let pt = CGPoint(x: c.x + CGFloat(cos(angle) * h), y: c.y + CGFloat(sin(angle) * h))
            
            if i == 0 {
                path.move(to: pt) // move to first vertex
            } else {
                path.addLine(to: pt) // draw line to next vertex
            }
        }
        
        path.closeSubpath()
        
        return path
    }
}
  • 我们随时都可以看到三角形,例如,在下面的花中,每个花瓣都由两条曲线组成;要画一条曲线,需要一个起点、一个终点和一个控制点,我们能用这三个点做什么呢?可以用来制作半瓣的三个点,另一半是对称的:

在这里插入图片描述

七、平滑进,平滑出

  • 正弦(或余弦)函数有一个特点,我们看它的图形,可以注意到图形的形状重复,它的最小值是 -1,最大值是 1,f(x) 开始缓慢增长,然后稳定,然后再次缓慢增长:

在这里插入图片描述

  • 如果稍微改变函数,为了移动和压缩图,我们得到一对理想的波,平滑地增加和减少一个任意值:

在这里插入图片描述

  • 当然,还有其他方法可以实现平滑值,但这是一个值得提及的简单方法。可以使用这个功能淡入淡出几乎任何东西:声音音量、定位、移动、颜色、缩放等。如下所示,创建具有渐进缩放值的文本:

在这里插入图片描述

struct ContentView: View {
    var body: some View {
        ProgressiveText(text: "AAAAAAAA")
    }
}

struct ProgressiveText: View {
    let text: String
    
    var body: some View {
        
        HStack(spacing: 10) {
            ForEach(Array(text.enumerated()), id: \.0) { (n, ch) in
                Text(String(ch)).font(.largeTitle).fontWeight(.bold).scaleEffect(self.scaleValue(n, self.text.count))
            }
        }
    }
    
    func scaleValue(_ idx: Int, _ totalCharacters: Int) -> CGFloat {
        
        // Normalized character position, to a value between 0 and 1
        let x = Double(idx) / Double(totalCharacters)
        
        // Get a number between 0 and 1, according to a sine wave
        let y = (sin(2 * .pi * x - (.pi / 2)) + 1) / 2.0
        
        // Return a scale value from 1 (normal) to 3 (3 times the size).
        return 1 + 2 * CGFloat(y)
    }
}
  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
东南亚位于我国倡导推进的“一带一路”海陆交汇地带,作为当今全球发展最为迅速的地区之一,近年来区域内生产总值实现了显著且稳定的增长。根据东盟主要经济体公布的最新数据,印尼西亚2023年国内生产总值(GDP)增长5.05%;越南2023年经济增长5.05%;马来西亚2023年经济增速为3.7%;泰国2023年经济增长1.9%;新加坡2023年经济增长1.1%;柬埔寨2023年经济增速预计为5.6%。 东盟国家在“一带一路”沿线国家中的总体GDP经济规模、贸易总额与国外直接投资均为最大,因此有着举足轻重的地位和作用。当前,东盟与中国已互相成为双方最大的交易伙伴。中国-东盟贸易总额已从2013年的443亿元增长至 2023年合计超逾6.4万亿元,占中国外贸总值的15.4%。在过去20余年中,东盟国家不断在全球多变的格局里面临挑战并寻求机遇。2023东盟国家主要经济体受到国内消费、国外投资、货币政策、旅游业复苏、和大宗商品出口价企稳等方面的提振,经济显现出稳步增长态势和强韧性的潜能。 本调研报告旨在深挖掘东南亚市场的增长潜力与发展机会,分析东南亚市场竞争态势、销售模式、客户偏好、整体市场营商环境,为国内企业出海开展业务提供客观参考意见。 本文核心内容: 市场空间:全球行业市场空间、东南亚市场发展空间。 竞争态势:全球份额,东南亚市场企业份额。 销售模式:东南亚市场销售模式、本地代理商 客户情况:东南亚本地客户及偏好分析 营商环境:东南亚营商环境分析 本文纳入的企业包括国外及印尼本土企业,以及相关上下游企业等,部分名单 QYResearch是全球知名的大型咨询公司,行业涵盖各高科技行业产业链细分市场,横跨如半导体产业链(半导体设备及零部件、半导体材料、集成电路、制造、封测、分立器件、传感器、光电器件)、光伏产业链(设备、硅料/硅片、电池片、组件、辅料支架、逆变器、电站终端)、新能源汽车产业链(动力电池及材料、电驱电控、汽车半导体/电子、整车、充电桩)、通信产业链(通信系统设备、终端设备、电子元器件、射频前端、光模块、4G/5G/6G、宽带、IoT、数字经济、AI)、先进材料产业链(金属材料、高分子材料、陶瓷材料、纳米材料等)、机械制造产业链(数控机床、工程机械、电气机械、3C自动化、工业机器人、激光、工控、无人机)、食品药品、医疗器械、农业等。邮箱:market@qyresearch.com

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

╰つ栺尖篴夢ゞ

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值