Skip to content

Commit

Permalink
ENH: Use PositiveEnum and NegativeEnum for orientation enums
Browse files Browse the repository at this point in the history
Move asymmetric conversion utility methods to protected functions.
Add missing NegativeEnum methods for symmetry.
  • Loading branch information
blowekamp committed Sep 11, 2024
1 parent 05127e3 commit 55d091f
Show file tree
Hide file tree
Showing 8 changed files with 158 additions and 130 deletions.
72 changes: 40 additions & 32 deletions Modules/Core/Common/include/itkAnatomicalOrientation.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ class ITKCommon_EXPORT AnatomicalOrientation
SuperiorToInferior = 9, ///< foot
};

private:
protected:
enum class CoordinateMajornessTermsEnum : uint8_t
{
PrimaryMinor = 0,
Expand All @@ -80,7 +80,7 @@ class ITKCommon_EXPORT AnatomicalOrientation
GetCoordinateTerm(CoordinateMajornessTermsEnum cmt) const;

public:
enum class ToEnum : uint32_t
enum class PositiveEnum : uint32_t

{
INVALID = 0,
Expand Down Expand Up @@ -236,7 +236,7 @@ class ITKCommon_EXPORT AnatomicalOrientation
CoordinateEnum::RightToLeft>
};

enum class FromEnum : uint32_t
enum class NegativeEnum : uint32_t

{
INVALID = 0,
Expand Down Expand Up @@ -400,7 +400,7 @@ class ITKCommon_EXPORT AnatomicalOrientation
*/
AnatomicalOrientation(CoordinateEnum primary, CoordinateEnum secondary, CoordinateEnum tertiary);

AnatomicalOrientation(ToEnum orientation)
AnatomicalOrientation(PositiveEnum orientation)
: m_Value(orientation)
{}

Expand All @@ -416,30 +416,33 @@ class ITKCommon_EXPORT AnatomicalOrientation
AnatomicalOrientation(LegacyOrientationType legacyOrientation);
#endif

AnatomicalOrientation(FromEnum orientation);
AnatomicalOrientation(NegativeEnum orientation);

explicit AnatomicalOrientation(const DirectionType & d)
: m_Value(DirectionCosinesToOrientation(d))
: m_Value(ConvertDirectionToPositiveEnum(d))
{}

operator ToEnum() const { return m_Value; }
static AnatomicalOrientation
CreateFromPositiveStringEncoding(const std::string & str);

std::string
GetAsToStringEncoding() const;
static AnatomicalOrientation
CreateFromNegativeStringEncoding(const std::string & str);

std::string
GetAsFromStringEncoding() const;
operator PositiveEnum() const { return m_Value; }

static AnatomicalOrientation
CreateFromToStringEncoding(std::string str);

static AnatomicalOrientation
CreateFromFromStringEncoding(std::string str);
std::string
GetAsPositiveStringEncoding() const;

std::string
GetAsNegativeStringEncoding() const;

/** An involution to convert between "to" and "from" single character encoding strings.
/** An involution to convert between "positive" and "negative" single character encoding strings.
*
* For example the string "RAS" is converted to "LPI" and vice versa.
*
* The input maybe upper or lower case, while the output is always upper case.
* There is not check that the input is a valid encoding.
*
* */
static std::string
Expand All @@ -448,15 +451,21 @@ class ITKCommon_EXPORT AnatomicalOrientation
DirectionType
GetAsDirection() const
{
return OrientationToDirectionCosines(m_Value);
return ConvertPositiveEnumToDirection(m_Value);
}

ToEnum
GetAsOrientation() const
PositiveEnum
GetAsPositiveOrientation() const
{
return m_Value;
}

NegativeEnum
GetAsNegativeOrientation() const
{
return NegativeEnum(uint32_t(this->m_Value));
}

CoordinateEnum
GetPrimaryTerm() const
{
Expand Down Expand Up @@ -488,42 +497,41 @@ class ITKCommon_EXPORT AnatomicalOrientation
return (static_cast<uint8_t>(a) & AxisField) == (static_cast<uint8_t>(b) & AxisField);
}

/** \brief Return the closest orientation for a direction cosine matrix. */
static ToEnum
DirectionCosinesToOrientation(const DirectionType & dir);

/** \brief Return the direction cosine matrix for a orientation. */
static DirectionType OrientationToDirectionCosines(ToEnum);
friend ITKCommon_EXPORT std::ostream &
operator<<(std::ostream & out, PositiveEnum value);

protected:
/** \brief Return the direction cosine matrix for a orientation. */
static DirectionType ConvertPositiveEnumToDirection(PositiveEnum);

friend ITKCommon_EXPORT std::ostream &
operator<<(std::ostream & out, ToEnum value);

/** \brief Return the closest orientation for a direction cosine matrix. */
static PositiveEnum
ConvertDirectionToPositiveEnum(const DirectionType & dir);

private:
// Private methods to create the maps, these will only be called once.

/** \brief Return the global instance of the map from orientation enum to strings.
*
* The implementation uses a function static local variable so the global is created only if needed, only once.
*/
static const std::map<ToEnum, std::string> &
static const std::map<PositiveEnum, std::string> &
GetCodeToString();

/** \brief Return the global instance of the map from string to orientation enum.
*/
static const std::map<std::string, ToEnum> &
static const std::map<std::string, PositiveEnum> &
GetStringToCode();

ToEnum m_Value;
PositiveEnum m_Value;
};


ITKCommon_EXPORT std::ostream &
operator<<(std::ostream & out, typename AnatomicalOrientation::CoordinateEnum value);

ITKCommon_EXPORT std::ostream &
operator<<(std::ostream & out, typename AnatomicalOrientation::ToEnum value);
operator<<(std::ostream & out, typename AnatomicalOrientation::PositiveEnum value);

ITKCommon_EXPORT std::ostream &
operator<<(std::ostream & out, const AnatomicalOrientation & orientation);
Expand Down
81 changes: 42 additions & 39 deletions Modules/Core/Common/src/itkAnatomicalOrientation.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@ AnatomicalOrientation::AnatomicalOrientation(CoordinateEnum primary, CoordinateE
if (SameOrientationAxes(primary, secondary) || SameOrientationAxes(primary, tertiary) ||
SameOrientationAxes(secondary, tertiary))
{
m_Value = ToEnum::INVALID;
m_Value = PositiveEnum::INVALID;
}
else
{
m_Value = static_cast<ToEnum>(
m_Value = static_cast<PositiveEnum>(
(static_cast<uint32_t>(primary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::PrimaryMinor)) +
(static_cast<uint32_t>(secondary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::SecondaryMinor)) +
(static_cast<uint32_t>(tertiary) << static_cast<uint8_t>(CoordinateMajornessTermsEnum::TertiaryMinor)));
Expand All @@ -48,13 +48,13 @@ AnatomicalOrientation::AnatomicalOrientation(LegacyOrientationType legacyOrienta
}
#endif

AnatomicalOrientation::AnatomicalOrientation(AnatomicalOrientation::FromEnum fromOrientation)
: m_Value(ToEnum(uint32_t(fromOrientation)))
AnatomicalOrientation::AnatomicalOrientation(AnatomicalOrientation::NegativeEnum fromOrientation)
: m_Value(PositiveEnum(uint32_t(fromOrientation)))
{}


std::string
AnatomicalOrientation::GetAsToStringEncoding() const
AnatomicalOrientation::GetAsPositiveStringEncoding() const
{

// a lambda function to convert a CoordinateEnum to a char
Expand All @@ -78,7 +78,7 @@ AnatomicalOrientation::GetAsToStringEncoding() const
}
};

if (m_Value == ToEnum::INVALID)
if (m_Value == PositiveEnum::INVALID)
{
return "INVALID";
}
Expand All @@ -88,30 +88,30 @@ AnatomicalOrientation::GetAsToStringEncoding() const


std::string
AnatomicalOrientation::GetAsFromStringEncoding() const
AnatomicalOrientation::GetAsNegativeStringEncoding() const
{
return ConvertStringEncoding(GetAsToStringEncoding());
return ConvertStringEncoding(GetAsPositiveStringEncoding());
}


AnatomicalOrientation
AnatomicalOrientation::CreateFromToStringEncoding(std::string str)
AnatomicalOrientation::CreateFromPositiveStringEncoding(const std::string & str)
{
std::transform(str.begin(), str.end(), str.begin(), ::toupper);

const std::map<std::string, typename AnatomicalOrientation::ToEnum> & stringToCode = GetStringToCode();
auto iter = stringToCode.find(str);
const std::map<std::string, typename AnatomicalOrientation::PositiveEnum> & stringToCode = GetStringToCode();
auto iter = stringToCode.find(str);
if (iter == stringToCode.end())
{
return AnatomicalOrientation(ToEnum::INVALID);
return AnatomicalOrientation(PositiveEnum::INVALID);
}
return AnatomicalOrientation(iter->second);
}

AnatomicalOrientation
AnatomicalOrientation::CreateFromFromStringEncoding(std::string str)
AnatomicalOrientation::CreateFromNegativeStringEncoding(const std::string & str)
{
return AnatomicalOrientation::CreateFromToStringEncoding(ConvertStringEncoding(str));
return AnatomicalOrientation::CreateFromPositiveStringEncoding(ConvertStringEncoding(str));
}


Expand Down Expand Up @@ -156,36 +156,39 @@ AnatomicalOrientation::GetCoordinateTerm(CoordinateMajornessTermsEnum cmt) const
}


const std::map<typename AnatomicalOrientation::ToEnum, std::string> &
const std::map<typename AnatomicalOrientation::PositiveEnum, std::string> &
AnatomicalOrientation::GetCodeToString()
{
auto createCodeToString = []() -> std::map<ToEnum, std::string> {
std::map<ToEnum, std::string> orientToString;

for (auto code : { ToEnum::RIP, ToEnum::LIP, ToEnum::RSP, ToEnum::LSP, ToEnum::RIA, ToEnum::LIA, ToEnum::RSA,
ToEnum::LSA, ToEnum::IRP, ToEnum::ILP, ToEnum::SRP, ToEnum::SLP, ToEnum::IRA, ToEnum::ILA,
ToEnum::SRA, ToEnum::SLA, ToEnum::RPI, ToEnum::LPI, ToEnum::RAI, ToEnum::LAI, ToEnum::RPS,
ToEnum::LPS, ToEnum::RAS, ToEnum::LAS, ToEnum::PRI, ToEnum::PLI, ToEnum::ARI, ToEnum::ALI,
ToEnum::PRS, ToEnum::PLS, ToEnum::ARS, ToEnum::ALS, ToEnum::IPR, ToEnum::SPR, ToEnum::IAR,
ToEnum::SAR, ToEnum::IPL, ToEnum::SPL, ToEnum::IAL, ToEnum::SAL, ToEnum::PIR, ToEnum::PSR,
ToEnum::AIR, ToEnum::ASR, ToEnum::PIL, ToEnum::PSL, ToEnum::AIL, ToEnum::ASL, ToEnum::INVALID })
auto createCodeToString = []() -> std::map<PositiveEnum, std::string> {
std::map<PositiveEnum, std::string> orientToString;

for (auto code : { PositiveEnum::RIP, PositiveEnum::LIP, PositiveEnum::RSP, PositiveEnum::LSP, PositiveEnum::RIA,
PositiveEnum::LIA, PositiveEnum::RSA, PositiveEnum::LSA, PositiveEnum::IRP, PositiveEnum::ILP,
PositiveEnum::SRP, PositiveEnum::SLP, PositiveEnum::IRA, PositiveEnum::ILA, PositiveEnum::SRA,
PositiveEnum::SLA, PositiveEnum::RPI, PositiveEnum::LPI, PositiveEnum::RAI, PositiveEnum::LAI,
PositiveEnum::RPS, PositiveEnum::LPS, PositiveEnum::RAS, PositiveEnum::LAS, PositiveEnum::PRI,
PositiveEnum::PLI, PositiveEnum::ARI, PositiveEnum::ALI, PositiveEnum::PRS, PositiveEnum::PLS,
PositiveEnum::ARS, PositiveEnum::ALS, PositiveEnum::IPR, PositiveEnum::SPR, PositiveEnum::IAR,
PositiveEnum::SAR, PositiveEnum::IPL, PositiveEnum::SPL, PositiveEnum::IAL, PositiveEnum::SAL,
PositiveEnum::PIR, PositiveEnum::PSR, PositiveEnum::AIR, PositiveEnum::ASR, PositiveEnum::PIL,
PositiveEnum::PSL, PositiveEnum::AIL, PositiveEnum::ASL, PositiveEnum::INVALID })
{
orientToString[code] = AnatomicalOrientation(code).GetAsToStringEncoding();
orientToString[code] = AnatomicalOrientation(code).GetAsPositiveStringEncoding();
}

return orientToString;
};
static const std::map<ToEnum, std::string> codeToString = createCodeToString();
static const std::map<PositiveEnum, std::string> codeToString = createCodeToString();
return codeToString;
}

const std::map<std::string, AnatomicalOrientation::ToEnum> &
const std::map<std::string, AnatomicalOrientation::PositiveEnum> &
AnatomicalOrientation::GetStringToCode()
{

auto createStringToCode = []() -> std::map<std::string, ToEnum> {
std::map<std::string, ToEnum> stringToCode;
const std::map<ToEnum, std::string> & codeToString = GetCodeToString();
auto createStringToCode = []() -> std::map<std::string, PositiveEnum> {
std::map<std::string, PositiveEnum> stringToCode;
const std::map<PositiveEnum, std::string> & codeToString = GetCodeToString();

for (const auto & kv : codeToString)
{
Expand All @@ -194,13 +197,13 @@ AnatomicalOrientation::GetStringToCode()
return stringToCode;
};

static const std::map<std::string, AnatomicalOrientation::ToEnum> stringToCode = createStringToCode();
static const std::map<std::string, AnatomicalOrientation::PositiveEnum> stringToCode = createStringToCode();
return stringToCode;
}


typename AnatomicalOrientation::ToEnum
AnatomicalOrientation::DirectionCosinesToOrientation(const DirectionType & dir)
AnatomicalOrientation::PositiveEnum
AnatomicalOrientation::ConvertDirectionToPositiveEnum(const DirectionType & dir)
{
// NOTE: This method was based off of itk::SpatialObjectAdaptor::FromDirectionCosines
// but it is DIFFERENT in the meaning of direction in terms of sign-ness.
Expand Down Expand Up @@ -265,7 +268,7 @@ AnatomicalOrientation::DirectionCosinesToOrientation(const DirectionType & dir)


typename AnatomicalOrientation::DirectionType
AnatomicalOrientation::OrientationToDirectionCosines(ToEnum orientationEnum)
AnatomicalOrientation::ConvertPositiveEnumToDirection(PositiveEnum orientationEnum)
{
const AnatomicalOrientation o(orientationEnum);

Expand Down Expand Up @@ -323,15 +326,15 @@ operator<<(std::ostream & out, typename AnatomicalOrientation::CoordinateEnum va
}

std::ostream &
operator<<(std::ostream & out, typename AnatomicalOrientation::ToEnum value)
operator<<(std::ostream & out, typename AnatomicalOrientation::PositiveEnum value)
{
return (out << AnatomicalOrientation(value).GetAsToStringEncoding());
return (out << AnatomicalOrientation(value).GetAsPositiveStringEncoding());
}

std::ostream &
operator<<(std::ostream & out, typename AnatomicalOrientation::FromEnum value)
operator<<(std::ostream & out, typename AnatomicalOrientation::NegativeEnum value)
{
return (out << AnatomicalOrientation(value).GetAsFromStringEncoding());
return (out << AnatomicalOrientation(value).GetAsNegativeStringEncoding());
}

std::ostream &
Expand Down
Loading

0 comments on commit 55d091f

Please sign in to comment.