views:

66

answers:

3

I have a line that I must do calculations on for each grid square the line passes through.

I have used the Superline algorithm to get all these grid squares. This gives me an array of X,Y coordinates to check.

Now, here is where I am stuck, I need to be able to calculate the distance traveled through each of the grid squares... As in, on a line not on either 90 degree or 45 degree angles, each grid square accommodates a different 'length' of the total line.

Image example here, need 10 reputation to post images

As you can see, some squares have much more 'line length' in them than others - this is what I need to find.

How do I work this out for each grid square? I've been at this for a while and request the help of the Stack Overflowers!

A: 

Use the Euclidean Distance.

sqrt((x2-x1)^2 + (y2-y1)^2)

This gives the actual distance in units between points (x1,y1) and (x2,y2)

You can fairly simply find this for each square.

You have the slope of the line m = (y2-y1)/(x2-x1).

You have the starting point: (x1,y2)

What is the y position at x1 + 1? (i.e. starting at the next square)

Assuming you set your starting point to 0 the equation of this line is simply: y_n = mx_n

so y_n = (y2-y1)/(x2-x1) * x_n

Then the coordinates at the first square are (x1,y1) and at the nth point: (1, ((y2-y1)/(x2-x1))*1) (2, ((y2-y1)/(x2-x1))*2) (3, ((y2-y1)/(x2-x1))*3) ... (n, ((y2-y1)/(x2-x1))*n)

Then the distance through the nth square is: sqrt((x_n+1 - x_n)^2 + (y_n+1 - y_n)^2)

akellehe
Yes I thought of doing this, but will this work over each grid square? (Assuming I leave the decimal fractions in?)- I mean, the algorithm I have will only calculate integer grid squares. Do I need to change it to calculate with decimal as well? I know this would solve my problem but I was after something simpler.
Johnny
That should be `^2` (or `**2`, depending on your notation) not `*2`.
adamse
This is the best method to calculate the actual distance between two points on a 2-d plane. It handles decimals just fine.
akellehe
Yes, the problem is I only know the start and end points and not the intermediate points, I believe the Siddons algorithm is closer to what I need.
Johnny
I see. Thanks for explaining this more fully. I will attempt to implement this and see where I get to.
Johnny
Good luck! I'll be around.
akellehe
Oh, you're going to run into an issue when you exit squares through the top... In those cases the x's don't increment fully by 1...
akellehe
Oh, check Jay out. I think he's got it covered.
akellehe
A: 

have a look at Siddon's algorithm: "Fast calculation of the exact radiological path for a three-dimensional CT array"

unfortunately you need a subscription to read the original paper, but it is fairly well described in this paper

Siddon's algorithm is an O(n) algorithm for finding the length of intersection of a line with each pixel/voxel in a regular 2d/3d grid.

second
Thanks, I am looking at this...
Johnny
+1  A: 

There may be some clever way to do this that is faster and easier, but you could always hack through it like this:

You know the distance formula: s=sqrt((x2-x1)^2+(y2-y1)^2). To apply this, you must find the x and y co-ordinates of the points where the line intersects the edges of each grid cell. You can do this by plugging the x and y co-ordinates of the boundaries of the cell into the equation of the line and solve for x or y as appropriate.

That is, each cell extends from some point (x0,y0) to (x0+1,y0+1). So we need to find y(x0), y(x0+1), x(y0), and x(y0+1). For each of these, the x or y value found may or may not be within the ranges for that co-ordinate for that cell. Specifically, two of them will be and two won't. The two that are correspond to the edges that the line passes through, and the two that aren't are edges that it doesn't pass through.

Okay, maybe this sounds pretty confusing, so let's work through an example.

Let's say your line has the equation x=2/3 * y. You want to know where it intersects the edges of the cell extending from (1,0) to (2,1).

Plug in x=1 and you get y=2/3. 2/3 is in the legal range for y -- 0 to 1 -- so (1,2/3) is a point on the edge where the line intersects this cell. Namely, the left edge.

Plug in x=2 and you get y=4/3. 4/3 is outside the range for y. So the line does not pass through the right edge.

Plug in y=0 and you get x=0. 0 is not in the range for x, so the line does not pass through the bottom edge.

Plug in y=1 and you get x=3/2. 3/2 is in the legal range for x, so (3/2,1) is another intersection point, on the top edge.

Thus, the two points where the line intersects the edges of the cell are (1,2/3) and (3/2,1). Plug these into the distance formula and you'll get the length of the line segement through this cell, namely sqrt((1-3/2)^2+(2/3-1)^2)=sqrt(1/4+1/9)=sqrt(13/36). You can approximate that to any desired level of precision.

To do this in a program you'd need something like: (I'll use pseudo code because I don't know what language you're using)

// Assuming y=mx+b

function y(x)
  return mx+b

function x(y)
  return (y-b)/m

// cellx, celly are co-ordinates of lower left corner of cell
// Upper right must therefore be cellx+1, celly+1
function segLength(cellx, celly)
  // We'll create two arrays pointx and pointy to hold co-ordinates of intersect points
  // n is index into these arrays
  // In an object-oriented language, we'd create an array of point objects, but whatever
  n=0
  y1=y(cellx)
  if y1>=celly and y1<=celly+1
    pointx[n]=cellx
    pointy[n]=y1
    n=n+1
  y2=y(cellx+1)
  if y2>=celly and y2<=celly+1
    pointx[n]=cellx+1
    pointy[n]=y2
    n=n+1
  x1=x(celly)
  if x1>=cellx and x1<=cellx+1
    pointx[n]=x1
    pointy[n]=celly
    n=n+1
  x2=x(celly+1)
  if x2>=cellx and x2<=cellx+1
    pointx[n]=x2
    pointy[n]=celly+1
    n=n+1
  if n==0
    return "Error: line does not intersect this cell"
  else if n==2
    return sqrt((pointx[0]-pointx[1])^2+(pointy[0]-pointy[1])^2)
  else
    return "Error: Impossible condition"

Well, I'm sure you could make the code a little cleaner, but that's the idea.

Jay
Thank you very much, I spent about 3 hours getting this to work properly, but that was mostly problems calculating my slope (was using the start and end points and not the actual line points) and I didn't know how to calculate to Y-Intercept. Once I got that going, I had to also copy your code block to include cellX-1 and Y-1 because I had lines going in multiple directions. Thanks very much!
Johnny