//#####################################################################
// Copyright 2015, Andre Pradhana, Chenfanfu Jiang.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class POISSON_DISK
//#####################################################################
#ifndef __POISSON_DISK__
#define __POISSON_DISK__
#include <Core/Math_Tools/RANGE.h>
#include <Core/Vectors/VECTOR.h>
namespace PhysBAM{
template<class TV> class GRID;
template<class TV> class IMPLICIT_OBJECT;
template<class TV> class RANDOM_NUMBERS;

template<class TV>
class POISSON_DISK
{
    typedef typename TV::SCALAR T;
    typedef VECTOR<int,TV::m> IV;

    VECTOR<bool,TV::m> need_periodic;
    RANGE<TV> wrap_zone;
    T min_distance;
    T h;

public:
    int max_attempts;
    RANGE<TV> periodic_boundary=RANGE<TV>::Unit_Box();
    VECTOR<bool,TV::m> is_periodic;

    POISSON_DISK(T min_distance,int max_attempts=30);
    ~POISSON_DISK();
    void Sample(RANDOM_NUMBERS<T>& random,IMPLICIT_OBJECT<TV>& object,ARRAY<TV>& X,T contour=0,bool threaded=false);
    void Sample(RANDOM_NUMBERS<T>& random,const RANGE<TV>& box,ARRAY<TV>& X,bool threaded=false);
    void Set_Distance_By_Volume(T volume_per_sample);
    void Set_Min_Distance(T min_dist);
    T Min_Distance() const {return min_distance;}
private:
    TV Generate_Random_Point_Around_Annulus(RANDOM_NUMBERS<T>& random,const TV& center) const;
    bool Check_Distance(const GRID<TV>& grid,ARRAY<int,IV>& grid_array,const TV& point,ARRAY<TV>& X) const;
    void Insert_In_Array(ARRAY<int,IV>& a,const GRID<TV>& grid,const TV& X,int index);
    void Sample_Raw(RANDOM_NUMBERS<T>& random,const RANGE<TV>& box,ARRAY<TV>& X);
    void Sample_Raw_Threaded(RANDOM_NUMBERS<T>& random,const RANGE<TV>& box,ARRAY<TV>& X);
    void Make_Samples_Periodic(ARRAY<TV>& X);
//#####################################################################
};

}
#endif
