Frobot
Frobot

Reputation: 1283

Interpolation of a triangle

I have a unit right triangle and a value at each of the 3 vertices. I need to interpolate to find the value at a point inside the triangle. Hours of searching have turned up nothing that actually tells me how to do this. Here is my closest attempt, which is actually pretty close but not quite right -

                result = 
                v1 * (1 - x) * (1 - y) +
                v2 * x * (1 - y) +
                v3 * x * y;

v1, v2, and v3 are the values at the 3 vertices of the triangle. (x, y) is the point in the triangle that you are trying to find the value of.

Any kind of method would help me here. It doesn't necessarily need to be a unit/right triangle.

Updated info: I have a grid of evenly spaced points and a value at each point. I make a triangle out of the nearest 3 points on the grid. Here is a picture to illustrate it - enter image description here
So I have to interpolate between 5, 3, and 7 to find the value of x. The point could also be inside the other triangle, meaning you would interpolate between 5, 7, and the value of the bottom left corner of the square.

In the code I showed, v1 = 5, v2 = 3, v3 = 7.
x is the fractional distance (range [0-1]) in the "x" direction, and y is the fractional distance in the "y" direction.
In the picture's example, x would probably be about 0.75 and y would be about 0.2

Here are my closest attempts -
enter image description here
Created using -

        if (x > y) //if x > y then the point is in the upper right triangle
            return
                v1 * (1 - x) * (1 - y) +
                v2 * x * (1 - y) +
                v3 * x * y;
        else //bottom left triangle
            return
                v1 * (1 - x) * (1 - y) +
                v4 * (1 - x) * y +
                v3 * x * y;

And another attempt -
enter image description here
Created using -

if (x > y)
            return
                (1 - x) * v1 + (x - y) * v2 + y * v3;
        else
            return
                (1 - y) * v1 + (y - x) * v4 + x * v3;

They're both close to what I need but obviously not quite right.

Upvotes: 18

Views: 32238

Answers (5)

Frobot
Frobot

Reputation: 1283

I asked this 3 years ago and have still been working on a way to do this. I do believe it is impossible to do it without artifacts unless using an equilateral triangle. Here is a decent way to do it using barycentric coordinates and then adding a technique that gets rid of most of the artifacts. v1, v2, v3 are the values at the three points of the triangle. x, y is the point you want to find a value for.

if (x > y)
        {
            b1 = -(x - 1);
            b2 = (x - 1) - (y - 1);
            b3 = 1 - b1 - b2;
        }
        else
        {
            b1 = -(y - 1);
            b2 = -((x - 1) - (y - 1));
            b3 = 1 - b1 - b2;
        }

        float
            abs = x - y;
        if (abs < 0) abs *= -1;
        if (abs < 0.25f)
        {
            abs = 0.25f - abs;
            abs *= abs;
            b1 -= abs;
            b3 -= abs;
        }

        b1 *= b1;
        b2 *= b2;
        b3 *= b3;
        float fd = 1 / (b1 + b2 + b3);
        b1 *= fd;
        b2 *= fd;
        b3 *= fd;

        return
                v1 * b1 +
                v2 * b2 +
                v3 * b3;

Upvotes: 2

reneekk
reneekk

Reputation: 233

You should use barycentric coordinates. There is a very thorough write-up here that also discusses alternative solutions and why barycentric coordinates are best: CodePlea - Interpolating in a Triangle

Basically, the weights will end up looking like this:

enter image description here

Upvotes: 21

titanae
titanae

Reputation: 2289

Actually the simplest and most robust solution is based on barycentric coordinates -

http://answers.unity3d.com/questions/383804/calculate-uv-coordinates-of-3d-point-on-plane-of-m.html

Upvotes: 7

Dan
Dan

Reputation: 10786

Ok, so we will do a linear interpolation, assuming that the gradient is constant with respect to x and to y. d/dx = v2 - v1 and d/dy = v3 - v2, and f(0,0) = v1. We have a simple two dimensional differential equation.

d{f(x,y)} = (v2 - v1)*dx
f(x,y) = (v2 - v1)*x + g(y)
d{f(x,y)} = g'(y) = (v3 - v2)*dy
g(y) = (v3 - v2)*y + C
f(x,y) = (v2 - v1)*x + (v3 - v2)*y + C
f(0,0) = v1 = (v2 - v1)*0 + (v3 - v2)*0 + C = C
f(x,y) = (v2 - v1)*x + (v3 - v2)*y + v1

or in terms of v1 v2 and v3

f(x,y) = (1 - x)*v1 + (x - y)*v2 + y*v3

If you want to do it in a square for four vertices, as above with v4 in the bottom left at x=0 y=1, here are the conditions: d/dx = (v2 - v1) (1 - y) + (v3 - v4) y, d/dy = (v3 - v2) x + (v4 - v1) (1 - x), f(0,0) = v1

d/dx = (v2 - v1) (1 - y) + (v3 - v4) y
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + g(y)
d/dy = (v3 - v2) x + (v4 - v1) (1 - x) = -(v2 - v1) x + (v3 - v4) x + g'(y)
v3 - v2 + (v4 - v1) / x + v4 - v1 = -v2 + v1 + v3 - v4 + g'(y) / x
(v4 - v1) / x + 2*(v4 - v1) = g'(y) / x
g'(y) = (v4 - v1) + 2 x (v4 - v1)
g(y) = (v4 - v1) (1 + 2 x) y + C
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + (v4 - v1) (1 + 2 x) y + C
f(0,0) = (v2 - v1) (1 - 0) 0 + (v3 - v4) 0 0 + (v4 - v1) (1 + 2 0) 0 + C = v1
f(x,y) = (v2 - v1) (1 - y) x + (v3 - v4) y x + (v4 - v1) (1 + 2 x) y + v1

Upvotes: 1

rsaxvc
rsaxvc

Reputation: 1778

Here is some pseudocode for nearest-neighbor:

if( dist( p, p1 ) <= dist( p, p2 ) && dist( p, p1 ) <= dist( p, p3 ) )
  return val( p1 )
if( dist( p, p2 ) <= dist( p, p3 ) && dist( p, p2 ) <= dist( p, p1 ) )
  return val( p2 )
if( dist( p, p3 ) <= dist( p, p1 ) && dist( p, p3 ) <= dist( p, p2 ) )
  return val( p3 )

I think this also generates a voronoi diagram

Upvotes: 0

Related Questions