/*========================================================================= * * 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 * * https://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 itkChainCodePath2D_h #define itkChainCodePath2D_h #include "itkChainCodePath.h" #include "itkIndex.h" #include #include namespace itk { /** * \class ChainCodePath2D * \brief Represent a 2D path as a sequence of connected image index offsets * * This class is intended to represent sequences of connected indices in a 2D * image plane. It does so by storing the offset of each index from its * immediately preceding, connected, index using a standard Freeman code * (1=up, 2=up to the right, and so on proceeding clockwise to 8=up * to the left). The only image index stored directly is that of the first * index. * ChainCodePath2D maps a 1D integer input (step number) to * a 2D integer output (either an offset or an image index, depending on * whether Evaluate or EvaluateToIndex is called). * * \sa ChainCodePath * \sa ParametricPath * \sa Path * \sa Index * * \ingroup PathObjects * \ingroup ITKPath */ class ITK_TEMPLATE_EXPORT ChainCodePath2D : public ChainCodePath<2> { public: ITK_DISALLOW_COPY_AND_MOVE(ChainCodePath2D); /** Dimension underlying input image. */ static constexpr unsigned int Dimension = 2; /** Standard class type aliases. */ using Self = ChainCodePath2D; using Superclass = ChainCodePath<2>; using Pointer = SmartPointer; using ConstPointer = SmartPointer; /** \see LightObject::GetNameOfClass() */ itkOverrideGetNameOfClassMacro(ChainCodePath2D); /** OutputType type alias support */ using OutputType = Superclass::OutputType; using InputType = Superclass::InputType; /** The output type of this function is an Index */ using OffsetType = OutputType; using IndexType = Index<2>; /** ChainCodeType is a useless relic of the parent class */ using ChainCodeType = Superclass::ChainCodeType; using ChainCodeSizeType = Superclass::ChainCodeSizeType; /** ChainCodePath2D stores its data as a Freeman-encoded chain code */ using ChainCode2DType = std::vector; // Functions inherited from Path /** Evaluate the chaincode for the offset at the specified path-position. */ OutputType Evaluate(const InputType & input) const override; /** Like Evaluate(), but returns the index at the specified path-position. */ IndexType EvaluateToIndex(const InputType & input) const override; /** Increment the input variable passed by reference and return the offset * stored at the previous path-position. If the chaincode is unable to be * incremented, input is not changed and an offset of zero is returned, which * may be used to check for the end of the chain code. */ OffsetType IncrementInput(InputType & input) const override; // Functions specific to ChainCodePath and its descendants /** New() method for dynamic construction */ itkNewMacro(Self); /** How many steps in the chaincode? */ ChainCodeSizeType NumberOfSteps() const override { return m_Chain2D.size(); } /** Insert a new step into the chaincode at a specified position */ inline void InsertStep(InputType position, int encodedStep) { m_Chain2D.insert(m_Chain2D.begin() + position, encodedStep); this->Modified(); } void InsertStep(InputType position, OffsetType step) override { m_Chain2D.insert(m_Chain2D.begin() + position, EncodeOffset(step)); this->Modified(); } /** Change the direction of a step in the chaincode */ inline void ChangeStep(InputType position, int encodedStep) { m_Chain2D[position] = encodedStep; this->Modified(); } void ChangeStep(InputType position, OffsetType step) override { m_Chain2D[position] = EncodeOffset(step); this->Modified(); } /** Remove all steps from the chain code */ void Clear() override { m_Chain2D.clear(); this->Modified(); } std::string GetChainCodeAsString() const; protected: ChainCodePath2D(); ~ChainCodePath2D() override; void PrintSelf(std::ostream & os, Indent indent) const override; /** Encode and Decode between an offset and a Freeman code */ inline int EncodeOffset(OffsetType step) const { return m_FreemanCode[step[0] + 1][step[1] + 1]; } inline OffsetType DecodeOffset(int encodedStep) const { return m_ReverseFreemanCode[encodedStep]; } private: ChainCode2DType m_Chain2D{}; // the Freeman-encoded chain code // FreemanCode[][] implements a lookup table for converting offsets to a // Freeman code. Within each dimension, the only allowable offset values are // { -1, 0, 1 }. The y-axis is assumed to point up. It is initialized in the // constructor. Use it as follows: // // encodedValue = m_FreemanCode[ x offset + 1 ][ y offset + 1 ] // int m_FreemanCode[3][3]{}; // m_ReverseFreemanCode[ encodedValue ] implements a lookup table for the // inverse of m_FreemanCode[][]. It is initialized in the constructor. OffsetType m_ReverseFreemanCode[9]{}; }; } // end namespace itk #endif