1

When I want to implement axis aligned 2d rectangles I always go with {x, y, w, h}, because that is the natural approach to it. With 3d axis aligned rectangles you need {x, y, z, w, h, d(depth)}. For a 2d triangle I need {x1, y1, x2, y2, x3, y3}. But what do I need for axis aligned right triangles. How would you store them?

I can imagine going with the same data as a rectangle and then a number 0 to 3 indicating which point is opposite to the hypotenuse. I can also imagine going with {x, y, w, h}, where w and h is allowed to be negative (opposite to the normal rects).

Which is the common approach to implementing right triangles?

EDIT:

Well I finally decided to go with {x, y, w, h, r}, where w, h >= 0 and r is the radians. So at first I can concentrate r = {0, pi/2, pi, 3pi/2} and if I wanna go crazy later on, I can do just that without breaking my interface.

  • 2
    How would you store [a right triangle]? -- The same way you would store any other triangle. Why would you specialize the storage of right triangles? – Robert Harvey Jan 24 '17 at 4:37
  • When I know that I don't need them. You could argue with the same argument that you shouldn't store rects as {x, y, w, h}, because well, not all rects are axis aligned. – hgiesel Jan 24 '17 at 4:49
  • That's exactly what I would argue. The additional complexity of having two ways to store a shape isn't worth it just for the byte savings, identifying the specialized shapes, or whatever advantage you think you're gaining by having two different structures. – Robert Harvey Jan 24 '17 at 5:03
  • Then I feel like you get to the "Banana-Gorilla-Jungle", where you just want to have a banana, but you get the whole ape and the jungle with it. I don't even want to think about how I can calculate whether trapezoids and equilateral triangles intersect... – hgiesel Jan 24 '17 at 5:09
  • 1
    That's hardly a comparable example. And you still have to figure out whether it's a right triangle before you know which collection you're going to stuff it into. If there's material information about your application that speaks to this decision which you're not telling us about, now would be a good time to disclose it. – Robert Harvey Jan 24 '17 at 5:19
6

There is no "common approach", because this is not a requirement occuring so frequently that it needs a special standard. So pick a solution which suits your needs like the one you suggested:

{x, y, w, h}, where w and h is allowed to be negative

That is actually the first idea which came into my mind when I saw your question, so why don't you give it a try?

Note if you implement this as an abstract data type or class Triangle, these four values are only needed as an internal storage representation, and there is no need for your classes's API to expose its internals. For example, the API can provide methods for querying the coordinates of the 3 corners in a uniform manner, without letting the user of that API see that one corner is stored internally "differently" than the other two. So if you later come to the point where you think the internal representation was chosen suboptimal, you can easily change it later without the need to change the code which uses the API.

So do not overthink the internal representation, better invest some time into the design of your API.

3

A triangle usually is implemented by storing 3 coordinates for the 3 corners. Any triangle, that is, regardless whether it's 2D or 3D, right, acute, equilateral, obtuse, or has whatever property you could think of.

Usually, there is no real need to special case axis aligned right triangles, because they don't have that many special properties compared to other triangles (other than being able to interpret it as half of an axis aligned rectangle, but why don't you use a rectangle in that case?).

Contrarily, there are some problems if you only allow axis aligned right triangles:

  • gaps between axis aligned right triangles can not always be filled with other axis aligned right triangles.
  • if you want to save bytes by reducing the data stored, you introduce some conventions that aren't always obvious and might lead to bugs later (look at your "clever" idea of storing negative width or height: you might easily introduce a bug that calculates negative area values!)

If you think your use case is special enough to profit from a different internal implementation, you could go for one. In that case, be sure to document what conventions you introduce (and as always, try to keep the API from leaking implementation details, especially in case you need to switch said implementation later)

  • I only partially agree. If the OP's use case involves mainly axis aligned triangles, using a representation which allows arbitrary triangles has a high risk of introducing bugs as well, because of the unnecessary redundancy. I fully agree to what you wrote in your initial paragraphs about the properties of such triangles, but such properties are typically designed as part of the public API of a "Triangle" type, and can be separated from the internal representation. – Doc Brown Jan 24 '17 at 7:25
1

For axis-aligned rectangles, I usually just go with {x1,y1,x2,y2} defining (either) one of its diagonals. Note that this uniquely defines an axis-aligned rectangle. And thus also defines two (axis-aligned) right triangles, with diagonal~hypoteneuse. To uniquely define just one, apply something like the "right-hand screw rule", i.e., hand open, palm up, point your right-hand thumb in the direction from {x1,y1} to {x2,y2}, and then your fingers point towards the right-angle.

  • This is correct, but I think one should mention this is 100% equivalent to storing these kind of triangles as {x, y, w, h}, it is neither better nor worse. – Doc Brown Jan 24 '17 at 16:28
  • I'd say it's worse, because there is redundant information in {x1, y1, x2, y2}, because x2 is just x1 + w and y2 is just y1 + h in any case – hgiesel Jan 24 '17 at 16:37
  • 2
    @hgiesel: you are confusing this up, there is nothing redundant. You only gave the formula to transform your suggested representation into John's and vice versa. Both are unique representations using four real values, it is hardly possible one of it is more redundant than the other. – Doc Brown Jan 24 '17 at 19:47
  • @DocBrown Yeah, 100% equivalent. I use this method (or actually, this object:) because my code invariably already has stuff like struct point { double x,y; }; and struct line { struct point pt1,pt2; }; So just typedef a triangle (or hypoteneuse) as a line (for syntactic clarity), and you're all done. No separate type to think about. "One size (or one representation) fits all". – John Forkosh Jan 24 '17 at 23:15
  • There are certainly worse things, but I'd still say {x, y, w, h} is slightly. For example think about moving, where you only have to change x, y in this version, but all values, if you have two points defined. {x, y, w, h} is simply the least amount of information to construct a aa rectangle. – hgiesel Jan 25 '17 at 2:14

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.