//#####################################################################
// Copyright 2002-2008, Ronald Fedkiw, Eran Guendelman, Geoffrey Irving, Sergey Koltakov, Frank Losasso, Neil Molino, Andrew Selle, Eftychios Sifakis, Rachel Weinstein.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class IMPLICIT_OBJECT
//#####################################################################
#ifndef __IMPLICIT_OBJECT__
#define __IMPLICIT_OBJECT__

#include <Core/Basic_Geometry/BASIC_GEOMETRY_FORWARD.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Meshes/MESHES_FORWARD.h>
#include <Core/Meshes/STRUCTURE.h>
namespace PhysBAM{

template<class T> class RAY_HIT;
template<class TV> class RAY;

template<class TV>
class IMPLICIT_OBJECT:public STRUCTURE<TV>
{
    typedef typename TV::SCALAR T;
public:
    typedef TV VECTOR_T;

    RANGE<TV> box; // box containing the voxelized implicit surface
    bool use_secondary_interpolation;

    IMPLICIT_OBJECT();
    virtual ~IMPLICIT_OBJECT();

    void Use_Secondary_Interpolation(const bool use_secondary_interpolation_input=true)
    {use_secondary_interpolation=use_secondary_interpolation_input;}

//#####################################################################
    virtual RANGE<TV>& Box();
    virtual void Update_Box();
    virtual void Update_Minimum_Cell_Size(const int maximum_depth=0);
    virtual T Minimum_Cell_Size_Within_Box(const RANGE<TV>& box) const;
    virtual T operator()(const TV& location) const;
    virtual T Signed_Distance(const TV& location) const; // to make this class compatible with the geometry classes
    virtual T Extended_Phi(const TV& location) const;
    virtual T Phi_Secondary(const TV& location) const;
    virtual TV Normal(const TV& location,const int aggregate=-1) const;
    virtual TV Extended_Normal(const TV& location,const int aggregate=-1) const;
    virtual void Compute_Normals();
    virtual void Compute_Cell_Minimum_And_Maximum(const bool recompute_if_exists=true);
    void Rescale(const T scaling_factor) override;
    virtual void Translate(const TV& translation);
    virtual void Inflate(const T inflation_distance);
    virtual bool Inside(const TV& location,const T thickness_over_two=0) const;
    virtual bool Outside(const TV& location,const T thickness_over_two=0) const;
    virtual bool Boundary(const TV& location,const T thickness_over_two) const;
    virtual bool Lazy_Inside(const TV& location,const T contour_value=0) const;
    virtual bool Lazy_Inside_And_Value(const TV& location,T& phi_value,const T contour_value=0) const;
    virtual bool Lazy_Inside_Extended_Levelset(const TV& unclamped_X,const T contour_value=0) const;
    virtual bool Lazy_Inside_Extended_Levelset_And_Value(const TV& unclamped_X,T& phi_value,const T contour_value=0) const;
    virtual bool Lazy_Outside(const TV& location,const T contour_value=0) const;
    virtual bool Lazy_Outside_Extended_Levelset(const TV& unclamped_X,const T contour_value=0) const;
    virtual bool Lazy_Outside_Extended_Levelset_And_Value(const TV& unclamped_X,T& phi_value,const T contour_value=0) const;
    virtual RAY_HIT<T> Intersects(const RAY<TV>& ray,const T isocontour=0) const=0;
    virtual void All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,const T isocontour) const=0;
    virtual TV Closest_Point_On_Boundary(const TV& location,const T tolerance=0,const int max_iterations=1,T* distance=0) const;
    // the following only exist in 3d
    virtual SYMMETRIC_MATRIX<T,TV::m> Hessian(const TV& X) const;
    virtual T Integration_Step(const T phi) const;
    virtual T Minimum_Cell_Size() const;
    void Test_Diff(const RANGE<TV>& range,bool test_hess=true) const;
//#####################################################################
};
template<class T,int d> VECTOR<T,d-1>
Compute_Principal_Curvatures(const VECTOR<T,d>& n,const SYMMETRIC_MATRIX<T,d>& H);
template<class T> POINT_SIMPLICES_1D<T>* Generate_Triangles(const IMPLICIT_OBJECT<VECTOR<T,1> >& implicit);
template<class T> SEGMENTED_CURVE<VECTOR<T,2> >* Generate_Triangles(const IMPLICIT_OBJECT<VECTOR<T,2> >& implicit);
template<class T> TRIANGULATED_SURFACE<T>* Generate_Triangles(const IMPLICIT_OBJECT<VECTOR<T,3> >& implicit);
//#####################################################################
}
#endif
