diff --git a/Core/Code/DataManagement/mitkTypeOperations.h b/Core/Code/DataManagement/mitkTypeOperations.h index 8797cb4d71..d7ba5bc743 100644 --- a/Core/Code/DataManagement/mitkTypeOperations.h +++ b/Core/Code/DataManagement/mitkTypeOperations.h @@ -1,97 +1,119 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef MITKTYPEOPERATIONS_H_ #define MITKTYPEOPERATIONS_H_ #include #include "mitkExceptionMacro.h" namespace mitk { + /** + * This file provides convenience methods to add and subtract itk::FixedArrays and to multiply and divide itk::FixedArrays with scalars. + * That means these methods apply to all types deriving from itk::FixedArray. + * This can e.g. useful to add points and divide them by the number of added points to build an average. + */ /** * @brief implements sum = addend1 + addend2 * Takes FixedArray so you sum all deriving classes like e.g. * sum two points returning a point or * sum a vector and a point, returning a vector. * * @attention Please make sure, that you really want to add the types you specified. * @attention E.g., summing two points does geometrically not make sense, which is why itk does * @attention not provide an operator+ for these types. * */ template< typename TCoordRep, unsigned int NPointDimension> void add(itk::FixedArray& sum, itk::FixedArray& addend1, itk::FixedArray& addend2) { for (typename itk::FixedArray::SizeType var = 0; var < NPointDimension; ++var) { sum[var] = addend1[var] + addend2[var]; } } + /** + * @brief implements difference = minuend - subtrahend. + * + * @param difference + * @param minuend + * @param subtrahend + */ template< typename TCoordRep, unsigned int NPointDimension> void sub(itk::FixedArray& difference, itk::FixedArray& minuend, itk::FixedArray& subtrahend) { for (typename itk::FixedArray::SizeType var = 0; var < NPointDimension; ++var) { difference[var] = minuend[var] - subtrahend[var]; } } + /** + * @brief Multiplies a scalar to a FixedArray: product = multiplicand * scalar + * E.g. multiplying the point {1.0, 2.0, 3.0} with 2.0 results in {2.0, 4.0, 6.0} + * + * @param product {2.0, 4.0, 6.0} in the above example + * @param multiplicand {1.0, 2.0, 3.0} in the above example + * @param scalar 2.0 in the above example + */ template< typename TCoordRep, unsigned int NPointDimension> void mul(itk::FixedArray& product, - itk::FixedArray& multiplicand, itk::FixedArray& multiplier) + itk::FixedArray& multiplicand, TCoordRep scalar) { for (typename itk::FixedArray::SizeType var = 0; var < NPointDimension; ++var) { - product[var] = multiplicand[var] * multiplier[var]; + product[var] = multiplicand[var] * scalar; } } /** - * + * @brief implements quotient = dividend / scalar. * @throws mitk::Exception in case division by zero is attempted * * @param quotient * @param dividend - * @param divisor + * @param scalar * @param eps defines how near to 0 an exception shall be thrown if trying to divide by such a value. */ template< typename TCoordRep, unsigned int NPointDimension> void div(itk::FixedArray& quotient, - itk::FixedArray& dividend, itk::FixedArray& divisor, + itk::FixedArray& dividend, const TCoordRep scalar, TCoordRep eps = mitk::eps) { + if (Equal(scalar, 0.0, eps)) // TODO SW: do we want an exception thrown when dividing against zero? + mitkThrow() << "Division by zero attempted. Scalar to divide is " << scalar; + for (typename itk::FixedArray::SizeType var = 0; var < NPointDimension; ++var) { - if (Equal(divisor[var], 0.0, eps)) - mitkThrow() << "Division by zero attempted. 0 found in " << divisor; - quotient[var] = dividend[var] / divisor[var]; // TODO SW: do we want an exception thrown when dividing against zero? + + quotient[var] = dividend[var] / scalar; } } } #endif /* MITKTYPEOPERATIONS_H_ */ diff --git a/Core/Code/Testing/mitkTypeOperationTest.cpp b/Core/Code/Testing/mitkTypeOperationTest.cpp index 8b93079066..bca1d864ca 100644 --- a/Core/Code/Testing/mitkTypeOperationTest.cpp +++ b/Core/Code/Testing/mitkTypeOperationTest.cpp @@ -1,131 +1,132 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkTestingMacros.h" #include "mitkPoint.h" #include "mitkTypeOperations.h" #include "mitkTypes.h" // for Equal method. TODO SW: Replace this once the Equal methods have their own header. #include using namespace mitk; static ScalarType bValues[3] = {14.123456, 10.2, 5.123456789}; static ScalarType cValues[3] = { 2.654321, 5.1, 2.543231111}; static Point3D a, b, c; static void Setup(void) { b = bValues; c = cValues; } template static void TestForValuesHelper(itk::FixedArray& result, ScalarType v0, ScalarType v1, ScalarType v2, std::string message, ScalarType eps = mitk::eps) { MITK_TEST_CONDITION_REQUIRED( Equal(result[0], v0, eps) && Equal(result[1], v1, eps) && Equal(result[2], v2, eps), message) } static void Test_Addition(void) { Setup(); mitk::add(a, b, c); TestForValuesHelper(a, 16.777777, 15.3, 7.6666879, "summation a = b + c correctly performed"); } static void Test_Substraction(void) { Setup(); mitk::sub(a, b, c); TestForValuesHelper(a, 11.469135, 5.1, 2.580225678, "difference a = b - c correctly performed"); } -static void Test_Multiplication(void) +static void Test_ScalarMultiplication(void) { Setup(); - mitk::mul(a, b, c); + mitk::mul(a, b, 2.123456789); - TestForValuesHelper(a, 37.4881858534, 52.02, 13.0301347016, "multiplication a = b * c correctly performed", 1E-10); + TestForValuesHelper(a, 29.9905485273, 21.6592592478, 10.8794391018, "multiplication a = b * scalar correctly performed", 1E-10); // google calculator provides us with only 10 digits after comma :) } -static void Test_Division(void) +static void Test_ScalarDivision(void) { Setup(); - mitk::div(a, b, c); + mitk::div(a, b, 2.123456789); - TestForValuesHelper(a, 5.32092991014, 2.0, 2.01454628596, "division a = b / c correctly performed", 1E-11); + TestForValuesHelper(a, 6.65116242212, 4.80348837463, 2.41279069842, "division a = b / scalar correctly performed", 1E-11); // 11 digits after comma provided by google calculator :) } static void Test_DivisionByZero(void) { Setup(); - c[2] = mitk::eps; + ScalarType scalar = mitk::eps; - MITK_TEST_FOR_EXCEPTION(mitk::Exception&, mitk::div(a,b,c, 2.0 * c[2])) + MITK_TEST_FOR_EXCEPTION(mitk::Exception&, mitk::div(a,b,scalar, 2.0 * scalar)) } static void Test_DivisionByAlmostZero(void) { Setup(); - c[2] = 2.0 * mitk::eps; + ScalarType scalar = 2.0 * mitk::eps; - mitk::div(a,b,c); + mitk::div(a,b,scalar); MITK_TEST_CONDITION_REQUIRED(true, "division by element almost equal to zero doesn't throw exception") } + + int mitkTypeOperationTest(int /*argc*/ , char* /*argv*/[]) { // always start with this! MITK_TEST_BEGIN("TypeOperationTest") Test_Addition(); Test_Substraction(); - Test_Multiplication(); + Test_ScalarMultiplication(); - Test_Division(); + Test_ScalarDivision(); Test_DivisionByZero(); Test_DivisionByAlmostZero(); MITK_TEST_END() - }