Skip to content

Commit

Permalink
ENH: Add Size::CalculateProductOfElements(), to compute number of pixels
Browse files Browse the repository at this point in the history
Added `CalculateProductOfElements()`, as a convenience function of `Size`,
typically useful to determine the total number of pixels (2D) or voxels (3D).

Included a GoogleTest unit test.
  • Loading branch information
N-Dekker authored and hjmjohnson committed Dec 26, 2023
1 parent 36e9549 commit c4ef860
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 0 deletions.
13 changes: 13 additions & 0 deletions Modules/Core/Common/include/itkSize.h
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,19 @@ struct ITK_TEMPLATE_EXPORT Size final
std::fill_n(begin(), size(), value);
} // MATCH std::array assign, ITK Fill

/** Multiplies all elements. Yields the number of pixels of an image of this size. */
[[nodiscard]] constexpr SizeValueType
CalculateProductOfElements() const
{
SizeValueType product{ 1 };

for (const SizeValueType value : m_InternalArray)
{
product *= value;
}
return product;
}

/** Size is an "aggregate" class. Its data is public (m_InternalArray)
* allowing for fast and convenient instantiations/assignments.
* ( See main class documentation for an example of initialization)
Expand Down
38 changes: 38 additions & 0 deletions Modules/Core/Common/test/itkSizeGTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,14 @@

// First include the header file to be tested:
#include "itkSize.h"
#include "itkMath.h"
#include "itkRangeGTestUtilities.h"

#include <gtest/gtest.h>

#include <functional> // For multiplies
#include <limits>
#include <numeric> // For accumulate.
#include <type_traits> // For integral_constant.


Expand Down Expand Up @@ -132,3 +137,36 @@ TEST(Size, Fill)
check(DimensionConstant<2>);
check(DimensionConstant<3>);
}


// Tests Size::CalculateProductOfElements().
TEST(Size, CalculateProductOfElements)
{
const auto checkFilledSizes = [](const auto dimensionConstant) {
// Check at runtime:
for (itk::SizeValueType sizeValue{}; sizeValue <= 2; ++sizeValue)
{
const auto size = itk::Size<dimensionConstant>::Filled(sizeValue);
EXPECT_EQ(size.CalculateProductOfElements(), itk::Math::UnsignedPower(sizeValue, dimensionConstant));
}

// Check at compile-time:
constexpr itk::SizeValueType sizeValue{ 3 };
constexpr auto size = itk::Size<dimensionConstant>::Filled(sizeValue);
static_assert(size.CalculateProductOfElements() == itk::Math::UnsignedPower(sizeValue, dimensionConstant));
};

// Check CalculateProductOfElements() for 1D, 2D, and 3D sizes, filled by `Size::Filled`:
checkFilledSizes(DimensionConstant<1>);
checkFilledSizes(DimensionConstant<2>);
checkFilledSizes(DimensionConstant<3>);

const auto checkArbitrarySize = [](const auto & size) {
EXPECT_EQ(size.CalculateProductOfElements(),
std::accumulate(size.cbegin(), size.cend(), itk::SizeValueType{ 1 }, std::multiplies<>{}));
};

// Do a few more trivial tests.
checkArbitrarySize(itk::MakeSize(2, 4));
checkArbitrarySize(itk::MakeSize(1, 2, 3));
}

0 comments on commit c4ef860

Please sign in to comment.