1 /*
2 *
3 * Copyright (C) 1998-2018, 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: DVPSSoftcopyVOI
20 *
21 */
22
23 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
24 #include "dcmtk/dcmdata/dcdeftag.h"
25 #include "dcmtk/dcmdata/dcsequen.h"
26 #include "dcmtk/dcmpstat/dvpssv.h"
27 #include "dcmtk/dcmpstat/dvpsri.h" /* for DVPSReferencedImage */
28 #include "dcmtk/dcmpstat/dvpsrsl.h" /* DVPSReferencedSeries_PList */
29 #include "dcmtk/dcmpstat/dvpsdef.h" /* for constants and macros */
30 #include "dcmtk/ofstd/ofstd.h"
31 #include "dcmtk/dcmpstat/dvpsrs.h" /* for DVPSReferencedSeries, needed by MSVC5 with STL */
32
33 /* --------------- class DVPSSoftcopyVOI --------------- */
34
DVPSSoftcopyVOI()35 DVPSSoftcopyVOI::DVPSSoftcopyVOI()
36 : referencedImageList()
37 , useLUT(OFFalse)
38 , voiLUTDescriptor(DCM_LUTDescriptor)
39 , voiLUTExplanation(DCM_LUTExplanation)
40 , voiLUTData(DCM_LUTData)
41 , windowCenter(DCM_WindowCenter)
42 , windowWidth(DCM_WindowWidth)
43 , windowCenterWidthExplanation(DCM_WindowCenterWidthExplanation)
44 {
45 }
46
DVPSSoftcopyVOI(const DVPSSoftcopyVOI & copy)47 DVPSSoftcopyVOI::DVPSSoftcopyVOI(const DVPSSoftcopyVOI& copy)
48 : referencedImageList(copy.referencedImageList)
49 , useLUT(copy.useLUT)
50 , voiLUTDescriptor(copy.voiLUTDescriptor)
51 , voiLUTExplanation(copy.voiLUTExplanation)
52 , voiLUTData(copy.voiLUTData)
53 , windowCenter(copy.windowCenter)
54 , windowWidth(copy.windowWidth)
55 , windowCenterWidthExplanation(copy.windowCenterWidthExplanation)
56 {
57 }
58
~DVPSSoftcopyVOI()59 DVPSSoftcopyVOI::~DVPSSoftcopyVOI()
60 {
61 }
62
read(DcmItem & dset)63 OFCondition DVPSSoftcopyVOI::read(DcmItem &dset)
64 {
65 OFCondition result = EC_Normal;
66 DcmStack stack;
67 DcmSequenceOfItems *seq;
68 DcmItem *item;
69
70 READ_FROM_DATASET(DcmDecimalString, EVR_DS, windowCenter)
71 READ_FROM_DATASET(DcmDecimalString, EVR_DS, windowWidth)
72 READ_FROM_DATASET(DcmLongString, EVR_LO, windowCenterWidthExplanation)
73
74 /* read VOI LUT Sequence */
75 if (result==EC_Normal)
76 {
77 stack.clear();
78 if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse))
79 {
80 seq=(DcmSequenceOfItems *)stack.top();
81 if (seq->card() ==1)
82 {
83 item = seq->getItem(0);
84 stack.clear();
85 if (EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(),
86 stack, ESM_fromHere, OFFalse))
87 {
88 voiLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
89 }
90 stack.clear();
91 if (EC_Normal == item->search((DcmTagKey &)voiLUTExplanation.getTag(),
92 stack, ESM_fromHere, OFFalse))
93 {
94 voiLUTExplanation = *((DcmLongString *)(stack.top()));
95 }
96 stack.clear();
97 if (EC_Normal == item->search((DcmTagKey &)voiLUTData.getTag(),
98 stack, ESM_fromHere, OFFalse))
99 {
100 voiLUTData = *((DcmUnsignedShort *)(stack.top()));
101 }
102 } else {
103 result=EC_TagNotFound;
104 DCMPSTAT_WARN("VOI LUT SQ does not have exactly one item in presentation state");
105 }
106 }
107 }
108
109 if (result==EC_Normal) result = referencedImageList.read(dset);
110
111 /* Now perform basic sanity checks */
112
113 if (result==EC_Normal)
114 {
115 if (windowCenter.getLength() > 0)
116 {
117 useLUT = OFFalse;
118
119 if (windowWidth.getLength() == 0)
120 {
121 result=EC_IllegalCall;
122 DCMPSTAT_WARN("windowCenter present but windowWidth absent or empty in presentation state");
123 }
124 else if (windowWidth.getVM() != 1)
125 {
126 result=EC_IllegalCall;
127 DCMPSTAT_WARN("windowCenter present but windowWidth VM != 1 in presentation state");
128 }
129 if (windowCenter.getVM() != 1)
130 {
131 result=EC_IllegalCall;
132 DCMPSTAT_WARN("windowCenter present but VM != 1 in presentation state");
133 }
134 } else useLUT = OFTrue;
135
136 if (voiLUTData.getLength() > 0)
137 {
138
139 if (! useLUT)
140 {
141 result=EC_IllegalCall;
142 DCMPSTAT_WARN("both VOI window and LUT present in presentation state");
143 }
144
145 if (voiLUTDescriptor.getLength() == 0)
146 {
147 result=EC_IllegalCall;
148 DCMPSTAT_WARN("voiLUTData present but voiLUTDescriptor absent or empty in presentation state");
149 }
150 else if (voiLUTDescriptor.getVM() != 3)
151 {
152 result=EC_IllegalCall;
153 DCMPSTAT_WARN("voiLUTData present but voiLUTDescriptor VM != 3 in presentation state");
154 }
155 }
156 else if (useLUT)
157 {
158 result=EC_IllegalCall;
159 DCMPSTAT_WARN("neither VOI window nor LUT present in presentation state");
160 }
161 }
162 return result;
163 }
164
write(DcmItem & dset)165 OFCondition DVPSSoftcopyVOI::write(DcmItem &dset)
166 {
167 OFCondition result = EC_Normal;
168 DcmElement *delem=NULL;
169 DcmSequenceOfItems *dseq=NULL;
170 DcmItem *ditem=NULL;
171
172 if (useLUT)
173 {
174 ditem = new DcmItem();
175 if (ditem)
176 {
177 dseq = new DcmSequenceOfItems(DCM_VOILUTSequence);
178 if (dseq)
179 {
180 delem = new DcmUnsignedShort(voiLUTDescriptor);
181 if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
182 delem = new DcmUnsignedShort(voiLUTData);
183 if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
184 if (voiLUTExplanation.getLength() >0)
185 {
186 delem = new DcmLongString(voiLUTExplanation);
187 if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
188 }
189 if (result==EC_Normal)
190 {
191 dseq->insert(ditem);
192 dset.insert(dseq, OFTrue /*replaceOld*/);
193 } else {
194 // out of memory during creation of sequence contents.
195 delete dseq;
196 delete ditem;
197 result = EC_MemoryExhausted;
198 }
199 } else {
200 // could allocate item but not sequence. Bail out.
201 delete ditem;
202 result = EC_MemoryExhausted;
203 }
204 }
205 else result = EC_MemoryExhausted;
206 }
207 else
208 {
209 ADD_TO_DATASET(DcmDecimalString, windowCenter)
210 ADD_TO_DATASET(DcmDecimalString, windowWidth)
211 if (windowCenterWidthExplanation.getLength() > 0) { ADD_TO_DATASET(DcmLongString, windowCenterWidthExplanation) }
212 }
213
214 if ((result == EC_Normal)&&(referencedImageList.size() >0)) result = referencedImageList.write(dset);
215 return result;
216 }
217
isApplicable(const char * instanceUID,unsigned long frame)218 OFBool DVPSSoftcopyVOI::isApplicable(const char *instanceUID, unsigned long frame)
219 {
220 return referencedImageList.isApplicable(instanceUID, frame);
221 }
222
matchesApplicability(const char * instanceUID,unsigned long frame,DVPSObjectApplicability applicability)223 OFBool DVPSSoftcopyVOI::matchesApplicability(const char *instanceUID, unsigned long frame, DVPSObjectApplicability applicability)
224 {
225 return referencedImageList.matchesApplicability(instanceUID, frame, applicability);
226 }
227
removeImageReference(DVPSReferencedSeries_PList & allReferences,const char * instanceUID,unsigned long frame,unsigned long numberOfFrames,DVPSObjectApplicability applicability)228 void DVPSSoftcopyVOI::removeImageReference(
229 DVPSReferencedSeries_PList& allReferences,
230 const char *instanceUID,
231 unsigned long frame,
232 unsigned long numberOfFrames,
233 DVPSObjectApplicability applicability)
234 {
235 referencedImageList.removeImageReference(allReferences, instanceUID, frame, numberOfFrames, applicability);
236 return;
237 }
238
addImageReference(const char * sopclassUID,const char * instanceUID,unsigned long frame,DVPSObjectApplicability applicability)239 OFCondition DVPSSoftcopyVOI::addImageReference(
240 const char *sopclassUID,
241 const char *instanceUID,
242 unsigned long frame,
243 DVPSObjectApplicability applicability)
244 {
245 return referencedImageList.addImageReference(sopclassUID, instanceUID, frame, applicability);
246 }
247
getCurrentVOIDescription()248 const char *DVPSSoftcopyVOI::getCurrentVOIDescription()
249 {
250 char *c=NULL;
251 if (useLUT)
252 {
253 if (EC_Normal == voiLUTExplanation.getString(c)) return c;
254 }
255 else
256 {
257 if (EC_Normal == windowCenterWidthExplanation.getString(c)) return c;
258 }
259 return NULL;
260 }
261
getCurrentWindowWidth(double & w)262 OFCondition DVPSSoftcopyVOI::getCurrentWindowWidth(double &w)
263 {
264 OFCondition result = EC_IllegalCall;
265 if (!useLUT)
266 {
267 Float64 temp=0.0;
268 result = windowWidth.getFloat64(temp,0);
269 if (EC_Normal==result) w = (double)temp;
270 }
271 return result;
272 }
273
getCurrentWindowCenter(double & c)274 OFCondition DVPSSoftcopyVOI::getCurrentWindowCenter(double &c)
275 {
276 OFCondition result = EC_IllegalCall;
277 if (!useLUT)
278 {
279 Float64 temp=0.0;
280 result = windowCenter.getFloat64(temp,0);
281 if (EC_Normal==result) c = (double)temp;
282 }
283 return result;
284 }
285
setVOIWindow(double wCenter,double wWidth,const char * description)286 OFCondition DVPSSoftcopyVOI::setVOIWindow(double wCenter, double wWidth, const char *description)
287 {
288 if (wWidth < 1.0)
289 {
290 DCMPSTAT_WARN("Window Width < 1 not allowed.");
291 return EC_IllegalCall;
292 }
293 DcmDecimalString wc(DCM_WindowCenter);
294 DcmDecimalString ww(DCM_WindowWidth);
295 DcmLongString expl(DCM_WindowCenterWidthExplanation);
296 char buf[80];
297
298 OFStandard::ftoa(buf, sizeof(buf), wCenter, OFStandard::ftoa_uppercase);
299 OFCondition result = wc.putString(buf);
300 OFStandard::ftoa(buf, sizeof(buf), wWidth, OFStandard::ftoa_uppercase);
301 if (EC_Normal == result) result = ww.putString(buf);
302 if ((EC_Normal == result)&&(description)) result = expl.putString(description);
303 if (EC_Normal == result)
304 {
305 // everything worked fine, now copy.
306 windowCenter = wc;
307 windowWidth = ww;
308 windowCenterWidthExplanation = expl;
309 voiLUTDescriptor.clear();
310 voiLUTData.clear();
311 voiLUTExplanation.clear();
312 useLUT = OFFalse;
313 }
314 return result;
315 }
316
setVOILUT(DcmUnsignedShort & lutDescriptor,DcmUnsignedShort & lutData,DcmLongString & lutExplanation)317 OFCondition DVPSSoftcopyVOI::setVOILUT(
318 DcmUnsignedShort& lutDescriptor,
319 DcmUnsignedShort& lutData,
320 DcmLongString& lutExplanation)
321 {
322 if (lutData.getLength() == 0) return EC_IllegalCall;
323 if (lutDescriptor.getVM() != 3) return EC_IllegalCall;
324 voiLUTDescriptor = lutDescriptor;
325 voiLUTData = lutData;
326 voiLUTExplanation = lutExplanation;
327 windowCenter.clear();
328 windowWidth.clear();
329 windowCenterWidthExplanation.clear();
330 useLUT = OFTrue;
331 return EC_Normal;
332 }
333