//#####################################################################
// Copyright 2011, Alexey Stomakhin.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class BOWL
//##################################################################### 
#include <Core/Basic_Geometry/BOWL.h>
#include <Core/Auto_Diff/AUTO_DIFF.h>
#include <Core/Auto_Diff/AUTO_HESS.h>
#include <Core/Basic_Geometry/CYLINDER.h>
#include <Core/Basic_Geometry/RAY_HIT.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Matrices/FRAME.h>
#include <Core/Meshes/TRIANGULATED_SURFACE.h>
#include <Core/Polynomials/QUADRATIC.h>
#include <Core/Random_Numbers/RANDOM_NUMBERS.h>
#include <Core/Read_Write/READ_WRITE.h>
#include <Core/Vectors/VECTOR.h>
namespace PhysBAM{
//#####################################################################
// Function Bounding_Box
//#####################################################################
template<class T> RANGE<VECTOR<T,3> > BOWL<T>::
Bounding_Box() const
{
    T outer_radius=inner_radius+thickness;
    return CYLINDER<T>(bottom,bottom+axis*(outer_radius),
        bottom_radius+outer_radius).Bounding_Box();
}
//#####################################################################
// Function Name
//#####################################################################
template<class T> std::string BOWL<T>::
Name()
{
    return "BOWL<T>";
}
//#####################################################################
// Function Read
//#####################################################################
template<class T> template<class RW> void BOWL<T>::
Read(UNTYPED_ISTREAM<RW>& input)
{
    Read_Binary_Group(input,bottom,axis,bottom_radius,inner_radius,thickness);
}
//#####################################################################
// Function Write
//#####################################################################
template<class T> template<class RW> void BOWL<T>::
Write(UNTYPED_OSTREAM<RW>& output) const
{
    Write_Binary_Group(output,bottom,axis,bottom_radius,inner_radius,thickness);
}
//#####################################################################
// Function Fill_Uniform
//#####################################################################
template<class T> void BOWL<T>::
Fill_Uniform(RANDOM_NUMBERS<T>& rand,const RANGE<TV>& box)
{
    CYLINDER<T> c;
    rand.Fill_Uniform(c,box);
    bottom=c.plane1.x0;
    axis=c.plane2.x0-bottom;
    T outer_radius=min(axis.Normalize(),(T).9*c.radius);
    rand.Fill_Uniform(inner_radius,0,outer_radius);
    rand.Fill_Uniform(thickness,0,outer_radius-inner_radius);
    rand.Fill_Uniform(bottom_radius,0,c.radius-(inner_radius+thickness));
}
//#####################################################################
// Function Scaled
//#####################################################################
template<class T,class TV> BOWL<T>
Scaled(const BOWL<T>& b,const TV& center,T scale)
{
    return BOWL<T>((b.bottom-center)*scale+center,
        b.axis,b.bottom_radius*scale,b.inner_radius*scale,b.thickness*scale);
}
//#####################################################################
// Function Transformed
//#####################################################################
template<class T,class TV> BOWL<T>
Transformed(const BOWL<T>& b,const FRAME<TV>& f)
{
    return BOWL<T>(f*b.bottom,f.r*b.axis,b.bottom_radius,b.inner_radius,b.thickness);
}
//#####################################################################
// Function Generate_Triangles
//#####################################################################
template<class T> TRIANGULATED_SURFACE<T>* Generate_Triangles(const BOWL<T>& b,
    const int n_radial,const int n_vertical)
{
    typedef VECTOR<T,3> TV;
    T outer_radius=b.inner_radius+b.thickness;
    TRIANGULATED_SURFACE<T>* surface=TRIANGULATED_SURFACE<T>::Create();
    int hres=2*n_vertical;
    surface->mesh.Initialize_Cylinder_Mesh(hres,n_radial);
    GEOMETRY_PARTICLES<TV>& particles=surface->particles;
    particles.Add_Elements(hres*n_radial+2);
    TV u=b.axis.Unit_Orthogonal_Vector();
    TV v=b.axis.Cross(u);
    int p=0;
    for(int j=n_vertical-1;j>=0;j--){
        T t=(T)(0.5*pi)/(n_vertical-1)*j;
        T sx=cos(t),sy=sin(t);
        for(int i=0;i<n_radial;i++){
            T t=2*pi_v<T>/n_radial*i;
            T rx=cos(t),ry=sin(t);
            particles.X(p++)=b.bottom+(outer_radius-b.inner_radius*sy)*b.axis+
                (b.bottom_radius+b.inner_radius*sx)*(rx*u+ry*v);}}
    for(int j=0;j<=n_vertical-1;j++){
        T t=(T)(0.5*pi)/(n_vertical-1)*j;
        T sx=cos(t),sy=sin(t);
        for(int i=0;i<n_radial;i++){
            T t=2*pi_v<T>/n_radial*i;
            T rx=cos(t),ry=sin(t);
            particles.X(p++)=b.bottom+(outer_radius-outer_radius*sy)*b.axis+
                (b.bottom_radius+outer_radius*sx)*(rx*u+ry*v);}}
    particles.X(p++)=b.bottom+b.thickness*b.axis;
    particles.X(p++)=b.bottom;
    PHYSBAM_ASSERT(p==particles.number);
    PHYSBAM_ASSERT(p==surface->mesh.number_nodes);
    return surface;
}
//#####################################################################
// Function Intersects
//#####################################################################
template<class T> RAY_HIT<T>
Intersects(const RAY<VECTOR<T,3> >& ray,const BOWL<T>& b,T isocontour)
{
    PHYSBAM_NOT_IMPLEMENTED();
}
//#####################################################################
// Function Intersection_Interval
//#####################################################################
template<class T> VECTOR<RAY_HIT<T>,4>
Intersection_Interval(const RAY<VECTOR<T,3> >& ray,const BOWL<T>& b,T isocontour)
{
    PHYSBAM_NOT_IMPLEMENTED();
}
//#####################################################################
// Function All_Intersections
//#####################################################################
template<class TV,class T> void
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,const BOWL<T>& b,const T isocontour)
{
    PHYSBAM_NOT_IMPLEMENTED();
}
//#####################################################################
template class BOWL<float>;
template class BOWL<double>;
template TRIANGULATED_SURFACE<float>* Generate_Triangles(const BOWL<float>&,const int,const int);
template TRIANGULATED_SURFACE<double>* Generate_Triangles(const BOWL<double>&,const int,const int);
template BOWL<double> Transformed<double,VECTOR<double,3> >(BOWL<double> const&,FRAME<VECTOR<double,3> > const&);
template BOWL<float> Transformed<float,VECTOR<float,3> >(BOWL<float> const&,FRAME<VECTOR<float,3> > const&);
template BOWL<double> Scaled<double,VECTOR<double,3> >(BOWL<double> const&,VECTOR<double,3> const&,double);
template BOWL<float> Scaled<float,VECTOR<float,3> >(BOWL<float> const&,VECTOR<float,3> const&,float);
template RAY_HIT<double> Intersects<double>(RAY<VECTOR<double,3> > const&,BOWL<double> const&,double);
template RAY_HIT<float> Intersects<float>(RAY<VECTOR<float,3> > const&,BOWL<float> const&,float);
template void All_Intersections<VECTOR<double,3>,double>(ARRAY<RAY_HIT<double>,int>&,RAY<VECTOR<double,3> > const&,BOWL<double> const&,double);
template void All_Intersections<VECTOR<float,3>,float>(ARRAY<RAY_HIT<float>,int>&,RAY<VECTOR<float,3> > const&,BOWL<float> const&,float);
template void BOWL<double>::Read(UNTYPED_ISTREAM<char>&);
template void BOWL<double>::Read(UNTYPED_ISTREAM<double>&);
template void BOWL<double>::Read(UNTYPED_ISTREAM<float>&);
template void BOWL<double>::Write(UNTYPED_OSTREAM<char>&) const;
template void BOWL<double>::Write(UNTYPED_OSTREAM<double>&) const;
template void BOWL<double>::Write(UNTYPED_OSTREAM<float>&) const;
template void BOWL<float>::Read(UNTYPED_ISTREAM<char>&);
template void BOWL<float>::Read(UNTYPED_ISTREAM<double>&);
template void BOWL<float>::Read(UNTYPED_ISTREAM<float>&);
template void BOWL<float>::Write(UNTYPED_OSTREAM<char>&) const;
template void BOWL<float>::Write(UNTYPED_OSTREAM<double>&) const;
template void BOWL<float>::Write(UNTYPED_OSTREAM<float>&) const;
}
