草庐IT

c++ - 两个 vector 之间的最短旋转方向

coder 2024-02-09 原文

我的问题是关于计算二维中两个 vector 之间的最小角度的方向。我正在用 C++ 制作游戏,其中一个障碍是热寻导弹发射器。我通过计算目标和子弹之间的 vector 、归一化 vector 然后乘以它的速度来让它工作。但是,我现在要回到这门课,让它变得更好。我不想立即锁定播放器,而是希望它仅在子弹 vector 在特定角度(子弹 vector 和 vector bulletloc->target 之间的角度)内时才这样做。否则,我希望它以一定程度缓慢地向目标平移,从而为玩家提供足够的空间来避开它。我已经完成了所有这些(在 vb.net 项目中,所以我可以简化问题,解决问题然后用 C++ 重新编写)。然而,即使最快的路线是逆时针方向,子弹也总是顺时针方向朝向目标旋转。所以问题是找出应用旋转的方向,以便覆盖最小的角度。这是我的代码,您可以尝试看看我在描述什么:

    Function Rotate(ByVal a As Double, ByVal tp As Point, ByVal cp As Point, ByVal cv As Point)
    'params a = angle, tp = target point, cp = current point, cv = current vector of bullet'
    Dim dir As RotDir 'direction to turn in'
    Dim tv As Point 'target vector cp->tp'
    Dim d As Point 'destination point (d) = cp + vector'
    Dim normal As Point
    Dim x1 As Double
    Dim y1 As Double
    Dim VeritcleResolution As Integer = 600

    tp.Y = VeritcleResolution - tp.Y 'modify y parts to exist in plane with origin (0,0) in bottom left'
    cp.Y = VeritcleResolution - cp.Y
    cv.Y = cv.Y * -1

    tv.X = tp.X - cp.X 'work out cp -> tp'
    tv.Y = tp.Y - cp.Y

    'calculate angle between vertor to target and vecrot currntly engaed on'
    Dim tempx As Double
    Dim tempy As Double

    tempx = cv.X * tv.X
    tempy = cv.Y * tv.Y

    Dim DotProduct As Double

    DotProduct = tempx + tempy 'dot product of cp-> d and cp -> tp'

    Dim magCV As Double 'magnitude of current vector'
    Dim magTV As Double 'magnitude of target vector'

    magCV = Math.Sqrt(Math.Pow(cv.X, 2) + Math.Pow(cv.Y, 2))
    magTV = Math.Sqrt(Math.Pow(tv.X, 2) + Math.Pow(tv.Y, 2))

    Dim VectorAngle As Double

    VectorAngle = Acos(DotProduct / (magCV * magTV))
    VectorAngle = VectorAngle * 180 / PI 'angle between cp->d and cp->tp'

    If VectorAngle < a Then 'if the angle is small enough translate directly towards target'
        cv = New Point(tp.X - cp.X, tp.Y - cp.Y)
        magCV = Math.Sqrt((cv.X ^ 2) + (cv.Y ^ 2))

        If magCV = 0 Then
            x1 = 0
            y1 = 0
        Else
            x1 = cv.X / magCV
            y1 = cv.Y / magCV
        End If

        normal = New Point(x1 * 35, y1 * 35)
        normal.Y = normal.Y * -1

        cv = normal
    ElseIf VectorAngle > a Then 'otherwise smootly translate towards the target'
        Dim x As Single
        d = New Point(cp.X + cv.X, cp.Y + cv.Y)


        a = (a * -1) * PI / 180 'THIS LINE CONTROL DIRECTION a = (a*-1) * PI / 180 would make the rotation counter clockwise'

        'rotate the point'
        d.X -= cp.X
        d.Y -= cp.Y

        d.X = (d.X * Cos(a)) - (d.Y * Sin(a))
        d.Y = (d.X * Sin(a)) + (d.Y * Cos(a))

        d.X += cp.X
        d.Y += cp.Y

        cv.X = d.X - cp.X
        cv.Y = d.Y - cp.Y

        cv.Y = cv.Y * -1
    End If

    Return cv

End Function

我的一个想法是计算出两个 vector 的方位角,如果差值大于 180 度,则顺时针旋转,否则逆时针旋转,任何想法都会有所帮助。谢谢。

编辑:我想补充一点,这个网站非常有帮助。我经常用别人提出的问题来解决我自己的问题,我想借此机会说声谢谢。

最佳答案

正如您在代码中所写,两个(归一化) vector 之间的角度是它们点积的反余弦值。

要获得一个有符号角,您可以使用第三个 vector 来表示其他两个 vector 所在平面的法线——在您的 2D 情况下,这将是一个指向直线的 3D vector “向上”,比如 (0, 0, 1)。

然后,将第一个 vector (您希望角度与其相关的 vector )与第二个 vector 进行叉积(注意叉积不可交换)。角度的符号应与所得 vector 与平面法线的点积符号相同。

在代码中(C#,抱歉)——注意所有 vector 都被假设为标准化:

public static double AngleTo(this Vector3 source, Vector3 dest)
{
    if (source == dest) {
        return 0;
    }
    double dot; Vector3.Dot(ref source, ref dest, out dot);
    return Math.Acos(dot);
}

public static double SignedAngleTo(this Vector3 source, Vector3 dest, Vector3 planeNormal)
{
    var angle = source.AngleTo(dest);
    Vector3 cross; Vector3.Cross(ref source, ref dest, out cross);
    double dot; Vector3.Dot(ref cross, ref planeNormal, out dot);
    return dot < 0 ? -angle : angle;
}

它的工作原理是利用两个 vector 之间的叉积产生第三个 vector ,该 vector 垂直于(法向)由前两个 vector 定义的平面(因此它本质上是一个 3D 运算)。 a x b = -(b x a),因此 vector 将始终垂直于平面,但在不同的一侧,具体取决于 a<>b(有一个叫做 right-hand rule 的东西)。

因此,叉积为我们提供了一个垂直于平面的有符号 vector ,当 vector 之间的角度超过 180° 时,该平面会改变方向。如果我们事先知道一个垂直于平面的 vector 指向正上方,那么我们可以通过检查点的符号来判断叉积是否与该平面法线方向相同产品。

关于c++ - 两个 vector 之间的最短旋转方向,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11022446/

有关c++ - 两个 vector 之间的最短旋转方向的更多相关文章

  1. ruby-on-rails - 如何在 ruby​​ 中使用两个参数异步运行 exe? - 2

    exe应该在我打开页面时运行。异步进程需要运行。有什么方法可以在ruby​​中使用两个参数异步运行exe吗?我已经尝试过ruby​​命令-system()、exec()但它正在等待过程完成。我需要用参数启动exe,无需等待进程完成是否有任何ruby​​gems会支持我的问题? 最佳答案 您可以使用Process.spawn和Process.wait2:pid=Process.spawn'your.exe','--option'#Later...pid,status=Process.wait2pid您的程序将作为解释器的子进程执行。除

  2. ruby-on-rails - Rails 应用程序之间的通信 - 2

    我构建了两个需要相互通信和发送文件的Rails应用程序。例如,一个Rails应用程序会发送请求以查看其他应用程序数据库中的表。然后另一个应用程序将呈现该表的json并将其发回。我还希望一个应用程序将存储在其公共(public)目录中的文本文件发送到另一个应用程序的公共(public)目录。我从来没有做过这样的事情,所以我什至不知道从哪里开始。任何帮助,将不胜感激。谢谢! 最佳答案 无论Rails是什么,几乎所有Web应用程序都有您的要求,大多数现代Web应用程序都需要相互通信。但是有一个小小的理解需要你坚持下去,网站不应直接访问彼此

  3. ruby-on-rails - 如何优雅地重启 thin + nginx? - 2

    我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server

  4. ruby - #之间? Cooper 的 *Beginning Ruby* 中的错误或异常 - 2

    在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee

  5. ruby-on-rails - `a ||= b` 和 `a = b if a.nil 之间的区别? - 2

    我正在检查一个Rails项目。在ERubyHTML模板页面上,我看到了这样几行:我不明白为什么不这样写:在这种情况下,||=和ifnil?有什么区别? 最佳答案 在这种特殊情况下没有区别,但可能是出于习惯。每当我看到nil?被使用时,它几乎总是使用不当。在Ruby中,很少有东西在逻辑上是假的,只有文字false和nil是。这意味着像if(!x.nil?)这样的代码几乎总是更好地表示为if(x)除非期望x可能是文字false。我会将其切换为||=false,因为它具有相同的结果,但这在很大程度上取决于偏好。唯一的缺点是赋值会在每次运行

  6. ruby - 这两个 Ruby 类初始化定义有什么区别? - 2

    我正在阅读一本关于Ruby的书,作者在编写类初始化定义时使用的形式与他在本书前几节中使用的形式略有不同。它看起来像这样:classTicketattr_accessor:venue,:datedefinitialize(venue,date)self.venue=venueself.date=dateendend在本书的前几节中,它的定义如下:classTicketattr_accessor:venue,:datedefinitialize(venue,date)@venue=venue@date=dateendend在第一个示例中使用setter方法与在第二个示例中使用实例变量之间是

  7. 旋转矩阵的几何意义 - 2

    点向量坐标矩阵的几何意义介绍旋转矩阵的几何含义之前,先介绍一下点向量坐标矩阵的几何含义点:在一维空间下就是一个标量,如同一条直线上,以任意某一个位置为0点,以一定的尺度间隔为1,2,3...,相反方向为-1,-2,-3...;如此就形成了一维坐标系,这时候任何一个点都可以用一个数值表示,如点p1=5,即即从原点出发沿着x轴正方向移动5个尺度;点p2=-3,负方向移动3个尺度;     在一维坐标系上过原点做垂直于一维坐标系的直线,则形成了二维坐标系,此时描述一个点需要两个数值来表示点p3=(3,2),即从原点出发沿着x轴正方向移动3个尺度,在此基础上沿着y轴正方向移动两个尺度的位置就是点p3。

  8. ruby - 使用 `+=` 和 `send` 方法 - 2

    如何将send与+=一起使用?a=20;a.send"+=",10undefinedmethod`+='for20:Fixnuma=20;a+=10=>30 最佳答案 恐怕你不能。+=不是方法,而是语法糖。参见http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_expressions.html它说Incommonwithmanyotherlanguages,Rubyhasasyntacticshortcut:a=a+2maybewrittenasa+=2.你能做的最好的事情是:

  9. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  10. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

随机推荐