text: /*=========================================================================
   *
   *  Copyright Insight Software Consortium
   *
   *  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 itkFastMarchingImageFilterBase_h
  #define itkFastMarchingImageFilterBase_h
  
  #include "itkFastMarchingBase.h"
  #include "itkImageRegionConstIteratorWithIndex.h"
  #include "itkNeighborhoodIterator.h"
  #include "itkArray.h"
  #include <bitset>
  
  namespace itk
  {
  /**
   * \class FastMarchingImageFilterBase
   * \brief Apply the Fast Marching method to solve an Eikonal equation on an image.
   *
   * The speed function can be specified as a speed image or a
   * speed constant. The speed image is set using the method
   * SetInput(). If the speed image is nullptr, a constant speed function
   * is used and is specified using method the SetSpeedConstant().
   *
   * If the speed function is constant and of value one, fast marching results
   * is an approximate distance function from the initial alive points.
   *
   * There are two ways to specify the output image information
   * (LargestPossibleRegion, Spacing, Origin):
   * \li it is copied directly from the input speed image
   * \li it is specified by the user.
   * Default values are used if the user does not specify all the information.
   *
   * The output information is computed as follows.
   *
   * If the speed image is nullptr or if the OverrideOutputInformation is set to
   * true, the output information is set from user specified parameters. These
   * parameters can be specified using methods
   * \li FastMarchingImageFilterBase::SetOutputRegion(),
   * \li FastMarchingImageFilterBase::SetOutputSpacing(),
   * \li FastMarchingImageFilterBase::SetOutputDirection(),
   * \li FastMarchingImageFilterBase::SetOutputOrigin().
   *
   * Else the output information is copied from the input speed image.
   *
   * Implementation of this class is based on Chapter 8 of
   * "Level Set Methods and Fast Marching Methods", J.A. Sethian,
   * Cambridge Press, Second edition, 1999.
   *
   * For an alternative implementation, see itk::FastMarchingImageFilter.
   *
   * \tparam TTraits traits
   *
   * \sa FastMarchingImageFilter
   * \sa ImageFastMarchingTraits
   * \sa ImageFastMarchingTraits2
   *
   * \ingroup ITKFastMarching
  */
  template< typename TInput, typename TOutput >
  class ITK_TEMPLATE_EXPORT FastMarchingImageFilterBase :
      public FastMarchingBase< TInput, TOutput >
    {
  public:
    ITK_DISALLOW_COPY_AND_ASSIGN(FastMarchingImageFilterBase);
  
    using Self = FastMarchingImageFilterBase;
    using Superclass = FastMarchingBase< TInput, TOutput >;
    using Pointer = SmartPointer< Self >;
    using ConstPointer = SmartPointer< const Self >;
    using Traits = typename Superclass::Traits;
  
    /** Method for creation through the object factory. */
    itkNewMacro(Self);
  
    /** Run-time type information (and related methods). */
    itkTypeMacro(FastMarchingImageFilterBase, FastMarchingBase);
  
  
    using InputImageType = typename Superclass::InputDomainType;
    using InputImagePointer = typename Superclass::InputDomainPointer;
    using InputPixelType = typename Superclass::InputPixelType;
  
    using OutputImageType = typename Superclass::OutputDomainType;
    using OutputImagePointer = typename Superclass::OutputDomainPointer;
    using OutputPixelType = typename Superclass::OutputPixelType;
    using OutputSpacingType = typename OutputImageType::SpacingType;
    using OutputSizeType = typename OutputImageType::SizeType;
    using OutputRegionType = typename OutputImageType::RegionType;
    using OutputPointType = typename OutputImageType::PointType;
    using OutputDirectionType = typename OutputImageType::DirectionType;
  
    using NodeType = typename Traits::NodeType;
    using NodePairType = typename Traits::NodePairType;
    using NodePairContainerType = typename Traits::NodePairContainerType;
    using NodePairContainerPointer = typename Traits::NodePairContainerPointer;
    using NodePairContainerConstIterator = typename Traits::NodePairContainerConstIterator;
  
    using LabelType = typename Superclass::LabelType;
  
    static constexpr unsigned int ImageDimension = Traits::ImageDimension;
  
  
    using LabelImageType = Image< unsigned char, ImageDimension >;
    using LabelImagePointer = typename LabelImageType::Pointer;
  
    using ConnectedComponentImageType =
        Image< unsigned int, ImageDimension >;
    using ConnectedComponentImagePointer = typename ConnectedComponentImageType::Pointer;
  
    using NeighborhoodIteratorType = NeighborhoodIterator<LabelImageType>;
    using NeighborhoodRadiusType = typename NeighborhoodIteratorType::RadiusType;
  
    class InternalNodeStructure;
  
  
    using InternalNodeStructureArray = FixedArray< InternalNodeStructure, ImageDimension >;
  
    itkGetModifiableObjectMacro(LabelImage, LabelImageType );
  
    /** The output largeset possible, spacing and origin is computed as follows.
     * If the speed image is nullptr or if the OverrideOutputInformation is true,
     * the output information is set from user specified parameters. These
     * parameters can be specified using methods SetOutputRegion(),
     * SetOutputSpacing(), SetOutputDirection(), and SetOutputOrigin().
     * Else if the speed image is not nullptr, the output information
     * is copied from the input speed image. */
    virtual void SetOutputSize(const OutputSizeType & size)
    { m_OutputRegion = size; }
    virtual OutputSizeType GetOutputSize() const
    { return m_OutputRegion.GetSize(); }
    itkSetMacro(OutputRegion, OutputRegionType);
    itkGetConstReferenceMacro(OutputRegion, OutputRegionType);
    itkSetMacro(OutputSpacing, OutputSpacingType);
    itkGetConstReferenceMacro(OutputSpacing, OutputSpacingType);
    itkSetMacro(OutputDirection, OutputDirectionType);
    itkGetConstReferenceMacro(OutputDirection, OutputDirectionType);
    itkSetMacro(OutputOrigin, OutputPointType);
    itkGetConstReferenceMacro(OutputOrigin, OutputPointType);
    itkSetMacro(OverrideOutputInformation, bool);
    itkGetConstReferenceMacro(OverrideOutputInformation, bool);
    itkBooleanMacro(OverrideOutputInformation);
  
  protected:
  
    FastMarchingImageFilterBase();
  
    ~FastMarchingImageFilterBase() override = default;
  
    void PrintSelf(std::ostream & os, Indent indent) const override;
  
    OutputRegionType  m_BufferedRegion;
    NodeType          m_StartIndex;
    NodeType          m_LastIndex;
  
    OutputRegionType    m_OutputRegion;
    OutputPointType     m_OutputOrigin;
    OutputSpacingType   m_OutputSpacing;
    OutputDirectionType m_OutputDirection;
    bool                m_OverrideOutputInformation{ false };
  
    /** Generate the output image meta information. */
    void GenerateOutputInformation() override;
  
    void EnlargeOutputRequestedRegion(DataObject *output) override;
  
    LabelImagePointer               m_LabelImage;
    ConnectedComponentImagePointer  m_ConnectedComponentImage;
  
    IdentifierType GetTotalNumberOfNodes() const override;
  
    void SetOutputValue( OutputImageType* oDomain,
                         const NodeType& iNode,
                         const OutputPixelType& iValue ) override;
  
    /** Returns the output value for a given node */
    const OutputPixelType GetOutputValue( OutputImageType* oImage,
                                    const NodeType& iNode ) const override;
  
    /** Returns the label value for a given node */
    unsigned char
    GetLabelValueForGivenNode( const NodeType& iNode ) const override;
  
    /** Set the label value for a given node */
    void SetLabelValueForGivenNode( const NodeType& iNode,
                                   const LabelType& iLabel ) override;
  
    /** Update values for the neighbors of a given node */
    void UpdateNeighbors( OutputImageType* oImage,
                                  const NodeType& iNode ) override;
  
    /** Update value for a given node */
    void UpdateValue( OutputImageType* oImage,
                              const NodeType& iValue ) override;
  
    /** Make sure the given node does not violate any topological constraint*/
    bool CheckTopology( OutputImageType* oImage,
                        const NodeType& iNode ) override;
    void InitializeOutput( OutputImageType* oImage ) override;
  
    /** Find the nodes were the front will propagate given a node */
    void GetInternalNodesUsed( OutputImageType* oImage,
                               const NodeType& iNode,
                               InternalNodeStructureArray& ioNodesUsed );
  
    /** Solve the quadratic equation */
    double Solve( OutputImageType* oImage,
                 const NodeType& iNode,
                 InternalNodeStructureArray& ioNeighbors ) const;
  
    //
    // Functions and variables to check for topology changes (2D/3D only).
    //
  
    // Functions/data for the 2-D case
    void InitializeIndices2D();
    bool IsChangeWellComposed2D( const NodeType& ) const;
    bool IsCriticalC1Configuration2D( const std::bitset<9>& ) const;
    bool IsCriticalC2Configuration2D( const std::bitset<9>& ) const;
    bool IsCriticalC3Configuration2D( const std::bitset<9>& ) const;
    bool IsCriticalC4Configuration2D( const std::bitset<9>& ) const;
  
    Array<unsigned char>  m_RotationIndices[4];
    Array<unsigned char>  m_ReflectionIndices[2];
  
    // Functions/data for the 3-D case
    void InitializeIndices3D();
    bool IsCriticalC1Configuration3D( const std::bitset<8>& ) const;
    unsigned int IsCriticalC2Configuration3D( const std::bitset<8>& ) const;
    bool IsChangeWellComposed3D( const NodeType& ) const;
  
    Array<unsigned char>                        m_C1Indices[12];
    Array<unsigned char>                        m_C2Indices[8];
  
    // Functions for both 2D/3D cases
    bool DoesVoxelChangeViolateWellComposedness( const NodeType& ) const;
    bool DoesVoxelChangeViolateStrictTopology( const NodeType& ) const;
  
    const InputImageType* m_InputCache;
  
  private:
  
  };
  } // end namespace itk
  
  #ifndef ITK_MANUAL_INSTANTIATION
  #include "itkFastMarchingImageFilterBase.hxx"
  #endif
  
  #endif // itkFastMarchingImageFilterBase_h
  