// This is core/vgl/vgl_intersection.h
#ifndef vgl_intersection_h_
#define vgl_intersection_h_
//:
// \file
// \brief Set of intersection functions
// \author Jan 25, 2007 Gamze Tunali
//
// For intersections of "homogeneous coordinates" objects like vgl_homg_line_2d<T>,
// see the static methods of vgl/algo/vgl_homg_operators_2d<T> and _3d.
//
// \verbatim
//  Modifications
//   01 Mar 2007 - Gamze Tunali - split up into vgl/algo and vgl parts
//   21 Jul 2009 - Peter Vanroose - added box intersection (2d and 3d)
//   21 Jul 2009 - Peter Vanroose - added inlined point intersection functions
// \endverbatim

#include <vgl/vgl_fwd.h> // forward declare various vgl classes
#include <vgl/vgl_box_2d.h> // method "contains()"
#include <vgl/vgl_box_3d.h> // method "contains()"
#include <vgl/vgl_point_2d.h> // method "operator==()"
#include <vgl/vgl_point_3d.h> // method "operator==()"
#include <vgl/vgl_line_3d_2_points.h>
#include <vgl/vgl_line_segment_3d.h>
#include <vgl/vgl_infinite_line_3d.h>
#include <vcl_vector.h>

//: Return true if the two points intersect, i.e., coincide
// \relatesalso vgl_point_2d
template <class T>
inline bool vgl_intersection(vgl_point_2d<T> const& p0,
                             vgl_point_2d<T> const& p1)
{ return p0 == p1; }

//: Return true if the two points intersect, i.e., coincide
// \relatesalso vgl_point_2d
template <class T>
inline bool vgl_intersection(vgl_point_3d<T> const& p0,
                             vgl_point_3d<T> const& p1)
{ return p0 == p1; }

//: Return true if line intersects box. If so, compute intersection points.
// \relatesalso vgl_line_2d
template <class T>
bool vgl_intersection(vgl_box_2d<T> const& box,
                      vgl_line_2d<T> const& line,
                      vgl_point_2d<T>& p0,
                      vgl_point_2d<T>& p1);

//: Returns the number of intersections of a line segment with a box, up to two are returned in p0 and p1.
// \relatesalso vgl_line_segment_2d
template <class T>
unsigned vgl_intersection(vgl_box_2d<T> const& box,
                          vgl_line_segment_2d<T> const& line,
                          vgl_point_2d<T>& p0,
                          vgl_point_2d<T>& p1);

//: Return the intersection point of two concurrent lines
// \relatesalso vgl_line_3d_2_points
//Allows intersection points outside the line segments
//Throws an assertion if lines not concurrent
template <class T>
vgl_point_3d<T> vgl_intersection(vgl_line_3d_2_points<T> const& l1,
                                 vgl_line_3d_2_points<T> const& l2);

//: Return the intersection point of segments of two concurrent lines. Returns false if the intersection point is not inside both line segments
// \relatesalso vgl_line_segment_3d. 
// 
template <class T>
bool vgl_intersection(vgl_line_segment_3d<T> const& l1,
                      vgl_line_segment_3d<T> const& l2,
                      vgl_point_3d<T>& i_pnt);

//: Return the intersection point of segments of a concurrent line and line segment pair. Returns false if the intersection point is not inside both line segments
// \relatesalso vgl_line_segment_3d
// \relatesalso vgl_line_3d_2_points
template <class T>
bool vgl_intersection(vgl_line_3d_2_points<T> const& l1,
                      vgl_line_segment_3d<T> const& l2,
                      vgl_point_3d<T>& i_pnt);

template <class T> inline
bool vgl_intersection(vgl_line_segment_3d<T> const& l1,
                      vgl_line_3d_2_points<T> const& l2,
                      vgl_point_3d<T>& i_pnt)
{
  return vgl_intersection(l2, l1, i_pnt);
}

//: Return the intersection point of infinite lines, if concurrent.
// \relatesalso vgl_infinite_line_3d
template <class T>
bool vgl_intersection(vgl_infinite_line_3d<T> const& l1,
                      vgl_infinite_line_3d<T> const& l2,
                      vgl_point_3d<T>& i_pnt);

//: Return the intersection point of rays. Returns false if rays are parallel or intersect outside of positive ray domain
// \relatesalso vgl_ray_3d
template <class T>
bool vgl_intersection(vgl_ray_3d<T> const& r1,
                      vgl_ray_3d<T> const& r2,
                      vgl_point_3d<T>& i_pnt);

//: Return the intersection point of two lines. Return false if lines are parallel
// \relatesalso vgl_line_2d
template <class T>
bool vgl_intersection(vgl_line_2d<T>  const& line0,
                      vgl_line_2d<T>  const& line1,
                      vgl_point_2d<T>       &intersection_point );


//: Return the intersection point of a line and a plane.
// \relatesalso vgl_line_3d_2_points
// \relatesalso vgl_plane_3d
template <class T>
vgl_point_3d<T> vgl_intersection(vgl_line_3d_2_points<T> const& line,
                                 vgl_plane_3d<T> const& plane);

//: Return the intersection point of a line and a plane.
// \relatesalso vgl_line_segment_3d
// \relatesalso vgl_plane_3d
template <class T>
bool vgl_intersection(vgl_line_segment_3d<T> const& line,
                      vgl_plane_3d<T> const& plane,
                      vgl_point_3d<T> & i_pt);


//: Return the intersection point of a line and a plane.
// \relatesalso vgl_line_segment_3d
// \relatesalso vgl_plane_3d
template <class T>
bool vgl_intersection(vgl_infinite_line_3d<T> const& line,
                      vgl_plane_3d<T> const& plane,
                      vgl_point_3d<T> & i_pt);

//: Return the intersection point of a ray and a plane.
// \relatesalso vgl_line_segment_3d
// \relatesalso vgl_plane_3d
template <class T>
bool vgl_intersection(vgl_ray_3d<T> const& ray,
                      vgl_plane_3d<T> const& plane,
                      vgl_point_3d<T> & i_pt);

//: Return the intersection line of two planes.
// Returns false if planes are effectively parallel
// \relatesalso vgl_line_segment_3d
// \relatesalso vgl_plane_3d
template <class T>
bool vgl_intersection(vgl_plane_3d<T> const& plane0,
                      vgl_plane_3d<T> const& plane1,
                      vgl_line_segment_3d<T> & line){
  vgl_infinite_line_3d<T> inf_l;
  bool status = vgl_intersection(plane0, plane1, inf_l);
  if (status)
    line.set(inf_l.point_t(T(0)), inf_l.point_t(T(1)));
  return status;
}

template <class T>
bool vgl_intersection(vgl_plane_3d<T> const& plane0,
                      vgl_plane_3d<T> const& plane1,
                      vgl_line_3d_2_points<T> & line){
  vgl_infinite_line_3d<T> inf_l;
  bool status = vgl_intersection(plane0, plane1, inf_l);
  if (status)
    line.set(inf_l.point_t(T(0)), inf_l.point_t(T(1)));
  return status;
}

template <class T>
bool vgl_intersection(vgl_plane_3d<T> const& plane0,
                      vgl_plane_3d<T> const& plane1,
                      vgl_infinite_line_3d<T> & line);

//: Return the intersection point of three planes.
// \relatesalso vgl_plane_3d
template <class T>
vgl_point_3d<T> vgl_intersection(vgl_plane_3d<T> const& p1,
                                 vgl_plane_3d<T> const& p2,
                                 vgl_plane_3d<T> const& p3);

//: Return true if any point on [p1,p2] is within tol of [q1,q2]
//  Tests two line segments for intersection or near intersection
//  (within given tolerance).
// \author Dan jackson
// \relatesalso vgl_point_2d
template <class T>
bool vgl_intersection(vgl_point_2d<T> const& p1,
                      vgl_point_2d<T> const& p2,
                      vgl_point_2d<T> const& q1,
                      vgl_point_2d<T> const& q2,
                      double tol = 1e-6);

//: Return true if the point lies inside the box
// \relatesalso vgl_point_2d
// \relatesalso vgl_box_2d
template <class T>
inline bool vgl_intersection(vgl_box_2d<T> const& b, vgl_point_2d<T> const& p)
{ return b.contains(p); }

//: Return true if the point lies inside the box
// \relatesalso vgl_point_2d
// \relatesalso vgl_box_2d
template <class T>
inline bool vgl_intersection(vgl_point_2d<T> const& p, vgl_box_2d<T> const& b)
{ return b.contains(p); }

//: Return true if the point lies inside the box
// \relatesalso vgl_point_3d
// \relatesalso vgl_box_3d
template <class T>
inline bool vgl_intersection(vgl_box_3d<T> const& b, vgl_point_3d<T> const& p)
{ return b.contains(p); }

//: Return true if the point lies inside the box
// \relatesalso vgl_point_3d
// \relatesalso vgl_box_3d
template <class T>
inline bool vgl_intersection(vgl_point_3d<T> const& p, vgl_box_3d<T> const& b)
{ return b.contains(p); }

//: Return true if line intersects box. If so, compute intersection points.
// \relatesalso vgl_infinite_line_3d
template <class T>
bool vgl_intersection(vgl_box_3d<T> const& box,
                      vgl_infinite_line_3d<T> const& line,
                      vgl_point_3d<T>& p0,
                      vgl_point_3d<T>& p1);
//: Return true if ray intersects box. If so, compute intersection points.
// If ray origin is inside box then p0==p1
// \relatesalso vgl_ray_3d
template <class T>
bool vgl_intersection(vgl_box_3d<T> const& box,
                      vgl_ray_3d<T> const& ray,
                      vgl_point_3d<T>& p0,
                      vgl_point_3d<T>& p1);
//: Return true if a box and plane intersect in 3D
// \relatesalso vgl_plane_3d
// \relatesalso vgl_box_3d
template <class T>
bool vgl_intersection(vgl_box_3d<T> const& b, vgl_plane_3d<T> const& plane);


//: Return the intersection of two boxes (which is itself either a box, or empty)
// \relatesalso vgl_box_2d
template <class T>
vgl_box_2d<T> vgl_intersection(vgl_box_2d<T> const&,vgl_box_2d<T> const&);

//: Return the intersection of two boxes (which is itself either a box, or empty)
// \relatesalso vgl_box_3d
template <class T>
vgl_box_3d<T> vgl_intersection(vgl_box_3d<T> const&,vgl_box_3d<T> const&);

//: Return true if the box and polygon regions intersect, regions include boundaries
// \relatesalso vgl_polygon
// \relatesalso vgl_box_2d
template <class T>
bool vgl_intersection(vgl_box_2d<T> const& b, vgl_polygon<T> const& poly);

//: Return the points from the list that lie inside the box
// \relatesalso vgl_point_2d
// \relatesalso vgl_box_2d
template <class T>
vcl_vector<vgl_point_2d<T> > vgl_intersection(vgl_box_2d<T> const& b, vcl_vector<vgl_point_2d<T> > const& p);

//: Return the points from the list that lie inside the box
// \relatesalso vgl_point_2d
// \relatesalso vgl_box_2d
template <class T>
vcl_vector<vgl_point_2d<T> > vgl_intersection(vcl_vector<vgl_point_2d<T> > const& p, vgl_box_2d<T> const& b);

//: Return the points from the list that lie inside the box
// \relatesalso vgl_point_3d
// \relatesalso vgl_box_3d
template <class T>
vcl_vector<vgl_point_3d<T> > vgl_intersection(vgl_box_3d<T> const& b, vcl_vector<vgl_point_3d<T> > const& p);

//: Return the points from the list that lie inside the box
// \relatesalso vgl_point_3d
// \relatesalso vgl_box_3d
template <class T>
vcl_vector<vgl_point_3d<T> > vgl_intersection(vcl_vector<vgl_point_3d<T> > const& p, vgl_box_3d<T> const& b);


#define VGL_INTERSECTION_INSTANTIATE(T) extern "please include vgl/vgl_intersection.txx first"
#define VGL_INTERSECTION_BOX_INSTANTIATE(T) extern "please include vgl/vgl_intersection.txx first"

#endif // vgl_intersection_h_
