1 /*
2  *
3  *  Copyright (C) 1999-2010, OFFIS e.V.
4  *  All rights reserved.  See COPYRIGHT file for details.
5  *
6  *  This software and supporting documentation were developed by
7  *
8  *    OFFIS e.V.
9  *    R&D Division Health
10  *    Escherweg 2
11  *    D-26121 Oldenburg, Germany
12  *
13  *
14  *  Module: dcmpstat
15  *
16  *  Author: Marco Eichelberg
17  *
18  *  Purpose:
19  *    classes: DVPSDisplayedArea_PList
20  *
21  */
22 
23 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
24 #include "dcmtk/dcmpstat/dvpsdal.h"
25 #include "dcmtk/dcmpstat/dvpsda.h"      /* for DVPSDisplayedArea */
26 #include "dcmtk/dcmpstat/dvpsri.h"      /* for DVPSReferencedImage, needed by MSVC5 with STL */
27 
28 
DVPSDisplayedArea_PList()29 DVPSDisplayedArea_PList::DVPSDisplayedArea_PList()
30 : list_()
31 {
32 }
33 
DVPSDisplayedArea_PList(const DVPSDisplayedArea_PList & arg)34 DVPSDisplayedArea_PList::DVPSDisplayedArea_PList(const DVPSDisplayedArea_PList &arg)
35 : list_()
36 {
37   OFListConstIterator(DVPSDisplayedArea *) first = arg.list_.begin();
38   OFListConstIterator(DVPSDisplayedArea *) last = arg.list_.end();
39   while (first != last)
40   {
41     list_.push_back((*first)->clone());
42     ++first;
43   }
44 }
45 
~DVPSDisplayedArea_PList()46 DVPSDisplayedArea_PList::~DVPSDisplayedArea_PList()
47 {
48   clear();
49 }
50 
clear()51 void DVPSDisplayedArea_PList::clear()
52 {
53   OFListIterator(DVPSDisplayedArea *) first = list_.begin();
54   OFListIterator(DVPSDisplayedArea *) last = list_.end();
55   while (first != last)
56   {
57     delete (*first);
58     first = list_.erase(first);
59   }
60 }
61 
read(DcmItem & dset)62 OFCondition DVPSDisplayedArea_PList::read(DcmItem &dset)
63 {
64   OFCondition result = EC_Normal;
65   DcmStack stack;
66   DVPSDisplayedArea *newImage = NULL;
67   DcmSequenceOfItems *dseq=NULL;
68   DcmItem *ditem=NULL;
69 
70   if (EC_Normal == dset.search(DCM_DisplayedAreaSelectionSequence, stack, ESM_fromHere, OFFalse))
71   {
72     dseq=(DcmSequenceOfItems *)stack.top();
73     if (dseq)
74     {
75       unsigned long numItems = dseq->card();
76       for (unsigned int i=0; i<numItems; i++)
77       {
78         ditem = dseq->getItem(i);
79         newImage = new DVPSDisplayedArea();
80         if (newImage && ditem)
81         {
82           result = newImage->read(*ditem);
83           list_.push_back(newImage);
84         } else result = EC_MemoryExhausted;
85       }
86     }
87   }
88 
89   return result;
90 }
91 
write(DcmItem & dset)92 OFCondition DVPSDisplayedArea_PList::write(DcmItem &dset)
93 {
94   OFCondition result = EC_Normal;
95   DcmSequenceOfItems *dseq=NULL;
96   DcmItem *ditem=NULL;
97 
98   dseq = new DcmSequenceOfItems(DCM_DisplayedAreaSelectionSequence);
99   if (dseq)
100   {
101     OFListIterator(DVPSDisplayedArea *) first = list_.begin();
102     OFListIterator(DVPSDisplayedArea *) last = list_.end();
103     while (first != last)
104     {
105       if (result==EC_Normal)
106       {
107         ditem = new DcmItem();
108         if (ditem)
109         {
110           result = (*first)->write(*ditem);
111           if (result==EC_Normal) dseq->insert(ditem); else delete ditem;
112         } else result = EC_MemoryExhausted;
113       }
114       ++first;
115     }
116     if (result==EC_Normal) dset.insert(dseq, OFTrue /*replaceOld*/); else delete dseq;
117   } else result = EC_MemoryExhausted;
118   return result;
119 }
120 
findDisplayedArea(const char * instanceUID,unsigned long frame)121 DVPSDisplayedArea *DVPSDisplayedArea_PList::findDisplayedArea(const char *instanceUID, unsigned long frame)
122 {
123   OFListIterator(DVPSDisplayedArea *) first = list_.begin();
124   OFListIterator(DVPSDisplayedArea *) last = list_.end();
125   while (first != last)
126   {
127     if ((*first)->isApplicable(instanceUID, frame)) return (*first);
128     ++first;
129   }
130   return NULL;
131 }
132 
rotateAndFlip(DVPSRotationType rotationFrom,OFBool isFlippedFrom,DVPSRotationType rotationTo,OFBool isFlippedTo)133 void DVPSDisplayedArea_PList::rotateAndFlip(
134   DVPSRotationType rotationFrom,
135   OFBool isFlippedFrom,
136   DVPSRotationType rotationTo,
137   OFBool isFlippedTo)
138 {
139   OFListIterator(DVPSDisplayedArea *) first = list_.begin();
140   OFListIterator(DVPSDisplayedArea *) last = list_.end();
141   while (first != last)
142   {
143     (*first)->rotateAndFlip(rotationFrom, isFlippedFrom, rotationTo, isFlippedTo);
144     ++first;
145   }
146 }
147 
createDisplayedArea(DVPSReferencedSeries_PList & allReferences,const char * sopclassUID,const char * instanceUID,unsigned long frame,unsigned long numberOfFrames,DVPSObjectApplicability applicability)148 DVPSDisplayedArea *DVPSDisplayedArea_PList::createDisplayedArea(
149     DVPSReferencedSeries_PList& allReferences,
150     const char *sopclassUID,
151     const char *instanceUID,
152     unsigned long frame,
153     unsigned long numberOfFrames,
154     DVPSObjectApplicability applicability)
155 {
156 
157   DVPSDisplayedArea *oldArea = findDisplayedArea(instanceUID, frame);
158   DVPSDisplayedArea *newArea = NULL;
159   if (oldArea == NULL) newArea = new DVPSDisplayedArea();
160   else
161   {
162     // Check if the existing displayed area selection happens to match the new
163     // applicability. If yes, we only need to return the existing item.
164     if (oldArea->matchesApplicability(instanceUID, frame, applicability)) return oldArea;
165 
166     // the applicability has changed. Rework the complete sequence.
167     newArea = new DVPSDisplayedArea(*oldArea); // create copy
168     if (newArea) newArea->clearImageReferences();
169 
170     OFListIterator(DVPSDisplayedArea *) first = list_.begin();
171     OFListIterator(DVPSDisplayedArea *) last = list_.end();
172     switch (applicability)
173     {
174       case DVPSB_currentFrame:
175       case DVPSB_currentImage:
176         while (first != last)
177         {
178           (*first)->removeImageReference(allReferences, instanceUID, frame, numberOfFrames, applicability);
179           if ((*first)->imageReferencesEmpty())
180           {
181             delete (*first);
182             first = list_.erase(first);
183           } else ++first;
184         }
185         break;
186       case DVPSB_allImages:
187         clear(); // delete all area selections
188         break;
189     }
190   }
191 
192   if (newArea)
193   {
194     if (applicability != DVPSB_allImages) newArea->addImageReference(sopclassUID, instanceUID, frame, applicability);
195     list_.push_back(newArea);
196   }
197   return newArea;
198 }
199