Calculating the Point3Ds of a Cuboid around a Line
algorithm, c#, vector-graphics
Solution
You need two direction vectors. One is along the line AB given by
Vector3D e = Normalize(B-A)
and one to descibe the "up" direction for the cross section. This can be given, or it can be calculated with the following algorithm (with preference towards +y)
if( e.X != 0 || e.Z != 0 )
{
// choose direction perpendicular to line closest to +y direction
Vector3D n = [-e.X*e.Y, e.X*e.X+e.Z*e.Z, -e.Z*e.Y];
} else {
// if line along +y already then choose +z for up vector
Vector3D n = [ 0, 0, 1];
}
Now you can calculate the 3rd direction to form a coordinate system
Vector3D k = Normalize( Cross(e,n) )
And you assemble the 3×3 rotation matrix that transforms local coordinates to world coordinates with
| k.X n.X e.X |
R = | k.Y n.Y e.Y |
| k.Z n.Z e.Z |
The local coordinate have the direction along the line as +z such that
Point3D a = A + R*[w,h,0]
Point3D b = A + R*[-w,h,0]
Point3D c = A + R*[w,-h,0]
Point3D d = A + R*[-w,-h,0]
Point3D e = B + R*[w,h,0]
Point3D f = B + R*[-w,h,0]
Point3D g = B + R*[w,-h,0]
Point3D h = B + R*[-w,-h,0]
where `R*[x,y,z]` designates a matrix-vector multiplication, `w` and `h` are the width and height of the rectangular cross section, and `A`, `B` are the point A and B position vectors. Addition here between vectors is element by element.
I have checked the code in my own code and it works. `vec3` is alias for a 3D vector, `mat3` is alias for 3×3 matrix.
vec3 u=(B-A).Normalized();
vec3 n = vec3.O;
if(Math.Abs(u.X)<=Math.Abs(u.Y)&&Math.Abs(u.X)<=Math.Abs(u.Z))
{
n=new vec3(u.Y*u.Y+u.Z*u.Z, -u.Y*u.X, -u.Z*u.X);
}
else if(Math.Abs(u.Y)<=Math.Abs(u.X)&&Math.Abs(u.Y)<=Math.Abs(u.Z))
{
n=new vec3(-u.X*u.Y, u.X*u.X+u.Z*u.Z, -u.Z*u.Y);
}
else if(Math.Abs(u.Z)<=Math.Abs(u.X)&&Math.Abs(u.Z)<=Math.Abs(u.Y))
{
n=new vec3(-u.X*u.Z, -u.Y*u.Z, u.X*u.X+u.Y*u.Y);
}
vec3 v=n.Cross(u);
mat3 R=mat3.Combine(v, n, u);
var a=A+R*new vec3(wt, ht, 0);
var b=A+R*new vec3(-wt, ht, 0);
var c=A+R*new vec3(wt, -ht, 0);
var d=A+R*new vec3(-wt, -ht, 0);
var e=B+R*new vec3(wt, ht, 0);
var f=B+R*new vec3(-wt, ht, 0);
var g=B+R*new vec3(wt, -ht, 0);
var h=B+R*new vec3(-wt, -ht, 0);
Problem
There are two Point3D's (A and B) and I want to calculate the points of a cuboid (a,b,c ... h) surrounding the line between A and B like a hull: There is one degree of freedom, the angle of the cuboid, because it can rotate around the line AB. I am not sure yet if this is a problem. I tried to calculate a vector normal to AB, D, and then the cross product of AB ⨯ AD = E. In the code, C is A - B so its the offset parallel to AB. I normalized these three vectors (C, D and E) and multiplied it with an offset to add / subtract them from A and B. It's not quite working yet. EDIT: see ja72's code for solution i also implemented a way of finding a normal vector: ``` double ax = Vector3D.AngleBetween(E, new Vector3D(1, 0, 0)); double ay = Vector3D.AngleBetween(E, new Vector3D(0, 1, 0)); double az = Vector3D.AngleBetween(E, new Vector3D(0, 0, 1)); ax = Math.Abs(ax - 90); ay = Math.Abs(ay - 90); az = Math.Abs(az - 90); if (ax <= ay & ax <= az) { n = Vector3D.CrossProduct(E, new Vector3D(1, 0, 0)); } else if (az <= ax && az <= ay) { n = Vector3D.CrossProduct(E, new Vector3D(0, 0, 1)); } else { n = Vector3D.CrossProduct(E, new Vector3D(0, 1, 0)); } n = normalize(n); ```