diff --git a/Modules/Core/Common/include/itkPointSet.h b/Modules/Core/Common/include/itkPointSet.h index 9300bc724888..57102f34b89d 100644 --- a/Modules/Core/Common/include/itkPointSet.h +++ b/Modules/Core/Common/include/itkPointSet.h @@ -28,7 +28,7 @@ #ifndef itkPointSet_h #define itkPointSet_h -#include "itkDataObject.h" +#include "itkPointSetBase.h" #include "itkDefaultStaticMeshTraits.h" #include #include @@ -79,14 +79,14 @@ namespace itk template > -class ITK_TEMPLATE_EXPORT PointSet : public DataObject +class ITK_TEMPLATE_EXPORT PointSet : public PointSetBase { public: ITK_DISALLOW_COPY_AND_MOVE(PointSet); /** Standard class type aliases. */ using Self = PointSet; - using Superclass = DataObject; + using Superclass = PointSetBase; using Pointer = SmartPointer; using ConstPointer = SmartPointer; @@ -104,39 +104,19 @@ class ITK_TEMPLATE_EXPORT PointSet : public DataObject using CoordRepType = typename MeshTraits::CoordRepType; using PointIdentifier = typename MeshTraits::PointIdentifier; using PointType = typename MeshTraits::PointType; - using PointsContainer = typename MeshTraits::PointsContainer; using PointDataContainer = typename MeshTraits::PointDataContainer; - /** For improving Python support for PointSet and Meshes **/ - using PointsVectorContainer = typename itk::VectorContainer; - using PointsVectorContainerPointer = typename PointsVectorContainer::Pointer; - /** Convenient type alias obtained from TMeshTraits template parameter. */ static constexpr unsigned int PointDimension = TMeshTraits::PointDimension; /** Create types that are pointers to each of the container types. */ - using PointsContainerPointer = typename PointsContainer::Pointer; - using PointsContainerConstPointer = typename PointsContainer::ConstPointer; using PointDataContainerPointer = typename PointDataContainer::Pointer; using PointDataContainerConstPointer = typename PointDataContainer::ConstPointer; /** Create types that are iterators for each of the container types. */ - using PointsContainerConstIterator = typename PointsContainer::ConstIterator; - using PointsContainerIterator = typename PointsContainer::Iterator; using PointDataContainerIterator = typename PointDataContainer::ConstIterator; - /** Type used to define Regions */ - using RegionType = long; - - /** Get the maximum number of regions that this data can be - * separated into. */ - itkGetConstMacro(MaximumNumberOfRegions, RegionType); - protected: - /** An object containing points used by the mesh. Individual points are - * accessed through point identifiers. */ - PointsContainerPointer m_PointsContainer{}; - /** An object containing data associated with the mesh's points. * Optionally, this can be nullptr, indicating that no data are associated with * the points. The data for a point can be accessed through its point @@ -144,43 +124,12 @@ class ITK_TEMPLATE_EXPORT PointSet : public DataObject PointDataContainerPointer m_PointDataContainer{}; public: - /** Copy the geometric and topological structure of the given input pointSet. - * The copying is done via reference counting. - */ - void - PassStructure(Self * inputPointSet); - /** Restore the PointSet to its initial state. Useful for data pipeline updates * without memory re-allocation. */ void Initialize() override; - /** Get the number of points in the points container. */ - PointIdentifier - GetNumberOfPoints() const; - - /** Set the points container. */ - void - SetPoints(PointsContainer *); - - /** Set the points container using a 1D vector. - \warning This member function is unsafe. It may just work, but it may also lead to undefined behavior. */ - void - SetPoints(PointsVectorContainer *); - - /** Sets the points by specifying its coordinates. */ - void - SetPointsByCoordinates(const std::vector & coordinates); - - /** Get the points container. */ - PointsContainer * - GetPoints(); - - /** Get the points container. */ - const PointsContainer * - GetPoints() const; - /** Set the point data container. */ void SetPointData(PointDataContainer *); @@ -193,23 +142,6 @@ class ITK_TEMPLATE_EXPORT PointSet : public DataObject const PointDataContainer * GetPointData() const; - /** Assign a point to a point identifier. If a spot for the point identifier - * does not exist, it will be created automatically. - */ - void SetPoint(PointIdentifier, PointType); - - /** Check if a point exists for a given point identifier. If a spot for - * the point identifier exists, the point is set, and true is returned. - * Otherwise, false is returned, and the point is not modified. - * If the point is nullptr, then it is never set, but the existence of the - * point is still returned. - */ - bool - GetPoint(PointIdentifier, PointType *) const; - - /** Get the point for the given point identifier. */ - PointType GetPoint(PointIdentifier) const; - /** Assign data to a point identifier. If a spot for the point identifier * does not exist, it will be created automatically. There is no check if * a point with the same identifier exists. @@ -225,44 +157,9 @@ class ITK_TEMPLATE_EXPORT PointSet : public DataObject bool GetPointData(PointIdentifier, PixelType *) const; - /** Methods to manage streaming. */ - void - UpdateOutputInformation() override; - - void - SetRequestedRegionToLargestPossibleRegion() override; - - void - CopyInformation(const DataObject * data) override; - void Graft(const DataObject * data) override; - bool - RequestedRegionIsOutsideOfTheBufferedRegion() override; - - bool - VerifyRequestedRegion() override; - - /** Set the requested region from this data object to match the requested - * region of the data object passed in as a parameter. This method - * implements the API from DataObject. The data object parameter must be - * castable to a PointSet. */ - void - SetRequestedRegion(const DataObject * data) override; - - /** Set/Get the Requested region */ - virtual void - SetRequestedRegion(const RegionType & region); - - itkGetConstMacro(RequestedRegion, RegionType); - - /** Set/Get the Buffered region */ - virtual void - SetBufferedRegion(const RegionType & region); - - itkGetConstMacro(BufferedRegion, RegionType); - protected: /** Constructor for use by New() method. */ PointSet() = default; @@ -270,21 +167,6 @@ class ITK_TEMPLATE_EXPORT PointSet : public DataObject void PrintSelf(std::ostream & os, Indent indent) const override; - // If the RegionType is ITK_UNSTRUCTURED_REGION, then the following - // variables represent the maximum number of region that the data - // object can be broken into, which region out of how many is - // currently in the buffered region, and the number of regions and - // the specific region requested for the update. Data objects that - // do not support any division of the data can simply leave the - // MaximumNumberOfRegions as 1. The RequestedNumberOfRegions and - // RequestedRegion are used to define the currently requested - // region. The LargestPossibleRegion is always requested region = 0 - // and number of regions = 1; - RegionType m_MaximumNumberOfRegions{ 1 }; - RegionType m_NumberOfRegions{ 1 }; - RegionType m_RequestedNumberOfRegions{}; - RegionType m_BufferedRegion{ -1 }; - RegionType m_RequestedRegion{ -1 }; }; // End Class: PointSet } // end namespace itk diff --git a/Modules/Core/Common/include/itkPointSet.hxx b/Modules/Core/Common/include/itkPointSet.hxx index c868dfc01a6c..9291412d7e2b 100644 --- a/Modules/Core/Common/include/itkPointSet.hxx +++ b/Modules/Core/Common/include/itkPointSet.hxx @@ -38,12 +38,6 @@ void PointSet::PrintSelf(std::ostream & os, Indent indent) const { Superclass::PrintSelf(os, indent); - os << indent << "Number Of Points: " << this->GetNumberOfPoints() << std::endl; - - os << indent << "Requested Number Of Regions: " << m_RequestedNumberOfRegions << std::endl; - os << indent << "Requested Region: " << m_RequestedRegion << std::endl; - os << indent << "Buffered Region: " << m_BufferedRegion << std::endl; - os << indent << "Maximum Number Of Regions: " << m_MaximumNumberOfRegions << std::endl; os << indent << "Point Data Container pointer: " << ((this->m_PointDataContainer) ? this->m_PointDataContainer.GetPointer() : nullptr) << std::endl; os << indent @@ -51,107 +45,6 @@ PointSet::PrintSelf(std::ostream & os, Inde << std::endl; } -template -void -PointSet::SetPoints(PointsContainer * points) -{ - itkDebugMacro("setting Points container to " << points); - if (m_PointsContainer != points) - { - m_PointsContainer = points; - this->Modified(); - } -} - -template -void -PointSet::SetPoints(PointsVectorContainer * points) -{ - - itkDebugMacro("setting Points container to " << points); - if (points->Size() % PointDimension != 0) - { - itkExceptionMacro("Number of entries in given 1d array incompatible with the point dimension"); - } - - // Note: this cast is unsafe. It may lead to undefined behavior. - auto * pointsPtr = reinterpret_cast(points); - - m_PointsContainer = pointsPtr; - this->Modified(); -} - - -template -void -PointSet::SetPointsByCoordinates(const std::vector & coordinates) -{ - itkDebugMacro("Setting the points to the specified coordinates"); - - const size_t numberOfCoordinates = coordinates.size(); - - if (numberOfCoordinates % PointDimension != 0) - { - itkExceptionMacro("Number of specified coordinates incompatible with the point dimension"); - } - - const size_t numberOfPoints = numberOfCoordinates / PointDimension; - - if (m_PointsContainer == nullptr) - { - m_PointsContainer = PointsContainer::New(); - } - - using STLContainerType = typename PointsContainer::STLContainerType; - - STLContainerType & points = m_PointsContainer->CastToSTLContainer(); - points.clear(); - - if constexpr (std::is_same_v>) - { - // STLContainerType is either an std::vector or an std::map. Only when it is an std::vector, it should be resized. - // std::map does not have a resize function. - points.resize(numberOfPoints); - } - else - { - static_assert(std::is_same_v>); - } - - auto coordinateIterator = coordinates.cbegin(); - - for (PointIdentifier pointIdentifier{}; pointIdentifier < numberOfPoints; ++pointIdentifier) - { - PointType & point = points[pointIdentifier]; - std::copy_n(coordinateIterator, PointDimension, point.begin()); - coordinateIterator += PointDimension; - } - - this->Modified(); -} - - -template -auto -PointSet::GetPoints() -> PointsContainer * -{ - itkDebugMacro("Starting GetPoints()"); - if (!m_PointsContainer) - { - this->SetPoints(PointsContainer::New()); - } - itkDebugMacro("returning Points container of " << m_PointsContainer); - return m_PointsContainer; -} - -template -auto -PointSet::GetPoints() const -> const PointsContainer * -{ - itkDebugMacro("returning Points container of " << m_PointsContainer); - return m_PointsContainer.GetPointer(); -} - template void PointSet::SetPointData(PointDataContainer * pointData) @@ -184,66 +77,6 @@ PointSet::GetPointData() const -> const Poi return m_PointDataContainer.GetPointer(); } -template -void -PointSet::SetPoint(PointIdentifier ptId, PointType point) -{ - /** - * Make sure a points container exists. - */ - if (!m_PointsContainer) - { - this->SetPoints(PointsContainer::New()); - } - - /** - * Insert the point into the container with the given identifier. - */ - m_PointsContainer->InsertElement(ptId, point); -} - -template -bool -PointSet::GetPoint(PointIdentifier ptId, PointType * point) const -{ - /** - * If the points container doesn't exist, then the point doesn't either. - */ - if (!m_PointsContainer) - { - return false; - } - - /** - * Ask the container if the point identifier exists. - */ - return m_PointsContainer->GetElementIfIndexExists(ptId, point); -} - -template -auto -PointSet::GetPoint(PointIdentifier ptId) const -> PointType -{ - /** - * If the points container doesn't exist, then the point doesn't either. - */ - if (!m_PointsContainer) - { - itkExceptionMacro("Point container doesn't exist."); - } - - /** - * Ask the container if the point identifier exists. - */ - PointType point; - bool exist = m_PointsContainer->GetElementIfIndexExists(ptId, &point); - if (!exist) - { - itkExceptionMacro("Point id doesn't exist: " << ptId); - } - return point; -} - template void PointSet::SetPointData(PointIdentifier ptId, PixelType data) @@ -281,80 +114,16 @@ PointSet::GetPointData(PointIdentifier ptId return m_PointDataContainer->GetElementIfIndexExists(ptId, data); } -template -void -PointSet::PassStructure(Self *) -{ - // IMPLEMENT ME -} - -template -auto -PointSet::GetNumberOfPoints() const -> PointIdentifier -{ - if (m_PointsContainer) - { - return m_PointsContainer->Size(); - } - return 0; -} - template void PointSet::Initialize() { Superclass::Initialize(); - m_PointsContainer = nullptr; m_PointDataContainer = nullptr; } -template -void -PointSet::UpdateOutputInformation() -{ - this->Superclass::UpdateOutputInformation(); - - // Now we should know what our largest possible region is. If our - // requested region was not set yet, (or has been set to something - // invalid - with no data in it ) then set it to the largest - // possible region. - if (m_RequestedRegion == -1 && m_RequestedNumberOfRegions == 0) - { - this->SetRequestedRegionToLargestPossibleRegion(); - } -} - -template -void -PointSet::SetRequestedRegionToLargestPossibleRegion() -{ - m_RequestedNumberOfRegions = 1; - m_RequestedRegion = 0; -} - -template -void -PointSet::CopyInformation(const DataObject * data) -{ - const auto * pointSet = dynamic_cast(data); - - if (!pointSet) - { - // pointer could not be cast back down - itkExceptionMacro("itk::PointSet::CopyInformation() cannot cast " << typeid(data).name() << " to " - << typeid(PointSet *).name()); - } - - m_MaximumNumberOfRegions = pointSet->GetMaximumNumberOfRegions(); - - m_NumberOfRegions = pointSet->m_NumberOfRegions; - m_RequestedNumberOfRegions = pointSet->m_RequestedNumberOfRegions; - m_BufferedRegion = pointSet->m_BufferedRegion; - m_RequestedRegion = pointSet->m_RequestedRegion; -} - template void PointSet::Graft(const DataObject * data) @@ -371,78 +140,10 @@ PointSet::Graft(const DataObject * data) << typeid(Self *).name()); } - this->SetPoints(pointSet->m_PointsContainer); + this->SetPoints(pointSet->Superclass::m_PointsContainer); this->SetPointData(pointSet->m_PointDataContainer); } -template -void -PointSet::SetRequestedRegion(const DataObject * data) -{ - const auto * pointSet = dynamic_cast(data); - - if (pointSet) - { - // only copy the RequestedRegion if the parameter is another PointSet - m_RequestedRegion = pointSet->m_RequestedRegion; - m_RequestedNumberOfRegions = pointSet->m_RequestedNumberOfRegions; - } -} - -template -void -PointSet::SetRequestedRegion(const RegionType & region) -{ - if (m_RequestedRegion != region) - { - m_RequestedRegion = region; - } -} - -template -void -PointSet::SetBufferedRegion(const RegionType & region) -{ - if (m_BufferedRegion != region) - { - m_BufferedRegion = region; - this->Modified(); - } -} - -template -bool -PointSet::RequestedRegionIsOutsideOfTheBufferedRegion() -{ - if (m_RequestedRegion != m_BufferedRegion || m_RequestedNumberOfRegions != m_NumberOfRegions) - { - return true; - } - - return false; -} - -template -bool -PointSet::VerifyRequestedRegion() -{ - bool retval = true; - - // Are we asking for more regions than we can get? - if (m_RequestedNumberOfRegions > m_MaximumNumberOfRegions) - { - itkExceptionMacro("Cannot break object into " << m_RequestedNumberOfRegions << ". The limit is " - << m_MaximumNumberOfRegions); - } - - if (m_RequestedRegion >= m_RequestedNumberOfRegions || m_RequestedRegion < 0) - { - itkExceptionMacro("Invalid update region " << m_RequestedRegion << ". Must be between 0 and " - << m_RequestedNumberOfRegions - 1); - } - - return retval; -} } // end namespace itk #endif diff --git a/Modules/Core/Common/include/itkPointSetBase.h b/Modules/Core/Common/include/itkPointSetBase.h new file mode 100644 index 000000000000..3edba96a0e05 --- /dev/null +++ b/Modules/Core/Common/include/itkPointSetBase.h @@ -0,0 +1,238 @@ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ +/*========================================================================= + * + * Portions of this file are subject to the VTK Toolkit Version 3 copyright. + * + * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + * + * For complete copyright, license and disclaimer of warranty information + * please refer to the NOTICE file at the top of the ITK source tree. + * + *=========================================================================*/ +#ifndef itkPointSetBase_h +#define itkPointSetBase_h + +#include "itkDataObject.h" +#include "itkVectorContainer.h" +#include + +namespace itk +{ + +/** \class PointSetBase + * \brief A superclass of the N-dimensional mesh structure; + * supports point (geometric coordinate and attribute) definition. + * + * PointSetBase is a superclass of the N-dimensional mesh structure (itk::Mesh). + * It provides the portion of the mesh definition for geometric coordinates + * (and associated attribute or pixel information). The defined API provides + * operations on points but does not tie down the underlying implementation + * and storage. A "MeshTraits" structure is used to define the container + * and identifier to access the points. See DefaultStaticMeshTraits + * for the set of type definitions needed. All types that are defined + * in the "MeshTraits" structure will have duplicate type alias in the resulting + * mesh itself. + * + * PointSetBase has two template parameters. The first is the pixel type, or the + * type of data stored (optionally) with the points. + * The second is the "MeshTraits" structure controlling type information + * characterizing the point set. Most users will be happy with the + * defaults, and will not have to worry about this second argument. + * + * Template parameters for PointSetBase: + * + * TMeshTraits = + * Type information structure for the point set. + * + * \ingroup MeshObjects + * \ingroup DataRepresentation + * \ingroup ITKCommon + */ + +template +class ITK_TEMPLATE_EXPORT PointSetBase : public DataObject +{ +public: + ITK_DISALLOW_COPY_AND_MOVE(PointSetBase); + + /** Standard class type aliases. */ + using Self = PointSetBase; + using Superclass = DataObject; + using Pointer = SmartPointer; + using ConstPointer = SmartPointer; + + /** \see LightObject::GetNameOfClass() */ + itkOverrideGetNameOfClassMacro(PointSetBase); + + /** Convenient type alias obtained from TMeshTraits template parameter. */ + using PointType = typename TPointsContainer::Element; + using CoordRepType = typename PointType::CoordRepType; + using PointIdentifier = typename TPointsContainer::ElementIdentifier; + using PointsContainer = TPointsContainer; + + /** For improving Python support for PointSetBase and Meshes **/ + using PointsVectorContainer = typename itk::VectorContainer; + using PointsVectorContainerPointer = typename PointsVectorContainer::Pointer; + + /** Convenient type alias obtained from TMeshTraits template parameter. */ + static constexpr unsigned int PointDimension = PointType::PointDimension; + + /** Create types that are pointers to each of the container types. */ + using PointsContainerPointer = typename PointsContainer::Pointer; + using PointsContainerConstPointer = typename PointsContainer::ConstPointer; + + /** Create types that are iterators for each of the container types. */ + using PointsContainerConstIterator = typename PointsContainer::ConstIterator; + using PointsContainerIterator = typename PointsContainer::Iterator; + + /** Type used to define Regions */ + using RegionType = long; + + /** Get the maximum number of regions that this data can be + * separated into. */ + itkGetConstMacro(MaximumNumberOfRegions, RegionType); + +protected: + /** An object containing points used by the mesh. Individual points are + * accessed through point identifiers. */ + PointsContainerPointer m_PointsContainer{}; + +public: + /** Copy the geometric and topological structure of the given input pointSet. + * The copying is done via reference counting. + */ + void + PassStructure(Self * inputPointSet); + + /** Restore the PointSetBase to its initial state. Useful for data pipeline updates + * without memory re-allocation. + */ + void + Initialize() override; + + /** Get the number of points in the points container. */ + PointIdentifier + GetNumberOfPoints() const; + + /** Set the points container. */ + void + SetPoints(PointsContainer *); + + /** Set the points container using a 1D vector. + \warning This member function is unsafe. It may just work, but it may also lead to undefined behavior. */ + void + SetPoints(PointsVectorContainer *); + + /** Sets the points by specifying its coordinates. */ + void + SetPointsByCoordinates(const std::vector & coordinates); + + /** Get the points container. */ + PointsContainer * + GetPoints(); + + /** Get the points container. */ + const PointsContainer * + GetPoints() const; + + /** Assign a point to a point identifier. If a spot for the point identifier + * does not exist, it will be created automatically. + */ + void SetPoint(PointIdentifier, PointType); + + /** Check if a point exists for a given point identifier. If a spot for + * the point identifier exists, the point is set, and true is returned. + * Otherwise, false is returned, and the point is not modified. + * If the point is nullptr, then it is never set, but the existence of the + * point is still returned. + */ + bool + GetPoint(PointIdentifier, PointType *) const; + + /** Get the point for the given point identifier. */ + PointType GetPoint(PointIdentifier) const; + + /** Methods to manage streaming. */ + void + UpdateOutputInformation() override; + + void + SetRequestedRegionToLargestPossibleRegion() override; + + void + CopyInformation(const DataObject * data) override; + + void + Graft(const DataObject * data) override; + + bool + RequestedRegionIsOutsideOfTheBufferedRegion() override; + + bool + VerifyRequestedRegion() override; + + /** Set the requested region from this data object to match the requested + * region of the data object passed in as a parameter. This method + * implements the API from DataObject. The data object parameter must be + * castable to a PointSetBase. */ + void + SetRequestedRegion(const DataObject * data) override; + + /** Set/Get the Requested region */ + virtual void + SetRequestedRegion(const RegionType & region); + + itkGetConstMacro(RequestedRegion, RegionType); + + /** Set/Get the Buffered region */ + virtual void + SetBufferedRegion(const RegionType & region); + + itkGetConstMacro(BufferedRegion, RegionType); + +protected: + /** Constructor for use by New() method. */ + PointSetBase() = default; + ~PointSetBase() override = default; + void + PrintSelf(std::ostream & os, Indent indent) const override; + + // If the RegionType is ITK_UNSTRUCTURED_REGION, then the following + // variables represent the maximum number of region that the data + // object can be broken into, which region out of how many is + // currently in the buffered region, and the number of regions and + // the specific region requested for the update. Data objects that + // do not support any division of the data can simply leave the + // MaximumNumberOfRegions as 1. The RequestedNumberOfRegions and + // RequestedRegion are used to define the currently requested + // region. The LargestPossibleRegion is always requested region = 0 + // and number of regions = 1; + RegionType m_MaximumNumberOfRegions{ 1 }; + RegionType m_NumberOfRegions{ 1 }; + RegionType m_RequestedNumberOfRegions{}; + RegionType m_BufferedRegion{ -1 }; + RegionType m_RequestedRegion{ -1 }; +}; // End Class: PointSetBase +} // end namespace itk + +#ifndef ITK_MANUAL_INSTANTIATION +# include "itkPointSetBase.hxx" +#endif + +#endif diff --git a/Modules/Core/Common/include/itkPointSetBase.hxx b/Modules/Core/Common/include/itkPointSetBase.hxx new file mode 100644 index 000000000000..84a14e1b1b1e --- /dev/null +++ b/Modules/Core/Common/include/itkPointSetBase.hxx @@ -0,0 +1,373 @@ +/*========================================================================= + * + * 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. + * + *=========================================================================*/ +/*========================================================================= + * + * Portions of this file are subject to the VTK Toolkit Version 3 copyright. + * + * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen + * + * For complete copyright, license and disclaimer of warranty information + * please refer to the NOTICE file at the top of the ITK source tree. + * + *=========================================================================*/ +#ifndef itkPointSetBase_hxx +#define itkPointSetBase_hxx + +#include "itkProcessObject.h" +#include + +namespace itk +{ +template +void +PointSetBase::PrintSelf(std::ostream & os, Indent indent) const +{ + Superclass::PrintSelf(os, indent); + os << indent << "Number Of Points: " << this->GetNumberOfPoints() << std::endl; + + os << indent << "Requested Number Of Regions: " << m_RequestedNumberOfRegions << std::endl; + os << indent << "Requested Region: " << m_RequestedRegion << std::endl; + os << indent << "Buffered Region: " << m_BufferedRegion << std::endl; + os << indent << "Maximum Number Of Regions: " << m_MaximumNumberOfRegions << std::endl; +} + +template +void +PointSetBase::SetPoints(PointsContainer * points) +{ + itkDebugMacro("setting Points container to " << points); + if (m_PointsContainer != points) + { + m_PointsContainer = points; + this->Modified(); + } +} + +template +void +PointSetBase::SetPoints(PointsVectorContainer * points) +{ + + itkDebugMacro("setting Points container to " << points); + if (points->Size() % PointDimension != 0) + { + itkExceptionMacro("Number of entries in given 1d array incompatible with the point dimension"); + } + + // Note: this cast is unsafe. It may lead to undefined behavior. + auto * pointsPtr = reinterpret_cast(points); + + m_PointsContainer = pointsPtr; + this->Modified(); +} + + +template +void +PointSetBase::SetPointsByCoordinates(const std::vector & coordinates) +{ + itkDebugMacro("Setting the points to the specified coordinates"); + + const size_t numberOfCoordinates = coordinates.size(); + + if (numberOfCoordinates % PointDimension != 0) + { + itkExceptionMacro("Number of specified coordinates incompatible with the point dimension"); + } + + const size_t numberOfPoints = numberOfCoordinates / PointDimension; + + if (m_PointsContainer == nullptr) + { + m_PointsContainer = PointsContainer::New(); + } + + using STLContainerType = typename PointsContainer::STLContainerType; + + STLContainerType & points = m_PointsContainer->CastToSTLContainer(); + points.clear(); + + if constexpr (std::is_same_v>) + { + // STLContainerType is either an std::vector or an std::map. Only when it is an std::vector, it should be resized. + // std::map does not have a resize function. + points.resize(numberOfPoints); + } + else + { + static_assert(std::is_same_v>); + } + + auto coordinateIterator = coordinates.cbegin(); + + for (PointIdentifier pointIdentifier{}; pointIdentifier < numberOfPoints; ++pointIdentifier) + { + PointType & point = points[pointIdentifier]; + std::copy_n(coordinateIterator, PointDimension, point.begin()); + coordinateIterator += PointDimension; + } + + this->Modified(); +} + + +template +auto +PointSetBase::GetPoints() -> PointsContainer * +{ + itkDebugMacro("Starting GetPoints()"); + if (!m_PointsContainer) + { + this->SetPoints(PointsContainer::New()); + } + itkDebugMacro("returning Points container of " << m_PointsContainer); + return m_PointsContainer; +} + +template +auto +PointSetBase::GetPoints() const -> const PointsContainer * +{ + itkDebugMacro("returning Points container of " << m_PointsContainer); + return m_PointsContainer.GetPointer(); +} + +template +void +PointSetBase::SetPoint(PointIdentifier ptId, PointType point) +{ + /** + * Make sure a points container exists. + */ + if (!m_PointsContainer) + { + this->SetPoints(PointsContainer::New()); + } + + /** + * Insert the point into the container with the given identifier. + */ + m_PointsContainer->InsertElement(ptId, point); +} + +template +bool +PointSetBase::GetPoint(PointIdentifier ptId, PointType * point) const +{ + /** + * If the points container doesn't exist, then the point doesn't either. + */ + if (!m_PointsContainer) + { + return false; + } + + /** + * Ask the container if the point identifier exists. + */ + return m_PointsContainer->GetElementIfIndexExists(ptId, point); +} + +template +auto +PointSetBase::GetPoint(PointIdentifier ptId) const -> PointType +{ + /** + * If the points container doesn't exist, then the point doesn't either. + */ + if (!m_PointsContainer) + { + itkExceptionMacro("Point container doesn't exist."); + } + + /** + * Ask the container if the point identifier exists. + */ + PointType point; + bool exist = m_PointsContainer->GetElementIfIndexExists(ptId, &point); + if (!exist) + { + itkExceptionMacro("Point id doesn't exist: " << ptId); + } + return point; +} + + +template +void +PointSetBase::PassStructure(Self *) +{ + // IMPLEMENT ME +} + +template +auto +PointSetBase::GetNumberOfPoints() const -> PointIdentifier +{ + if (m_PointsContainer) + { + return m_PointsContainer->Size(); + } + return 0; +} + +template +void +PointSetBase::Initialize() +{ + Superclass::Initialize(); + + m_PointsContainer = nullptr; +} + + +template +void +PointSetBase::UpdateOutputInformation() +{ + this->Superclass::UpdateOutputInformation(); + + // Now we should know what our largest possible region is. If our + // requested region was not set yet, (or has been set to something + // invalid - with no data in it ) then set it to the largest + // possible region. + if (m_RequestedRegion == -1 && m_RequestedNumberOfRegions == 0) + { + this->SetRequestedRegionToLargestPossibleRegion(); + } +} + +template +void +PointSetBase::SetRequestedRegionToLargestPossibleRegion() +{ + m_RequestedNumberOfRegions = 1; + m_RequestedRegion = 0; +} + +template +void +PointSetBase::CopyInformation(const DataObject * data) +{ + const auto * pointSet = dynamic_cast(data); + + if (!pointSet) + { + // pointer could not be cast back down + itkExceptionMacro("itk::PointSetBase::CopyInformation() cannot cast " << typeid(data).name() << " to " + << typeid(PointSetBase *).name()); + } + + m_MaximumNumberOfRegions = pointSet->GetMaximumNumberOfRegions(); + + m_NumberOfRegions = pointSet->m_NumberOfRegions; + m_RequestedNumberOfRegions = pointSet->m_RequestedNumberOfRegions; + m_BufferedRegion = pointSet->m_BufferedRegion; + m_RequestedRegion = pointSet->m_RequestedRegion; +} + +template +void +PointSetBase::Graft(const DataObject * data) +{ + // Copy Meta Data + this->CopyInformation(data); + + const auto * pointSet = dynamic_cast(data); + + if (!pointSet) + { + // pointer could not be cast back down + itkExceptionMacro("itk::PointSetBase::CopyInformation() cannot cast " << typeid(data).name() << " to " + << typeid(Self *).name()); + } + + this->SetPoints(pointSet->m_PointsContainer); +} + +template +void +PointSetBase::SetRequestedRegion(const DataObject * data) +{ + const auto * pointSet = dynamic_cast(data); + + if (pointSet) + { + // only copy the RequestedRegion if the parameter is another PointSetBase + m_RequestedRegion = pointSet->m_RequestedRegion; + m_RequestedNumberOfRegions = pointSet->m_RequestedNumberOfRegions; + } +} + +template +void +PointSetBase::SetRequestedRegion(const RegionType & region) +{ + if (m_RequestedRegion != region) + { + m_RequestedRegion = region; + } +} + +template +void +PointSetBase::SetBufferedRegion(const RegionType & region) +{ + if (m_BufferedRegion != region) + { + m_BufferedRegion = region; + this->Modified(); + } +} + +template +bool +PointSetBase::RequestedRegionIsOutsideOfTheBufferedRegion() +{ + if (m_RequestedRegion != m_BufferedRegion || m_RequestedNumberOfRegions != m_NumberOfRegions) + { + return true; + } + + return false; +} + +template +bool +PointSetBase::VerifyRequestedRegion() +{ + bool retval = true; + + // Are we asking for more regions than we can get? + if (m_RequestedNumberOfRegions > m_MaximumNumberOfRegions) + { + itkExceptionMacro("Cannot break object into " << m_RequestedNumberOfRegions << ". The limit is " + << m_MaximumNumberOfRegions); + } + + if (m_RequestedRegion >= m_RequestedNumberOfRegions || m_RequestedRegion < 0) + { + itkExceptionMacro("Invalid update region " << m_RequestedRegion << ". Must be between 0 and " + << m_RequestedNumberOfRegions - 1); + } + + return retval; +} +} // end namespace itk + +#endif