/*
   math/boundingbox3f.h
   This file is part of the Osirion project and is distributed under
   the terms of the GNU General Public License version 2
*/

#ifndef __INCLUDED_MATH_BOUNDINGBOX3F_H__
#define __INCLUDED_MATH_BOUNDINGBOX3F_H__

#include "math/vector3f.h"

namespace math {

/**
 * @brief a bounding box class
 */
class BoundingBox3f {
public:
	BoundingBox3f();
	BoundingBox3f(const Vector3f &center);
	
	/**
	 * @brief returns the minimum coordinates of the bounding box
	 */
	inline const Vector3f & min() const {
		return boundingbox_min;
	}
	
	/**
	 * @brief returns the maximum coordinates of the bounding box
	 */
	inline const Vector3f & max() const {
		return boundingbox_max;
	}

	/**
	 * @brief test if a point is located inside the bounding box
	 */
	inline const bool inside(const Vector3f & point) const {
		for (size_t i =0; i < 3; i++) {
			if ((point[i] < boundingbox_min[i]) || (point[i] > boundingbox_max[i])) {
				return false;
			}
		}
		return true;
	}
	
	/**
	 * @brief test if a point is located outside the bounding box
	 */
	inline const bool outside(const Vector3f & point) const {
		for (size_t i =0; i < 3; i++) {
			if ((point[i] < boundingbox_min[i]) || (point[i] > boundingbox_max[i])) {
				return true;
			}
		}
		return false;
	}
	
	void assign(const BoundingBox3f & other);
	
	void assign(const Vector3f & min, const Vector3f & max);
	
	void assign(const Vector3f &center);
	
	void assign(const float min, const float max);
	
	void clear();
	
	/**
	 * @brief expand the bounding box to contain a point
	 */
	inline void expand(const Vector3f & point) {
		for (size_t i =0; i < 3; i++) {
			if (point[i] < boundingbox_min[i]) {
				boundingbox_min[i] = point[i];
			}
			
			if (point[i] > boundingbox_max[i]) {
				boundingbox_max[i] = point[i];
			}
		}
	}
	
	/**
	 * @brief expand the bounding box to contain another bounding box
	 */
	inline void expand(const Vector3f & min, const Vector3f & max) {
		for (size_t i =0; i < 3; i++) {
			if (min[i] < boundingbox_min[i]) {
				boundingbox_min[i] = min[i];
			}
			
			if (max[i] > boundingbox_max[i]) {
				boundingbox_max[i] = max[i];
			}
		}
	}
	
	/**
	 * @brief expand the bounding box to contain another bounding box
	 */
	inline void expand(const BoundingBox3f & other) {
		expand(other.boundingbox_min, other.boundingbox_max);
	}
	
	/**
	 * @brief expand the bounding box by a range
	 */
	inline void expand(const float range) {
		for (size_t i =0; i < 3; i++) {
			boundingbox_min[i] -= range;
			boundingbox_max[i] += range;
		}
		
	}
	
private:
	Vector3f	boundingbox_min;
	Vector3f	boundingbox_max;
};

} // namespace math
#endif // __INCLUDED_MATH_BOUNDINGBOX3F_H__