|See what's going on with flipcode!|
3D Geometry Primer: Chapter 2 - Issue 02 - Appendix
by (03 September 2002)
|Return to The Archives|
Hi everybody, I don't have much time, so I'm going to do this quickly.|
"Good coders drink a lot of coffee. Belgians drink a lot of coffee. Belgians are good coders.", Bram "Bramz" de Greve (1980-...) Belgian weirdo and author of the 3D Geometry Primer
All In Line
Today I present you again two files Line3D.h and Line3D.cpp but this time for only one class: Line3D. Both Vector3D and Point3D were structures, but this time, I've chosen to use a class. This is because I wanted to keep the data of Line3D private. This is necessary since I always want to keep the direction vector normalized. I can only ensure that by using private data. Hence the rule of thumb says I should use a class.|
This time, you'll find three constructors of which one is the default constructor. The default constructor creates a line with the origin O(0, 0, 0) as support point S and K(0, 0, 1) as direction vector D (i.e. pointing along the positive z-axis).
The second one takes a support point S and a direction vector D for the line. The line is simply initialized with these data with an additional normalizing of the direction vector.
And the last one takes two points through which the line will be constructed. One of them (the first) will act as support point. The direction vector will be chosen to point from the support to the second point, of course normalized.
Accessors to get and set the support point and direction vector are all implemented. Again with the additional normalizing for the direction vector.
Two accessors are provided to set the entire line. They have both the same name void set(...). One version takes a support point and direction vector, the other takes two points. Both do pretty much the same as the constructors that take the same parameters.
Point3D getPoint(float a_t) const: this method does a very simple thing: you provide it a paramater t of a point of the line, and it returns you that point P(t) = S + t * D. In fact, this is where the parametric equation of the line is represented.
Point3D project(const Point3D& a_point): this one will project a given point orthogonal on a line. This shouldn't be much of a problem. If you look in the "theory" part how to calculate the distance, you'll find we need to project that point on the line too. So, you'll find out there how it works.
bool contains(const Point3D& a_point, float a_tolerance = 0.0f): the last method I present you is one that can check if a given point is a point of the line. A point lies on a line if the distance to that line is zero. So, we simply check this distance. Of course, you know that nothing in numerical analysis is "exact". In this case we use a tolerance to determine if the point lies on the line.
All possible versions of the function float dist(...) are provided. The one calculates the distance between two lines. The other two calculate the distance between a line and a point. There are two versions so that it doesn't matter in which order you provide the operands. However, you can see that the second version simply uses the first one.
int intersect(const Line3D& a_line1, const Line3D& a_line2, float& a_t1, float& a_t2) is the last function of this week. It calculates the intersection of two lines. I won't explain how it works here in detail. You should read the appropriate issue of the primer for this. You can see I've hardcoded the calculate-the-distance part to reuse the cross product.
REMARK: I didn't use any form of tolerances in the dist and intersection functions. This can give some weird results. I hadn't the time to think of a good and general tolerance system. Hopefully this will be fixed somewhere in the future.
That was it for today,
non nobis, non nobis domine, sed nomini tuo da gloriam
Bram "Graaf Letho" de Greve