如何在 C++ 中表示线段的向量方程?
How can I represent a vector equation of a line segment in C++?
我正在使用计算机图形学。
我想表示一条有两个端点的线,然后我希望我的 Line2d
class 有一个 returns a Vector2d
的方法对象。
假设,我有以下 classes:
struct Point2d
{
int x;
int y;
};
然后,我可以很容易地用两个点表示一条线段:
class LineSegment2d
{
private:
Point2d start;
Point2d end;
public:
...
...
};
根据定义,矢量由大小和方向组成。
class Vector2d
{
private:
Point2d p;
public:
double Magnitude(void);
Point Component(void);
Vector2d Normal();
Vector2d & Add(Vector & rhs);
Vector2d & Subtract(Vector & rhs);
Vector2d & Multiply(int scalar);
int DotProduct(Vector2d rhs);
Vector2d & CrossProduct(Vector2d rhs);
};
Point2d
的一个对象足以表示一个向量。例如,向量的大小 = sqrt(p.x*p.x + p.y*p.y);
。并且,p.x
和p.y
共同代表方向。
另一方面,我们知道通过 (x0,y0,z0)
的直线的向量方程是 r =r0 + tv
在哪里,
r
是主题行的向量。
r0
是一个位置向量,指向(x0, y0, z0)
点的方向。由于 r0 是一个位置向量,显然,r0 的原点是 (0,0,0)
。
t
是任何实数值,其中,−∞<t<∞ –
。
v
是平行于我们主题直线的向量。
点P(1, 3, 2)
和Q(-4, 3, 0)
之间的线段向量方程:
根据上式,直线PQ
的向量方程可以是
r =<1,3,2> + tv
或者,
r =<-4,3,0> + tv
连接 P
和 Q
两点的向量是
PQ = <(-4-1), (3-3), (0-2)>
= <-5, 0, -2>
而且,这个向量肯定与我们的主题行平行。
所以,我们可以写,
r =<1, 3, 2> + t <-5, 0, -2>
=<1, 3, 2>+<-5t, 0, -2t>
= <(1-5t), (3+0), (2-2t)>
=<1-5t, 3, 2-2t>
根据线段的向量方程,我想,我的向量class应该是这样的:
class LineVector2d
{
private:
Vector2d v;
double t;
public:
..........
};
这是正确的表述吗?
如果是这样,我如何calculate/set/find t
的值?
有many forms of line representation个。
如果您指的是线(不是线段),那么您可能会发现使用包含 BasePoint 和 UnitDirectionVector 的 class/structure 更方便。
对于线段,选择 (Point pt0, Point pt1
) 形式和 (Point pt, Vector v = pt1 - pt0
) 形式。
第二个更适合参数化方法,例如,
X = P0.X + t * D.X
等
如果要将线段转换为向量,您必须知道转换没有 "universal semantic",由您定义转换的含义。也就是说,我假设您想要一个与线段长度具有相同(欧几里得)范数并指向相同方向的向量,即像这样的东西:
class LineSegment2d
{
....
Vector2d getVector() const {
return Vector2d(end) - Vector2d(start);
}
};
也就是说,将线段偏移到坐标系的原点。然后可以将终点转换为向量。
编辑:在进一步了解您想要这个的原因后,您可能正在寻找另一种表示形式
class LineSegment2d
{
....
Vector2d getVector() const {
return Vector2d(end);
}
};
这将为每条线段提供一个向量:终点。如果您的多边形由连接的线段组成,这将为您提供多边形中的所有顶点。
使用问题中的线段表示。
我将为起点 a
和终点 b
的线段写 LS(a,b)
。
现在给定两个这样的段 LS(a,b)
,并且 LS(c,d)
相交(在您的上下文中,一个来自裁剪多边形,一个来自被裁剪的多边形;我假设您知道如何确定这个)。
您似乎想要回答的是,如果这个交点 LS(c,d)
在穿过边 LS(a,b)
时进入多边形的内部。
为此,确定线段方向之间的角度就足够了。这与向量 v = b-a
和 w = d-c
之间的角度相同。
还有,你连角度都不需要,看角度是正还是负就可以了;所以看看向量 w-v
。如果 LS(c,d)
穿过 LS(a,b)
到里面,这个向量将在下半平面。如果 LS(c,d)
穿过 LS(a,b)
到外面,这个向量将在上半平面。
判断上半平面和下半平面就是看end-start
的第二个坐标。
对文字墙深表歉意,但 mathjax 在此站点上似乎并不活跃。也没有代码,但我相信(如果我没有犯任何错误)我提到的所有操作都很容易转化为代码。
如果你想变得非常数学,也许这可以帮助:https://en.wikipedia.org/wiki/Homogeneous_coordinates
在 2d 中,这意味着位置是 (x,y,1) 和方向 (dx,dy,0)。原因是投影,这在 2d 中很少见,但在 3d 中很常见。
所以尝试回答:一直使用 4 个分量向量。位置有一个 w=1,方向有一个 w=0.
试一试基于两点 A 和 B 的直线,它们的 w=1。从A到B的向量是B-A,最后w=0.
此外,您在代码中使用的内容也无关紧要,除非您最终优化了一个特殊情况。只需要最小的数据结构。开始和结束应该没问题。
也许考虑索引:所有顶点的平面数组,每行只是顶点数组的两个索引。
我认为由于以下原因有些混乱
According to the definition, a vector is composed of a magnitude and a direction.
表示向量的方法不止一种。我认为在你的问题中你的意思是一个向量可以用一个幅度(标量)和一个表示方向的单位向量来表示。一个向量可以只是一个有序的三元组(对于三维),它指示大小(sqrt(x^2 + y^2 + z^2)
)和从原点的方向。
我想你的问题的答案是,你不需要计算t
。如果我弄错了请纠正我,但我认为您将 t
解释为震级?您可以使用 sqrt(x^2 + y^2 + z^2)
从 v
计算,但是 v
本身可以将大小和方向作为有序的三元组保存。
编辑:
template <typename T>
struct Point2d
{
T x;
T y;
Point2d operator + (const Point2d<T>& rhs) const
{
return Point2d<T>{x + rhs.x, y + rhs.y};
}
Point2d operator - (const Point2d<T>& rhs) const
{
return Point2d<T>{x - rhs.x, y - rhs.y};
}
// ...
Point2d operator * (const T value) const
{
return Point2d<T>{x*value, y*value};
}
Point2d operator / (const T value) const
{
return Point2d<T>{x/value, y/value};
}
// ...
};
template <typename T>
class Vector2d
{
private:
Point2d<T> p;
public:
Vector2d(const Point2d<T>& point) : p{point} {}
/*double Magnitude();
Point2d<T> Component();
Vector2d Normal();
int DotProduct(Vector2d rhs);
Vector2d& CrossProduct(Vector2d rhs);*/
Vector2d operator + (const Vector2d<T>& rhs) const
{
return p + rhs.p;
}
Vector2d operator - (const Vector2d<T>& rhs) const
{
return p - rhs.p;
}
// ...
Vector2d operator * (const T value) const
{
return p*value;
}
Vector2d operator / (const T value) const
{
return p/value;
}
// ...
};
template <typename T>
class LineVector2d
{
private:
Point2d<T> p;
Vector2d<T> v;
public:
LineVector2d() = default;
LineVector2d(const Point2d<T>& point, const Vector2d<T>& direction) : p{point}, v{direction} {}
/// Returns the point on the line for the time/value `t`
Point2d<T> valueAt(T t)
{
return p + v*t;
}
};
您对 class LineSegment2d
的描述很好。但是 class Vector2d
的表示是不正确的。这是因为您只考虑那些通过原点的向量。 2d 平面上的矢量可以用 3 个分量表示,就像在 3d space 中一样。矢量的 3 个分量是:方向、大小和它经过的点。如果我们为 3d space 定义 x、y 和 z 轴,那么对于 x-y 平面中的一个点,z 分量等于 0。此外,3d space 中的方向以方向的形式定义余弦(即向量和轴之间夹角的余弦)。因此,对于 x-y 平面中的矢量,矢量与 z 轴之间夹角的余弦值等于零(因为角度 = 90 度)。
我正在使用计算机图形学。
我想表示一条有两个端点的线,然后我希望我的 Line2d
class 有一个 returns a Vector2d
的方法对象。
假设,我有以下 classes:
struct Point2d
{
int x;
int y;
};
然后,我可以很容易地用两个点表示一条线段:
class LineSegment2d
{
private:
Point2d start;
Point2d end;
public:
...
...
};
根据定义,矢量由大小和方向组成。
class Vector2d
{
private:
Point2d p;
public:
double Magnitude(void);
Point Component(void);
Vector2d Normal();
Vector2d & Add(Vector & rhs);
Vector2d & Subtract(Vector & rhs);
Vector2d & Multiply(int scalar);
int DotProduct(Vector2d rhs);
Vector2d & CrossProduct(Vector2d rhs);
};
Point2d
的一个对象足以表示一个向量。例如,向量的大小 = sqrt(p.x*p.x + p.y*p.y);
。并且,p.x
和p.y
共同代表方向。
另一方面,我们知道通过 (x0,y0,z0)
的直线的向量方程是 r =r0 + tv
在哪里,
r
是主题行的向量。
r0
是一个位置向量,指向(x0, y0, z0)
点的方向。由于 r0 是一个位置向量,显然,r0 的原点是 (0,0,0)
。
t
是任何实数值,其中,−∞<t<∞ –
。
v
是平行于我们主题直线的向量。
点P(1, 3, 2)
和Q(-4, 3, 0)
之间的线段向量方程:
根据上式,直线PQ
的向量方程可以是
r =<1,3,2> + tv
或者,
r =<-4,3,0> + tv
连接 P
和 Q
两点的向量是
PQ = <(-4-1), (3-3), (0-2)>
= <-5, 0, -2>
而且,这个向量肯定与我们的主题行平行。
所以,我们可以写,
r =<1, 3, 2> + t <-5, 0, -2>
=<1, 3, 2>+<-5t, 0, -2t>
= <(1-5t), (3+0), (2-2t)>
=<1-5t, 3, 2-2t>
根据线段的向量方程,我想,我的向量class应该是这样的:
class LineVector2d
{
private:
Vector2d v;
double t;
public:
..........
};
这是正确的表述吗?
如果是这样,我如何calculate/set/find t
的值?
有many forms of line representation个。
如果您指的是线(不是线段),那么您可能会发现使用包含 BasePoint 和 UnitDirectionVector 的 class/structure 更方便。
对于线段,选择 (Point pt0, Point pt1
) 形式和 (Point pt, Vector v = pt1 - pt0
) 形式。
第二个更适合参数化方法,例如,
X = P0.X + t * D.X
等
如果要将线段转换为向量,您必须知道转换没有 "universal semantic",由您定义转换的含义。也就是说,我假设您想要一个与线段长度具有相同(欧几里得)范数并指向相同方向的向量,即像这样的东西:
class LineSegment2d
{
....
Vector2d getVector() const {
return Vector2d(end) - Vector2d(start);
}
};
也就是说,将线段偏移到坐标系的原点。然后可以将终点转换为向量。
编辑:在进一步了解您想要这个的原因后,您可能正在寻找另一种表示形式
class LineSegment2d
{
....
Vector2d getVector() const {
return Vector2d(end);
}
};
这将为每条线段提供一个向量:终点。如果您的多边形由连接的线段组成,这将为您提供多边形中的所有顶点。
使用问题中的线段表示。
我将为起点 a
和终点 b
的线段写 LS(a,b)
。
现在给定两个这样的段 LS(a,b)
,并且 LS(c,d)
相交(在您的上下文中,一个来自裁剪多边形,一个来自被裁剪的多边形;我假设您知道如何确定这个)。
您似乎想要回答的是,如果这个交点 LS(c,d)
在穿过边 LS(a,b)
时进入多边形的内部。
为此,确定线段方向之间的角度就足够了。这与向量 v = b-a
和 w = d-c
之间的角度相同。
还有,你连角度都不需要,看角度是正还是负就可以了;所以看看向量 w-v
。如果 LS(c,d)
穿过 LS(a,b)
到里面,这个向量将在下半平面。如果 LS(c,d)
穿过 LS(a,b)
到外面,这个向量将在上半平面。
判断上半平面和下半平面就是看end-start
的第二个坐标。
对文字墙深表歉意,但 mathjax 在此站点上似乎并不活跃。也没有代码,但我相信(如果我没有犯任何错误)我提到的所有操作都很容易转化为代码。
如果你想变得非常数学,也许这可以帮助:https://en.wikipedia.org/wiki/Homogeneous_coordinates
在 2d 中,这意味着位置是 (x,y,1) 和方向 (dx,dy,0)。原因是投影,这在 2d 中很少见,但在 3d 中很常见。
所以尝试回答:一直使用 4 个分量向量。位置有一个 w=1,方向有一个 w=0.
试一试基于两点 A 和 B 的直线,它们的 w=1。从A到B的向量是B-A,最后w=0.
此外,您在代码中使用的内容也无关紧要,除非您最终优化了一个特殊情况。只需要最小的数据结构。开始和结束应该没问题。
也许考虑索引:所有顶点的平面数组,每行只是顶点数组的两个索引。
我认为由于以下原因有些混乱
According to the definition, a vector is composed of a magnitude and a direction.
表示向量的方法不止一种。我认为在你的问题中你的意思是一个向量可以用一个幅度(标量)和一个表示方向的单位向量来表示。一个向量可以只是一个有序的三元组(对于三维),它指示大小(sqrt(x^2 + y^2 + z^2)
)和从原点的方向。
我想你的问题的答案是,你不需要计算t
。如果我弄错了请纠正我,但我认为您将 t
解释为震级?您可以使用 sqrt(x^2 + y^2 + z^2)
从 v
计算,但是 v
本身可以将大小和方向作为有序的三元组保存。
编辑:
template <typename T>
struct Point2d
{
T x;
T y;
Point2d operator + (const Point2d<T>& rhs) const
{
return Point2d<T>{x + rhs.x, y + rhs.y};
}
Point2d operator - (const Point2d<T>& rhs) const
{
return Point2d<T>{x - rhs.x, y - rhs.y};
}
// ...
Point2d operator * (const T value) const
{
return Point2d<T>{x*value, y*value};
}
Point2d operator / (const T value) const
{
return Point2d<T>{x/value, y/value};
}
// ...
};
template <typename T>
class Vector2d
{
private:
Point2d<T> p;
public:
Vector2d(const Point2d<T>& point) : p{point} {}
/*double Magnitude();
Point2d<T> Component();
Vector2d Normal();
int DotProduct(Vector2d rhs);
Vector2d& CrossProduct(Vector2d rhs);*/
Vector2d operator + (const Vector2d<T>& rhs) const
{
return p + rhs.p;
}
Vector2d operator - (const Vector2d<T>& rhs) const
{
return p - rhs.p;
}
// ...
Vector2d operator * (const T value) const
{
return p*value;
}
Vector2d operator / (const T value) const
{
return p/value;
}
// ...
};
template <typename T>
class LineVector2d
{
private:
Point2d<T> p;
Vector2d<T> v;
public:
LineVector2d() = default;
LineVector2d(const Point2d<T>& point, const Vector2d<T>& direction) : p{point}, v{direction} {}
/// Returns the point on the line for the time/value `t`
Point2d<T> valueAt(T t)
{
return p + v*t;
}
};
您对 class LineSegment2d
的描述很好。但是 class Vector2d
的表示是不正确的。这是因为您只考虑那些通过原点的向量。 2d 平面上的矢量可以用 3 个分量表示,就像在 3d space 中一样。矢量的 3 个分量是:方向、大小和它经过的点。如果我们为 3d space 定义 x、y 和 z 轴,那么对于 x-y 平面中的一个点,z 分量等于 0。此外,3d space 中的方向以方向的形式定义余弦(即向量和轴之间夹角的余弦)。因此,对于 x-y 平面中的矢量,矢量与 z 轴之间夹角的余弦值等于零(因为角度 = 90 度)。