Skip to content

Commit

Permalink
Update Writer class to support OD, OL and OV value representations (#94)
Browse files Browse the repository at this point in the history
  • Loading branch information
ClementTroesch committed Apr 2, 2024
1 parent ec44c7b commit 030183b
Show file tree
Hide file tree
Showing 6 changed files with 170 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/odil/VR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ _build_enum_to_name()
ADD_TO_MAP(result, OD);
ADD_TO_MAP(result, OF);
ADD_TO_MAP(result, OL);
ADD_TO_MAP(result, OV);
ADD_TO_MAP(result, OW);
ADD_TO_MAP(result, PN);
ADD_TO_MAP(result, SH);
Expand Down
20 changes: 17 additions & 3 deletions src/odil/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,9 @@ ::size(
(
element.vr == odil::VR::OB || element.vr == odil::VR::OW
|| element.vr == odil::VR::OF || element.vr == odil::VR::SQ
|| element.vr == odil::VR::UT || element.vr == odil::VR::UN)
|| element.vr == odil::VR::UT || element.vr == odil::VR::UN
|| element.vr == odil::VR::OD || element.vr == odil::VR::OL
|| element.vr == odil::VR::OV)
? 2+4 /* PS3.5, table 7.1-1*/
: 2 /* PS3.5, table 7.1-2*/ )
: 4 /* PS 3.5, table 7.1-3 */;
Expand Down Expand Up @@ -648,18 +650,30 @@ ::operator()(Value::Binary const & value) const
Writer::write_binary(item, this->stream, this->byte_ordering);
}
}
else if(this->vr == VR::OF)
else if(this->vr == VR::OF || this->vr == VR::OL)
{
if(value[0].size()%4 != 0)
{
throw Exception("Value cannot be written as OF");
throw Exception("Value cannot be written as " + as_string(this->vr));
}
for(int i=0; i<value[0].size(); i+=4)
{
uint32_t item = *reinterpret_cast<uint32_t const *>(&value[0][i]);
Writer::write_binary(item, this->stream, this->byte_ordering);
}
}
else if(this->vr == VR::OD || this->vr == VR::OV)
{
if(value[0].size()%8 != 0)
{
throw Exception("Value cannot be written as " + as_string(this->vr));
}
for(int i=0; i<value[0].size(); i+=8)
{
uint64_t item = *reinterpret_cast<uint64_t const *>(&value[0][i]);
Writer::write_binary(item, this->stream, this->byte_ordering);
}
}
else
{
throw Exception("Cannot write "+as_string(this->vr)+" as binary");
Expand Down
18 changes: 18 additions & 0 deletions src/odil/dcmtk/ElementAccessor.txx
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,24 @@ get_binary(DcmElement const & element, unsigned long const position)
condition = const_cast<DcmElement&>(element).getFloat32Array(typed_data);
data = reinterpret_cast<typename TValueType::value_type *>(typed_data);
}
else if(evr == EVR_OL)
{
Uint32 * typed_data;
condition = const_cast<DcmElement&>(element).getUint32Array(typed_data);
data = reinterpret_cast<typename TValueType::value_type *>(typed_data);
}
else if(evr == EVR_OD)
{
Float64 * typed_data;
condition = const_cast<DcmElement&>(element).getFloat64Array(typed_data);
data = reinterpret_cast<typename TValueType::value_type *>(typed_data);
}
else if(evr == EVR_OV)
{
Uint64 * typed_data;
condition = const_cast<DcmElement&>(element).getUint64Array(typed_data);
data = reinterpret_cast<typename TValueType::value_type *>(typed_data);
}
else
{
throw Exception(
Expand Down
93 changes: 92 additions & 1 deletion src/odil/dcmtk/conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,10 @@ DcmEVR convert(VR vr)
else if(vr == VR::LO) { return EVR_LO; }
else if(vr == VR::LT) { return EVR_LT; }
else if(vr == VR::OB) { return EVR_OB; }
else if(vr == VR::OD) { return EVR_OD; }
else if(vr == VR::OF) { return EVR_OF; }
else if(vr == VR::OL) { return EVR_OL; }
else if(vr == VR::OV) { return EVR_OV; }
else if(vr == VR::OW) { return EVR_OW; }
else if(vr == VR::PN) { return EVR_PN; }
else if(vr == VR::SH) { return EVR_SH; }
Expand Down Expand Up @@ -75,7 +78,10 @@ VR convert(DcmEVR evr)
else if(evr == EVR_LO) { return VR::LO; }
else if(evr == EVR_LT) { return VR::LT; }
else if(evr == EVR_OB) { return VR::OB; }
else if(evr == EVR_OD) { return VR::OD; }
else if(evr == EVR_OF) { return VR::OF; }
else if(evr == EVR_OL) { return VR::OL; }
else if(evr == EVR_OV) { return VR::OV; }
else if(evr == EVR_OW) { return VR::OW; }
else if(evr == EVR_PN) { return VR::PN; }
else if(evr == EVR_SH) { return VR::SH; }
Expand Down Expand Up @@ -219,6 +225,14 @@ DcmElement * convert(const Tag & tag, Element const & source)
convert(source, static_cast<DcmOtherByteOtherWord*>(destination));
}
}
else if(source.vr == VR::OD)
{
destination = new DcmOtherDouble(destination_tag);
if(!source.empty())
{
convert(source, static_cast<DcmOtherDouble*>(destination));
}
}
else if(source.vr == VR::OF)
{
destination = new DcmOtherFloat(destination_tag);
Expand All @@ -227,6 +241,22 @@ DcmElement * convert(const Tag & tag, Element const & source)
convert(source, static_cast<DcmOtherFloat*>(destination));
}
}
else if(source.vr == VR::OL)
{
destination = new DcmOtherLong(destination_tag);
if(!source.empty())
{
convert(source, static_cast<DcmOtherLong*>(destination));
}
}
else if(source.vr == VR::OV)
{
destination = new DcmOther64bitVeryLong(destination_tag);
if(!source.empty())
{
convert(source, static_cast<DcmOther64bitVeryLong*>(destination));
}
}
else if (source.vr == VR::PN)
{
destination = new DcmPersonName(destination_tag);
Expand Down Expand Up @@ -417,7 +447,8 @@ Element convert(DcmElement * source)
destination = std::make_shared<Element>(Value::Integers(), destination_vr);
convert<Uint32, Value::Integers>(source, *destination, &Element::as_int);
}
else if(source_vr == EVR_OB || source_vr == EVR_OF || source_vr == EVR_OW ||
else if(source_vr == EVR_OB || source_vr == EVR_OD || source_vr == EVR_OF ||
source_vr == EVR_OL || source_vr == EVR_OV || source_vr == EVR_OW ||
source_vr == EVR_UN)
{
destination = std::make_shared<Element>(Value::Binary(), destination_vr);
Expand Down Expand Up @@ -485,6 +516,66 @@ void convert(Element const & source, DcmOtherFloat * destination)
}
}

void convert(Element const & source, DcmOtherLong * destination)
{
auto const & value = source.as_binary();
if(value.size() > 1)
{
throw Exception("Cannot convert multiple valued binary element");
}

if(value[0].size()%4 != 0)
{
throw Exception("Cannot convert OL from odd-sized array");
}

for(unsigned int i=0; i<value[0].size()/4; ++i)
{
uint32_t const f = *reinterpret_cast<uint32_t const *>(&value[0][i*4]);
destination->putUint32(f, i);
}
}

void convert(Element const & source, DcmOtherDouble * destination)
{
auto const & value = source.as_binary();
if(value.size() > 1)
{
throw Exception("Cannot convert multiple valued binary element");
}

if(value[0].size()%8 != 0)
{
throw Exception("Cannot convert OD from odd-sized array");
}

for(unsigned int i=0; i<value[0].size()/8; ++i)
{
double const f = *reinterpret_cast<double const *>(&value[0][i*8]);
destination->putFloat64(f, i);
}
}

void convert(Element const & source, DcmOther64bitVeryLong * destination)
{
auto const & value = source.as_binary();
if(value.size() > 1)
{
throw Exception("Cannot convert multiple valued binary element");
}

if(value[0].size()%8 != 0)
{
throw Exception("Cannot convert OV from odd-sized array");
}

for(unsigned int i=0; i<value[0].size()/8; ++i)
{
uint64_t const f = *reinterpret_cast<uint64_t const *>(&value[0][i*8]);
destination->putUint64(f, i);
}
}

DcmItem * convert(std::shared_ptr<DataSet const> source, bool as_data_set)
{
DcmItem * destination = as_data_set?(new DcmDataset()):(new DcmItem());
Expand Down
9 changes: 9 additions & 0 deletions src/odil/dcmtk/conversion.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ void convert(Element const & source, DcmOtherByteOtherWord * destination);
/// @brief Low-level element converter.
ODIL_API void convert(Element const & source, DcmOtherFloat * destination);

/// @brief Low-level element converter.
ODIL_API void convert(Element const & source, DcmOtherLong * destination);

/// @brief Low-level element converter.
ODIL_API void convert(Element const & source, DcmOtherDouble * destination);

/// @brief Low-level element converter.
ODIL_API void convert(Element const & source, DcmOther64bitVeryLong * destination);

/// @brief Low-level element converter.
template<typename TSourceType, typename TDestinationType>
void convert(
Expand Down
33 changes: 33 additions & 0 deletions tests/code/Writer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,17 @@ BOOST_AUTO_TEST_CASE(OF)
do_test(odil_data_set);
}

BOOST_AUTO_TEST_CASE(OL)
{
odil::Element odil_element(
odil::Value::Binary({{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08}}),
odil::VR::OL);
auto odil_data_set = std::make_shared<odil::DataSet>();
odil_data_set->add(odil::registry::LongTrianglePointIndexList, odil_element);

do_test(odil_data_set);
}

BOOST_AUTO_TEST_CASE(OW)
{
odil::Element odil_element(
Expand All @@ -174,6 +185,28 @@ BOOST_AUTO_TEST_CASE(OW)
do_test(odil_data_set);
}

BOOST_AUTO_TEST_CASE(OD)
{
odil::Element odil_element(
odil::Value::Binary({{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}}}),
odil::VR::OD);
auto odil_data_set = std::make_shared<odil::DataSet>();
odil_data_set->add(odil::registry::VolumetricCurvePoints, odil_element);

do_test(odil_data_set);
}

BOOST_AUTO_TEST_CASE(OV)
{
odil::Element odil_element(
odil::Value::Binary({{{0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10}}}),
odil::VR::OV);
auto odil_data_set = std::make_shared<odil::DataSet>();
odil_data_set->add(odil::registry::ExtendedOffsetTable, odil_element);

do_test(odil_data_set);
}

BOOST_AUTO_TEST_CASE(SL)
{
odil::Element odil_element({12345678, -8765432}, odil::VR::SL);
Expand Down

0 comments on commit 030183b

Please sign in to comment.