简体   繁体   English

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

[英]Define rectangle as two points or origin / size?

This is a question which came up several times in my career, and which splits me and my colleagues into two camps.这是一个在我的职业生涯中多次出现的问题,它把我和我的同事分成了两个阵营。 I thought it might be best answered on this site, once and for all.我认为最好在这个网站上一劳永逸地回答这个问题。

Almost all graphics UI libraries implement a Rectangle structure, but the way they do it usually divides along two possible options:几乎所有图形 UI 库都实现了 Rectangle 结构,但它们的实现方式通常分为两种可能的选择:

  1. The rectangle is defined as two 2D points within the same coordinate system, usually named p0 and p1, or with individual components, as x0, y0, x1, y1.矩形被定义为同一坐标系中的两个二维点,通常命名为 p0 和 p1,或者具有单独的分量,如 x0、y0、x1、y1。
  2. The rectangle is defined as 2D origin and size vectors, usually named position and size, or, individually, x, y, width, height.矩形被定义为二维原点和大小向量,通常命名为 position 和大小,或者单独命名为 x、y、宽度、高度。

Now, say I were to write an UI library, which of the two choices should I take?现在,假设我要编写一个 UI 库,我应该选择这两个选项中的哪一个?

Update : The question concerns the implementation, not the interface.更新:问题涉及实现,而不是接口。 Of course the rectangle's interface could well support both approaches, but how would you store the data within the rectangle?当然,矩形的接口可以很好地支持这两种方法,但是如何在矩形内存储数据呢?

Why not choose both?为什么不两者都选?

Really, the only thing that matters is the interface between your library and its internals.真的,唯一重要的是你的库和它的内部之间的接口。 Or, how your users will use the library.或者,您的用户将如何使用图书馆。 You can store the information for a rectangle however you'd like, but that should be encapsulated far, far away from the user so that they don't need to worry about how their rectangle is stored, just that it is indeed a rectangle.您可以随心所欲地存储矩形的信息,但是应该将其封装在远离用户的地方,这样他们就不必担心矩形的存储方式,只需知道它确实是一个矩形即可。

In other words on choosing both, if you're writing object oriented code, you can store the rectangle however you want, and then let your user create a rectangle using either method.换句话说,如果您正在编写面向 object 的代码,那么在选择两者时,您可以根据需要存储矩形,然后让您的用户使用任一方法创建一个矩形。

For example, your declaration might look something like this:例如,您的声明可能如下所示:

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

(C++, since you tagged that) (C++,因为你标记了它)

Where Point is some class:其中 Point 是一些 class:

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

This way, your library isn't limited to only supporting one type of specification for creating a rectangle.这样,您的库不限于仅支持一种用于创建矩形的规范。

As far as implementation specifically, it really doesn't matter.就具体实施而言,这真的无关紧要。 They both work and can easily be converted to one another and use the same amount of memory, and therefore there will be no major performance implications of using one over the other.它们都可以工作并且可以很容易地相互转换并使用相同数量的 memory,因此使用其中一个不会对性能产生重大影响。

For simple ease of development, consider what the use cases of your rectangle are.为了简化开发,请考虑矩形的用例。 Take a look at each member function you'll need to write for that class and think about which format will make it easier to write those functions.查看您需要为 class 编写的每个成员 function 并考虑哪种格式可以更轻松地编写这些函数。

If it were me I'd probably implement it with the two points.如果是我,我可能会用这两个点来实现它。

Edit: An academic approach to why I think implementing it either way will make absolutely no difference in most cases.编辑:为什么我认为以任何一种方式实施它在大多数情况下都没有任何区别的学术方法。

Let there be a member function or an operation on our Rectangle class that does work on our rectangle or makes some calculation.假设有一个成员 function 或对我们的矩形 class 的操作确实对我们的矩形起作用或进行一些计算。 Assume one method of implementation (width/height/origin or two points) will do this operation significantly faster than the other implementation.假设一种实现方法(宽度/高度/原点或两点)将比其他实现更快地执行此操作。

We can convert from implementation width/height/origin with the following:我们可以使用以下方法从实现宽度/高度/原点转换:

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

And we can convert from implementation two points with the following:我们可以通过以下方式从实现中转换两点:

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

Therefore, the implementation which performs this operation much slower/worse than the other implementation can be converted to the other implementation in O(1) running time, so that other implementation cannot be that much better than the first implementation.因此,执行此操作比其他实现慢得多/差得多的实现可以在 O(1) 运行时间内转换为其他实现,因此其他实现不会第一个实现好多少。

Unless you're doing this operation several thousand times a second or on an extremely performance-limited device, I'm very convinced that there will be no performance difference.除非您每秒执行此操作数千次或在性能极其受限的设备上,否则我坚信不会有性能差异。 There is already no memory difference because both implementations pretty much just store 4 floats/ints.已经没有 memory 差异,因为这两种实现几乎只存储 4 个浮点数/整数。

This pretty much leaves convenience of coding, and like I said above in my original post, you can simply "consider what the use cases of your rectangle are. Take a look at each member function you'll need to write for that class and think about which format will make it easier to write those functions."这几乎留下了编码的便利性,就像我在上面的原始帖子中所说的那样,您可以简单地“考虑矩形的用例是什么。看看每个成员 function,您需要为该 class 编写并思考关于哪种格式会使编写这些函数更容易。”

Without any question this of course depends solely on the problem you are facing.毫无疑问,这当然完全取决于您面临的问题。

For graphics drawing algorithm the 2nd option seems to have a very minor advantage IMHO.对于图形绘制算法,第二个选项似乎有一个非常小的优势恕我直言。 Whereas for general "geometric" algorithms defined on euclidian plane - the 1st option is somewhat more convenient.而对于在欧几里德平面上定义的一般“几何”算法 - 第一个选项更方便一些。

Also, once I was working on an algorithm defined on the Earth surface.此外,有一次我正在研究一种在地球表面定义的算法。 Means, x,y coordinates represent longitude/latitude respectively.意思是,x,y坐标分别代表经度/纬度。 The x-coordinate is obviously cyclic . x坐标显然是循环的。 In this specific case in order to define a (sort of) rect - it's insufficient to define just corners, you aslo need a direction .在这种特定情况下,为了定义(某种)矩形 - 仅定义角是不够的,您还需要一个方向 This may be handled by the convention that the 1st point (p0) is the left-most point, whereas the 2nd point (p1) - the right-most.这可以通过第一个点 (p0) 是最左边的点,而第二个点 (p1) - 最右边的约定来处理。 But I preferred to switch to the 2nd convention instead, where you have naturally a corner and an offset vector.但我更喜欢切换到第二个约定,在那里你自然有一个角和一个偏移向量。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM