//#####################################################################
// Copyright 2011.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class SMOOTH_GEAR
//##################################################################### 
#ifndef __SMOOTH_GEAR__
#define __SMOOTH_GEAR__

#include <Core/Basic_Geometry/TRANSFORMED_OBJECT.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Meshes/MESHES_FORWARD.h>
#include <Core/Vectors/VECTOR.h>
namespace PhysBAM{

template<class TV> class SMOOTH_GEAR;

template<class T>
class SMOOTH_GEAR<VECTOR<T,2> >
{
    typedef VECTOR<T,2> TV;
public:
    typedef TV VECTOR_T;

    T r,s,co,ci,den;
    int n;
    TV Co,Ci;

    SMOOTH_GEAR(T R=1,T S=.4,int N=8);
    SMOOTH_GEAR(const TV& dimensions,int N=8);

    struct HELPER
    {
        T a,d,k,b,m,sd;
        bool flip,ui;
        TV Y,dY,P;
    };

//#####################################################################
    void Compute_Centers();
    void Compute_Helper(const TV& X,HELPER& h) const;
    RANGE<TV> Bounding_Box() const;
    T Signed_Distance(const TV& X) const;
    TV Surface(const TV& X) const;
    TV Surface(const TV& X,const HELPER& h) const;
    TV Normal(const TV& X) const;
    TV Normal(const TV& X,const HELPER& h) const;
    TV Normal(const TV& X,const int aggregate) const;
    SYMMETRIC_MATRIX<T,2> Hessian(const TV& X) const;
    bool Lazy_Inside(const TV& X) const;
    bool Lazy_Outside(const TV& X) const;
    bool Inside(const TV& X,const T thickness_over_two=0) const;
    bool Outside(const TV& X,const T thickness_over_two=0) const;
    bool Boundary(const TV& X,const T thickness_over_two) const;
    static std::string Name();
    template<class RW> void Read(UNTYPED_ISTREAM<RW>& input);
    template<class RW> void Write(UNTYPED_OSTREAM<RW>& output) const;
//#####################################################################
};   

template<class T>
class SMOOTH_GEAR<VECTOR<T,3> >
{
    typedef VECTOR<T,3> TV;
public:
    typedef TV VECTOR_T;typedef SMOOTH_GEAR<VECTOR<T,2> > GEAR;

    GEAR g;
    T w;

    SMOOTH_GEAR(T R=1,T S=.4,int N=8,T W=1);
    SMOOTH_GEAR(const TV& dimensions,int N=8);

//#####################################################################
    RANGE<TV> Bounding_Box() const;
    T Signed_Distance(const TV& X) const;
    TV Surface(const TV& X) const;
    TV Normal(const TV& X) const;
    TV Normal(const TV& X,const int aggregate) const;
    SYMMETRIC_MATRIX<T,3> Hessian(const TV& X) const;
    bool Lazy_Inside(const TV& X) const;
    bool Lazy_Outside(const TV& X) const;
    bool Inside(const TV& X,const T thickness_over_two=0) const;
    bool Outside(const TV& X,const T thickness_over_two=0) const;
    bool Boundary(const TV& X,const T thickness_over_two) const;
    static std::string Name();
    template<class RW> void Read(UNTYPED_ISTREAM<RW>& input);
    template<class RW> void Write(UNTYPED_OSTREAM<RW>& output) const;
//#####################################################################
};
template<class T> void Boundary_Points(ARRAY<VECTOR<T,2> >& pts,const SMOOTH_GEAR<VECTOR<T,2> >& gear,int n=4);
template<class T> TRIANGULATED_SURFACE<T>* Generate_Triangles(const SMOOTH_GEAR<VECTOR<T,3> >& gear,int n=4);
template<class T> TRIANGULATED_AREA<T>* Generate_Triangles(const SMOOTH_GEAR<VECTOR<T,2> >& gear,int n=4);
template<class T> TRIANGULATED_SURFACE<T>* Tessellate_Boundary(const SMOOTH_GEAR<VECTOR<T,3> >& gear,int n=4)
{return Generate_Triangles(gear,n=4);}
template<class T> SEGMENTED_CURVE<VECTOR<T,2> >* Tessellate_Boundary(const SMOOTH_GEAR<VECTOR<T,2> >& gear,int n=4);
template<class T,class TV> TRANSFORMED_OBJECT<TV,SMOOTH_GEAR<TV> > Scaled(const SMOOTH_GEAR<TV>& b,const VECTOR<T,2>& center,T scale);
template<class T,class TV> TRANSFORMED_OBJECT<TV,SMOOTH_GEAR<TV> > Scaled(const SMOOTH_GEAR<TV>& b,const VECTOR<T,3>& center,T scale);
template<class TV> TRANSFORMED_OBJECT<TV,SMOOTH_GEAR<TV> > Transformed(const SMOOTH_GEAR<TV>& b,const FRAME<TV>& f)
{return {b,f};}
template<class TV> class RAY;
template<class TV> class RAY_HIT;

template<class T> RAY_HIT<T> Intersects(const RAY<VECTOR<T,2> >& ray,const SMOOTH_GEAR<VECTOR<T,2> >& gear,T isocontour=0);
template<class TV,class T> void
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,const SMOOTH_GEAR<VECTOR<T,2> >& gear,const T isocontour=0);
template<class T> RAY_HIT<T> Intersects(const RAY<VECTOR<T,3> >& ray,const SMOOTH_GEAR<VECTOR<T,3> >& gear,T isocontour=0);
template<class TV,class T> void
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,const SMOOTH_GEAR<VECTOR<T,3> >& gear,const T isocontour=0);
}
#endif
