23 :m_Precision(precision)
29 :m_Precision(other.m_Precision)
39 std::ostringstream resultString;
40 resultString.str(std::string());
42 resultString.setf(std::ios::fixed, std::ios::floatfield);
43 resultString.precision(m_Precision);
45 std::stringstream ss(input);
50 std::istringstream converter(item);
51 while (std::getline(ss, item,
'\\'))
55 if (converter >> number && converter.eof())
58 resultString << number;
72 return resultString.str();
101 for(
auto ti = m_TagValueProcessor.cbegin();
102 ti != m_TagValueProcessor.cend();
112 ,m_DistinguishingTags( other.m_DistinguishingTags )
113 ,m_SortCriterion( other.m_SortCriterion )
114 ,m_StrictSorting( other.m_StrictSorting )
115 ,m_ExpectDistanceOne( other.m_ExpectDistanceOne )
141 m_TagValueProcessor[ti->first] = ti->second->Clone();
151 if (
const DICOMTagBasedSorter* otherSelf = dynamic_cast<const DICOMTagBasedSorter*>(&other))
153 if (this->m_StrictSorting != otherSelf->m_StrictSorting)
return false;
154 if (this->m_ExpectDistanceOne != otherSelf->m_ExpectDistanceOne)
return false;
156 bool allTagsPresentAndEqual(
true);
157 if (this->m_DistinguishingTags.size() != otherSelf->m_DistinguishingTags.size())
160 for (
auto myTag = this->m_DistinguishingTags.cbegin();
161 myTag != this->m_DistinguishingTags.cend();
164 allTagsPresentAndEqual &= (std::find( otherSelf->m_DistinguishingTags.cbegin(), otherSelf->m_DistinguishingTags.cend(), *myTag )
165 != otherSelf->m_DistinguishingTags.cend());
169 if (!allTagsPresentAndEqual)
return false;
171 if (this->m_SortCriterion.IsNotNull() && otherSelf->m_SortCriterion.IsNotNull())
173 return *(this->m_SortCriterion) == *(otherSelf->m_SortCriterion);
177 return this->m_SortCriterion.IsNull() && otherSelf->m_SortCriterion.IsNull();
190 os << indent <<
"Tag based sorting "
191 <<
"(strict=" << (m_StrictSorting?
"true":
"false")
192 <<
", expectDistanceOne=" << (m_ExpectDistanceOne?
"true":
"false") <<
"):"
195 for (
auto tagIter = m_DistinguishingTags.begin();
196 tagIter != m_DistinguishingTags.end();
199 os << indent <<
" Split on ";
205 while (crit.IsNotNull())
207 os << indent <<
" Sort by ";
210 crit = crit->GetSecondaryCriterion();
218 m_StrictSorting = strict;
225 return m_StrictSorting;
232 m_ExpectDistanceOne = strict;
239 return m_ExpectDistanceOne;
249 const DICOMTagList sortingRelevantTags = m_SortCriterion->GetAllTagsOfInterest();
250 allTags.insert( allTags.end(), sortingRelevantTags.cbegin(), sortingRelevantTags.cend() );
259 return m_DistinguishingTags;
266 auto loc = m_TagValueProcessor.find(tag);
267 if (loc != m_TagValueProcessor.cend())
281 m_DistinguishingTags.push_back(tag);
282 m_TagValueProcessor[tag] = tagValueProcessor;
289 m_SortCriterion = criterion;
296 return m_SortCriterion;
309 this->SetNumberOfOutputs(sortedGroups.size());
310 unsigned int outputIndex(0);
311 for (
auto groupIter = sortedGroups.cbegin();
312 groupIter != sortedGroups.cend();
313 ++outputIndex, ++groupIter)
315 this->SetOutput(outputIndex, groupIter->second);
325 std::stringstream groupID;
327 for (
auto tagIter = m_DistinguishingTags.cbegin();
328 tagIter != m_DistinguishingTags.cend();
331 groupID << tagIter->GetGroup() << tagIter->GetElement();
333 std::string processedTagValue;
334 if ( m_TagValueProcessor[*tagIter] !=
nullptr && rawTagValue.
isValid)
336 processedTagValue = (*m_TagValueProcessor[*tagIter])(rawTagValue.
value);
340 processedTagValue = rawTagValue.
value;
342 groupID << processedTagValue;
345 return groupID.str();
356 for (
auto dsIter = input.cbegin();
357 dsIter != input.cend();
363 std::string groupID = this->BuildGroupID( dataset );
365 listForGroupID[groupID].push_back(dataset);
368 MITK_DEBUG <<
"After tag based splitting: " << listForGroupID.size() <<
" groups";
370 return listForGroupID;
377 if (m_SortCriterion.IsNotNull())
397 unsigned int groupIndex(0);
398 for (
auto gIter = groups.begin();
399 gIter != groups.end();
400 ++groupIndex, ++gIter)
404 #ifdef MBILOG_ENABLE_DEBUG
405 MITK_DEBUG <<
" --------------------------------------------------------------------------------";
406 MITK_DEBUG <<
" DICOMTagBasedSorter before sorting group : " << groupIndex;
407 for (
auto oi = dsList.begin();
411 MITK_DEBUG <<
" INPUT : " << (*oi)->GetFilenameIfAvailable();
413 #endif // #ifdef MBILOG_ENABLE_DEBUG
418 #ifdef MBILOG_ENABLE_DEBUG
419 MITK_DEBUG <<
" --------------------------------------------------------------------------------";
420 MITK_DEBUG <<
" DICOMTagBasedSorter after sorting group : " << groupIndex;
421 for (
auto oi = dsList.cbegin();
425 MITK_DEBUG <<
" OUTPUT : " << (*oi)->GetFilenameIfAvailable();
427 MITK_DEBUG <<
" --------------------------------------------------------------------------------";
429 #endif // MBILOG_ENABLE_DEBUG
437 unsigned int groupIndex(0);
438 for (
auto gIter = groups.begin();
439 gIter != groups.end();
442 std::stringstream groupKey;
443 groupKey << std::setfill(
'0') << std::setw(6) << groupIndex++;
447 unsigned int dsIndex(0);
448 double constantDistance(0.0);
449 bool constantDistanceInitialized(
false);
450 for (
auto dataset = dsList.cbegin();
451 dataset != dsList.cend();
452 ++dsIndex, ++dataset)
459 const double currentDistance = m_SortCriterion->NumericDistance(previousDS, *dataset);
460 if (constantDistanceInitialized)
462 if (fabs(currentDistance - constantDistance) < fabs(constantDistance * 0.01))
465 MITK_DEBUG <<
"Checking currentDistance==" << currentDistance <<
": small enough";
470 MITK_DEBUG <<
"Split consecutive group at index " << dsIndex <<
" (current distance " << currentDistance <<
", constant distance " << constantDistance <<
")";
472 groupKey.str(std::string());
474 groupKey << std::setfill(
'0') << std::setw(6) << groupIndex++;
490 if (m_ExpectDistanceOne)
492 if ((currentDistance - (
int)currentDistance == 0.0) && fabs(currentDistance) != 1.0)
495 MITK_DEBUG <<
"Split consecutive group at index " << dsIndex <<
" (special case: expected distance 1 exactly)";
496 groupKey.str(std::string());
498 groupKey << std::setfill(
'0') << std::setw(6) << groupIndex++;
502 MITK_DEBUG <<
"Initialize strict distance to currentDistance=" << currentDistance;
504 constantDistance = currentDistance;
505 constantDistanceInitialized =
true;
508 consecutiveGroups[groupKey.str()].push_back(*dataset);
509 previousDS = *dataset;
515 consecutiveGroups = groups;
529 for (
auto gIter = consecutiveGroups.cbegin();
530 gIter != consecutiveGroups.cend();
533 assert(!gIter->second.empty());
534 firstSlices.push_back(gIter->second.front());
540 unsigned int groupKeyValue(0);
541 for (
auto firstSlice = firstSlices.cbegin();
542 firstSlice != firstSlices.cend();
545 for (
auto gIter = consecutiveGroups.cbegin();
546 gIter != consecutiveGroups.cend();
547 ++groupKeyValue, ++gIter)
549 if (gIter->second.front() == *firstSlice)
551 std::stringstream groupKey;
552 groupKey << std::setfill(
'0') << std::setw(6) << groupKeyValue;
553 sortedResultBlocks[groupKey.str()] = gIter->second;
558 groups = sortedResultBlocks;
561 #ifdef MBILOG_ENABLE_DEBUG
562 unsigned int groupIndex( 0 );
563 for (
auto gIter = groups.begin(); gIter != groups.end(); ++groupIndex, ++gIter )
566 MITK_DEBUG <<
" --------------------------------------------------------------------------------";
567 MITK_DEBUG <<
" DICOMTagBasedSorter after sorting group : " << groupIndex;
568 for (
auto oi = dsList.begin(); oi != dsList.end(); ++oi )
570 MITK_DEBUG <<
" OUTPUT : " << ( *oi )->GetFilenameIfAvailable();
572 MITK_DEBUG <<
" --------------------------------------------------------------------------------";
574 #endif // MBILOG_ENABLE_DEBUG
583 :m_SortCriterion(criterion)
void SetStrictSorting(bool strict)
Whether or not groups should be checked for consecutive tag values.
DICOMTagList GetDistinguishingTags() const
virtual void PrintConfiguration(std::ostream &os, const std::string &indent="") const override
Print configuration details into given stream.
void SetExpectDistanceOne(bool strict)
Flag for a special case in "strict sorting". Please see documentation of SetStrictSorting().
The sorting/splitting building-block of DICOMITKSeriesGDCMReader.
void SetSortCriterion(DICOMSortCriterion::ConstPointer criterion)
Define the sorting criterion (which holds seconardy criteria)
std::vector< DICOMTag > DICOMTagList
ParameterizedDatasetSort(DICOMSortCriterion::ConstPointer)
GroupIDToListType & SortGroups(GroupIDToListType &groups)
Implements the sorting step. Relatively simple implementation thanks to std::sort and a parameterizat...
DICOMTagList m_DistinguishingTags
Representation of a DICOM tag.
virtual bool operator==(const DICOMDatasetSorter &other) const override
std::map< std::string, DICOMDatasetList > GroupIDToListType
CutDecimalPlaces(unsigned int precision)
itk::SmartPointer< const Self > ConstPointer
Helper struct to feed into std::sort, configured via DICOMSortCriterion.
Interface to datasets that is presented to sorting classes such as DICOMDatasetSorter.
GroupIDToListType SplitInputGroups()
Implements the "distiguishing tags". To sort datasets into different groups, a long string will be bu...
void AddDistinguishingTag(const DICOMTag &, TagValueProcessor *tagValueProcessor=nullptr)
Datasets that differ in given tag's value will be sorted into separate outputs.
const TagValueProcessor * GetTagValueProcessorForDistinguishingTag(const DICOMTag &) const
unsigned int GetPrecision() const
bool GetStrictSorting() const
virtual DICOMDatasetFinding GetTagValueAsString(const DICOMTag &tag) const =0
Return a DICOMDatasetFinding instance of the tag. The return containes (if valid) the raw value of th...
TagValueProcessorMap m_TagValueProcessor
virtual std::string operator()(const std::string &) const override
Implements the "processing".
DICOMTagBasedSorter & operator=(const DICOMTagBasedSorter &other)
DICOMSortCriterion::ConstPointer m_SortCriterion
DICOMSortCriterion::ConstPointer GetSortCriterion() const
virtual void Sort() override
Actually sort as described in the Detailed Description.
bool operator()(const mitk::DICOMDatasetAccess *left, const mitk::DICOMDatasetAccess *right)
virtual TagValueProcessor * Clone() const override
bool GetExpectDistanceOne() const
virtual DICOMTagList GetTagsOfInterest() override
A list of all the tags needed for processing (facilitates scanning).
Cuts a number after configured number of decimal places. An instance of this class can be used to avo...
virtual std::string GetFilenameIfAvailable() const =0
Return a filename if possible. If DICOM is not read from file but from somewhere else (network...
Sort DICOM datasets based on configurable tags.
Processes tag values before they are compared. These classes could do some kind of normalization such...
DICOMDatasetSorter & operator=(const DICOMDatasetSorter &other)
std::vector< DICOMDatasetAccess * > DICOMDatasetList
std::string BuildGroupID(DICOMDatasetAccess *dataset)
Helper for SplitInputGroups().
virtual ~DICOMTagBasedSorter()