Recently, I created a blog entry about using C++ std::complex
as an alternative to points for computational geometry. We will now apply this technique for more geometry for C++!.
Triangle centers are important for they create a connection between triangles, circles, and angles in geometric construction. But the classical technique is a little hassle to either derive, or code. For example, we can get the circumcenter by constructing two perpendicular bisectors and intersecting them. Math for dummies provides a brief explanation of some triangle center formulae if you want to know what I'm talking about.
But can we generalize the way to get ALL kinds of triangle centers?
Barycentric Coordinates
Barycentric coordinates is a kind of coordinate system that uses the three vertices of the triangle as its coordinate system. Basically, a coordinate has three real numbers (a, b, c) determining the "weight" of the vertex at vertices (A, B, C) respectively. This paper provides a well-formed definition of the Barycentric coordinates. The vertices A, B, and C here will be fixed.
Essentially, Barycentric coordinates determines a unique point using the formula bary(A,B,C,a,b,c) = (A*a + B*b + C*c) / (a + b + c)
. In physics, you might relate this formula to the center of mass or the weighted average of three objects in space. If you notice the denominator in the formula, the Barycentric point itself can be determined by any scale of a, b, and c because it is normalized. In essence, (a, b, c) == (k*a, k*b, k*c) for all real k, k != 0
.
The Bary Function
We need to have a function that converts Barycentric coordinates to Cartesian points. Well, the formula is rather straightforward so it's rather easy. Since std::complex
allows us vector addition and scalar multiplication, it's a 1-liner. Remember, we're using complex numbers so don't forget to typedef std::complex<double> point
.
point bary(point A, point B, point C, double a, double b, double c) {
return (A*a + B*b + C*c) / (a + b + c);
}
// geometric center of mass
point centroid(point A, point B, point C) {
return bary(A, B, C, 1, 1, 1);
}
// intersection of perpendicular bisectors
point circumcenter(point A, point B, point C) {
double a = norm(B - C), b = norm(C - A), c = norm(A - B);
return bary(A, B, C, a*(b+c-a), b*(c+a-b), c*(a+b-c));
}
// intersection of internal angle bisectors
point incenter(point A, point B, point C) {
return bary(A, B, C, abs(B-C), abs(A-C), abs(A-B));
}
// intersection of altitudes, angles form 120 degrees
point orthocenter(point A, point B, point C) {
double a = norm(B - C), b = norm(C - A), c = norm(A - B);
return bary(A, B, C, (a+b-c)*(c+a-b), (b+c-a)*(a+b-c), (c+a-b)*(b+c-a));
}
// intersection of two external angle bisectors
// note: there are three excenters
point excenter(point A, point B, point C) {
double a = abs(B - C), b = abs(A - C), c = abs(A - B);
return bary(A, B, C, -a, b, c);
// return bary(A, B, C, a, -b, c);
// return bary(A, B, C, a, b, -c);
}
Too short? Amazed much? If you want to know how it works, Wolfram-alpha provides a brief summary and some equations for each triangle center. The site also provides other centers I did not mention here, such as the Symmedian point.
For the proofs, some of them are straightforward. For example, for the centroid, you just need to show that if a = b = c = 1, then (A*a + B*b + C*c) / (a + b + c) == (A + B + C) / 3
. But for the others, you might want to look into papers online because they're extensive. I liked the explanation from Silvester's book "Geometry — Ancient & Modern" for he also showed theorems built around Barycentric coordinates, though it's not available online so you should buy it in a bookstore. If you also found some research papers that look useful, I would also like to know.