/*=========================================================================
*
*  Copyright NumFOCUS
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0.txt
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language governing permissions and
*  limitations under the License.
*
*=========================================================================*/
#ifndef sitkScalarChanAndVeseDenseLevelSetImageFilter_h
#define sitkScalarChanAndVeseDenseLevelSetImageFilter_h

/*
 * WARNING: DO NOT EDIT THIS FILE!
 * THIS FILE IS AUTOMATICALLY GENERATED BY THE SIMPLEITK BUILD PROCESS.
 * Please look at sitkImageFilterTemplate.h.in to make changes.
 */

#include <memory>

#include "sitkBasicFilters.h"
#include "sitkImageFilter.h"

namespace itk::simple {

    /**\class ScalarChanAndVeseDenseLevelSetImageFilter
\brief Dense implementation of the Chan and Vese multiphase level set image filter.

This code was adapted from the paper: "An active contour model without edges"
 T. Chan and L. Vese.
 In Scale-Space Theories in Computer Vision, pages 141-151, 1999.
 \author Mosaliganti K., Smith B., Gelas A., Gouaillard A., Megason S.


This code was taken from the Insight Journal paper: "Cell Tracking using Coupled Active Surfaces for Nuclei and Membranes"
https://doi.org/10.54294/wvwmf8
 That is based on the papers: "Level Set Segmentation: Active Contours without edge"
https://doi.org/10.54294/8jk6oy

and

"Level set segmentation using coupled active surfaces"
https://doi.org/10.54294/23ugmy
\sa itk::simple::ScalarChanAndVeseDenseLevelSet for the procedural interface
\sa itk::ScalarChanAndVeseDenseLevelSetImageFilter for the Doxygen on the original ITK class.
     */
    class SITKBasicFilters_EXPORT ScalarChanAndVeseDenseLevelSetImageFilter : public ImageFilter {
    public:
      using Self = ScalarChanAndVeseDenseLevelSetImageFilter;

      /** Destructor */
      virtual ~ScalarChanAndVeseDenseLevelSetImageFilter();

      /** Default Constructor that takes no arguments and initializes
       * default parameters */
      ScalarChanAndVeseDenseLevelSetImageFilter();

      /** Define the pixels types supported by this filter */
      using PixelIDTypeList = RealPixelIDTypeList;
\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetMaximumRMSError ( double MaximumRMSError ) { this->m_MaximumRMSError = MaximumRMSError; return *this; }

      /**
       */
      double GetMaximumRMSError() const { return this->m_MaximumRMSError; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetNumberOfIterations ( uint32_t NumberOfIterations ) { this->m_NumberOfIterations = NumberOfIterations; return *this; }

      /**
       */
      uint32_t GetNumberOfIterations() const { return this->m_NumberOfIterations; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetLambda1 ( double Lambda1 ) { this->m_Lambda1 = Lambda1; return *this; }

      /**
       */
      double GetLambda1() const { return this->m_Lambda1; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetLambda2 ( double Lambda2 ) { this->m_Lambda2 = Lambda2; return *this; }

      /**
       */
      double GetLambda2() const { return this->m_Lambda2; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetEpsilon ( double Epsilon ) { this->m_Epsilon = Epsilon; return *this; }

      /**
       */
      double GetEpsilon() const { return this->m_Epsilon; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetCurvatureWeight ( double CurvatureWeight ) { this->m_CurvatureWeight = CurvatureWeight; return *this; }

      /**
       */
      double GetCurvatureWeight() const { return this->m_CurvatureWeight; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetAreaWeight ( double AreaWeight ) { this->m_AreaWeight = AreaWeight; return *this; }

      /**
       */
      double GetAreaWeight() const { return this->m_AreaWeight; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetReinitializationSmoothingWeight ( double ReinitializationSmoothingWeight ) { this->m_ReinitializationSmoothingWeight = ReinitializationSmoothingWeight; return *this; }

      /**
       */
      double GetReinitializationSmoothingWeight() const { return this->m_ReinitializationSmoothingWeight; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetVolume ( double Volume ) { this->m_Volume = Volume; return *this; }

      /**
       */
      double GetVolume() const { return this->m_Volume; }\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetVolumeMatchingWeight ( double VolumeMatchingWeight ) { this->m_VolumeMatchingWeight = VolumeMatchingWeight; return *this; }

      /**
       */
      double GetVolumeMatchingWeight() const { return this->m_VolumeMatchingWeight; }

      typedef enum {AtanRegularizedHeaviside,SinRegularizedHeaviside,Heaviside} HeavisideStepFunctionType;\

      /**
       */
      SITK_RETURN_SELF_TYPE_HEADER SetHeavisideStepFunction ( HeavisideStepFunctionType HeavisideStepFunction ) { this->m_HeavisideStepFunction = HeavisideStepFunction; return *this; }

      /**
       */
      HeavisideStepFunctionType GetHeavisideStepFunction() const { return this->m_HeavisideStepFunction; }\

      /**
       * Use the image spacing information in calculations. Use this option if you want derivatives in physical space. Default is UseImageSpacingOn.

       */
      SITK_RETURN_SELF_TYPE_HEADER SetUseImageSpacing ( bool UseImageSpacing ) { this->m_UseImageSpacing = UseImageSpacing; return *this; }

      /** Set the value of UseImageSpacing to true or false respectfully. */
      SITK_RETURN_SELF_TYPE_HEADER UseImageSpacingOn() { return this->SetUseImageSpacing(true); }
      SITK_RETURN_SELF_TYPE_HEADER UseImageSpacingOff() { return this->SetUseImageSpacing(false); }

      /**
       * Use the image spacing information in calculations. Use this option if you want derivatives in physical space. Default is UseImageSpacingOn.

       */
      bool GetUseImageSpacing() const { return this->m_UseImageSpacing; }
     /** \brief Number of iterations run.
      *
      *
      * This is a measurement. Its value is updated in the Execute
      * methods, so the value will only be valid after an execution.
      */
     uint32_t GetElapsedIterations() const { return this->m_ElapsedIterations; };

     /** \brief The Root Mean Square of the levelset upon termination.
      *
      *
      * This is a measurement. Its value is updated in the Execute
      * methods, so the value will only be valid after an execution.
      */
     double GetRMSChange() const { return this->m_RMSChange; };


      /** Name of this class */
      std::string GetName() const { return std::string ("ScalarChanAndVeseDenseLevelSetImageFilter"); }

      /** Print ourselves out */
      std::string ToString() const;


      /** Execute the filter on the input image */

      Image Execute ( const Image & initialImage, const Image & featureImage );

    private:

      /** Setup for member function dispatching */

      using MemberFunctionType = Image (Self::*)( const Image * initialImage, const Image * featureImage );
      template <class TImageType> Image ExecuteInternal ( const Image * initialImage, const Image * featureImage );


      friend struct detail::MemberFunctionAddressor<MemberFunctionType>;

      std::unique_ptr<detail::MemberFunctionFactory<MemberFunctionType> > m_MemberFactory;


      /* Value of RMS change below which the filter should stop. This is a convergence criterion. */
      double  m_MaximumRMSError{0.02};

      /* Number of iterations to run */
      uint32_t  m_NumberOfIterations{1000u};

      /* Lambda1. Internal intensity difference weight */
      double  m_Lambda1{1.0};

      /* Lambda2. External intensity difference weight */
      double  m_Lambda2{1.0};

      /* Width of regularization of Heaviside function. */
      double  m_Epsilon{1.0};

      /* Gamma. Scales all curvature weight values  */
      double  m_CurvatureWeight{1.0};

      /* Nu. Area regularization values */
      double  m_AreaWeight{0.0};

      /* Weight of the laplacian smoothing term */
      double  m_ReinitializationSmoothingWeight{0.0};

      /*  Pixel Volume = Number of pixels inside the level-set */
      double  m_Volume{0.0};

      /* Volume matching weight. */
      double  m_VolumeMatchingWeight{0.0};

      /* Step functions */
      HeavisideStepFunctionType  m_HeavisideStepFunction{itk::simple::ScalarChanAndVeseDenseLevelSetImageFilter::AtanRegularizedHeaviside};

      bool  m_UseImageSpacing{true};


      uint32_t m_ElapsedIterations{0};

      double m_RMSChange{0.0};


    };

    /**\
     * \brief Dense implementation of the Chan and Vese multiphase level set image filter.
     *
     * This function directly calls the execute method of ScalarChanAndVeseDenseLevelSetImageFilter
     * in order to support a procedural API
     *
     * \sa itk::simple::ScalarChanAndVeseDenseLevelSetImageFilter for the object oriented interface
     * @{
     */

     SITKBasicFilters_EXPORT Image ScalarChanAndVeseDenseLevelSet ( const Image & initialImage, const Image & featureImage, double maximumRMSError = 0.02, uint32_t numberOfIterations = 1000u, double lambda1 = 1.0, double lambda2 = 1.0, double epsilon = 1.0, double curvatureWeight = 1.0, double areaWeight = 0.0, double reinitializationSmoothingWeight = 0.0, double volume = 0.0, double volumeMatchingWeight = 0.0, ScalarChanAndVeseDenseLevelSetImageFilter::HeavisideStepFunctionType heavisideStepFunction = itk::simple::ScalarChanAndVeseDenseLevelSetImageFilter::AtanRegularizedHeaviside, bool useImageSpacing = true );

     /** @} */
}
#endif
