views:

394

answers:

5

For a right triangle specified by an equation aX + bY <= c on integers

I want to plot each pixel(*) in the triangle once and only once, in a pseudo-random order, and without storing a list of previously hit points.

I know how to do this with a line segment between 0 and x

pick a random point'o' along the line,
pick 'p' that is relatively prime to x
repeat for up to x times: Onext = (Ocur + P) MOD x

To do this for a triangle, I would
1. Need to count the number of pixels in the triangle sans lists
2. Map an integer 0..points into a x,y pair that is a valid pixel inside the triangle

I hope any solution could be generalized to pyramids and higher dimensional shapes.

(*) I use the CG term pixel for the pair of integer points X,Y such that the equation is satisfied.

+3  A: 

Since you want to guarantee visiting each pixel once and only once, it's probably better to think in terms of pixels rather than the real triangles. You can slice the triangles horizontally and get bunch of horizontal scan lines. Connect the scan lines together and you have converted your "triangle" into a long line. Apply your point visiting algorithm to your long chain of scan lines.

By the way, this mapping only needs to happen on paper, all you need is a function that can return (x, y) given (t) along the virtual scan line.

Edit: To convert two points to a line segment, you can look for Bresenham's scan conversion. Once you get the 3 line segments converted into series of points, you can put all points into a bucket and group all points by y. Within the same y-value, sort points by x. The smallest x within a y-value is the begin point of the scan line and the largest x within the y-value is the end point of the scan line. This is called "scan converting triangle". You can find more info if you Google.

eed3si9n
This seems to require a list of scan-line, and determining which line a given number represents requires walking a structure (balanced tree?)Trying to generalize this seems to rapidly get out of control though
Procedural Throwback
t just has to map to correct set of (x, y), so within the function it can use Windows programmer's approach and pick point from bounding rectangle and return "false" if it's not in the triangle.
eed3si9n
Given the equation of a triangle, what would a function for (x,y) = f(t) look like?
Procedural Throwback
Procedural, f(t) in this case could take an integer and it simply returns the x,y value of that 'numbered' pixel in the triangle. You can also do that with a normalised t in the range [0,1] and do a multiplication to scale it up. That's still fairly easy.
workmad3
Pick three points (x1, y1), (x2, y2), (x3, y3) from your equation. (Min(x),Min(y)), (Max(x), Max(y)) defines your bounding box. Width is Max(x) - Min(x), so that's the length of a scan line. Number of scan line is Max(y) - Min(y). x = t % width + Min(x) and y = t / width + Min(y).
eed3si9n
workmad3 - I tried working out such an equation, and couldn't figure it out, but my math is rusty. I can't even reliably calculate the number of "pixels" in a triangle without iterating the lines (which gets really complex as dimension increases)
Procedural Throwback
However, if (x, y) is outside of your triangle, you return "false" instead.
eed3si9n
eed3si9n - With floating point, wouldn't the mapping from (integer) t to (integer x, y) result in duplicates ? Min(x), Min(y) are both 0, so this seems like it should be simple
Procedural Throwback
I also can't calculate the number of pixels in the triangle without iterating the lines. That's why I posted my ugly hack.
Windows programmer
@Procedural Throwback, where did the floating point come from?, it's all integers. There should be no duplicate for t -> (x,y) mapping.
eed3si9n
Sorry, I had FP on the brain from the earlier [0..1] comment.the bounding box + discard method gets impractical fast as the dimension increases. 50% of the work is wasted for triangles, but 75% for pyramids?
Procedural Throwback
@Procedural Throwback, I added more on how to get the scan lines on the answer.
eed3si9n
A: 

One method is to put all of the pixels into an array and then shuffle the array (this is O(n)), then visit the pixels in the order in the shuffled array. This could require quite a lot of memory though.

1800 INFORMATION
A: 

Here's a method which wastes some CPU time but probably doesn't waste as much as a more complicated method would do.

Compute a rectangle that circumscribes the triangle. It will be easy to "linearize" that rectangle, each scan line followed by the next. Use the algorithm that you already know in order to traverse the pixels of the rectangle. When you hit each pixel, check if the pixel is in the triangle, and if not then skip it.

Windows programmer
+1  A: 

Here's a solution for Triangle Point Picking.

What you have to do is choose two vectors (sides) of your triangle, multiply each with a random number in [0,1] and add them up. This will provide a uniform distribution in the quadrilateral defined by the vectors. You'll have to check whether the result lies inside the original triangle; if it doesn't either transform it back in or simply discard it and try again.

efotinis
The distribution is in the floating point space, though - does it still apply to the integer pixels? I can't see how this could be used to get complete coverage.. only probably complete coverage?
Procedural Throwback
You're right. After I wrote it I realized it wasn't what you were asking for. I was going to delete my answer, but maybe someone else will find it useful. :0)
efotinis
A: 

I would consider the lines of the triangle as single line, which is cut into segments. The segments would be stored in an array where the length of the segment also stored as well as the offset in the total length of the lines. Then depending on the value of O, you can select which array element contains the pixel you want to draw at that moment based on this information and paint the pixel based on the values in the element.