//#####################################################################
// Copyright 2007-2009, Jon Gretarsson, Geoffrey Irving, Nipun Kwatra, Andrew Selle, Jonathan Su.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
#include <Core/Basic_Geometry/POINT_SIMPLEX_1D.h>
#include <Core/Basic_Geometry/RAY.h>
#include <Core/Basic_Geometry/RAY_HIT.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Read_Write/READ_WRITE.h>
namespace PhysBAM{
//#####################################################################
// Function Point_Face_Collision
//#####################################################################
template<class T> bool POINT_SIMPLEX_1D<T>::
Point_Face_Collision(const POINT_SIMPLEX_1D<T>& initial_simplex,
    const VECTOR<T,1>& x,const VECTOR<T,1>& v,const VECTOR<T,1>& v1,
    const T dt,const T collision_thickness,T& collision_time,
    VECTOR<T,1>& normal,VECTOR<T,2>& weights,const bool exit_early)
{
    weights.x=-1;
    weights.y=1;
    T distance=x.x-initial_simplex.X.x.x,relative_speed=-weights.x*v.x-weights.y*v1.x;
    if(distance*relative_speed>=0 || abs(distance)>abs(dt*relative_speed)) return false;
    collision_time=distance/relative_speed;
    if(distance>0) normal=VECTOR<T,1>(1);
    else normal=VECTOR<T,1>(-1);
    return true;
}
//#####################################################################
// Function Robust_Point_Face_Collision
//#####################################################################
template<class T> auto POINT_SIMPLEX_1D<T>::
Robust_Point_Face_Collision(const POINT_SIMPLEX_1D<T>& initial_simplex,
    const POINT_SIMPLEX_1D<T>& final_simplex,const VECTOR<T,1>& x,
    const VECTOR<T,1>& final_x,const T dt,const T collision_thickness,
    T& collision_time,VECTOR<T,1>& normal,VECTOR<T,2>& weights)
    -> POINT_SIMPLEX_COLLISION_TYPE
{
    if(final_simplex.Bounding_Box().Thickened(collision_thickness).Lazy_Inside(final_x)){
        collision_time=dt;
        return POINT_SIMPLEX_COLLISION_ENDS_INSIDE;}
    if(initial_simplex.Bounding_Box().Thickened(collision_thickness).Lazy_Inside(x)){
        collision_time=0;
        return POINT_SIMPLEX_COLLISION_ENDS_OUTSIDE;}
    VECTOR<T,1> v1=(final_simplex.X.x-initial_simplex.X.x)/dt,v=(final_x-x)/dt;
    if(Point_Face_Collision(initial_simplex,x,v,v1,dt,collision_thickness,collision_time,normal,weights,false))
        return POINT_SIMPLEX_COLLISION_ENDS_OUTSIDE;
    return POINT_SIMPLEX_NO_COLLISION;
}
//#####################################################################
// Function Read
//#####################################################################
template<class T> template<class RW> void POINT_SIMPLEX_1D<T>::
Read(UNTYPED_ISTREAM<RW>& input)
{
    Read_Binary_Group(input,direction,X.x);
}
//#####################################################################
// Function Write
//#####################################################################
template<class T> template<class RW> void POINT_SIMPLEX_1D<T>::
Write(UNTYPED_OSTREAM<RW>& output) const
{
    Write_Binary_Group(output,direction,X.x);
}
//#####################################################################
// Function Intersects
//#####################################################################
template<class T> RAY_HIT<T>
Intersects(const RAY<VECTOR<T,1> >& ray,const POINT_SIMPLEX_1D<T>& point,
    const T thickness_over_two)
{
    return Intersects(ray,RANGE<VECTOR<T,1> >(point.X.x),thickness_over_two);
}
//#####################################################################
// Function Closest_Non_Intersecting_Point
//#####################################################################
template<class T> RAY_HIT<T>
Closest_Non_Intersecting_Point(const RAY<VECTOR<T,1> >& ray,
    const POINT_SIMPLEX_1D<T>& point,const T isocontour)
{
    return Intersects(ray,RANGE<VECTOR<T,1> >(point.X.x),isocontour);
}
//#####################################################################
// Function Intersection_Interval
//#####################################################################
template<class T> VECTOR<RAY_HIT<T>,2>
Intersection_Interval(const RAY<VECTOR<T,3> >& ray,
    const POINT_SIMPLEX_1D<T>& point,T isocontour)
{
    return Intersection_Interval(ray,RANGE<VECTOR<T,1> >(point.X.x),isocontour);
}
//#####################################################################
// Function All_Intersections
//#####################################################################
template<class TV,class T> void
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,
    const POINT_SIMPLEX_1D<T>& point,const T isocontour)
{
    All_Intersections(hits,ray,RANGE<VECTOR<T,1> >(point.X.x),isocontour);
}
template class POINT_SIMPLEX_1D<float>;
template class POINT_SIMPLEX_1D<double>;
template RAY_HIT<float> Intersects(const RAY<VECTOR<float,1> >&,const POINT_SIMPLEX_1D<float>&,const float);
template RAY_HIT<float> Closest_Non_Intersecting_Point(const RAY<VECTOR<float,1> >&,const POINT_SIMPLEX_1D<float>&,const float);
template RAY_HIT<double> Intersects(const RAY<VECTOR<double,1> >&,const POINT_SIMPLEX_1D<double>&,const double);
template RAY_HIT<double> Closest_Non_Intersecting_Point(const RAY<VECTOR<double,1> >&,const POINT_SIMPLEX_1D<double>&,const double);
template void All_Intersections<VECTOR<double,1>,double>(ARRAY<RAY_HIT<double>,int>&,RAY<VECTOR<double,1> > const&,POINT_SIMPLEX_1D<double> const&,double);
template void All_Intersections<VECTOR<float,1>,float>(ARRAY<RAY_HIT<float>,int>&,RAY<VECTOR<float,1> > const&,POINT_SIMPLEX_1D<float> const&,float);
template void POINT_SIMPLEX_1D<double>::Read(UNTYPED_ISTREAM<char>&);
template void POINT_SIMPLEX_1D<double>::Read(UNTYPED_ISTREAM<double>&);
template void POINT_SIMPLEX_1D<double>::Read(UNTYPED_ISTREAM<float>&);
template void POINT_SIMPLEX_1D<double>::Write(UNTYPED_OSTREAM<char>&) const;
template void POINT_SIMPLEX_1D<double>::Write(UNTYPED_OSTREAM<double>&) const;
template void POINT_SIMPLEX_1D<double>::Write(UNTYPED_OSTREAM<float>&) const;
template void POINT_SIMPLEX_1D<float>::Read(UNTYPED_ISTREAM<char>&);
template void POINT_SIMPLEX_1D<float>::Read(UNTYPED_ISTREAM<double>&);
template void POINT_SIMPLEX_1D<float>::Read(UNTYPED_ISTREAM<float>&);
template void POINT_SIMPLEX_1D<float>::Write(UNTYPED_OSTREAM<char>&) const;
template void POINT_SIMPLEX_1D<float>::Write(UNTYPED_OSTREAM<double>&) const;
template void POINT_SIMPLEX_1D<float>::Write(UNTYPED_OSTREAM<float>&) const;
}
