Jörg Riesmeier wrote:
I would rather go one level of abstraction up and define something like getNumberOfExposures() - but of course only for very important elements that are accessed quite often.
I think the following approach makes sense:
Define access functions to sequence objects like this (example from RTDose):
Code:
OFList<DRTStructureSetROISequence::Item> getDRTStructureSetROISequenceElements();
DRTStructureSetROISequence::Item getDRTStructureSetROISequenceElement(Uint16);
Implementation:
Code:
OFList<DRTROIContourSequence::Item> DRTDose::getDRTROIContourSequenceElements()
{
OFList<DRTROIContourSequence::Item> roi_contour_list;
DRTROIContourSequence &seq = this->getROIContourSequence();
if(!seq.isEmpty())
{
if (seq.gotoFirstItem().good())
{
do
{
DRTROIContourSequence::Item &item = seq.getCurrentItem();
roi_contour_list.push_back(item);
} while (seq.gotoNextItem().good());
}
}
return roi_contour_list;
}
DRTROIContourSequence::Item DRTDose::getDRTROIContourSequenceElement(Uint16 element)
{
OFList<DRTROIContourSequence::Item> list = this->getDRTROIContourSequenceElements();
size_t size = list.size();
OFListIterator(DRTROIContourSequence::Item) start = list.begin();
OFListIterator(DRTROIContourSequence::Item) stop = list.end();
Uint16 ctr=0;
DRTROIContourSequence::Item current = *start;
while (start != stop)
{
if(element == ctr)
break;
++start;
++ctr;
}
return current;
}
These functions will access the StructureSetROISequence objects. The first one returns a list of all objects of that kind found. The second returns one item from the sequence (selected by the position in the sequence).
So far this is straight forward.
For sequences containing sequences i propose the following:
One case is the RoiContourSequence where each item can contain another ContourSequence.
Code:
(3006,0039) SQ (Sequence with undefined length #=1) # u/l, 1 ROIContourSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(3006,002a) IS [0\0\255] # 8, 3 ROIDisplayColor
(3006,0040) SQ (Sequence with undefined length #=1) # u/l, 1 ContourSequence
(fffe,e000) na (Item with undefined length #=3) # u/l, 1 Item
(3006,0042) CS [POINT] # 6, 1 ContourGeometricType
(3006,0046) IS [1] # 2, 1 NumberOfContourPoints
(3006,0050) DS [7.10\-174.70\-841.50] # 20, 3 ContourData
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
(3006,0084) IS [1] # 2, 1 ReferencedROINumber
(fffe,e00d) na (ItemDelimitationItem) # 0, 0 ItemDelimitationItem
(fffe,e0dd) na (SequenceDelimitationItem) # 0, 0 SequenceDelimitationItem
Here the following would handle the access
Code:
OFList<DRTContourSequence::Item> DRTDose::getDRTContourSequenceElements(Uint16);
DRTContourSequence::Item DRTDose::getDRTContourSequenceElement(Uint16, Uint16);
Implementation:
Code:
OFList<DRTContourSequence::Item> DRTDose::getDRTContourSequenceElements(Uint16 RoiCSEelement)
{
DRTROIContourSequence::Item ROIContSequenceElement = getDRTROIContourSequenceElement(RoiCSEelement);
OFList<DRTContourSequence::Item> contour_list;
DRTContourSequence &seq = ROIContSequenceElement.getContourSequence();
if(!seq.isEmpty())
{
if (seq.gotoFirstItem().good())
{
do
{
DRTContourSequence::Item &item = seq.getCurrentItem();
contour_list.push_back(item);
} while (seq.gotoNextItem().good());
}
}
return contour_list;
}
DRTContourSequence::Item DRTDose::getDRTContourSequenceElement(Uint16 RoiCSEelement, Uint16 CSelement)
{
OFList<DRTContourSequence::Item> list = getDRTContourSequenceElements(RoiCSEelement);
size_t size = list.size();
OFListIterator(DRTContourSequence::Item) start = list.begin();
OFListIterator(DRTContourSequence::Item) stop = list.end();
Uint16 ctr=0;
DRTContourSequence::Item current = *start;
while (start != stop)
{
if(CSelement == ctr)
break;
++start;
++ctr;
}
return current;
}
This will create flat access points to sequence items of any kind. Of course the user still has to know the logical connections between the objects in nested sequences.
For tripple nested objects the logic would be
Code:
OFList<AnySequence::Item> DRTDose::getDRTAnySequenceElements(Uint16, Uint16);
AnySequence::Item DRTDose::getDRTAnySequenceElement(Uint16, Uint16, Uint16);
Since these access functions are structurally always very similar i thought about using templated functions. But i am not sure if this is a clever idea or even possible.
What is your opinion.
Do you think the mid-API sequence handling of RT IODs is well addressed?