几何向量:Angle/SignedAngle函数解析

2023-11-01 03:21

本文主要是介绍几何向量:Angle/SignedAngle函数解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

      最近又跑去温习基础数序去了,没办法,人对某个事物的永久记忆是七次理解才能达成,所以抽空写一些常用的数学计算。

      在二维和三维开发中,计算向量之间夹角属于很常见的操作,在数学中我们可以使用下面:

       1.余弦定理,如果我们知道三边的情况下,使用余弦定理可以计算出任意角的角度,如图:      

         

        2.点乘(点积),我们可以通过点乘(点积)推导出:

               a·b = |a|*|b|*cosθ

               cosθ = (a·b)/(|a|*|b|)

        可以回过头去看下上面的公式定理和推导,加深记忆,接下来我们就在unity中实现一下,代码如下:

        

using System.Collections;
using System.Collections.Generic;
using UnityEngine;public class AngleTest : MonoBehaviour
{void Start(){CalculateVector2Angle();CalculateVector3Angle();}private void CalculateVector2Angle(){Vector2 a = new Vector2(1, 3);Vector2 b = new Vector2(2, 8);Vector2 c = b - a;float apiangle = Vector2.Angle(a, b);float cosangle = Mathf.Acos((a.x * a.x + a.y * a.y + b.x * b.x + b.y * b.y - c.x * c.x-c.y*c.y) / (2 * Mathf.Sqrt(a.x * a.x + a.y * a.y) * Mathf.Sqrt(b.x * b.x + b.y * b.y))) * Mathf.Rad2Deg;float dotangle = Mathf.Acos((a.x * b.x + a.y * b.y) / (Mathf.Sqrt(a.x * a.x + a.y * a.y) * Mathf.Sqrt(b.x * b.x + b.y * b.y))) * Mathf.Rad2Deg;
#if UNITY_EDITORDebug.LogFormat("vector2 apiangle = {0} cosangle = {1} dotangle = {2}", apiangle, cosangle, dotangle);
#endif}private void CalculateVector3Angle(){Vector3 a = new Vector3(1, 3, 5);Vector3 b = new Vector3(2, 8, 4);Vector3 c = b - a;float apiangle = Vector3.Angle(a, b);float cosangle = Mathf.Acos((a.x * a.x + a.y * a.y + a.z * a.z + b.x * b.x + b.y * b.y + b.z * b.z - c.x * c.x - c.y * c.y - c.z * c.z) / (2 * Mathf.Sqrt(a.x * a.x + a.y * a.y + a.z * a.z) * Mathf.Sqrt(b.x * b.x + b.y * b.y + b.z * b.z))) * Mathf.Rad2Deg;float dotangle = Mathf.Acos((a.x * b.x + a.y * b.y + a.z * b.z) / (Mathf.Sqrt(a.x * a.x + a.y * a.y + a.z * a.z) * Mathf.Sqrt(b.x * b.x + b.y * b.y + b.z * b.z))) * Mathf.Rad2Deg;
#if UNITY_EDITORDebug.LogFormat("vector3 apiangle = {0} cosangle = {1} dotangle = {2}", apiangle, cosangle, dotangle);
#endif}
}

        

      因为我们对几何公式的理解,所以很容易实现这个Angle的功能,如果你细心你会发现一点,这个Angle函数不带顺逆时针旋转,也就是不带正负号。

      如果你是认真学习了三角函数,那么应该知道,在二维坐标系中,逆时针旋转方向的夹角为正角,如下图:

      

     那么三维中呢?这里有个叫做左手旋转定则的规范,文字描叙就是:伸出左手,大拇指翘起,四指握拳,那么大拇指指向旋转轴方向(比如Z轴),则其余四指旋转方向就是正角方向。改造一下上面的二维坐标系旋转夹角标识图到三维则如下:

      

      拿左手比划一下就看得出来了,那么我们可以默认认为,一般情况下,我们做二维中角度相关计算,虚拟Z轴指向纸内。

      回到需要谈论的问题,那就是Angle计算是不带顺逆时针判断的,也就是不带正负号,那么我们需要构建一个函数,它既计算了夹角,又判断了顺逆时针方向。

      unity提供了我们Vector.SingedAngle这个API去获取带正负号的夹角。

      如果我们设计这个函数的话,用叉积很方便,因为叉积就是判断顺逆时针旋转的,想象一下Vector2扩展出Z轴,同时两个Vector2向量a和b的扩展出的Vector3向量a'和b'的叉积向量c,那么向量c的z值正负号可以用来判断夹角的正负号,使用上面说的左手规则即可。函数设计如下:

       

private void CalculateVector2SingedAngle(Vector2 a, Vector2 b){float apiangle = Vector2.SignedAngle(a, b);Vector3 a3d = new Vector3(a.x, a.y, 0);Vector3 b3d = new Vector3(b.x, b.y, 0);float crossangle = Vector2.Angle(a, b) * Mathf.Sign(Vector3.Cross(a3d, b3d).z);#if UNITY_EDITORDebug.LogFormat("vector2 apiangle = {0} crossangle = {1}", apiangle, crossangle);
#endif}void Start(){Vector2 a = new Vector2(1, 3);Vector2 b = new Vector2(2, 8);CalculateVector2SingedAngle(a,b);a = new Vector2(1, 7);b = new Vector2(2, 8);CalculateVector2SingedAngle(a, b);a = new Vector2(-1, -7);b = new Vector2(2, 8);CalculateVector2SingedAngle(a, b);}

     

   那么Vector3.SingedAngle怎么去理解呢?先看下官方的函数设计,如下:

   

       看得出来吧,因为三维向量可以是任意朝向的,那么我们就必须限定一个旋转轴,不然我们怎么确定左手规则的大拇指朝向呢?那么我们来设计这个函数,两个Vector3向量a和b,他们的叉积向量c,我们就把向量c当做旋转轴,那么永远是正角,因为向量c是通过ab叉积反推出来的,向量c的左手规则四指旋转方向就是a到b的夹角正方向,所以如下:

       

private void CalculateVector3SingedAngle(Vector3 a, Vector3 b){Vector3 cross = Vector3.Cross(a, b);Vector3 axis = cross;float apiangle = Vector3.SignedAngle(a, b, axis);float crossangle = Vector3.Angle(a, b);
#if UNITY_EDITORDebug.LogFormat("vector3 apiangle = {0} crossangle = {1}", apiangle, crossangle);
#endif}void Start(){Vector3 a = new Vector3(1, 3, 10);Vector3 b = new Vector3(2, 8, 4);CalculateVector3SingedAngle(a, b);a = new Vector3(1, 5, 2);b = new Vector3(2, 8, 5);CalculateVector3SingedAngle(a, b);a = new Vector3(-1, -7, -10);b = new Vector3(2, 4, -9);CalculateVector3SingedAngle(a, b);a = new Vector3(-1, 7, 8);b = new Vector3(2, -3, -5);CalculateVector3SingedAngle(a, b);}

       

        那如果我们使用其他旋转轴去当做axis参数呢?就需要判断axis和cross的夹角是否大于无符号90°,大于说明旋转相反了。函数设计如下:

     

 private void CalculateVector3SingedAngle(Vector3 a, Vector3 b){Vector3 cross = Vector3.Cross(a, b);Vector3 axis = new Vector3(1, -5, 4);float apiangle = Vector3.SignedAngle(a, b, axis);float crossangle = Vector3.Angle(a, b) * Mathf.Sign(90 - Vector3.Angle(cross, axis));
#if UNITY_EDITORDebug.LogFormat("vector3 apiangle = {0} crossangle = {1}", apiangle, crossangle);
#endif}

      

        稍微画一个示意图吧,如下:

    

     使用左手规则比划一下是不是发现,旋转方向随着θ和β角度不同而相反。

     好了,偶尔写一篇几何数学函数详解,顺便学英语。

这篇关于几何向量:Angle/SignedAngle函数解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/320129

相关文章

IDEA与JDK、Maven安装配置完整步骤解析

《IDEA与JDK、Maven安装配置完整步骤解析》:本文主要介绍如何安装和配置IDE(IntelliJIDEA),包括IDE的安装步骤、JDK的下载与配置、Maven的安装与配置,以及如何在I... 目录1. IDE安装步骤2.配置操作步骤3. JDK配置下载JDK配置JDK环境变量4. Maven配置下

Java8需要知道的4个函数式接口简单教程

《Java8需要知道的4个函数式接口简单教程》:本文主要介绍Java8中引入的函数式接口,包括Consumer、Supplier、Predicate和Function,以及它们的用法和特点,文中... 目录什么是函数是接口?Consumer接口定义核心特点注意事项常见用法1.基本用法2.结合andThen链

MySQL 日期时间格式化函数 DATE_FORMAT() 的使用示例详解

《MySQL日期时间格式化函数DATE_FORMAT()的使用示例详解》`DATE_FORMAT()`是MySQL中用于格式化日期时间的函数,本文详细介绍了其语法、格式化字符串的含义以及常见日期... 目录一、DATE_FORMAT()语法二、格式化字符串详解三、常见日期时间格式组合四、业务场景五、总结一、

Python中配置文件的全面解析与使用

《Python中配置文件的全面解析与使用》在Python开发中,配置文件扮演着举足轻重的角色,它们允许开发者在不修改代码的情况下调整应用程序的行为,下面我们就来看看常见Python配置文件格式的使用吧... 目录一、INI配置文件二、YAML配置文件三、jsON配置文件四、TOML配置文件五、XML配置文件

Spring中@Lazy注解的使用技巧与实例解析

《Spring中@Lazy注解的使用技巧与实例解析》@Lazy注解在Spring框架中用于延迟Bean的初始化,优化应用启动性能,它不仅适用于@Bean和@Component,还可以用于注入点,通过将... 目录一、@Lazy注解的作用(一)延迟Bean的初始化(二)与@Autowired结合使用二、实例解

golang panic 函数用法示例详解

《golangpanic函数用法示例详解》在Go语言中,panic用于触发不可恢复的错误,终止函数执行并逐层向上触发defer,最终若未被recover捕获,程序会崩溃,recover用于在def... 目录1. panic 的作用2. 基本用法3. recover 的使用规则4. 错误处理建议5. 常见错

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

MySQL数据库函数之JSON_EXTRACT示例代码

《MySQL数据库函数之JSON_EXTRACT示例代码》:本文主要介绍MySQL数据库函数之JSON_EXTRACT的相关资料,JSON_EXTRACT()函数用于从JSON文档中提取值,支持对... 目录前言基本语法路径表达式示例示例 1: 提取简单值示例 2: 提取嵌套值示例 3: 提取数组中的值注意

C语言中自动与强制转换全解析

《C语言中自动与强制转换全解析》在编写C程序时,类型转换是确保数据正确性和一致性的关键环节,无论是隐式转换还是显式转换,都各有特点和应用场景,本文将详细探讨C语言中的类型转换机制,帮助您更好地理解并在... 目录类型转换的重要性自动类型转换(隐式转换)强制类型转换(显式转换)常见错误与注意事项总结与建议类型