【问题标题】:Vector projection/rejection in C#?C# 中的矢量投影/拒绝?
【发布时间】:2014-11-16 14:47:21
【问题描述】:

我正在尝试在 C# 中为 vector rejection 实现一个函数。那就是:

我一直在尝试用 C# 编写这个公式,但是由于某种原因它总是返回零。这是我到目前为止所拥有的:

private Vector3 Projection(Vector3 vectorA, Vector3 vectorB) {
    Vector3 a2 = Vector3.Scale ( Divide (Vector3.Scale (vectorA, vectorB), Vector3.Scale (vectorB, vectorB)), vectorB);
    return a2;
}

private Vector3 Rejection(Vector3 vectorA, Vector3 vectorB) {
    Vector3 a2 = vectorA - Projection(vectorA, vectorB);
    return a2;
}

private Vector3 Divide(Vector3 a, Vector3 b) {
    Vector3 c = new Vector3 ();
    c.x = a.x / b.x;
    c.y = a.y / b.y;
    c.z = a.z / b.z;
    return c;
}

private void Example() {
    Vector3 a = new Vector3 (5, 5, 0);
    Vector3 b = new Vector3 (0, 10, 0);
    Vector3 c = Rejection(a, b); // Returns (NaN, 0, NaN)
}

// The Vector3 class represents a 3D vector and it's x, y and z components are of float type. It's [scale method][3] multiplies two vectors component wise.

例子:

假设矢量 A 是施加到沿地面移动的物体的力,矢量 B 是重力(垂直于地面)。当向量 A 作用于物体时,它运动的轨迹应该是垂直于重力的第三个向量,可以认为是 A 垂直于 B 行进。这就是 A 对 B 的排斥。

【问题讨论】:

  • 能贴出Vector的定义(尤其是x,y,z的类型)和Scale的定义吗?另外,您输入的参数是什么?它在返回什么?你说它返回零,但它返回一个向量,所以这是不可能的。
  • 您可能希望将此问题标记为特定于 Unity,因为您询问的是 Unity 的 Vector3 类的功能。
  • 嗨,我没有意识到这个类是 Unity 特有的。我可以使用不同的,但我会将它标记到 Unity。
  • 那么您能否举例说明您投入其中的输入类型以及预期和实际输出是什么?
  • 我认为你不能有一个既垂直于 B 又指向与 A 相同方向的向量,因为 A 本身并不垂直于 B。你的意思是别的吗?

标签: c# vector 3d unity3d


【解决方案1】:

符号a·b 表示vector dot product,结果是一个标量值。

所以你需要这样的代码:

public struct Vector3
{
    public readonly double x, y, z;
    public Vector3(double x, double y, double z)
    {
        this.x=x;
        this.y=y;
        this.z=z;
    }
    public double Dot(Vector3 other)
    {
        return x*other.x+y*other.y+z*other.z;
    }
    public Vector3 Scale(double factor)
    {
        return new Vector3(factor*x, factor*y, factor*z);
    }
    public Vector3 Add(Vector3 other)
    {
        return new Vector3(x+other.x, y+other.y, z+other.z);
    }
    public static Vector3 operator+(Vector3 a, Vector3 b) { return a.Add(b); }
    public static Vector3 operator-(Vector3 a) { return a.Scale(-1); }
    public static Vector3 operator-(Vector3 a, Vector3 b) { return a.Add(-b); }
    public static Vector3 operator*(double f, Vector3 a) { return a.Scale(f); }
    public static Vector3 operator/(Vector3 a, double d) { return a.Scale(1/d); }
    public static double operator*(Vector3 a, Vector3 b) { return a.Dot(b); }

    public Vector3 Projection(Vector3 other)
    {
        // (scalar/scalar)*(vector) = (vector)
        return (other*this)/(other*other)*other;
    }
    public Vector3 Rejection(Vector3 other)
    {
        // (vector)-(vector) = (vector)
        return this-Projection(other);
    }
}

class Program
{
    static void Main(string[] args)
    {
        var A=new Vector3(5, 5, 0);
        var B=new Vector3(0, 10, 0);
        var C=A.Rejection(B);
        // C = { 5,0,0}, expected answer from math {5,5,0}-0.5*{0,10,0}
    }
}

编辑

如果您无法控制代码,您可以将代码移到 Vector3 类之外

// Vector3 defined elsewhere with .x, .y and .z fields

class VectorAlgebra
{
    public static Vector3 Subtract(Vector3 a, Vector3 b)
    {
        return new Vector3(a.x-b.x, a.y-b.y, a.z-b.z);
    }
    public static Vector3 Scale(float f, Vector3 a)
    {
        return new Vector3(f*a.x, f*a.y, f*a.z);
    }

    public static float Dot(Vector3 a, Vector3 b)
    {
        return (a.x*b.x)+(a.y*b.y)+(a.z*b.z);
    }

    public static Vector3 Projection(Vector3 a, Vector3 b)
    {
        return Scale(Dot(a, b)/Dot(b, b), b);
    }
    public static Vector3 Rejection(Vector3 a, Vector3 b)
    {
        return Subtract(a, Projection(a, b));
    }

    static void Main(string[] args)
    {
        var A=new Vector3(5, 5, 0);
        var B=new Vector3(0, 10, 0);
        var C=Rejection(A, B);
        // C = { 5,0,0}, expected answer from math {5,5,0}-0.5*{0,10,0}
    }
}

查看当您编写向量代数规则时,投影和拒绝的编码变得与数学书籍中的公式相同。您可以通过Wolfram Alpha查看答案。

【讨论】:

  • 来自the documentation,看起来像Scale 点积,虽然我同意这是一个奇怪的术语。
  • 谢谢,你是救生员。此外,我将代码移到 Vector3 之外,您为我节省了很多工作。我将用我最后使用的内容编辑答案。
【解决方案2】:

好的,现在我们有了一些数字,让我们分解步骤

Vector3.Scale ( Divide (Vector3.Scale (vectorA, vectorB), Vector3.Scale (vectorB, vectorB)), vectorB);

var numerator = Vector3.Scale (vectorA, vectorB);
var denominator = Vector3.Scale (vectorB, vectorB);
var divided = Divide(numerator, denominator);
var result = Vector3.Scale(divided, vectorB);

你的数字会是什么

vectorA = (5,5,0)
vectorB = (0,10,0)
numerator = (0,50,0)
denominator = (0,100,0)
divided = (NaN,.5,NaN) <- since you can't divide by zero
result = (NaN,5,NaN)

不确定为什么第二维得到 0 而不是 5(错字?某种类型转换问题?),但希望这可以解释为什么会弹出 NaNs。

【讨论】:

  • 诀窍是Scale()返回一个标量,不需要与Divide()进行向量除法。
  • @ja72 这不是 Scale 的文档所显示的 - 在文档中它返回一个向量
  • 在您提到的另一条评论中,Scale 是点积。它不能是点积并返回向量。
  • 哦,你是对的,抱歉,它不是点积,它只是将每个组件相乘
猜你喜欢
  • 1970-01-01
  • 2017-05-09
  • 2018-02-13
  • 2021-08-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-02-17
相关资源
最近更新 更多