Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Define rectangle as two points or origin / size?

Tags:

c++

c

oop

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:

  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.
  2. The rectangle is defined as 2D origin and size vectors, usually named position and size, or, individually, x, y, width, height.

Now, say I were to write an UI library, which of the two choices should I take?

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?

like image 330
paniq Avatar asked Apr 05 '12 10:04

paniq


2 Answers

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.

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)

Where Point is some 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.

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.

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. 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.

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.

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."

like image 162
Andrew Rasmussen Avatar answered Sep 29 '22 03:09

Andrew Rasmussen


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. The x-coordinate is obviously cyclic. 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. But I preferred to switch to the 2nd convention instead, where you have naturally a corner and an offset vector.

like image 39
valdo Avatar answered Sep 29 '22 01:09

valdo