0

From a start point for 3 variables, x,y,z to another point; what is the best linear algorithm.

Example: From x:0, y=0, z=0 to x:10, y=20, z=50.

The way i am looking for is the equal steps on each homogenised increase block.

edit for ambiguity: I asked this question for motor control. Motors controlling x and y coordinates, but they can't perform steps at same time. So my motion has to be like ladder or squares. So, I am looking for the smallest ladder steps for 3 (or more) coordinates, like least squares logic, exactly in c#.

ithnegique
  • 139
  • 1
  • 1
  • 9

2 Answers2

1

You can use simple linear interpolation:

f(t) = start + t * (end - start), t in [0, 1]
     = (1 - t) * start + t * end

If you increase t by a constant amount, the step size will be constant, too. If you want to perform n steps, you should increase t by

dt = 1 / n

in each step.

The interpolation can be calculated independently per coordinate.

Nico Schertler
  • 32,049
  • 4
  • 39
  • 70
  • Do we have chances to improve linear interpolation by taking it recursively? (The question edited.) – ithnegique May 22 '13 at 10:37
  • Actually, your edit confused me even more. You can calculate the interpolation iteratively by adding `dt * (end - start)` each step. – Nico Schertler May 22 '13 at 10:40
0

Using integer coordinates, you can divide the differences by the Greatest common divisor:

var gcd = Gcd(x2 - x1, y2 - y1, z2 - z1);
var stepX = (x2 - x1) / gcd;
var stepY = (y2 - y1) / gcd;
var stepZ = (z2 - z1) / gcd;

Some lines will only have two steps, since they can't be divided evenly in all three dimensions. (E.g. (0,0,0)-(17,19,23))


Alternativly, you could use Bresenham's line algorithm

public static IEnumerable<Point> GetPointsOnLine(int x0, int y0, int z0, int x1, int y1, int z1)
{
    bool swapXY = Math.Abs(y1 - y0) > Math.Abs(x1 - x0);
    bool swapXZ = Math.Abs(z1 - z0) > Math.Abs(x1 - x0);

    if (swapXY)
    {
        int tmp;
        tmp = x0; x0 = y0; y0 = tmp;
        tmp = x1; x1 = y1; y1 = tmp;
    }

    if (swapXZ)
    {
        int tmp;
        tmp = x0; x0 = z0; z0 = tmp;
        tmp = x1; x1 = z1; z1 = tmp;
    }

    int deltaX = Math.Abs(x1 - x0);
    int deltaY = Math.Abs(y1 - y0);
    int deltaZ = Math.Abs(z1 - z0);

    int driftXY = deltaX / 2;
    int driftXZ = deltaX / 2;

    int stepX = x0 <= x1 ? 1 : -1;
    int stepY = y0 <= y1 ? 1 : -1;
    int stepZ = z0 <= z1 ? 1 : -1;

    int y = y0;
    int z = z0;

    for (int x = x0; x*stepX <= x1*stepX; x += stepX)
    {
        int xc = swapXY ? y : swapXZ ? z : x;
        int yc = swapXY ? swapXZ ? z : x : y;
        int zc = swapXZ ? x : z;

        yield return new Point(xc, yc, zc);

        driftXY -= deltaY;
        if (driftXY < 0)
        {
            y += stepY;
            driftXY += deltaX;
        }

        driftXZ -= deltaZ;
        if (driftXZ < 0)
        {
            z += stepZ;
            driftXZ += deltaX;
        }
    }
}

Demonstration

Markus Jarderot
  • 86,735
  • 21
  • 136
  • 138
  • Thanks a lot for your help, Markus. The first part of the problem is being solved by your way. Finally, i have the hardest part , homogenising steps. For example: x1,y1,z1 = 0,0,0; x2,y2,z2= 2,50,100; And gcd(d1,d2,d3)= 2; After dividing we have this values : 1,25,50: The second i im talking for is it mustn't step 25 times before 50, the steps must be like this: 1,1,1;0,0,1;0,1,1;0,0,1;0,1,1;....(50 times) by every time checking the next coordinate's priority. What would you say? Thanks. – ithnegique May 22 '13 at 15:39
  • If you want small steps, try the Bresenham algorithm in my answer. It will step at most (1,1,1) each time, and will stay close to the ideal line. – Markus Jarderot May 22 '13 at 16:00