//#####################################################################
// Copyright 2006-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.
//#####################################################################
// Class SMOOTH_LEVELSET_IMPLICIT_OBJECT
//#####################################################################
#include <Core/Implicit_Objects/SMOOTH_LEVELSET_IMPLICIT_OBJECT.h>
#include <Core/Level_Sets/LEVELSET.h>
#include <Core/Matrices/MATRIX.h>
#include <Core/Matrices/SYMMETRIC_MATRIX.h>
#include <Core/Registry/STRUCTURE_REGISTRY.h>
using namespace PhysBAM;
//#####################################################################
// Constructor
//#####################################################################
template<class TV> SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
SMOOTH_LEVELSET_IMPLICIT_OBJECT(const GRID<TV>& grid_input,ARRAY<T,IV>& phi_input)
    :BASE(grid_input,at_nodes,phi_input)
{
}
//#####################################################################
// Destructor
//#####################################################################
template<class TV> SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
~SMOOTH_LEVELSET_IMPLICIT_OBJECT()
{
}
//#####################################################################
// Function Create
//#####################################################################
template<class TV> SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>* SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Create()
{
    SMOOTH_LEVELSET_IMPLICIT_OBJECT* levelset_implicit_object=new SMOOTH_LEVELSET_IMPLICIT_OBJECT(GRID<TV>(),*new ARRAY<T,IV>);
    levelset_implicit_object->need_destroy_data=true;
    return levelset_implicit_object;
}
//#####################################################################
// Function Normal
//#####################################################################
template<class TV> TV SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Normal(const TV& location,const int aggregate) const
{
    return levelset.interpolation->Gradient_Node(levelset.Reg_Grid(),levelset.phi,location);
}
//#####################################################################
// Function Extended_Normal
//#####################################################################
template<class TV> TV SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Extended_Normal(const TV& location,const int aggregate) const
{
    TV clamped_location(levelset.Reg_Grid().domain.Clamp(location));
    TV diff=location-clamped_location;
    T magnitude_squared=diff.Magnitude_Squared();
    TV phi_value_grad=levelset.interpolation->Gradient_Node(levelset.Reg_Grid(),levelset.phi,clamped_location);
    if(!magnitude_squared) return phi_value_grad;
    T phi_value=levelset.interpolation->Interpolate_Node(levelset.Reg_Grid(),levelset.phi,clamped_location);
    if(phi_value<=0) diff.Normalized();
    for(int i=0;i<TV::m;i++) if(diff(i)) phi_value_grad(i)=0;
    T r=sqrt(magnitude_squared+sqr(phi_value));
    return (diff+phi_value*phi_value_grad)/r;
}
//#####################################################################
// Function Compute_Normals
//#####################################################################
template<class TV> void SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Compute_Normals()
{
    PHYSBAM_FATAL_ERROR();
}
//#####################################################################
// Function Hessian
//#####################################################################
template<class TV> SYMMETRIC_MATRIX<typename TV::SCALAR,TV::m> SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Hessian(const TV& X) const
{
    return levelset.interpolation->Hessian_Node(levelset.Reg_Grid(),levelset.phi,X);
}
//#####################################################################
// Function Name
//#####################################################################
template<class TV> std::string SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Static_Name()
{
    return LOG::sprintf("SMOOTH_LEVELSET_IMPLICIT_OBJECT<T,VECTOR<T,%d>,%d>",TV::m,0);
}
//#####################################################################
// Function Extension
//#####################################################################
template<class TV> std::string SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Static_Extension()
{
    return 0?(TV::m==2?"phi2d_mac":"phi_mac"):(TV::m==2?"phi2d":"phi");
}
//#####################################################################
// Function Name
//#####################################################################
template<class TV> std::string SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Name() const
{
    return Static_Name();
}
//#####################################################################
// Function Extension
//#####################################################################
template<class TV> std::string SMOOTH_LEVELSET_IMPLICIT_OBJECT<TV>::
Extension() const
{
    return Static_Extension();
}
//#####################################################################
namespace PhysBAM{
template class SMOOTH_LEVELSET_IMPLICIT_OBJECT<VECTOR<float,1> >;
template class SMOOTH_LEVELSET_IMPLICIT_OBJECT<VECTOR<float,2> >;
template class SMOOTH_LEVELSET_IMPLICIT_OBJECT<VECTOR<float,3> >;
template class SMOOTH_LEVELSET_IMPLICIT_OBJECT<VECTOR<double,1> >;
template class SMOOTH_LEVELSET_IMPLICIT_OBJECT<VECTOR<double,2> >;
template class SMOOTH_LEVELSET_IMPLICIT_OBJECT<VECTOR<double,3> >;
}
