如何在 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.xp.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

连接 PQ 两点的向量是

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-aw = 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 度)。