//#####################################################################
// Copyright 2007, Geoffrey Irving, Andrew Selle.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
#include <Core/Implicit_Objects/ANALYTIC_IMPLICIT_OBJECT.h>
#include <Core/Basic_Geometry/BOUNDED_HORIZONTAL_PLANE.h>
#include <Core/Basic_Geometry/BOWL.h>
#include <Core/Basic_Geometry/CONE.h>
#include <Core/Basic_Geometry/CYLINDER.h>
#include <Core/Basic_Geometry/HOURGLASS.h>
#include <Core/Basic_Geometry/LINE_2D.h>
#include <Core/Basic_Geometry/ORIENTED_BOX.h>
#include <Core/Basic_Geometry/POINT_SIMPLEX_1D.h>
#include <Core/Basic_Geometry/RAY.h>
#include <Core/Basic_Geometry/RAY_HIT.h>
#include <Core/Basic_Geometry/RING.h>
#include <Core/Basic_Geometry/SMOOTH_GEAR.h>
#include <Core/Basic_Geometry/SPHERE.h>
#include <Core/Basic_Geometry/TORUS.h>
#include <Core/Implicit_Objects/IMPLICIT_OBJECT.h>
#include <Core/Read_Write/READ_WRITE.h>
namespace PhysBAM{
//#####################################################################
// Constructor
//#####################################################################
template<class T_ANALYTIC> ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
ANALYTIC_IMPLICIT_OBJECT(const T_ANALYTIC& analytic_input)
    :analytic(analytic_input),cell_size(0)
{
    Update_Box();
}
//#####################################################################
// Destructor
//#####################################################################
template<class T_ANALYTIC> ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
~ANALYTIC_IMPLICIT_OBJECT()
{
}
//#####################################################################
// Function Create
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Create() -> ANALYTIC_IMPLICIT_OBJECT*
{
    return new ANALYTIC_IMPLICIT_OBJECT(T_ANALYTIC());
}
//#####################################################################
// Function Update_Box
//#####################################################################
template<class T_ANALYTIC> void ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Update_Box()
{
    box=analytic.Bounding_Box();
}
//#####################################################################
// Function Update_Minimum_Cell_Size
//#####################################################################
template<class T_ANALYTIC> void ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Update_Minimum_Cell_Size(const int maximum_depth)
{
}
//#####################################################################
// Function operator
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
operator()(const TV& location) const -> T
{
    return analytic.Signed_Distance(location);
}
//#####################################################################
// Function Extended_Phi
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Extended_Phi(const TV& location) const -> T
{
    return analytic.Signed_Distance(location);
}
//#####################################################################
// Function Normal
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Normal(const TV& location,const int aggregate) const -> TV
{
    return analytic.Normal(location);
}
//#####################################################################
// Function Extended_Normal
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Extended_Normal(const TV& location,const int aggregate) const -> TV
{
    return analytic.Normal(location);
}
//#####################################################################
// Function Compute_Normals
//#####################################################################
template<class T_ANALYTIC> void ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Compute_Normals()
{
}
//#####################################################################
// Function Compute_Cell_Minimum_And_Maximum
//#####################################################################
template<class T_ANALYTIC> void ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Compute_Cell_Minimum_And_Maximum(const bool recompute_if_exists)
{
}
//#####################################################################
// Function Lazy_Inside
//#####################################################################
template<class T_ANALYTIC> bool ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Lazy_Inside(const TV& location,const T contour_value) const
{
    return box.Inside(location,-contour_value)&&analytic.Signed_Distance(location)<=contour_value;
}
//#####################################################################
// Function Lazy_Inside_And_Value
//#####################################################################
template<class T_ANALYTIC> bool ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Lazy_Inside_And_Value(const TV& location,T& phi_value,const T contour_value) const
{
    if(box.Inside(location,-contour_value)){phi_value=analytic.Signed_Distance(location);if(phi_value<=contour_value) return true;
}
    return false;}
//#####################################################################
// Function Lazy_Inside_Extended_Levelset
//#####################################################################
template<class T_ANALYTIC> bool ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Lazy_Inside_Extended_Levelset(const TV& unclamped_X,const T contour_value) const
{
    return Lazy_Inside(unclamped_X,contour_value);
}
//#####################################################################
// Function Lazy_Inside_Extended_Levelset_And_Value
//#####################################################################
template<class T_ANALYTIC> bool ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Lazy_Inside_Extended_Levelset_And_Value(const TV& unclamped_X,T& phi_value,const T contour_value) const
{
    return Lazy_Inside_And_Value(unclamped_X,phi_value,contour_value);
}
//#####################################################################
// Function Lazy_Outside
//#####################################################################
template<class T_ANALYTIC> bool ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Lazy_Outside(const TV& location,const T contour_value) const
{
    return !Lazy_Inside(location,contour_value);
}
//#####################################################################
// Function Lazy_Outside_Extended_Levelset
//#####################################################################
template<class T_ANALYTIC> bool ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Lazy_Outside_Extended_Levelset(const TV& unclamped_X,const T contour_value) const
{
    return !Lazy_Inside_Extended_Levelset(unclamped_X,contour_value);
}
//#####################################################################
// Function Lazy_Outside_Extended_Levelset_And_Value
//#####################################################################
template<class T_ANALYTIC> bool ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Lazy_Outside_Extended_Levelset_And_Value(const TV& unclamped_X,T& phi_value,const T contour_value) const
{
    return !Lazy_Inside_Extended_Levelset_And_Value(unclamped_X,phi_value,contour_value);
}
//#####################################################################
// Function Name
//#####################################################################
template<class T_ANALYTIC> std::string ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Name() const {
    return Static_Name();
}
//#####################################################################
// Function Static_Name
//#####################################################################
template<class T_ANALYTIC> std::string ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Static_Name()
{
    return LOG::sprintf("ANALYTIC_IMPLICIT_OBJECT<%s>",T_ANALYTIC::Name().c_str());
}
//#####################################################################
// Function Extension
//#####################################################################
template<class T_ANALYTIC> std::string ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Extension() const
{
    return "analytic";
}
//#####################################################################
// Function Minimum_Cell_Size_Within_Box
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Minimum_Cell_Size_Within_Box(const RANGE<TV>& box) const -> T
{
    return cell_size;
}
//#####################################################################
// Function Minimum_Cell_Size
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Minimum_Cell_Size() const -> T
{
    return cell_size;
}
//#####################################################################
// Function Hessian
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Hessian(const TV& X) const -> SYMMETRIC_MATRIX<T,TV::m>
{
    return analytic.Hessian(X);
}
//#####################################################################
// Function Read
//#####################################################################
template<class T_ANALYTIC> void ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Read(TYPED_ISTREAM& input)
{
    Read_Binary(input,analytic);
    Update_Box();
}
//#####################################################################
// Function Write
//#####################################################################
template<class T_ANALYTIC> void ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Write(TYPED_OSTREAM& output) const
{
    Write_Binary(output,analytic);
}
//#####################################################################
// Function Intersects
//#####################################################################
template<class T_ANALYTIC> auto ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
Intersects(const RAY<TV>& ray,const T isocontour) const -> RAY_HIT<T>
{
    using ::PhysBAM::Intersects; // unqualified lookup + ADL
    return Intersects(ray,analytic,isocontour);
}
//#####################################################################
// Function All_Intersections
//#####################################################################
template<class T_ANALYTIC> void ANALYTIC_IMPLICIT_OBJECT<T_ANALYTIC>::
All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,const T isocontour) const
{
    using ::PhysBAM::All_Intersections; // unqualified lookup + ADL
    All_Intersections(hits,ray,analytic,isocontour);
}
//#####################################################################

template<class OBJ>
enable_if_t<sizeof(&OBJ::Name)!=0,ANALYTIC_IMPLICIT_OBJECT<OBJ>*>
Make_IO(const OBJ& obj)
{
    return new ANALYTIC_IMPLICIT_OBJECT<OBJ>(obj);
}

template class ANALYTIC_IMPLICIT_OBJECT<BOUNDED_HORIZONTAL_PLANE<VECTOR<double,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<BOUNDED_HORIZONTAL_PLANE<VECTOR<double,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<BOUNDED_HORIZONTAL_PLANE<VECTOR<float,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<BOUNDED_HORIZONTAL_PLANE<VECTOR<float,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<BOWL<double> >;
template class ANALYTIC_IMPLICIT_OBJECT<BOWL<float> >;
template class ANALYTIC_IMPLICIT_OBJECT<CYLINDER<double> >;
template class ANALYTIC_IMPLICIT_OBJECT<CYLINDER<float> >;
template class ANALYTIC_IMPLICIT_OBJECT<LINE_2D<double> >;
template class ANALYTIC_IMPLICIT_OBJECT<LINE_2D<float> >;
template class ANALYTIC_IMPLICIT_OBJECT<ORIENTED_BOX<VECTOR<double,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<ORIENTED_BOX<VECTOR<double,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<ORIENTED_BOX<VECTOR<float,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<ORIENTED_BOX<VECTOR<float,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<PLANE<double> >;
template class ANALYTIC_IMPLICIT_OBJECT<PLANE<float> >;
template class ANALYTIC_IMPLICIT_OBJECT<POINT_SIMPLEX_1D<double> >;
template class ANALYTIC_IMPLICIT_OBJECT<POINT_SIMPLEX_1D<float> >;
template class ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<double,1> > >;
template class ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<double,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<double,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<float,1> > >;
template class ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<float,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<float,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<RING<double> >;
template class ANALYTIC_IMPLICIT_OBJECT<RING<float> >;
template class ANALYTIC_IMPLICIT_OBJECT<SMOOTH_GEAR<VECTOR<double,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<SMOOTH_GEAR<VECTOR<double,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<SMOOTH_GEAR<VECTOR<float,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<SMOOTH_GEAR<VECTOR<float,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<double,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<double,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<float,2> > >;
template class ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<float,3> > >;
template class ANALYTIC_IMPLICIT_OBJECT<TORUS<double> >;
template class ANALYTIC_IMPLICIT_OBJECT<TORUS<float> >;

template ANALYTIC_IMPLICIT_OBJECT<CONE<double> >::ANALYTIC_IMPLICIT_OBJECT(CONE<double> const&);
template ANALYTIC_IMPLICIT_OBJECT<CONE<float> >::ANALYTIC_IMPLICIT_OBJECT(CONE<float> const&);
template ANALYTIC_IMPLICIT_OBJECT<HOURGLASS<VECTOR<double,2> > >::ANALYTIC_IMPLICIT_OBJECT(HOURGLASS<VECTOR<double,2> > const&);
template ANALYTIC_IMPLICIT_OBJECT<HOURGLASS<VECTOR<double,3> > >::ANALYTIC_IMPLICIT_OBJECT(HOURGLASS<VECTOR<double,3> > const&);
template ANALYTIC_IMPLICIT_OBJECT<HOURGLASS<VECTOR<float,2> > >::ANALYTIC_IMPLICIT_OBJECT(HOURGLASS<VECTOR<float,2> > const&);
template ANALYTIC_IMPLICIT_OBJECT<HOURGLASS<VECTOR<float,3> > >::ANALYTIC_IMPLICIT_OBJECT(HOURGLASS<VECTOR<float,3> > const&);

template ANALYTIC_IMPLICIT_OBJECT<BOWL<double> >* Make_IO<BOWL<double> >(BOWL<double> const&);
template ANALYTIC_IMPLICIT_OBJECT<BOWL<float> >* Make_IO<BOWL<float> >(BOWL<float> const&);
template ANALYTIC_IMPLICIT_OBJECT<CYLINDER<double> >* Make_IO<CYLINDER<double> >(CYLINDER<double> const&);
template ANALYTIC_IMPLICIT_OBJECT<CYLINDER<float> >* Make_IO<CYLINDER<float> >(CYLINDER<float> const&);
template ANALYTIC_IMPLICIT_OBJECT<LINE_2D<double> >* Make_IO<LINE_2D<double> >(LINE_2D<double> const&);
template ANALYTIC_IMPLICIT_OBJECT<LINE_2D<float> >* Make_IO<LINE_2D<float> >(LINE_2D<float> const&);
template ANALYTIC_IMPLICIT_OBJECT<PLANE<double> >* Make_IO<PLANE<double> >(PLANE<double> const&);
template ANALYTIC_IMPLICIT_OBJECT<PLANE<float> >* Make_IO<PLANE<float> >(PLANE<float> const&);
template ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<double,2> > >* Make_IO<RANGE<VECTOR<double,2> > >(RANGE<VECTOR<double,2> > const&);
template ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<double,3> > >* Make_IO<RANGE<VECTOR<double,3> > >(RANGE<VECTOR<double,3> > const&);
template ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<float,2> > >* Make_IO<RANGE<VECTOR<float,2> > >(RANGE<VECTOR<float,2> > const&);
template ANALYTIC_IMPLICIT_OBJECT<RANGE<VECTOR<float,3> > >* Make_IO<RANGE<VECTOR<float,3> > >(RANGE<VECTOR<float,3> > const&);
template ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<double,2> > >* Make_IO<SPHERE<VECTOR<double,2> > >(SPHERE<VECTOR<double,2> > const&);
template ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<double,3> > >* Make_IO<SPHERE<VECTOR<double,3> > >(SPHERE<VECTOR<double,3> > const&);
template ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<float,2> > >* Make_IO<SPHERE<VECTOR<float,2> > >(SPHERE<VECTOR<float,2> > const&);
template ANALYTIC_IMPLICIT_OBJECT<SPHERE<VECTOR<float,3> > >* Make_IO<SPHERE<VECTOR<float,3> > >(SPHERE<VECTOR<float,3> > const&);
}
