blob: a68ac83cd325d4e3f53533ffec36134580218cd2 [file] [log] [blame]
//#####################################################################
// Copyright 2002,2003,2004, Ronald Fedkiw, Eran Guendelman.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class ORIENTED_BOX_3D
//#####################################################################
#ifndef __ORIENTED_BOX_3D__
#define __ORIENTED_BOX_3D__
#include "../Matrices_And_Vectors/VECTOR_3D.h"
#include "../Matrices_And_Vectors/QUATERNION.h"
#include "BOX_3D.h"
namespace PhysBAM
{
template<class T>
class ORIENTED_BOX_3D
{
public:
VECTOR_3D<T> corner; // root corner of the box
VECTOR_3D<T> edge1, edge2, edge3; // principle edges of the box, emanating from the corner
ORIENTED_BOX_3D()
: corner (0, 0, 0), edge1 (1, 0, 0), edge2 (0, 1, 0), edge3 (0, 0, 1)
{}
ORIENTED_BOX_3D (const VECTOR_3D<T>& corner_input, const VECTOR_3D<T>& edge1_input, const VECTOR_3D<T>& edge2_input, const VECTOR_3D<T>& edge3_input)
: corner (corner_input), edge1 (edge1_input), edge2 (edge2_input), edge3 (edge3_input)
{}
ORIENTED_BOX_3D (const BOX_3D<T>& box, const QUATERNION<T>& rotation)
{
rotation.Get_Rotated_Frame (edge1, edge2, edge3);
corner = box.xmin * edge1 + box.ymin * edge2 + box.zmin * edge3; // same as rotation.Rotate(box.Minimum_Corner())
edge1 *= (box.xmax - box.xmin);
edge2 *= (box.ymax - box.ymin);
edge3 *= (box.zmax - box.zmin);
}
ORIENTED_BOX_3D (const BOX_3D<T>& box, const MATRIX_4X4<T>& transform)
{
corner = transform * box.Minimum_Corner();
MATRIX_3X3<T> rotation_only = transform.Upper_3X3();
edge1 = (box.xmax - box.xmin) * rotation_only.Column (1);
edge2 = (box.ymax - box.ymin) * rotation_only.Column (2);
edge3 = (box.zmax - box.zmin) * rotation_only.Column (3);
}
ORIENTED_BOX_3D (const BOX_3D<T>& box, const QUATERNION<T>& rotation, const VECTOR_3D<T>& corner_input)
: corner (corner_input)
{
rotation.Get_Rotated_Frame (edge1, edge2, edge3);
edge1 *= (box.xmax - box.xmin);
edge2 *= (box.ymax - box.ymin);
edge3 *= (box.zmax - box.zmin);
}
BOX_3D<T> Axis_Aligned_Bounding_Box() const
{
T xmin = corner.x, xmax = corner.x, ymin = corner.y, ymax = corner.y, zmin = corner.z, zmax = corner.z;
if (edge1.x > 0) xmax += edge1.x;
else xmin += edge1.x;
if (edge2.x > 0) xmax += edge2.x;
else xmin += edge2.x;
if (edge3.x > 0) xmax += edge3.x;
else xmin += edge3.x;
if (edge1.y > 0) ymax += edge1.y;
else ymin += edge1.y;
if (edge2.y > 0) ymax += edge2.y;
else ymin += edge2.y;
if (edge3.y > 0) ymax += edge3.y;
else ymin += edge3.y;
if (edge1.z > 0) zmax += edge1.z;
else zmin += edge1.z;
if (edge2.z > 0) zmax += edge2.z;
else zmin += edge2.z;
if (edge3.z > 0) zmax += edge3.z;
else zmin += edge3.z;
return BOX_3D<T> (xmin, xmax, ymin, ymax, zmin, zmax);
}
bool Intersection (const ORIENTED_BOX_3D<T>& box) const
{
if (Separating_Plane_Test (box, edge1)) return false;
if (Separating_Plane_Test (box, edge2)) return false;
if (Separating_Plane_Test (box, edge3)) return false;
if (Separating_Plane_Test (box, box.edge1)) return false;
if (Separating_Plane_Test (box, box.edge2)) return false;
if (Separating_Plane_Test (box, box.edge3)) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge1, box.edge1))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge1, box.edge2))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge1, box.edge3))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge2, box.edge1))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge2, box.edge2))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge2, box.edge3))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge3, box.edge1))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge3, box.edge2))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge3, box.edge3))) return false;
return true;
} // otherwise
bool Intersection (const BOX_3D<T>& box) const
{
T line_min = corner.x, line_max = corner.x;
if (edge1.x > 0) line_max += edge1.x;
else line_min += edge1.x;
if (edge2.x > 0) line_max += edge2.x;
else line_min += edge2.x;
if (edge3.x > 0) line_max += edge3.x;
else line_min += edge3.x;
if (line_max < box.xmin || line_min > box.xmax) return false;
line_min = line_max = corner.y;
if (edge1.y > 0) line_max += edge1.y;
else line_min += edge1.y;
if (edge2.y > 0) line_max += edge2.y;
else line_min += edge2.y;
if (edge3.y > 0) line_max += edge3.y;
else line_min += edge3.y;
if (line_max < box.ymin || line_min > box.ymax) return false;
line_min = line_max = corner.z;
if (edge1.z > 0) line_max += edge1.z;
else line_min += edge1.z;
if (edge2.z > 0) line_max += edge2.z;
else line_min += edge2.z;
if (edge3.z > 0) line_max += edge3.z;
else line_min += edge3.z;
if (line_max < box.zmin || line_min > box.zmax) return false;
if (Separating_Plane_Test (box, edge1)) return false;
if (Separating_Plane_Test (box, edge2)) return false;
if (Separating_Plane_Test (box, edge3)) return false;
VECTOR_3D<T> box_edge1 (box.xmax - box.xmin, 0, 0);
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge1, box_edge1))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge2, box_edge1))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge3, box_edge1))) return false;
VECTOR_3D<T> box_edge2 (0, box.ymax - box.ymin, 0);
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge1, box_edge2))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge2, box_edge2))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge3, box_edge2))) return false;
VECTOR_3D<T> box_edge3 (0, 0, box.zmax - box.zmin);
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge1, box_edge3))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge2, box_edge3))) return false;
if (Separating_Plane_Test (box, VECTOR_3D<T>::Cross_Product (edge3, box_edge3))) return false;
return true;
} // otherwise
bool Separating_Plane_Test (const ORIENTED_BOX_3D<T>& box, const VECTOR_3D<T>& plane_normal_direction) const
{
T min1, max1;
Project_Points_Onto_Line (plane_normal_direction, min1, max1);
T min2, max2;
box.Project_Points_Onto_Line (plane_normal_direction, min2, max2);
if (max2 < min1 || min2 > max1) return true;
else return false;
}
bool Separating_Plane_Test (const BOX_3D<T>& box, const VECTOR_3D<T>& plane_normal_direction) const
{
T min1, max1;
Project_Points_Onto_Line (plane_normal_direction, min1, max1);
T min2, max2;
box.Project_Points_Onto_Line (plane_normal_direction, min2, max2);
if (max2 < min1 || min2 > max1) return true;
else return false;
}
void Project_Points_Onto_Line (const VECTOR_3D<T>& direction, T& line_min, T& line_max) const
{
line_min = line_max = VECTOR_3D<T>::Dot_Product (direction, corner);
T e1 = VECTOR_3D<T>::Dot_Product (direction, edge1), e2 = VECTOR_3D<T>::Dot_Product (direction, edge2), e3 = VECTOR_3D<T>::Dot_Product (direction, edge3);
if (e1 > 0) line_max += e1;
else line_min += e1;
if (e2 > 0) line_max += e2;
else line_min += e2;
if (e3 > 0) line_max += e3;
else line_min += e3;
}
//#####################################################################
//#####################################################################
};
}
#endif