将矩形定义为两点或原点/大小

Define rectangle as two points or origin / size?

本文关键字:两点 原点 大小 定义      更新时间:2023-10-16

这个问题在我的职业生涯中多次出现,它将我和我的同事分为两个阵营。我认为最好在这个网站上一劳永逸地回答这个问题。

几乎所有图形 UI 库都实现了矩形结构,但它们的执行方式通常分为两个可能的选项:

  1. 矩形定义为同一坐标系中的两个 2D 点,通常命名为 p0 和 p1,或者将单个分量定义为 x0、y0、x1、y1。
  2. 矩形定义为 2D 原点和大小矢量,通常称为位置和大小,或者单独命名为 x、y、宽度、高度。

现在,假设我要编写一个 UI 库,我应该选择两个选项中的哪一个?

更新:问题涉及实现,而不是接口。当然,矩形的界面可以很好地支持这两种方法,但是如何将数据存储在矩形中呢?

为什么不同时选择两者?

实际上,唯一重要的是库与其内部之间的接口。或者,用户将如何使用库。您可以根据需要存储矩形的信息,但应该将其封装在远离用户的位置,这样他们就不必担心矩形的存储方式,只需担心它确实是一个矩形。

换句话说,在选择两者时,如果您正在编写面向对象的代码,则可以根据需要存储矩形,然后让用户使用任一方法创建矩形。

例如,您的声明可能如下所示:

class Rectangle
{
public:
    Rectangle(Point p1, Point p2);
    Rectangle(Point origin, int width, int height);
    ...
};

(C++,因为你标记了)

其中 Point 是某个类:

class Point
{
public:
    Point(int x, int y) : mX(x), mY(y) {}
private:
    int mX;
    int mY;
};

这样,您的库就不仅限于支持一种类型的规范来创建矩形。

具体来说,这并不重要。它们都可以工作,并且可以轻松地相互转换并使用相同数量的内存,因此使用一个不会对性能产生重大影响。

为了便于开发,请考虑矩形的用例。查看您需要为该类编写的每个成员函数,并考虑哪种格式可以更轻松地编写这些函数。

如果是我,

我可能会用这两点来实现它。

编辑:一种学术方法,为什么我认为在大多数情况下,无论哪种方式实施它都不会有任何区别。

让我们的 Rectangle 类上有一个成员函数或操作,它确实适用于我们的矩形或进行一些计算。假设一种实现方法(宽度/高度/原点或两点)执行此操作的速度明显快于另一种实现。

我们可以通过以下方式从实现宽度/高度/原点转换:

// assuming x0,y0 is top left and x1,y1 is bottom right
x0 = originX;
y0 = originY;
x1 = originX + width;
y1 = originY + height;

我们可以通过以下方式从实现转换两点:

// assuming x0,y0 is top left and x1,y1 is bottom right
originX = x0;
originY = y0;
width = x1 - x0;
height = y1 - y0;

因此,执行此操作的实现比其他实现慢/差得多,可以在 O(1) 运行时转换为另一个实现,这样其他实现就不可能比第一个实现好多少

除非您每秒执行此操作数千次或在性能极其受限的设备上执行此操作,否则我非常确信不会有性能差异。已经没有内存差异,因为两个实现几乎只存储 4 个浮点数/整数。

这几乎为编码留下了便利,就像我上面在原始帖子中所说的那样,您可以简单地"考虑矩形的用例是什么。看看你需要为该类编写的每个成员函数,并考虑哪种格式可以更容易地编写这些函数。

毫无疑问,这当然完全取决于您面临的问题。

对于图形绘制算法,恕我直言,第二个选项似乎有一个非常小的优势。而对于在欧几里得平面上定义的一般"几何"算法 - 第一个选项更方便一些。

另外,有一次我正在研究在地球表面上定义的算法。平均值,x,y 坐标分别表示经度/纬度。x 坐标显然是循环的。在这种特定情况下,为了定义一个(某种)矩形 - 仅仅定义拐角是不够的,你还需要一个方向。这可以通过约定来处理,即第一点 (p0) 是最左边的点,而第二点 (p1) - 最右边的点。但我更喜欢切换到第二个约定,在那里你自然有一个角和一个偏移向量。