//#####################################################################
// Copyright 2003-2007, Zhaosheng Bao, Geoffrey Irving, Eftychios Sifakis.
// 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/LINE_2D.h>
#include <Core/Basic_Geometry/RAY.h>
#include <Core/Basic_Geometry/RAY_HIT.h>
#include <Core/Implicit_Objects/INTERSECTION_HELPERS.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Matrices/FRAME.h>
#include <Core/Meshes/SEGMENTED_CURVE.h>
#include <Core/Random_Numbers/RANDOM_NUMBERS.h>
#include <Core/Read_Write/READ_WRITE.h>
namespace PhysBAM{
//#####################################################################
// Function Segment_Line_Intersection
//#####################################################################
template<class T> bool LINE_2D<T>::
Segment_Line_Intersection(const TV& endpoint1,const TV& endpoint2,
    T& interpolation_fraction) const 
{
    T denominator=normal.Dot(endpoint2-endpoint1);
    if(!denominator){
        interpolation_fraction=FLT_MAX;
        return false;} // parallel
    interpolation_fraction=normal.Dot(x0-endpoint1)/denominator;
    return interpolation_fraction>=0 && interpolation_fraction<=1;
}
//#####################################################################
// Function Fill_Uniform
//#####################################################################
template<class T> void LINE_2D<T>::
Fill_Uniform(RANDOM_NUMBERS<T>& rand,const RANGE<TV>& box)
{
    rand.Fill_Uniform(x0,box);
    normal=rand.template Get_Direction<TV>();
}
//#####################################################################
// Function Read
//#####################################################################
template<class T> template<class RW> void LINE_2D<T>::
Read(UNTYPED_ISTREAM<RW>& input)
{
    Read_Binary_Group(input,normal,x0);
}
//#####################################################################
// Function Write
//#####################################################################
template<class T> template<class RW> void LINE_2D<T>::
Write(UNTYPED_OSTREAM<RW>& output) const
{
    Write_Binary_Group(output,normal,x0);
}
//#####################################################################
// Function Scaled
//#####################################################################
template<class T,class TV> LINE_2D<T>
Scaled(const LINE_2D<T>& b,const TV& center,T scale)
{
    return LINE_2D<T>(b.normal,(b.x0-center)*scale+center);
}
//#####################################################################
// Function Transformed
//#####################################################################
template<class T,class TV> LINE_2D<T>
Transformed(const LINE_2D<T>& b,const FRAME<TV>& f)
{
    return LINE_2D<T>(f.r.Rotate(b.normal),f*b.x0);
}
//#####################################################################
// Function Tessellate_Boundary
//#####################################################################
template<class T> SEGMENTED_CURVE<VECTOR<T,2> >*
Tessellate_Boundary(const LINE_2D<T>& line,T tesselated_size,int elements_per_side)
{
    typedef VECTOR<T,2> TV;
    SEGMENTED_CURVE<TV>* curve=SEGMENTED_CURVE<TV>::Create();
    int m=elements_per_side+1,n=elements_per_side;
    curve->mesh.Initialize_Straight_Mesh(m);
    curve->particles.Add_Elements(m);
    TV u=tesselated_size*line.normal.Orthogonal_Vector();
    for(int i=0;i<=n;i++)
        curve->particles.X(i)=line.x0+u*((T)2*i/n-1);
    curve->Update_Number_Nodes();
    return curve;
}
//#####################################################################
// Function Intersects
//#####################################################################
template<class T> RAY_HIT<T> Intersects(const RAY<VECTOR<T,2> >& ray,const LINE_2D<T>& plane,T isocontour)
{
    T distance=plane.normal.Dot(ray.endpoint-plane.x0)-isocontour;
    T rate_of_approach=-plane.normal.Dot(ray.direction);
    if(rate_of_approach*distance<=0) return {}; // no intersection
    return RAY_HIT<T>{distance/rate_of_approach};
}
//#####################################################################
// Function Intersection_Interval
//#####################################################################
template<class T> VECTOR<RAY_HIT<T>,2>
Intersection_Interval(const RAY<VECTOR<T,2> >& ray,const LINE_2D<T>& plane,T isocontour)
{
    T distance=plane.normal.Dot(ray.endpoint-plane.x0)-isocontour;
    T rate_of_approach=-plane.normal.Dot(ray.direction);
    VECTOR<RAY_HIT<T>,2> v;
    if(distance<0)
    {
        v(0).Set(0);
        if(rate_of_approach<0) v(1).Set(distance/rate_of_approach);
    }
    else if(rate_of_approach>0) v(0).Set(distance/rate_of_approach);
    return v;
}
//#####################################################################
// Function All_Intersections
//#####################################################################
template<class T> void
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<VECTOR<T,2> >& ray,const LINE_2D<T>& plane,const T isocontour)
{
    auto iv=Intersection_Interval(ray,plane,isocontour);
    hits=iv.Array_View(0,Actual_Length(iv));
}
template SEGMENTED_CURVE<VECTOR<double,2> >* Tessellate_Boundary<double>(LINE_2D<double> const&,double,int);
template SEGMENTED_CURVE<VECTOR<float,2> >* Tessellate_Boundary<float>(LINE_2D<float> const&,float,int);
template LINE_2D<double> Scaled<double,VECTOR<double,2> >(LINE_2D<double> const&,VECTOR<double,2> const&,double);
template LINE_2D<double> Transformed<double,VECTOR<double,2> >(LINE_2D<double> const&,FRAME<VECTOR<double,2> > const&);
template RAY_HIT<double> Intersects<double>(RAY<VECTOR<double,2> > const&,LINE_2D<double> const&,double);
template RAY_HIT<float> Intersects<float>(RAY<VECTOR<float,2> > const&,LINE_2D<float> const&,float);
template void All_Intersections<double>(ARRAY<RAY_HIT<double>,int>&,RAY<VECTOR<double,2> > const&,LINE_2D<double> const&,double);
template void All_Intersections<float>(ARRAY<RAY_HIT<float>,int>&,RAY<VECTOR<float,2> > const&,LINE_2D<float> const&,float);
template void LINE_2D<double>::Read(UNTYPED_ISTREAM<char>&);
template void LINE_2D<double>::Read(UNTYPED_ISTREAM<double>&);
template void LINE_2D<double>::Read(UNTYPED_ISTREAM<float>&);
template void LINE_2D<double>::Write(UNTYPED_OSTREAM<char>&) const;
template void LINE_2D<double>::Write(UNTYPED_OSTREAM<double>&) const;
template void LINE_2D<double>::Write(UNTYPED_OSTREAM<float>&) const;
template void LINE_2D<float>::Read(UNTYPED_ISTREAM<char>&);
template void LINE_2D<float>::Read(UNTYPED_ISTREAM<double>&);
template void LINE_2D<float>::Read(UNTYPED_ISTREAM<float>&);
template void LINE_2D<float>::Write(UNTYPED_OSTREAM<char>&) const;
template void LINE_2D<float>::Write(UNTYPED_OSTREAM<double>&) const;
template void LINE_2D<float>::Write(UNTYPED_OSTREAM<float>&) const;
template bool LINE_2D<double>::Segment_Line_Intersection(VECTOR<double,2> const&,VECTOR<double,2> const&,double&) const;
template bool LINE_2D<float>::Segment_Line_Intersection(VECTOR<float,2> const&,VECTOR<float,2> const&,float&) const;
template void LINE_2D<double>::Fill_Uniform(RANDOM_NUMBERS<double>&,RANGE<VECTOR<double,2> > const&);
template void LINE_2D<float>::Fill_Uniform(RANDOM_NUMBERS<float>&,RANGE<VECTOR<float,2> > const&);
template VECTOR<RAY_HIT<double>,2> Intersection_Interval<double>(RAY<VECTOR<double,2> > const&,LINE_2D<double> const&,double);
template VECTOR<RAY_HIT<float>,2> Intersection_Interval<float>(RAY<VECTOR<float,2> > const&,LINE_2D<float> const&,float);
}
