用户:  密码: 记住我     找回密码 
| 文章 >> 编程通用 >> 算法

一个C#中的向量类​​型

日期 | 作者ř波特 | 浏览86 | 评分100 | 标签算法 评论
简介
,多年来,我所看到的人与矢量数学斗争。本指南应通过创建一个可重用的Vector3类型和它背后的数学的步行。后固定3仅仅指的是在3维的向量(X,Y,Z)。
代码没有设计成快速或有效的,但要尽可能简单和理解。为此,作为个人喜好,Vector3类型是挤满了相关的功能和多个接口的方法(如静态和非静态方法的变种)。很多人会认为这个臃肿的代码,但是,我认为,它使代码的程序员友好。显然,成长,我会倾向于重构功能的退了出去,因为我创建对象和类型的功能更好地适应作为一个项目。我看到,实现最大程度的凝聚力和减少耦合和依赖。
我已经用在三维直角坐标系(即三个垂直的X,Y和Z轴)和欧几里德几何。不要担心这些条款,他们只是在高中所涉及的一些数学的正式名称。向量空间体积(立方体);注意,您可以使用其他的向量空间,如一个圆柱形的空间,一轴(通常Z)与圆柱的半径。
你可能已经猜到,电脑是相当缓慢的,这种类型的数学。矩阵数学,更有效,但更难理解。您将需要一个三角和代数的基本掌握,了解本指南。
除非另有说明,我假设的矢量位置,在点(0,0,0)的。替代位置向量,单位向量,这可以解释为没有数量或无限幅度和载体对载体的起源是另一个载体,幅度正在从原点向量的距离。
请注意,本指南非常详细,似乎光顾经验丰富的C#程序员。请不要得罪了,我已经编写了广大观众的引导。
一个快速的词汇:运营商,这是用于定义一个操作,如加(符号)(AB)操作数,这些都是在操作使用的变量,如(a)及(b)在(AB)。左手侧(左轴)的操作数是(A),右手端(右轴)的操作数是(B)。
本指南中的所有方程假设(或V1)和B(或V2)可以分解成:
(A B C)=(D E F)= B使用代码
首先,让我们定义如何将存储矢量信息。我常常不创建结构时编码,但我们Vector3这是完美的。如果你正在读这篇文章,你可能已经知道,一个向量沿轴的数量代表的值。在本教程中,我们将开发一个立体型,所以... ...你的变量和三个轴。
public struct Vector3

{

   private double x, y, z;

}

是什么方向轴?从一个可视化的背景下,我总是假设:
{S0}
您可能已经注意到,Z是负你看不起轴。这是一种常见的约定,如OpenGL图形库。这将成为重要的考虑俯仰,滚转和偏航方法时。
快速分流:为什么一个结构,而不是一类?

struct和class之间的差别:而struct是值类型,而不是堆栈上创建,从而减少垃圾收集的开销。他们是按值传递的,而不是通过引用。他们快速,高效地创建和处理。你不能从中他们(即非继承)其他类型。 他们只是少数的成员(变量)的类型。微软建议一个结构应小于16个字节。您不需要新的关键字来实例化一个结构。
基本上,它的样子,行为像,是一个原始类型。虽然,没有向量类型为何不能创建一个类的原因。发展一个结构的缺点是,集合类。NET框架类铸铁结构。这意味着一个Vector3的大集合,将有一个高的铸造开销。
一个结构上更深入的文章已被写入由S. Senthil库马尔访问变量
你有没有注意到的变数是私人?
虽然我选择了建立一个结构,我习惯性地隐藏我的变量,并创建公共访问的mutator属性。这不是严格把好结构的做法,但我创造了他们的情况下,我觉得有必要在稍后的日期转换成一个类(这是好的做法,阶级结构)。
另外的属性,数组风格的界面,也提供了。这允许用户调用Vector3 myVector [X],myVector [Y],myVector [Z]。此外,用户可以获取或设置使用数组属性的数组中的所有组件,即myVector.Array = {X,Y,Z}。{C}
有物业还提供了访问和操作一个向量的大小。一个向量幅度(或绝对值),不论是它的长度方向,并且可以使用公式确定:
{S1}
SumComponentSquares法(以下使用),可以看到在本文的后面。请注意,幅度始终是积极的,不能设置一个向量(0,0,0)的幅度。
public double Magnitude

{

   get 

   {

      return Math.Sqrt ( SumComponentSqrs() );

   }

   set 

   {

      if (value < 0)

      { throw new ArgumentOutOfRangeException("value", value, 

          NEGATIVE_MAGNITUDE); }



      if (this == origin)

      { throw new ArgumentException(ORAGIN_VECTOR_MAGNITUDE, "this"); }



      this = this * (value / Magnitude);

   }

}



private const string NEGATIVE_MAGNITUDE = 

  "The magnitude of a Vector must be a positive value, (i.e. greater than 0)";



private const string ORAGIN_VECTOR_MAGNITUDE = 

   "Cannot change the magnitude of Vector(0,0,0)";
构建一个Vector3
构造类型,使用下面的构造方法已提供的典型的类语法:
public Vector3(double x, double y, double z)

{

   this.x = 0;

   this.y = 0;

   this.z = 0;



   X = x;

   Y = y;

   Z = z;

}



public Vector3 (double[] xyz)

{

   this.x = 0;

   this.y = 0;

   this.z = 0;



   Array = xyz;

}



public Vector3(Vector3 v1)

{

   this.x = 0;

   this.y = 0;

   this.z = 0;



   X = v1.X;

   Y = v1.Y;

   Z = v1.Z;

}

您可能会奇怪,为什么我之前设置赋值X,Y和Z为0。一个结构不会允许访问之前的每个变量(小写的x,Y,Z),已初始化的属性(大写的X,Y,Z轴)。米莎#322; BRY#322;家评论说,这是不寻常,使用构造函数的属性赋值时。作为个人口味问题,我总是试图以这种方式使用的属性。它确保任何验证的代码写入到设定的方法是由构造救起。我觉得这是有利于维护代码时。在Vector3类型,因为它代表,有没有这样的问题在属性的验证,是学术。这两种范式将是有效的。操作符重载
我们现在有一个用于存储,访问和变异的Vector3及其组成部分(X,Y,Z)的框架。现在,我们可以考虑适用于向量的数学运算。首先,让我们通过重载基本的数学运算符。
重载运算符允许程序员定义一个类型是如何在代码中使用。举个例子来说,加号运算符()。对于数字类型,这表明除了两个数字。对于字符串,它代表了两个字符串的连接。运算符重载是巨大的好处,程序员描述一个类型应该如何与系统交互时。在C#中的下列运算符可以被重载:此外,串联,并加固()减法和否定( - )逻辑非(!)按位求补(〜)增量()递减( - )布尔真理(真实)布尔值false(假)乘(*)司(/)除法的余数(%)逻辑AND(&)逻辑OR(|)逻辑异或(^)二进制左移(<<)二进制右移(GT,GT;)运营商平等,平等和不相等(==和!=)差异\比较运算符,小于和大于(LT和GT;)差异\比较运算符,小于或等于和大于或等于(<=和GT; =)此外(V3 = V1 V2)
另外两个向量是通过简单地增加了X,Y,和一个矢量的z分量(即XX,YY,ZZ)。
public static Vector3 operator+(Vector3 v1, Vector3 v2)

{

   return

   (

      new Vector3

      (

         v1.X + v2.X,

         v1.Y + v2.Y,

         v1.Z + v2.Z

      )

   );

}
减法(V3 = V1 - V2)
两个向量的加减是简单的减法的X,Y,z分量和一个向量(即XX,YY,ZZ)。
public static Vector3 operator-(Vector3 v1, Vector3 v2 )

{

   return

   (

      new Vector3

      (

          v1.X - v2.X,

          v1.Y - v2.Y,

          v1.Z - v2.Z

      )

   );

}
否定(V2 - V1)
否定一个向量反转其方向。这是通过简单地否定每个向量的组成部分。
public static Vector3 operator-(Vector3 v1)



{

   return

   (

      new Vector3

      (

         - v1.X,

         - v1.Y,

         - v1.Z

      )

   );

}
钢筋(V2 = V1)
向量的加固实际上什么也不做,但返回原向量加法规则(即- X - X和X = X)。
public static Vector3 operator+(Vector3 v1)



{

   return

   (

      new Vector3

      (

         + v1.X,

         + v1.Y,

         + v1.Z

      )

   );

}
比较(LT,GT;,LT; =,和GT; =)
当比较两个向量,我们使用的大小(之前看到的)。小于(结果= V1 小于比较两个向量,则返回true,仅在左手侧的向量(V1)的幅度小于其他的幅度(V2)。
public static bool operator<(Vector3 v1, Vector3 v2)

{

   return v1.Magnitude < v2.Magnitude;

}
小于或等于(= V1 LT = V2)
欠大于或等于的比较两个向量,则返回true,仅在左手侧的向量(V1)的幅度小于其他(V2)或两个幅度相等的幅度。
public static bool operator<=(Vector3 v1, Vector3 v2)

{

   return v1.Magnitude <= v2.Magnitude;

}
大于(结果= V1> V2)
大于比较两个向量,则返回true,仅在左手侧的向量(V1)的幅度大于其他的幅度(V2)。
public static bool operator>(Vector3 v1, Vector3 v2)

{

   return v1.Magnitude > v2.Magnitude;

}
大于或等于(结果= V1 GT = V2)
大于或等于比较两个向量,则返回true,只有左手端向量(V1)的幅度大于其他的幅度(V2)或两个幅度相等。平等(结果= V1 == V2)
要检查,如果两个向量是相等的,我们只是检查组件对。我们和结果,使任何一对不等于将导致错误。
public static bool operator==(Vector3 v1, Vector3 v2)

{

   return

   (

      (v1.X == v2.X)&&

      (v1.Y == v2.Y)&&

      (v1.Z == v2.Z)

   );

}

有在这个阈值时使用的计算平等的文章的意见很多讨论。从存储小数(即浮动,双,和十进制变量)的精度问题茎的需要。我个人同意用红色男爵谁建议:{BR }"...你不应该实现代码内的公差值。
什么是一个适合这种宽容的价值呢?
这是问题... ..."
然而,妥协的我已经实现平等宽容作为一个可以设置为零(忽略)常数。
public static bool operator==(Vector3 v1, Vector3 v2)

{

   return

   (

      Math.Abs(v1.X - v2.X) <= EqualityTolerence &&

      Math.Abs(v1.Y - v2.Y) <= EqualityTolerence &&

      Math.Abs(v1.Z - v2.Z) <= EqualityTolerence

   );

}



public const double EqualityTolerence = Double.Epsilon;

你应该现在发现,下面的代码产生:
1号线:假
2号线:真
static void Main(string[] args)

{

    Vector3 vect = new Vector3(1, 2, 3);

    Vector3 vect2 = new Vector3(1, 2, 3.000000000000001);

    Vector3 vect3 = new Vector3(1, 2, 3.0000000000000001);

    Console.WriteLine(vect == vect2);

    Console.WriteLine(vect == vect3);

            

    Console.ReadKey();

}
不等式(结果= V1 = V2)
如果被重载的运算符==(等于),C#的力量,以覆盖!=(不等于)。这简直是​​平等的倒数。
public static bool operator!=(Vector3 v1, Vector3 v2)

{

   return !(v1==v2);

}
司(V3 = V1 / S2)
由一个标量(如2)的矢量司是通过除以除数(S2)的每一个组成部分。
public static Vector3 operator/(Vector3 v1, double s2)

{

   return

   (

      new Vector3

      (

         v1.X / s2,

         v1.Y / s2,

         v1.Z / s2

      )

   );

}
乘法(点,横,由标)
向量的乘法是棘手的。有三种不同类型的矢量乘法:一个标量乘法(V3 = V1 * S2)点产品(S3 = V1,V2)交叉产品(V3 = V1 * V2)
只有乘法标和标司已实现运算符重载。我所看到的运营商,如〜点的产品,以区别于跨产品的重载;我相信,这可能会导致混乱和选择不提供点和跨产品,让用户调用相应的方法,而不是运营商。
标量乘法实现乘以每个组成部分的标量值。
public static Vector3 operator*(Vector3 v1, double s2)

{

   return

   (

      new Vector3

      (

         v1.X * s2,

         v1.Y * s2,

         v1.Z * s2

      )

   );

}

乘法的操作数的顺序可以颠倒,这是被可交换。
public static Vector3 operator*(double s1, Vector3 v2)

{

   return v2 * s1;

}

两个向量跨产品产生一个给定的两个向量平面的正常。
{S2}
这个公式(其中V1 =和v2 = B)
{S3}
{S4}的
{五}
这个方程总是产生一个向量结果。
THETA的正弦是用来核算矢量的方向。西塔始终把A和B之间(即)最小的角度。
该公式的右边是在扩大和简化的左侧,使用规则:黄大仙
0??= 0
仙90??= 1
在矩阵式符号,这看起来像:
{七}
,你应该知道这个公式是可交换非。这意味着,跨产品的V1 V2是V2跨产品V1相同。
这一切​​的C#代码:
在可能的情况下,我已经创建了延长程序员的选项时,使用类型的静态方法。这直接影响或影响的实例的方法,简单地调用的静态方法。由于这样的实例对应的静态方法是:
public Vector3 CrossProduct(Vector3 other)

{

   return CrossProduct(this, other);

}

注意实例方法,这并不影响从它被调用,但返回一个新的Vector3对象实例。我之所以选择来实施这种方式的原因有两个跨产品之一,以点产品它可以不产生一个向量,和两个,因为跨产品是通常用来产生其他地方使用一个正常的,在原Vector3需要保持一致要保持不变。
[附注]手动计算两个向量的交叉产品的快速模板:

两个向量的点积是一个标量值的公式定义;
{S3}


方程应该总是产生一个标结果。
余弦THETA是考虑到矢量的方向。西塔始终把A和B(即)之间的最小角度。
该公式的右边是在扩大和简化的左侧,使用规则:
COS 0??= 1
COS 90??= 0
这在C#代码:
public static double DotProduct(Vector3 v1, Vector3 v2)

{

   return

   (

      v1.X * v2.X +

      v1.Y * v2.Y +

      v1.Z * v2.Z

   );

}

和它的:
public double DotProduct(Vector3 other)

{

   return DotProduct(this, other);

}
扩展功能
我们现在有一个Vector3类型所需的所有基本功能。为了使这种类型的真正有用的,我已经提供了额外的功能。正常化和单位向量
单位向量1级。如果要测试向量是单位向量,我们只需检查对已经定义的幅度方法1。
public static bool IsUnitVector(Vector3 v1)

{

   return v1.Magnitude == 1;

}



public bool IsUnitVector()

{

   return IsUnitVector(this);

}

改变相等(==)运算符允许一个门槛,我们必须做相同的静态IsUnitVector方法(实例方法不变):
public static bool IsUnitVector(Vector3 v1)

{

   return Math.Abs(v1.Magnitude -1) <= EqualityTolerence;

}

规范化是一些单位向量的向量转换的过程。这个公式是:
public static Vector3 Normalize(Vector3 v1)



{

   // Check for divide by zero errors

   if ( v1.Magnitude == 0 )

   {

      throw new DivideByZeroException( NORMALIZE_0 );

   }

   else

   {

      // find the inverse of the vectors magnitude

      double inverse = 1 / v1.Magnitude;

      return

      (

         new Vector3

         (

            // multiply each component by the inverse of the magnitude

            v1.X * inverse,

            v1.Y * inverse,

            v1.Z * inverse

         )

      );

   }

}



public void Normalize()

{

   this = Normalize(this);

}



private const string NORMALIZE_0 = "Can not normalize a vector when" + 

    "it's magnitude is zero";

正常化的实例方法直接影响的实例。插值
这种方法需要从两个向量之间的插补值。这种方法需要三个参数,一个起点(矢量V1),终点(矢量V2),和一个控制这是1和0之间的一小部分。 V1和V2之间的一点是采取控制决定。控制为0,将返回V1和V2控制将返回1。

N = N1(1 - T)n2t

n的= N1吨(N2 - N1)

N = N1 TN2 - TN1
或:

其中:
N =当前值
N1 =初始值(V1)
N2 =终值(V2)
T =控制参数,
public static Vector3 Interpolate(Vector3 v1, Vector3 v2, double control)

{

   if (control >1 || control <0)

   {

      // Error message includes information about the actual value of the 

      // argument

      throw new ArgumentOutOfRangeException

      (

          "control",

          control,

          INTERPOLATION_RANGE + "\n" + ARGUMENT_VALUE + control

      );

   }

   else

   {

      return

      (

         new Vector3

         (

             v1.X * (1-control) + v2.X * control,

             v1.Y * (1-control) + v2.Y * control,

             v1.Z * (1-control) + v2.Z * control

          )

      );

   }

}



public Vector3 Interpolate(Vector3 other, double control)

{

   return Interpolate(this, other, control);

}



private const string INTERPOLATION_RANGE = "Control parameter must be a" + 



    "value between 0 & 1";
距离
这种方法发现使用毕达哥拉斯定理的两个位置向量之间的距离。

public static double Distance(Vector3 v1, Vector3 v2)

{

   return

   (

      Math.Sqrt

      (

          (v1.X - v2.X) * (v1.X - v2.X) +

          (v1.Y - v2.Y) * (v1.Y - v2.Y) +

          (v1.Z - v2.Z) * (v1.Z - v2.Z)

      )

   );

}



public double Distance(Vector3 other)

{

   return Distance(this, other);

}
绝对
向量的绝对值是它的大小。 ABS的方法提供了帮助程序员谁不知道这两个功能是相同的的,并提供一个静态接口的规模经营者。
public static Double Abs(Vector3 v1)

{

  return v1.Magnitude;

}

</implementation />

public double Abs()

{

  return this.Magnitude;

}


这种方法发现正常化和点产品使用两个向量之间的角度。




^指归一(单位)向量
| |指向量的大小。
public static double Angle(Vector3 v1, Vector3 v2)

{

   return

   (

      Math.Acos

      (

         Normalize(v1).DotProduct(Normalize(v2))

      )

   );

}



public double Angle(Vector3 other)

{

   return Angle(this, other);

}
最大和最小
这些方法比较两个向量幅度,分别返回向量的最大或最小的幅度。
public static Vector3 Max(Vector3 v1, Vector3 v2)

{

   if (v1 >= v2){return v1;}

   return v2;

}



public Vector3 Max(Vector3 other)

{

   return Max(this, other);

}



public static Vector3 Min(Vector3 v1, Vector3 v2)

{

   if (v1 <= v2){return v1;}

   return v2;

}



public Vector3 Min(Vector3 other)

{

   return Min(this, other);

}
旋转
欧拉旋转围绕轴X,Y,Z分别使用方法俯仰,偏航和滚动。

Eric__评论说,他所期望的不同的配置。{BR }"...横滚,俯仰和偏航是指飞机的议案的概念。
这是标准的符号X是(鼻子),Y是右翼和Z是(向水平飞行的地球)
因此它遵循,辊是关于X积极的,间距是积极的,绕Y(沥青手段爬上)和偏航是​​积极围绕Z(积极偏航时,飞机机头移动到右)。"
为了说明他的观点考虑如下图:
这似乎完全合理。它!但只有当考虑单一的飞机对象。当我们考虑虚拟场景与多个对象(例如电脑游戏或虚拟现实环境),所有的对象必须是有关他们的用户感知。虚拟场景的标准轴Z轴往下看用户。
所以到飞机的例子,它极有可能,我们将以下的飞机,因为它进入现场苍蝇:

我们希望,这解释了为什么所述轴和俯仰,偏航,辊配置。音高
这种方法绕X轴的向量旋转一个度(欧拉绕X旋转)。













斜边(R)取消方程。
public static Vector3 Pitch(Vector3 v1, double degree)

{

   double x = v1.X;

   double y = ( v1.Y * Math.Cos(degree) ) - ( v1.Z * Math.Sin(degree) );

   double z = ( v1.Y * Math.Sin(degree) ) + ( v1.Z * Math.Cos(degree) );

   return new Vector3(x, y, z);

}



public void Pitch(double degree)

{

   this = Pitch(this, degree);

}

这个方法直接影响到该方法被称为实例。偏航
这种方法绕Y轴的向量旋转一个度(欧拉绕Y旋转)。













斜边(R)取消方程。
public static Vector3 Yaw(Vector3 v1, double degree)

{

   double x = ( v1.Z * Math.Sin(degree) ) + ( v1.X * Math.Cos(degree) );

   double y = v1.Y;

   double z = ( v1.Z * Math.Cos(degree) ) - ( v1.X * Math.Sin(degree) );

   return new Vector(x, y, z);

}



public void Yaw(double degree)

{

   this = Yaw(this, degree);

}

这个方法直接影响到该方法被称为实例。滚
这个方法旋转一个度(欧拉围绕Z轴旋转)绕Z轴的矢量。













斜边(R)取消方程。
public static Vector3 Roll(Vector3 v1, double degree)

{

   double x = ( v1.X * Math.Cos(degree) ) - ( v1.Y * Math.Sin(degree) );

   double y = ( v1.X * Math.Sin(degree) ) + ( v1.Y * Math.Cos(degree) );

   double z = v1.Z;

   return new Vector3(x, y, z);

}



public void Roll(double degree)

{

   this = Roll(this, degree);

}

这个方法直接影响到该方法被称为实例。背面
这种方法解释为面对正常的载体,并确定是否正常代表一个背对着飞机行的视线向量。一个背对着飞机将是无形的,在渲染场景,这样,可以从许多场景计算除外。

如果,然后
如果,然后
public static bool IsBackFace(Vector3 normal, Vector3 lineOfSight)

{

   return normal.DotProduct(lineOfSight) < 0;

}



public bool IsBackFace(Vector3 lineOfSight)

{

   return IsBackFace(this, lineOfSight);

}
垂直
此方法检查,如果两个向量垂直(即如果一个向量是正常的)。
public static bool IsPerpendicular(Vector3 v1, Vector3 v2)

{

  return v1.DotProduct(v2) == 0;

}



public bool IsPerpendicular(Vector3 other)

{

   return IsPerpendicular(this, other);

}
混合产品
此方法的代码提供了米莎#322; BRY#322;家。该方法计算的三个向量的标量三重积。这是一个平行六面体的几何形状的体积。更多信息可在。这种方法是可交换非的。
public static double MixedProduct(Vector3 v1, Vector3 v2, Vector3 v3)

{

   return DotProduct(CrossProduct(v1, v2), v3);

}



public double MixedProduct(Vector3 other_v1, Vector3 other_v2)

{

   return DotProduct(CrossProduct(this, other_v1), other_v2);

}

组件功能
我提供了一个目标向量组件的功能。这些都是作为一个整体的向量数学上并不有效。例如,有没有一个向量提高电源(据我所知),但是PowComponents方法可以用来提高每到一个给定的功率的X,Y,Z的概念。萨姆组件
这种方法简单相加的矢量分量(X,Y,Z)。
public static double SumComponents(Vector3 v1)

{

   return (v1.X + v1.Y + v1.Z);

}



public double SumComponents()

{

   return SumComponents(this);

}
电源
这种方法给定的功率乘以向量的组件。
public static Vector3 PowComponents(Vector3 v1, double power)

{

   return

   (

      new Vector

      (

         Math.Pow(v1.X, power),

         Math.Pow(v1.Y, power),

         Math.Pow(v1.Z, power)

      )

   );

}



public void PowComponents(double power)

{

   this = PowComponents(this, power);

}
平方根
这种方法适用于每个向量组件的平方根函数。广场
这种方法广场每个向量的组件。
public static Vector3 SqrComponents(Vector3 v1)

{

    return

    (

       new Vector3

       (

           v1.X * v1.X,

           v1.Y * v1.Y,

           v1.Z * v1.Z

       )

     );

}



public void SqrComponents()

{

   this = SqrtComponents(this);

}
平方和
该方法找到每个向量组件平方的总和。
public static double SumComponentSqrs(Vector3 v1)

{

   Vector3 v2 = SqrComponents(v1);

   return v2.SumComponents();

}



public double SumComponentSqrs()

{

   return SumComponentSqrs(this);

}
可用性功能
为了完整的标准化方法已添加完整的类型。这些实现IComparable,IComparablelt; Vector3gt,IEquatablelt; Vector3gt,IFormattable。
的方法来获取一个类型的文字描述和实现IFormattable。
VerbString提供了详细的文字描述。的ToString可以接受数字格式字符串进行选择一个字符x,Y或Z表示有关矢量分量来形容。
public string ToVerbString()

{

   string output = null;

   

   if (IsUnitVector()) 

   { 

      output += UNIT_VECTOR; 

   } 

   else 

   { 

      output += POSITIONAL_VECTOR; 

   } 

   

   output += string.Format("( x={0}, y={1}, z={2})", X, Y, Z); 

   output += MAGNITUDE + Magnitude; 

   return output; 

} 



private const string UNIT_VECTOR = 

   "Unit vector composing of "; 



private const string POSITIONAL_VECTOR = 

   "Positional vector composing of "; 



private const string MAGNITUDE = 

   " of magnitude "; 



public string ToString(string format, IFormatProvider formatProvider) 

{ 

   // If no format is passed 

   if (format == null || format == "") 

      return String.Format("({0}, {1}, {2})", X, Y, Z); 



   char firstChar = format[0]; 

   string remainder = null; 



   if (format.Length > 1) 

      remainder = format.Substring(1);



   switch (firstChar) 

   { 

      case 'x': 

         return X.ToString(remainder, formatProvider); 

      case 'y': 

         return Y.ToString(remainder, formatProvider); 

      case 'z': 

         return Z.ToString(remainder, formatProvider); 

      default: 

         return 

            String.Format

            (

               "({0}, {1}, {2})", 

               X.ToString(format, formatProvider), 

               Y.ToString(format, formatProvider), 

               Z.ToString(format, formatProvider) 

            ); 

   } 

}



public override string ToString() 

{ 

   return ToString(null, null); 

}

要产生一个系统使用的哈希代码(需要,以实现比较操作(即==,!=)):
public override int GetHashCode()

{

   return

   (

      (int)((X + Y + Z) % Int32.MaxValue)

   );

}

检查相等(==操作符的标准化版本)和实施IEquatablelt; Vector3gt;
public override bool Equals(object other)

{

   // Check object other is a Vector3 object

   if(other is Vector3)

   {

     // Convert object to Vector3

     Vector3 otherVector = (Vector3)other;



     // Check for equality

     return otherVector == this;

   }

   else

   {

     return false;

   }

 }



public bool Equals(Vector3 other)

{

   return other == this;

}

两个向量,它返回的比较方法:-1,如果幅度不到别人的幅度0如果值等于其他的幅度1,如果幅度大于其他的幅度
这使得Vector类型实现IComparable和IComparablelt; Vector3gt;接口。
Public int CompareTo(object other)

{

   if(other is Vector3)

   {

      Vector3 otherVector = (Vector3)other;



      if( this < otherVector ) { return -1; }

      else if( this > otherVector ) { return 1; }



      return 0;

   }

   else

   {

      // Error condition: other is not a Vector object

      throw new ArgumentException

      (

         // Error message includes information about the actual type of the 

         // argument

         NON_VECTOR_COMPARISON + "\n" + ARGUMENT_TYPE + 

             other.GetType().ToString(),

         "other"

      );

   }

}



public int CompareTo(Vector3 other)

{

   if (this < other)

   {

      return -1;

   }

   else if (this > other)

   {

      return 1;

   }



   return 0;

}



private const string NON_VECTOR_COMPARISON = 

"Cannot compare a Vector to a non-Vector";



private const string ARGUMENT_TYPE = 

"The argument provided is a type of ";
标准笛卡尔向量和常量
最后四个标准的矢量常量定义:
public static readonly Vector3 origin = new Vector3(0,0,0);

public static readonly Vector3 xAxis = new Vector3(1,0,0);

public static readonly Vector3 yAxis = new Vector3(0,1,0);

public static readonly Vector3 zAxis = new Vector3(0,0,1);

和杂项的只读值:
public static readonly Vector3 MinValue = 

   new Vector3(Double.MinValue, Double.MinValue, Double.MinValue);



public static readonly Vector3 MaxValue = 

   new Vector3(Double.MaxValue, Double.MaxValue, Double.MaxValue);



public static readonly Vector3 Epsilon = 

   new Vector3(Double.Epsilon, Double.Epsilon, Double.Epsilon);

序列化
Vector3实现了[Serializable]属性,因此可以被写入文件。我建议以下几点:
static void Main(string[] args)

{

   Vector3 vect = new Vector3(1, 2, 3);

   XmlSerializer x = new XmlSerializer(vect.GetType());

   x.Serialize

   (

      new System.IO.FileStream("test.xml", System.IO.FileMode.Create), 

      vect

   );

}

产生一个XML文件,其中包含:
<?xml version="1.0"?>

<Vector

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:xsd="http://www.w3.org/2001/XMLSchema">

   <X>1</X>

   <Y>2</Y>

   <Z>3</Z>

   <Magnitude>3.7416573867739413</Magnitude>

</Vector>
摘要
我们现在有一个Vector3类型具有以下功能:
构造函数Vector3(双X双Y,双ž)Vector3(双[] XYZ)Vector3(矢量V1)属性XŸž大小运营商此[]索引器 - ==!=*/LT;GT;LT; = 静态方法交叉积DotProductMixedProduct正常化IsUnitVector插距离ABS角最大闵偏航音高滚IsBackFaceIsPerpendicularSumComponentsSumComponentSqrsSqrComponentsSqrtComponentsPowComponents这直接影响到实例变量的实例方法正常化偏航音高滚SqrComponentsSqrtComponentsPowComponents返回一个新的对象或类型的实例方法交叉积DotProductMixedProductIsUnitVector插ABS角最大闵IsBackFaceIsPerpendicularSumComponentsSumComponentSqrs的CompareTo等于的ToStringGetHashCode的 只读和常量的值MaxValue的MINVALUEEPSILON原产地X轴ZAXIS兴趣点
有我在这篇文章,并提供源代码的发展中使用的资源的数量,我想确认以下内容:项目 - 卢卡斯通孔Livschitz项目 - 奔休斯敦计算机图形学的基本数学 - 约翰文斯(国际标准书号1-85233-380-4)历史
到:方法,以反映有关给定的正常Vector3一个图形测试\演示应用程序变化:(V1.00 - V1.20)震级的方法是封装在propertiy不正确的序列化属性已被删除平等和IsUnitVector方法,允许的公差现在的Abs方法返回幅度通用IEquatable和IComparable接口已实施IFormattable接口已落实实施混合产品功能额外添加,并改名为基于组件的功能(如SumComponentSquares)矢量改名到Vector3
关于作者:ř波特


中国
我是一名编程爱好者,
谢谢orcode.com为我们提供一个学习和分享的平台。
有什么问题。可以就本内容回复,我看到时。会尽量回复的。
评论会员:utkugenc 时间:2011/12/07
第一 - 库表示感谢。它将证明非常有用,我当前的项目。

我可以看到你的观点"滚"的定义,"间距"和"偏航"...但我也看到由Eric__点(我倾向于同意他更多 - 当你使用这些术语,你是aboout一个旋转轴的主观看法,在他的飞机的例子)。

出于这个原因,我没有当我下载你的代码的第一件事是改变卷(),间距()和偏航()方法的名称分别RotateOnZ(),RotateOnX和RotateOnY()。
,移除所有的模糊性和方法可用,不管你个人的看法意味着什么"滚","间距"和"偏航"。
第二件事是改变你的参数,从程度角度。
再次删除例程是否期望弧度,度,磨粉机,或梯度的模糊性。克莱夫j典乍
维多利亚,BC
评论会员:会员8060642 时间:2011/12/07
文章和代码注释说,横滚,俯仰和偏航方法旋转轴的度数,但我想所有这些方法都期望角度以弧度参数
评论会员:xcho20 时间:2011/12/07
同样的评论。没有它,但它会保存其他一些小的混乱有人大。

这无疑是一个写得很好的类,我觉得这是为什么人们可以假设它doesnt有像这样的明显错误
评论会员:。会员8416019 时间:2011/12/07
优秀文章!非常详细的和可以理解的的
评论会员:ggraham412 时间:2011/12/07
同上,感谢您分享这么多
评论会员:ga5p0d3 时间:2011/12/07
非常全面的
评论会员:罗布Achmann 时间:2011/12/07
实例广场是调用静态平方根。

公共无效SqrComponents()
{
这= SqrtComponents(本);
}

虽然尼斯类。
评论会员:ned_cis 时间:2011/12/07
更多。

其中一个功能是"Vector3的组件平方"。
另一种是"个人平方根Vector3的组件"
"错字"是不正确的的。GaltSalt
制造商净thingys
评论会员:阿西夫拉赫曼巴伯 时间:2011/12/07

评论会员:阿西夫拉赫曼巴伯 时间:2011/12/07
这是一个伟大的文章有关的空气动力学...

我想问问2问题...

我想计算...

1)当飞机飞行和空袭,从aynwhere然后我怎么能能够计算出偏航,俯仰,横滚角... ...这风引起的偏航,俯仰和滚转改变的角度... ?
2)在UR Vector3.cs类,"偏航"功能是作为输入的角度... ...这一定是角风罢工后的飞机吗?
打击的代码,我发现有关... ...但它是无风的影响(无码太惊魂)...{ BR}
http://www.euclideanspace.com/maths/geometry/rotations/euler/program/index.htm

我将很高兴,如果能提供一些代码...
评论会员:布雷穆尔维 时间:2011/12/07
这是一个伟大的文章,关于空气动力学...

我想问问2问题...

我想计算...

1)当飞机飞行和空袭,从aynwhere然后我怎么能能够计算出偏航,俯仰,横滚角... ...这风引起的偏航,俯仰和滚转改变的角度... ?
2)在UR Vector3.cs类,"偏航"功能是作为输入的角度... ...这一定是角风罢工后的飞机吗?
打击的代码,我发现有关... ...但它是无风的影响(无码太惊魂)...{ BR}
http://www.euclideanspace.com/maths/geometry/rotations/euler/program/index.htm

我将很高兴,如果能提供一些代码...
评论会员:nahuelgq 时间:2011/12/07
角法Math.Acos在使用时可能会失败的两个向量平行。由于浮点舍入后,做的正常化和网络产品,您可以最终结果略大于1.0,并Math.Acos将返回double.NaN。这将是更好返回在这种情况下,0.0
评论会员:。BillWoodruff 时间:2011/12/07
这里有一个额外的方法投射到另一个载体


/// <summary>

/// Projects the specified v1 onto the specified v2

/// </summary>

/// <param name="v1">The vector that will be projected.</param>

/// <param name="v2">The vector that will be projected upon.</param>

/// <returns></returns>

public static Vector3 Projection(Vector3 v1, Vector3 v2)

{

    // http://de.wikibooks.org/wiki/Ing_Mathematik:_Vektoren#Vektorprojektion

    // http://mathworld.wolfram.com/Reflection.html

    // V1_projectedOn_V2 = v2 * (v1 * v2 / (|v2| ^ 2))

 

    return new Vector3(v2 * ( v1.DotProduct(v2) / Math.Pow(v2.Magnitude, 2) ) );

}

 

/// <summary>

/// Projects this vector onto the specified v2

/// </summary>

/// <param name="v2">The vector that will be projected upon.</param>

/// <returns></returns>

public Vector3 Projection(Vector3 v2)

{

    return Vector3.Projection(this, v2);

}

 



顺便说一句,世界是一个伟大的地方,其实。必须看到它
评论会员:!woudwijk 时间:2011/12/07
,而这里的反射的方法,仍然是这个项目的TODO列表
/ / /
/ / /反映了对一个给定的向量
Vector3 / / /

/ / / Vector3反映  0; / / /
/ / /反映Vector3
/ / /
 0; 公共Vector3的反射(Vector3反射)
& #160; {
这= Vector3.Reflection(反射);

返回; }

 0; / / /
/ / /反映了对一个给定的向量
Vector3 / / /
  ;
/ / / Vector3反映 / / /
/ / /反映Vector3
& #160; / / /
公共静态Vector3反思(Vector3载体,Vector3反射)
  ; {
/ /如果反射有一个向量,向量返回的直角和不做
&# 160; / /计算
& #160; 如果(Math.Abs​​(Math.Abs​​(vector.Angle(反射)) - 使用Math.PI / 2)  60; {
&# 160; 返回向量;
}
ELSE
 60; {
&# 160; Vector3 RETVAL =新Vector3(2 * vector.Projection(反射) - 向量);
retval.Magnitude = vector.Magnitude;
 60; 返回RETVAL;
&# 160; }
}
类,这是很对我有益的,即使我需要一个2D Vector类,
但我可以做小的修改。
请注意,我的投影和反射方法元数独立的向量
既可以用于2D或3D的版本。

顺便说一句,世界是一个伟大的地方,其实。必须看到它
评论会员:保罗康拉德 时间:2011/12/07
只要我一直在寻找。 Thankss
评论会员:blackstorm 时间:2011/12/07
这一定是CP的最好的教程之一!因此"完全充实"

希望我是年轻,报名参加在赫尔ü和坐在你的类
希望你将继续演变,而在未来,我们将有来自你更多。
方面,条例草案

"大人们之间的社会和文化的距离,更神奇的光,春天从他们的联系。"米兰昆德拉在旧约Trahis
评论会员:taumuon 时间:2011/12/07
?当你(微软)要在像这样的框架
"你时,这些类型(S)/添加sse/sse2/sse3/sse4 / 3D现在/ ... ... suport
另外重新设计的System.Color,使本使用。

这将使框架一大堆更多usefuller声音/图形处理。



我的第二台电脑是你的Linux box
评论会员:。kangaloosh 时间:2011/12/07

文章是做得很好。伟大的工作
"任何在VB6的工作是必然要提供几个跆拳道的时刻。" - 基督教Graus
评论会员:ř波特 时间:2011/12/07
您好,

非常不错的文章您张贴在这里。我评为5。我也分享您的意见 - 使用构造函数中的代码,关于脂肪接口的属性。"程序员尽可能友好"

但我认为,向量算术应尽可能完美,像任何其他数值计算,如果你曾经在一个3 - D环境中使用这个类来定位对象 - 也就是说,一个游戏引擎 - 这将成为极为重要的。
引用红色男爵"... ...你不应该实施代码内的公差值。这种宽容的一个合适的值是什么?"
干杯!A

Ajith库马尔
评论会员:NavajoKnight 时间:2011/12/07
你在哪里说:
"一个发展一个结构的缺点是,。NET框架类铸铁结构的集合类,这意味着一个Vector3的大集合,将有一个高的铸造开销。"这是不是真正的泛型集合类(引进)。

或许在您的文章讨论的使用结构和类之间的差异。例如,如果你有一个方法,它暴露了一个向量:

Quaternion.Vector轴
{}

用户修改该值:

myQuaternion.Axis.X = 1.0;
一类修改的四元,但一个结构修改从Axis方法返回的临时结构的副本,并且将被丢弃的变化。
初学者可能会在此行程达,所以它可能是值得一提的文章。你甚至可以考虑这个原因,你的载体一成不变。

近开始当您显示如何轴排列,说明它是一个左手坐标系

ORAGIN_VECTOR_MAGNITUDE应ORIGIN_VECTOR_MAGNITUDE

正如我在我刚才的评论说:
大于或等于在文章中的文字是:
公共静态布尔运算符>(Vector3 V1,V2 Vector3)
应该是:
公共静态布尔运算符> =(Vector3 V1,V2 Vector3)

您是使用性能的一个结构 - 这样,你应该重载方法允许结构要通过REF(以避免不必要的复制),例如也有
公共静态Vector3交叉积(参考文献Vector3 Vector3 V1,V2)
用户可以选择调用,如果他们关心性能(同样,提供方法,以替代被覆盖的运营商ref参数)。

你在哪里引用"... ...你不应该实施代码内的公差值。什么是适合这种宽容的价值?
它取决于问题..."{ BR}
您应该仍然比较平等的公差内,但类的客户端提供了一个机制,以指定的公差。

你的Equals(其它对象),应立即致电等于(Vector3等)同样的CompareTo(对象除外),应立即致电的CompareTo(Vector3其他)

http://www.taumuon.co.uk/jabuka/
taumuon.blogspot.com
评论会员:ř波特 时间:2011/12/07
您好,

优秀的Vector3类,谢谢你。

我只是想澄清的角度和偏航/俯仰/旋转方法 - 参数都是所谓的"度",但我能找到转换为弧度。您正在使用Math.Sin,cos等弧度暗示。

你能否确认他们应请,

再次感谢

kangaloosh。
评论会员:Desinderlase 时间:2011/12/07
你绝对正确的,他们是弧度。我现在作出更正
遗憾的延迟反应,我一直在忙于另一个项目。

理查德波特
________________________{ BR}模拟和可视化研究小组
赫尔
大学r.potter @ dcs.hull.ac.uk
_________________________{ BR}
 文章分类
 桌面
 网页开发
 移动开发
 数据库
 多媒体
 编程语言
 平台,框架和库
 编程通用
 图形/设计
 开发周期
 一般阅读
 第三方产品
 作者资源
 其他
快速解答标签
c x 6850
VC x 7405