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);
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);
I can't give you a real piece of code, but I can give you an idea.
Ok, suppose you are already have a proper cuboid. I mean it has right width and height. Lets locate it on plane xy. After that you need to offset it to center (minus offset vector). The last thing is to rotate it according to your line rotation.
Again:
You may use matrix multiplication to achieve this transformations.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With