Monday 13 February 2006

I’m doing a lot of coding these days involving XY coordinates, and there’s a handful of little annoyances. They’re no one’s fault, I just want to vent.

First, it’s natural to say “x and y”, and it’s natural to say “height and width”, but x corresponds to width, and y to height, so I often make mistakes that switch the two:

`ht, wd = foox, fooy # This is wrong.`

The same goes for loops over x and y. The natural order to visit the points in a grid is the raster order: finish a row, then go on to the next row. But that means having the first loop be over y rather than x:

`for y in range(lowy, hiy):`

for x in range(lowx, hix):

do_something(x, y)

For this last, there’s a solution: create a generator that makes x,y pairs in a single loop:

`def xyrange(startx, endx, starty, endy):`

""" Generate the pairs (x, y) in a rectangle.

"""

for y in range(starty, endy):

for x in range(startx, endx):

yield x,y

Then this function is the only place that needs the inside-out y x ugliness, and you can use a single loop everywhere else:

`for x, y in xyrange(lowx, hix, lowy, hiy):`

do_something(x, y)

This has the advantage that you can break out of the loop cleanly when you find a point you are looking for. It has the disadvantage that you can’t do an action at the end of each row.

*Update:* Richard Schwartz noticed that I originally had
said,

First, it’s natural to say “x and y”, and it’s natural to say “height and width”, but x corresponds to

height, and y towidth, so I often make mistakes that switch the two.

which makes that sentence itself an error of the sort it describes, making it an unintentionally self-referential sentence!

## Comments

Pete Lyons8:34 AM on 13 Feb 2006Y is High-t, I repeat this little mantra all the time when working with coordinates.

andrew8:54 AM on 13 Feb 2006I know nothing about py, but can you pass in an optional callback (pointer, delegate, address) that will get called after each row?

Bill Mill9:33 AM on 13 Feb 2006@andrew: yes, you certainly could allow the generator to take an optional function reference if you wanted to. It even seems to me like it wouldn't be that ugly. Just call it end_of_row or something descriptive...

Ned Batchelder10:42 AM on 13 Feb 2006You could, but likely the thing you want to do at the end of row involves your local variables, and now you have to package them up, and the whole thing becomes more cumbersome than just putting in two loops.

Or, in the loop, you could check if x is equal to lowx, and then do beginning of row processing...

Damien Katz11:48 AM on 13 Feb 2006Couldn't you return a third value in the tuple that's a flag to indicate last row?

Michael Chermside1:55 PM on 13 Feb 2006Interesting. I never say "height and width", always "width and height". And I specifically recall being fairly young and wondering which was the natural order of these. I compared to "x and y" and went based on that.

Marius Gedminas2:29 PM on 13 Feb 2006"Width, height" is the natural order to me as well. On the other hand, I say "row, column", which makes it easy to think about indexing two-dimensional arrays (e.g., map[row][col]).

Ned Batchelder3:01 PM on 13 Feb 2006row, col is another one!

Ayende Rahien4:13 PM on 13 Feb 2006def xyrange(startx, endx, starty, endy):

""" Generate the pairs (x, y) in a rectangle.

"""

for y in range(starty, endy):

for x in range(startx, endx):

yield x,y, x == endx

That should give you the ability to check for the end of line

Alexander Belchenko4:18 PM on 13 Feb 2006In my last project where I need to draw on two types of displays (normal and rotated on 90 degrees) I leave width and height and start to using sizex and sizey.

James6:44 PM on 13 Feb 2006From the title I thought you would propose a way to program in 3d. Using 3d goggles I suppose or perhaps a holographic projector in order to do your programming. However, I don't even want visualize a 3d diff file. :)

Jonathon Duerig11:20 PM on 13 Feb 2006My first thought is that you were going to discuss Befunge, where the language is two-dimensional:

http://esoteric.voxelperfect.net/wiki/Befunge

Shane Hathaway3:40 PM on 15 Feb 2006What about the fact that the Y axis is upside down? That's the main thing that mixes me up. In math, graphs are drawn with Y increasing as you move upward. But in computer graphics, Y increases as you move downward. (I take this as evidence that computer scientists don't always listen to mathematicians.)

Also, precisely what part of a pixel do does a coordinate refer to? When you say (0,0), does that mean the center of the top left pixel or the top left of the top left pixel? This matters if the lines are antialiased.

Haukur Hreinsson9:44 PM on 18 Feb 2006Ah, the pixel thing. Didn't you get the memo?

ftp://ftp.alvyray.com/Acrobat/6_Pixel.pdf

I have an additional 2D programming annoyance. You tend to write two lines where one does something with say x, width, and cos, and the other with y, height, and sin. Then there may be a few things that go in both lines. And of course you write the second by copying and modifying the first. The fun starts when you forget one of the required changes. And even if you don't, it still feels wrong.

I get way too hung up on stuff like that.

Ed Davies8:03 AM on 15 Jun 2006Try doing graphics for geographical positions (i.e., maps). Latitude and longitude but easting and northing.

## Add a comment: