Advertisement

barycentric coordinates C++ code check

Started by March 07, 2012 12:32 AM
3 comments, last by Alessandro 12 years, 8 months ago
I'm using the following code to calculate barycentric coordinates for a point on triangle t1/t2/t3 and use those to gather the related point position on a second triangle T1/T2/T3.
It seems to work but sometimes I'm not totally sure about it, and I'd be more confident if you guys could check on that.
Do you see any possible trouble or issue with it? Do you perhaps have other C++ code to share?
Thanks for any help.


// compute the area of a triangle using Heron's formula
double triarea(double a, double b, double c)
{
double s = (a + b + c)/2.0;
double area=sqrt(fabs(s*(s-a)*(s-b)*(s-c)));
return area;
}

// compute the distance between two 2d points
double dist(double x0, double y0, double z0, double x1, double y1, double z1)
{
double a = x1 - x0;
double b = y1 - y0;
double c = z1 - z0;
return sqrt(a*a + b*b + c*c);
}

// calculate barycentric coordinates
// triangle 1st vertex: x0,y0,z0
// triangle 2nd vertex: x1,y1,z1
// triangle 3rd vertex: x2,y2,z2
// point inside triangle: vx, vy,vz
// *u,*v,*w are the coordinates returned
void barycent(double x0, double y0, double z0, double x1, double y1, double z1, double x2, double y2, double z2,
double vx, double vy, double vz,
double *u, double *v, double *w)
{
// compute the area of the big triangle
double a = dist(x0, y0, z0, x1, y1, z1);
double b = dist(x1, y1, z1, x2, y2, z2);
double c = dist(x2, y2, z2, x0, y0, z0);
double totalarea = triarea(a, b, c);

// compute the distances from the outer vertices to the inner vertex
double length0 = dist(x0, y0, z0, vx, vy, vz);
double length1 = dist(x1, y1, z1, vx, vy, vz);
double length2 = dist(x2, y2, z2, vx, vy, vz);

// divide the area of each small triangle by the area of the big triangle
*u = triarea(b, length1, length2)/totalarea;
*v = triarea(c, length0, length2)/totalarea;
*w = triarea(a, length0, length1)/totalarea;
}

void main()
{
double r1,r2,r3; // barycentric coordinates
barycent(t1.x, t1.y, t1.z, t2.x, t2.y, t2.z, t3.x, t3.y, t3.z, firstPoint.x, firstPoint.y, firstPoint.z, &r1, &r2, &r3);
Point3d newPoint(T1.x*r1 + T2.x*r2 + T3.x*r3, T1.y*r1 + T2.y*r2 + T3.y*r3, T1.z*r1 + T2.z*r2 + T3.z*r3); // T1,T2,T3 are the coordinates of another triangle
}
I've done fairly intensive stuff with this sort of thing in the past... was drawing/defining tendon insertion points into polygonal bones. I just felt my way through it and did not ever encounter any trouble.

I don't think the area of the triangle is a factor you should be concerned with. Probably you just want to be doing some simple projections. If you are working with an object oriented language such as C++ you should find a vector library you are happy with. It will make things much more presentable and easier to proof for yourself.

PS: I was probably not using literal "barycentric" coordinates. It depends on what your application is I suppose. But if you need to fix a point onto a triangle, two coordinates does the trick. Also just trying to be helpful (your post has been languishing for a while)

EDITED: I could've sworn I explained that you can get away with one ratio for the distance between the first two corners, and then a second ratio for the distance between that point and the last corner. Don't know what happened to that. Anyway, again, depends on the application.
Advertisement
I've never seen barycentric coordinates calculated like that... that's a fairly expensive way to calculate them, using square roots and all. I'm writing a software renderer using barycentric coordinates for school. Here's the part where I calculate the coordinates:


// This function is a member of my Triangle class, which holds 3 3D vectors,
// a, b, and c which denote the 3 points making up the triangle. The 3
// values for the barycentric coordinates get stored in lambda
Vector<3, T> baryCoords(Vector<2, T> vec) const
{
Vector<3, T> lambda;
T den = 1 / ((b.y - c.y) * (a.x - c.x) + (c.x - b.x) * (a.y - c.y));

lambda.x = ((b.y - c.y) * (vec.x - c.x) + (c.x - b.x) * (vec.y - c.y)) * den;
lambda.y = ((c.y - a.y) * (vec.x - c.x) + (a.x - c.x) * (vec.y - c.y)) * den;
lambda.z = 1 - lambda.x - lambda.y;

return lambda;
}

// I use it kinda like this:
Triangle<float> t; // assign it's ABC points
Vector<2, float> p; // Give it some position
Vector<3, float> lambda = t.baryCoords(p);
Vector<3, float> final = lambda.x * t.getA() + lambda.y * t.getB() + lambda.z * t.getC();


I'm following the equations from Wikipedia.

[edit]

Ah, I see why you're doing it like that now. You have to be sure the point lies in the same plane as the triangle, and if it does, you can simplify it to be calculated like my function.
[size=2][ I was ninja'd 71 times before I stopped counting a long time ago ] [ f.k.a. MikeTacular ] [ My Blog ] [ SWFer: Gaplessly looped MP3s in your Flash games ]
Thank you very much for all the suggestions, and the code example as well. I implemented that in my barycentric routine and everything now works as expected! laugh.png
Also, getting rid of those square roots now allows to do the calculations much faster: I'm using that barycentric routine to calculate UV coordinates (I need to find the UV point that correspond to a point on a 3D model), and that runs for a large set of data. Now, without sqrt's, the routine does it in about 1/12th than earlier.

This topic is closed to new replies.

Advertisement