Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Calculating the Point3Ds of a Cuboid around a Line

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:

enter image description here

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 ABAD = 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);
like image 623
Stefan Avatar asked Feb 18 '14 14:02

Stefan


2 Answers

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.

Cube

    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);
like image 90
John Alexiou Avatar answered Oct 18 '22 00:10

John Alexiou


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:

  • Create cuboid and locate it on xy plane
  • Move it according to your offsets
  • Rotate it according to your line rotation

You may use matrix multiplication to achieve this transformations.

like image 24
Alex Avatar answered Oct 17 '22 22:10

Alex