//#####################################################################
// Copyright 2007, Michael Lentine, Andrew Selle.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYRIGHT.txt.
//#####################################################################
// Class IMPLICIT_OBJECT_COMBINED
//#####################################################################
#ifndef __IMPLICIT_OBJECT_COMBINED__
#define __IMPLICIT_OBJECT_COMBINED__

#include <Core/Basic_Geometry/BASIC_GEOMETRY_POLICY.h>
#include <Core/Basic_Geometry/ORIENTED_BOX.h>
#include <Core/Grids/GRID.h>
#include <Core/Implicit_Objects/IMPLICIT_OBJECT.h>
#include <Core/Matrices/MATRIX.h>

namespace PhysBAM{

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

template<class TV>
class IMPLICIT_OBJECT_COMBINED:public IMPLICIT_OBJECT<TV>
{
    typedef typename TV::SCALAR T;typedef VECTOR<int,TV::m> IV;
    typedef typename BASIC_GEOMETRY_POLICY<TV>::ORIENTED_BOX T_ORIENTED_BOX;
    enum WORKAROUND {d=TV::m};
public:
    typedef IMPLICIT_OBJECT<TV> BASE;
    using BASE::box;

    IMPLICIT_OBJECT<TV> *implicit_object1,*implicit_object2;
    bool owns_implicit_object1,owns_implicit_object2;
    T alpha;
    
    IMPLICIT_OBJECT_COMBINED(IMPLICIT_OBJECT<TV>* implicit_object1_input,bool owns_implicit_object1_input,IMPLICIT_OBJECT<TV>* implicit_object2_input, bool owns_implicit_object2_input)
        :implicit_object1(implicit_object1_input),implicit_object2(implicit_object2_input),owns_implicit_object1(owns_implicit_object1_input),owns_implicit_object2(owns_implicit_object2_input)
    {}

    virtual ~IMPLICIT_OBJECT_COMBINED();

    void Set_Weights(T alpha_input)
    {alpha=alpha_input;}

    T Value(const TV& location) const
    {return (1-alpha)*(*implicit_object1)(location)+alpha*(*implicit_object2)(location);}

    T Extended_Value(const TV& location) const
    {return (1-alpha)*implicit_object1->Extended_Phi(location)+alpha*implicit_object1->Extended_Phi(location);}

    void Update_Box() override;
    void Update_Minimum_Cell_Size(const int maximum_depth=0) override;
    T Minimum_Cell_Size_Within_Box(const RANGE<TV>& box) const override;
    T operator()(const TV& location) const override;
    T Signed_Distance(const TV& location) const override;
    T Extended_Phi(const TV& location) const override;
    T Phi_Secondary(const TV& location) const override;
    TV Normal(const TV& location,const int aggregate) const override;
    TV Extended_Normal(const TV& location,const int aggregate=-1) const override;
    void Compute_Normals() override;
    void Compute_Cell_Minimum_And_Maximum(const bool recompute_if_exists=true) override;
    void Rescale(const T scaling_factor) override;
    void Inflate(const T inflation_distance) override;
    bool Lazy_Inside(const TV& location,const T contour_value=0) const override;
    bool Lazy_Inside_And_Value(const TV& location,T& phi,const T contour_value=0) const override;
    bool Lazy_Inside_Extended_Levelset(const TV& location,const T contour_value=0) const override;
    bool Lazy_Inside_Extended_Levelset_And_Value(const TV& location,T& phi_value,const T contour_value=0) const override;
    bool Lazy_Outside(const TV& location,const T contour_value=0) const override;
    bool Lazy_Outside_Extended_Levelset(const TV& location,const T contour_value=0) const override;
    bool Lazy_Outside_Extended_Levelset_And_Value(const TV& location,T& phi_value,const T contour_value=0) const override;
    SYMMETRIC_MATRIX<T,TV::m> Hessian(const TV& X) const override;
    T Integration_Step(const T phi) const override;
    T Minimum_Cell_Size() const override;
    virtual void Read(TYPED_ISTREAM& input) override;
    virtual void Write(TYPED_OSTREAM& output) const override;
    RAY_HIT<T> Intersects(const RAY<TV>& ray,const T isocontour=0) const override;
    void All_Intersections(ARRAY<RAY_HIT<T> >& hits,const RAY<TV>& ray,const T isocontour=0) const override;
//#####################################################################
};
}
#endif

