//#####################################################################
// Copyright 2009, Jon Gretarsson.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Namespace SIGNED_DISTANCE
//##################################################################### 
#include <Core/Grids_Uniform_Computations/TRIANGULATED_SURFACE_SIGNED_DISTANCE_UNIFORM.h>
#include <Core/Grids/NODE_ITERATOR.h>
#include <Core/Level_Sets/LEVELSET.h>
#include <Core/Log/LOG.h>
#include <Core/Math_Tools/RANGE.h>
#include <Core/Meshes/TRIANGULATED_SURFACE.h>
#include <Core/Spatial_Acceleration/MESH_HIERARCHY.h>
namespace PhysBAM{

namespace SIGNED_DISTANCE{
//#####################################################################
// Function Calculate
//#####################################################################
template<class T> void Calculate(TRIANGULATED_SURFACE<T>& surface,const GRID<VECTOR<T,3> >& grid,AT_NODES,ARRAY<T,VECTOR<int,3> >& phi,bool print_progress)
{
    // initialize acceleration structures
    bool triangle_list_defined=surface.triangle_list!=0;
    if(!triangle_list_defined) surface.Update_Triangle_List();
    bool hierarchy_defined=surface.hierarchy!=0;
    if(!hierarchy_defined) surface.Initialize_Hierarchy(true);
    bool bounding_box_defined=surface.bounding_box!=0;
    if(!bounding_box_defined) surface.Update_Bounding_Box();
    bool adjacent_elements_defined=surface.mesh.adjacent_elements!=0;
    if(!adjacent_elements_defined) surface.mesh.Initialize_Adjacent_Elements();
    bool incident_elements_defined=surface.mesh.incident_elements!=0;
    if(!incident_elements_defined) surface.mesh.Initialize_Incident_Elements();

    // ensure the phi array size matches the grid
    phi.Resize(grid.Node_Indices(),no_init);

    T epsilon=(T)1e-8*grid.dX.Min();
    int total_cells=grid.Numbers_Of_Nodes().x*grid.Numbers_Of_Nodes().y*grid.Numbers_Of_Nodes().z,cells_done=0,progress=-1;
    for(RANGE_ITERATOR<3> it(grid.Node_Indices());it.Valid();it.Next()){
        phi(it.index)=surface.Calculate_Signed_Distance(grid.Node_X(it.index),epsilon);
        if(print_progress){
            cells_done++;int new_progress=(int)((T)100*cells_done/total_cells);
            if(new_progress > progress){
                LOG::cout<<new_progress<<"% "<<std::flush;
                progress=new_progress;}}}
    if(print_progress) LOG::cout<<std::endl;

    // delete acceleration structures if defined in this function
    if(!incident_elements_defined){delete surface.mesh.incident_elements;surface.mesh.incident_elements=0;}
    if(!adjacent_elements_defined){delete surface.mesh.adjacent_elements;surface.mesh.adjacent_elements=0;}
    if(!bounding_box_defined){delete surface.bounding_box;surface.bounding_box=0;}
    if(!hierarchy_defined){delete surface.hierarchy;surface.hierarchy=0;}
    if(!triangle_list_defined){delete surface.triangle_list;surface.triangle_list=0;}

}
//##################################################################### 
template void Calculate(TRIANGULATED_SURFACE<float>&,const GRID<VECTOR<float,3> >&,AT_NODES,ARRAY<float,VECTOR<int,3> >&,bool);
template void Calculate(TRIANGULATED_SURFACE<double>&,const GRID<VECTOR<double,3> >&,AT_NODES,ARRAY<double,VECTOR<int,3> >&,bool);
}
}
