blob: e55b6274c10f4edaae8e988d60b2c48695e45b66 [file] [log] [blame]
//#####################################################################
// Copyright 2003, 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_2D
//#####################################################################
#ifndef __ORIENTED_BOX_2D__
#define __ORIENTED_BOX_2D__
#include "../Matrices_And_Vectors/MATRIX_2X2.h"
#include "../Matrices_And_Vectors/VECTOR_2D.h"
#include "BOX_2D.h"
#include "RAY_2D.h"
#include "SEGMENT_2D.h"
namespace PhysBAM
{
template<class T> class BOX_2D;
template<class T>
class ORIENTED_BOX_2D
{
public:
VECTOR_2D<T> corner; // root corner of the box
VECTOR_2D<T> edge1, edge2; // principle edges of the box, emanating from the corner
ORIENTED_BOX_2D()
: corner (0, 0), edge1 (1, 0), edge2 (0, 1)
{}
ORIENTED_BOX_2D (const VECTOR_2D<T>& corner_input, const VECTOR_2D<T>& edge1_input, const VECTOR_2D<T>& edge2_input)
: corner (corner_input), edge1 (edge1_input), edge2 (edge2_input)
{}
ORIENTED_BOX_2D (const BOX_2D<T>& box, const T rotation_angle)
{
MATRIX_2X2<T> mat = MATRIX_2X2<T>::Rotation_Matrix (rotation_angle);
corner = mat * box.Minimum_Corner();
edge1 = (box.xmax - box.xmin) * mat.Column (1);
edge2 = (box.ymax - box.ymin) * mat.Column (2);
}
ORIENTED_BOX_2D (const BOX_2D<T>& box, const T rotation_angle, const VECTOR_2D<T>& corner_input)
: corner (corner_input)
{
MATRIX_2X2<T> mat = MATRIX_2X2<T>::Rotation_Matrix (rotation_angle);
edge1 = (box.xmax - box.xmin) * mat.Column (1);
edge2 = (box.ymax - box.ymin) * mat.Column (2);
}
BOX_2D<T> Axis_Aligned_Bounding_Box() const
{
T xmin = corner.x, xmax = corner.x, ymin = corner.y, ymax = corner.y;
if (edge1.x > 0) xmax += edge1.x;
else xmin += edge1.x;
if (edge2.x > 0) xmax += edge2.x;
else xmin += edge2.x;
if (edge1.y > 0) ymax += edge1.y;
else ymin += edge1.y;
if (edge2.y > 0) ymax += edge2.y;
else ymin += edge2.y;
return BOX_2D<T> (xmin, xmax, ymin, ymax);
}
bool Lazy_Inside (const VECTOR_2D<T> &location) const
{
VECTOR_2D<T> vec = location - corner;
T edge1_projection = VECTOR_2D<T>::Dot_Product (vec, edge1);
T edge2_projection = VECTOR_2D<T>::Dot_Product (vec, edge2);
return (0 <= edge1_projection && edge1_projection <= edge1.Magnitude_Squared() &&
0 <= edge2_projection && edge2_projection <= edge2.Magnitude_Squared());
}
bool Intersection (const ORIENTED_BOX_2D<T>& box) const
{
if (Separating_Line_Test (box, edge1)) return false;
if (Separating_Line_Test (box, edge2)) return false;
if (Separating_Line_Test (box, box.edge1)) return false;
if (Separating_Line_Test (box, box.edge2)) return false;
return true;
} // otherwise
bool Intersection (const BOX_2D<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 (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 (line_max < box.ymin || line_min > box.ymax) return false;
if (Separating_Line_Test (box, edge1)) return false;
if (Separating_Line_Test (box, edge2)) return false;
return true;
} // otherwise
bool Intersection (RAY_2D<T>& ray, T segment_intersection_epsilon) const // done like this to prevent short circuit errors
{
bool test1 = SEGMENT_2D<T> (corner, corner + edge1).Intersection (ray, segment_intersection_epsilon),
test2 = SEGMENT_2D<T> (corner, corner + edge2).Intersection (ray, segment_intersection_epsilon),
test3 = SEGMENT_2D<T> (corner + edge2, corner + edge1 + edge2).Intersection (ray, segment_intersection_epsilon),
test4 = SEGMENT_2D<T> (corner + edge1, corner + edge1 + edge2).Intersection (ray, segment_intersection_epsilon);
return (test1 || test2 || test3 || test4);
}
bool Fuzzy_Intersection (RAY_2D<T>& ray, T segment_intersection_epsilon) const // done like this to prevent short circuit errors
{
bool test1 = SEGMENT_2D<T> (corner, corner + edge1).Fuzzy_Intersection (ray, segment_intersection_epsilon),
test2 = SEGMENT_2D<T> (corner, corner + edge2).Fuzzy_Intersection (ray, segment_intersection_epsilon),
test3 = SEGMENT_2D<T> (corner + edge2, corner + edge1 + edge2).Fuzzy_Intersection (ray, segment_intersection_epsilon),
test4 = SEGMENT_2D<T> (corner + edge1, corner + edge1 + edge2).Fuzzy_Intersection (ray, segment_intersection_epsilon);
return (test1 || test2 || test3 || test4);
}
bool Separating_Line_Test (const ORIENTED_BOX_2D<T>& box, const VECTOR_2D<T>& line_direction) const
{
T min1, max1;
Project_Points_Onto_Line (line_direction, min1, max1);
T min2, max2;
box.Project_Points_Onto_Line (line_direction, min2, max2);
if (max2 < min1 || min2 > max1) return true;
else return false;
}
bool Separating_Line_Test (const BOX_2D<T>& box, const VECTOR_2D<T>& line_direction) const
{
T min1, max1;
Project_Points_Onto_Line (line_direction, min1, max1);
T min2, max2;
box.Project_Points_Onto_Line (line_direction, min2, max2);
if (max2 < min1 || min2 > max1) return true;
else return false;
}
void Project_Points_Onto_Line (const VECTOR_2D<T>& direction, T& line_min, T& line_max) const
{
line_min = line_max = VECTOR_2D<T>::Dot_Product (direction, corner);
T e1 = VECTOR_2D<T>::Dot_Product (direction, edge1), e2 = VECTOR_2D<T>::Dot_Product (direction, edge2);
if (e1 > 0) line_max += e1;
else line_min += e1;
if (e2 > 0) line_max += e2;
else line_min += e2;
}
//#####################################################################
//#####################################################################
};
}
#endif