1 /*
2 *
3 * Copyright (C) 2000-2017, 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: dcmsr
15 *
16 * Author: Joerg Riesmeier
17 *
18 * Purpose:
19 * classes: DSRNumericMeasurementValue
20 *
21 */
22
23
24 #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */
25
26 #include "dcmtk/dcmsr/dsrtypes.h"
27 #include "dcmtk/dcmsr/dsrnumvl.h"
28 #include "dcmtk/dcmsr/dsrxmld.h"
29
30 #include "dcmtk/dcmdata/dcdeftag.h"
31 #include "dcmtk/dcmdata/dcvrds.h"
32
33
DSRNumericMeasurementValue()34 DSRNumericMeasurementValue::DSRNumericMeasurementValue()
35 : NumericValue(),
36 MeasurementUnit(),
37 ValueQualifier(),
38 FloatingPointValue(DCM_FloatingPointValue),
39 RationalNumeratorValue(DCM_RationalNumeratorValue),
40 RationalDenominatorValue(DCM_RationalDenominatorValue)
41 {
42 }
43
44
DSRNumericMeasurementValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const OFBool check)45 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const OFString &numericValue,
46 const DSRCodedEntryValue &measurementUnit,
47 const OFBool check)
48 : NumericValue(),
49 MeasurementUnit(),
50 ValueQualifier(),
51 FloatingPointValue(DCM_FloatingPointValue),
52 RationalNumeratorValue(DCM_RationalNumeratorValue),
53 RationalDenominatorValue(DCM_RationalDenominatorValue)
54 {
55 /* use the set method for checking purposes */
56 setValue(numericValue, measurementUnit, check);
57 }
58
59
DSRNumericMeasurementValue(const DSRCodedEntryValue & valueQualifier,const OFBool check)60 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const DSRCodedEntryValue &valueQualifier,
61 const OFBool check)
62 : NumericValue(),
63 MeasurementUnit(),
64 ValueQualifier(),
65 FloatingPointValue(DCM_FloatingPointValue),
66 RationalNumeratorValue(DCM_RationalNumeratorValue),
67 RationalDenominatorValue(DCM_RationalDenominatorValue)
68 {
69 /* use the set method for checking purposes */
70 setValue(valueQualifier, check);
71 }
72
73
DSRNumericMeasurementValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const DSRCodedEntryValue & valueQualifier,const OFBool check)74 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const OFString &numericValue,
75 const DSRCodedEntryValue &measurementUnit,
76 const DSRCodedEntryValue &valueQualifier,
77 const OFBool check)
78 : NumericValue(),
79 MeasurementUnit(),
80 ValueQualifier(),
81 FloatingPointValue(DCM_FloatingPointValue),
82 RationalNumeratorValue(DCM_RationalNumeratorValue),
83 RationalDenominatorValue(DCM_RationalDenominatorValue)
84 {
85 /* use the set method for checking purposes */
86 setValue(numericValue, measurementUnit, valueQualifier, check);
87 }
88
89
DSRNumericMeasurementValue(const DSRNumericMeasurementValue & numericMeasurement)90 DSRNumericMeasurementValue::DSRNumericMeasurementValue(const DSRNumericMeasurementValue &numericMeasurement)
91 : NumericValue(numericMeasurement.NumericValue),
92 MeasurementUnit(numericMeasurement.MeasurementUnit),
93 ValueQualifier(numericMeasurement.ValueQualifier),
94 FloatingPointValue(numericMeasurement.FloatingPointValue),
95 RationalNumeratorValue(numericMeasurement.RationalNumeratorValue),
96 RationalDenominatorValue(numericMeasurement.RationalDenominatorValue)
97 {
98 /* do not check since this would be unexpected to the user */
99 }
100
101
~DSRNumericMeasurementValue()102 DSRNumericMeasurementValue::~DSRNumericMeasurementValue()
103 {
104 }
105
106
operator =(const DSRNumericMeasurementValue & numericMeasurement)107 DSRNumericMeasurementValue &DSRNumericMeasurementValue::operator=(const DSRNumericMeasurementValue &numericMeasurement)
108 {
109 /* do not check since this would be unexpected to the user */
110 NumericValue = numericMeasurement.NumericValue;
111 MeasurementUnit = numericMeasurement.MeasurementUnit;
112 ValueQualifier = numericMeasurement.ValueQualifier;
113 FloatingPointValue = numericMeasurement.FloatingPointValue;
114 RationalNumeratorValue = numericMeasurement.RationalNumeratorValue;
115 RationalDenominatorValue = numericMeasurement.RationalDenominatorValue;
116 return *this;
117 }
118
119
operator ==(const DSRNumericMeasurementValue & numericMeasurement) const120 OFBool DSRNumericMeasurementValue::operator==(const DSRNumericMeasurementValue &numericMeasurement) const
121 {
122 /* only the basic information is used for comparing the two values */
123 return (NumericValue == numericMeasurement.NumericValue) &&
124 (MeasurementUnit == numericMeasurement.MeasurementUnit) &&
125 (ValueQualifier == numericMeasurement.ValueQualifier);
126 }
127
128
operator !=(const DSRNumericMeasurementValue & numericMeasurement) const129 OFBool DSRNumericMeasurementValue::operator!=(const DSRNumericMeasurementValue &numericMeasurement) const
130 {
131 /* only the basic information is used for comparing the two values */
132 return (NumericValue != numericMeasurement.NumericValue) ||
133 (MeasurementUnit != numericMeasurement.MeasurementUnit) ||
134 (ValueQualifier != numericMeasurement.ValueQualifier);
135 }
136
137
clear()138 void DSRNumericMeasurementValue::clear()
139 {
140 NumericValue.clear();
141 MeasurementUnit.clear();
142 ValueQualifier.clear();
143 FloatingPointValue.clear();
144 RationalNumeratorValue.clear();
145 RationalDenominatorValue.clear();
146 }
147
148
isValid() const149 OFBool DSRNumericMeasurementValue::isValid() const
150 {
151 /* the MeasuredValueSequence can be empty (type 2) */
152 return (isEmpty() || (checkNumericValue(NumericValue).good() && checkMeasurementUnit(MeasurementUnit).good()))
153 && checkNumericValueQualifier(ValueQualifier).good();
154 }
155
156
isEmpty() const157 OFBool DSRNumericMeasurementValue::isEmpty() const
158 {
159 /* the NumericValueQualifierCodeSequence is not checked */
160 return NumericValue.empty() && MeasurementUnit.isEmpty();
161 }
162
163
isComplete() const164 OFBool DSRNumericMeasurementValue::isComplete() const
165 {
166 /* officially, the NumericValueQualifierCodeSequence is optional (type 3) */
167 return (!NumericValue.empty() && MeasurementUnit.isComplete()) || ValueQualifier.isComplete();
168 }
169
170
print(STD_NAMESPACE ostream & stream,const size_t flags) const171 OFCondition DSRNumericMeasurementValue::print(STD_NAMESPACE ostream &stream,
172 const size_t flags) const
173 {
174 if (isEmpty())
175 {
176 /* empty value */
177 stream << "empty";
178 /* check for optional numeric value qualifier */
179 if (!ValueQualifier.isEmpty())
180 {
181 stream << " ";
182 ValueQualifier.print(stream, OFTrue /*printCodeValue*/, flags);
183 }
184 } else {
185 OFString printString;
186 stream << "\"" << DSRTypes::convertToPrintString(NumericValue, printString) << "\" ";
187 MeasurementUnit.print(stream, OFTrue /*printCodeValue*/, flags);
188 }
189 return EC_Normal;
190 }
191
192
readXML(const DSRXMLDocument & doc,DSRXMLCursor cursor,const size_t flags)193 OFCondition DSRNumericMeasurementValue::readXML(const DSRXMLDocument &doc,
194 DSRXMLCursor cursor,
195 const size_t flags)
196 {
197 OFCondition result = SR_EC_CorruptedXMLStructure;
198 if (cursor.valid())
199 {
200 cursor.gotoChild();
201 /* get "value" element (might be absent since "Measured Value Sequence" is type 2) */
202 if (!doc.getStringFromNodeContent(doc.getNamedNode(cursor, "value", OFFalse /*required*/), NumericValue).empty())
203 {
204 /* get additional representations of the numeric value (if any) */
205 doc.getElementFromNodeContent(doc.getNamedNode(cursor, "float", OFFalse /*required*/), FloatingPointValue);
206 const DSRXMLCursor childNode = doc.getNamedNode(cursor, "rational", OFFalse /*required*/).getChild();
207 if (childNode.valid())
208 {
209 doc.getElementFromNodeContent(doc.getNamedNode(childNode, "numerator"), RationalNumeratorValue);
210 doc.getElementFromNodeContent(doc.getNamedNode(childNode, "denominator"), RationalDenominatorValue);
211 }
212 /* get "unit" element (only if "value" present) */
213 result = MeasurementUnit.readXML(doc, doc.getNamedNode(cursor, "unit"), flags);
214 } else
215 result = EC_Normal;
216 if (result.good())
217 {
218 /* get "qualifier" element (optional, do not report if absent or erroneous) */
219 ValueQualifier.readXML(doc, doc.getNamedNode(cursor, "qualifier", OFFalse /*required*/), flags);
220 }
221 if (!isValid())
222 result = SR_EC_InvalidValue;
223 }
224 return result;
225 }
226
227
writeXML(STD_NAMESPACE ostream & stream,const size_t flags) const228 OFCondition DSRNumericMeasurementValue::writeXML(STD_NAMESPACE ostream &stream,
229 const size_t flags) const
230 {
231 /* write numeric value */
232 DSRTypes::writeStringValueToXML(stream, NumericValue, "value", (flags & DSRTypes::XF_writeEmptyTags) > 0);
233 /* write floating point representation */
234 Float64 floatValue;
235 const OFBool hasFloating = getFloatingPointRepresentation(floatValue).good();
236 if (hasFloating || (flags & DSRTypes::XF_writeEmptyTags))
237 {
238 stream << "<float>";
239 if (hasFloating)
240 {
241 /* increase default precision */
242 const STD_NAMESPACE streamsize oldPrecision = stream.precision(8);
243 stream << floatValue;
244 /* reset i/o manipulators */
245 stream.precision(oldPrecision);
246 }
247 stream << "</float>" << OFendl;
248 }
249 /* write rational representation */
250 Sint32 numeratorValue;
251 Uint32 denominatorValue;
252 const OFBool hasRational = getRationalRepresentation(numeratorValue, denominatorValue).good();
253 if (hasRational || (flags & DSRTypes::XF_writeEmptyTags))
254 {
255 stream << "<rational>" << OFendl;
256 if (hasRational)
257 {
258 stream << "<numerator>" << numeratorValue << "</numerator>" << OFendl;
259 stream << "<denominator>" << denominatorValue << "</denominator>" << OFendl;
260 }
261 stream << "</rational>" << OFendl;
262 }
263 /* write measurement unit */
264 if (!MeasurementUnit.isEmpty() || (flags & DSRTypes::XF_writeEmptyTags))
265 {
266 if (flags & DSRTypes::XF_codeComponentsAsAttribute)
267 stream << "<unit"; // bracket ">" is closed in the next writeXML() routine
268 else
269 stream << "<unit>" << OFendl;
270 MeasurementUnit.writeXML(stream, flags);
271 stream << "</unit>" << OFendl;
272 }
273 /* write value qualifier */
274 if (!ValueQualifier.isEmpty() || (flags & DSRTypes::XF_writeEmptyTags))
275 {
276 if (flags & DSRTypes::XF_codeComponentsAsAttribute)
277 stream << "<qualifier"; // bracket ">" is closed in the next writeXML() routine
278 else
279 stream << "<qualifier>" << OFendl;
280 ValueQualifier.writeXML(stream, flags);
281 stream << "</qualifier>" << OFendl;
282 }
283 return EC_Normal;
284 }
285
286
readItem(DcmItem & dataset,const size_t flags)287 OFCondition DSRNumericMeasurementValue::readItem(DcmItem &dataset,
288 const size_t flags)
289 {
290 const OFBool acceptViolation = (flags & DSRTypes::RF_acceptInvalidContentItemValue) > 0;
291 /* read NumericValue */
292 OFCondition result = DSRTypes::getAndCheckStringValueFromDataset(dataset, DCM_NumericValue, NumericValue, "1", "1", "MeasuredValueSequence", acceptViolation);
293 if (result.good())
294 {
295 /* read some optional attributes */
296 DSRTypes::getAndCheckElementFromDataset(dataset, FloatingPointValue, "1", "1C", "MeasuredValueSequence");
297 if (DSRTypes::getAndCheckElementFromDataset(dataset, RationalNumeratorValue, "1", "1C", "MeasuredValueSequence").good())
298 DSRTypes::getAndCheckElementFromDataset(dataset, RationalDenominatorValue, "1", "1" /* was 1C */, "MeasuredValueSequence");
299 /* read MeasurementUnitsCodeSequence */
300 result = MeasurementUnit.readSequence(dataset, DCM_MeasurementUnitsCodeSequence, "1" /*type*/, flags);
301 }
302 return result;
303 }
304
305
writeItem(DcmItem & dataset) const306 OFCondition DSRNumericMeasurementValue::writeItem(DcmItem &dataset) const
307 {
308 /* write NumericValue */
309 OFCondition result = DSRTypes::putStringValueToDataset(dataset, DCM_NumericValue, NumericValue);
310 /* write some optional attributes */
311 DSRTypes::addElementToDataset(result, dataset, new DcmFloatingPointDouble(FloatingPointValue), "1", "1C", "MeasuredValueSequence");
312 DSRTypes::addElementToDataset(result, dataset, new DcmSignedLong(RationalNumeratorValue), "1", "1C", "MeasuredValueSequence");
313 DSRTypes::addElementToDataset(result, dataset, new DcmUnsignedLong(RationalDenominatorValue), "1", "1C", "MeasuredValueSequence");
314 /* write MeasurementUnitsCodeSequence */
315 if (result.good())
316 result = MeasurementUnit.writeSequence(dataset, DCM_MeasurementUnitsCodeSequence);
317 return result;
318 }
319
320
readSequence(DcmItem & dataset,const size_t flags)321 OFCondition DSRNumericMeasurementValue::readSequence(DcmItem &dataset,
322 const size_t flags)
323 {
324 /* read MeasuredValueSequence */
325 DcmSequenceOfItems *dseq = NULL;
326 OFCondition result = dataset.findAndGetSequence(DCM_MeasuredValueSequence, dseq);
327 DSRTypes::checkElementValue(dseq, DCM_MeasuredValueSequence, "1", "2", result, "NUM content item");
328 if (result.good())
329 {
330 /* check for empty sequence (allowed!) */
331 if (!dseq->isEmpty())
332 {
333 /* read first item */
334 DcmItem *ditem = dseq->getItem(0);
335 if (ditem != NULL)
336 result = readItem(*ditem, flags);
337 else
338 result = SR_EC_InvalidDocumentTree;
339 }
340 }
341 if (result.good())
342 {
343 /* read NumericValueQualifierCodeSequence (optional) */
344 ValueQualifier.readSequence(dataset, DCM_NumericValueQualifierCodeSequence, "3" /*type*/, flags);
345 }
346 return result;
347 }
348
349
writeSequence(DcmItem & dataset) const350 OFCondition DSRNumericMeasurementValue::writeSequence(DcmItem &dataset) const
351 {
352 OFCondition result = EC_MemoryExhausted;
353 /* write MeasuredValueSequence */
354 DcmSequenceOfItems *dseq = new DcmSequenceOfItems(DCM_MeasuredValueSequence);
355 if (dseq != NULL)
356 {
357 /* check for empty value */
358 if (isEmpty())
359 result = EC_Normal;
360 else
361 {
362 DcmItem *ditem = new DcmItem();
363 if (ditem != NULL)
364 {
365 /* write item */
366 result = writeItem(*ditem);
367 if (result.good())
368 dseq->insert(ditem);
369 else
370 delete ditem;
371 } else
372 result = EC_MemoryExhausted;
373 }
374 /* write sequence (might be empty) */
375 if (result.good())
376 result = dataset.insert(dseq, OFTrue /*replaceOld*/);
377 if (result.bad())
378 delete dseq;
379 }
380 if (result.good())
381 {
382 /* write NumericValueQualifierCodeSequence (optional) */
383 if (!ValueQualifier.isEmpty())
384 ValueQualifier.writeSequence(dataset, DCM_NumericValueQualifierCodeSequence);
385 }
386 return result;
387 }
388
389
renderHTML(STD_NAMESPACE ostream & docStream,STD_NAMESPACE ostream &,size_t &,const size_t flags) const390 OFCondition DSRNumericMeasurementValue::renderHTML(STD_NAMESPACE ostream &docStream,
391 STD_NAMESPACE ostream & /*annexStream*/,
392 size_t & /*annexNumber*/,
393 const size_t flags) const
394 {
395 if (isEmpty())
396 {
397 /* empty value */
398 docStream << "<i>empty</i>";
399 } else {
400 OFString htmlString;
401 const OFBool fullCode = (flags & DSRTypes::HF_renderNumericUnitCodes) &&
402 ((flags & DSRTypes::HF_renderInlineCodes) || (flags & DSRTypes::HF_renderItemsSeparately));
403 if (!fullCode || (flags & DSRTypes::HF_useCodeDetailsTooltip))
404 {
405 if (flags & DSRTypes::HF_XHTML11Compatibility)
406 docStream << "<span class=\"num\">";
407 else if (flags & DSRTypes::HF_HTML32Compatibility)
408 docStream << "<u>";
409 else /* HTML 4.01 */
410 docStream << "<span class=\"under\">";
411 }
412 docStream << DSRTypes::convertToHTMLString(NumericValue, htmlString, flags) << " ";
413 /* render full code of the measurement unit (value first?) or code value only */
414 MeasurementUnit.renderHTML(docStream, flags, fullCode, (flags & DSRTypes::HF_useCodeMeaningAsUnit) == 0 /*valueFirst*/);
415 if (!fullCode || (flags & DSRTypes::HF_useCodeDetailsTooltip))
416 {
417 if (flags & DSRTypes::HF_HTML32Compatibility)
418 docStream << "</u>";
419 else
420 docStream << "</span>";
421 }
422 }
423 if (!ValueQualifier.isEmpty())
424 {
425 /* render optional numeric value qualifier */
426 docStream << " [";
427 ValueQualifier.renderHTML(docStream, flags, (flags & DSRTypes::HF_renderInlineCodes) > 0 /*fullCode*/);
428 docStream << "]";
429 }
430 return EC_Normal;
431 }
432
433
getValue(DSRNumericMeasurementValue & numericMeasurement) const434 OFCondition DSRNumericMeasurementValue::getValue(DSRNumericMeasurementValue &numericMeasurement) const
435 {
436 numericMeasurement = *this;
437 return EC_Normal;
438 }
439
440
getMeasurementUnit(DSRCodedEntryValue & measurementUnit) const441 OFCondition DSRNumericMeasurementValue::getMeasurementUnit(DSRCodedEntryValue &measurementUnit) const
442 {
443 measurementUnit = MeasurementUnit;
444 return EC_Normal;
445 }
446
447
getNumericValueQualifier(DSRCodedEntryValue & valueQualifier) const448 OFCondition DSRNumericMeasurementValue::getNumericValueQualifier(DSRCodedEntryValue &valueQualifier) const
449 {
450 valueQualifier = ValueQualifier;
451 return EC_Normal;
452 }
453
454
getFloatingPointRepresentation(Float64 & floatingPoint) const455 OFCondition DSRNumericMeasurementValue::getFloatingPointRepresentation(Float64 &floatingPoint) const
456 {
457 OFCondition result = SR_EC_RepresentationNotAvailable;
458 /* cast away the const specifier (yes, this is ugly) */
459 DcmFloatingPointDouble &floatElement = OFconst_cast(DcmFloatingPointDouble &, FloatingPointValue);
460 if (!floatElement.isEmpty())
461 result = floatElement.getFloat64(floatingPoint);
462 return result;
463 }
464
465
getRationalRepresentation(Sint32 & rationalNumerator,Uint32 & rationalDenominator) const466 OFCondition DSRNumericMeasurementValue::getRationalRepresentation(Sint32 &rationalNumerator,
467 Uint32 &rationalDenominator) const
468 {
469 OFCondition result = SR_EC_RepresentationNotAvailable;
470 /* cast away the const specifier (yes, this is ugly) */
471 DcmSignedLong &signedElement = OFconst_cast(DcmSignedLong &, RationalNumeratorValue);
472 DcmUnsignedLong &unsignedElement = OFconst_cast(DcmUnsignedLong &, RationalDenominatorValue);
473 /* check whether both values are present or absent */
474 if (signedElement.isEmpty() != unsignedElement.isEmpty())
475 result = EC_CorruptedData;
476 /* determine rational numerator and denominator (if present) */
477 else if (!signedElement.isEmpty() && !unsignedElement.isEmpty())
478 {
479 result = signedElement.getSint32(rationalNumerator);
480 if (result.good())
481 result = unsignedElement.getUint32(rationalDenominator);
482 }
483 return result;
484 }
485
486
setValue(const DSRNumericMeasurementValue & numericMeasurement,const OFBool check)487 OFCondition DSRNumericMeasurementValue::setValue(const DSRNumericMeasurementValue &numericMeasurement,
488 const OFBool check)
489 {
490 /* first set the basic parameters */
491 OFCondition result = setValue(numericMeasurement.NumericValue,
492 numericMeasurement.MeasurementUnit,
493 numericMeasurement.ValueQualifier,
494 check);
495 /* then the additional representations */
496 if (result.good())
497 {
498 Float64 floatValue;
499 if (numericMeasurement.getFloatingPointRepresentation(floatValue).good())
500 result = setFloatingPointRepresentation(floatValue, check);
501 if (result.good())
502 {
503 Sint32 numeratorValue;
504 Uint32 denominatorValue;
505 if (numericMeasurement.getRationalRepresentation(numeratorValue, denominatorValue).good())
506 result = setRationalRepresentation(numeratorValue, denominatorValue, check);
507 }
508 }
509 return result;
510 }
511
512
setValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const OFBool check)513 OFCondition DSRNumericMeasurementValue::setValue(const OFString &numericValue,
514 const DSRCodedEntryValue &measurementUnit,
515 const OFBool check)
516 {
517 const DSRCodedEntryValue valueQualifier;
518 /* call the function doing the real work */
519 return setValue(numericValue, measurementUnit, valueQualifier, check);
520 }
521
522
setValue(const DSRCodedEntryValue & valueQualifier,const OFBool check)523 OFCondition DSRNumericMeasurementValue::setValue(const DSRCodedEntryValue &valueQualifier,
524 const OFBool check)
525 {
526 const DSRCodedEntryValue measurementUnit;
527 /* call the function doing the real work */
528 return setValue("" /*numericValue*/, measurementUnit, valueQualifier, check);
529 }
530
531
setValue(const OFString & numericValue,const DSRCodedEntryValue & measurementUnit,const DSRCodedEntryValue & valueQualifier,const OFBool check)532 OFCondition DSRNumericMeasurementValue::setValue(const OFString &numericValue,
533 const DSRCodedEntryValue &measurementUnit,
534 const DSRCodedEntryValue &valueQualifier,
535 const OFBool check)
536 {
537 OFCondition result = EC_Normal;
538 if (check)
539 {
540 /* only check if at least one of the two values is non-empty */
541 if (!numericValue.empty() || !measurementUnit.isEmpty())
542 {
543 /* check whether the passed values are valid */
544 result = checkNumericValue(numericValue);
545 if (result.good())
546 result = checkMeasurementUnit(measurementUnit);
547 }
548 if (result.good())
549 result = checkNumericValueQualifier(valueQualifier);
550 } else {
551 /* make sure that both values are either empty or non-empty */
552 if (numericValue.empty() != measurementUnit.isEmpty())
553 result = EC_IllegalParameter;
554 }
555 if (result.good())
556 {
557 NumericValue = numericValue;
558 MeasurementUnit = measurementUnit;
559 ValueQualifier = valueQualifier;
560 /* clear additional representations */
561 FloatingPointValue.clear();
562 RationalNumeratorValue.clear();
563 RationalDenominatorValue.clear();
564 }
565 return result;
566 }
567
568
setNumericValue(const OFString & numericValue,const OFBool check)569 OFCondition DSRNumericMeasurementValue::setNumericValue(const OFString &numericValue,
570 const OFBool check)
571 {
572 OFCondition result = EC_Normal;
573 if (check)
574 {
575 /* check whether the passed value is valid */
576 result = checkNumericValue(numericValue);
577 } else {
578 /* make sure that the mandatory values are non-empty */
579 if (numericValue.empty())
580 result = EC_IllegalParameter;
581 }
582 if (result.good())
583 {
584 NumericValue = numericValue;
585 /* clear additional representations */
586 FloatingPointValue.clear();
587 RationalNumeratorValue.clear();
588 RationalDenominatorValue.clear();
589 }
590 return result;
591 }
592
593
setNumericValue(const DcmElement & delem,const unsigned long pos,const OFBool check)594 OFCondition DSRNumericMeasurementValue::setNumericValue(const DcmElement &delem,
595 const unsigned long pos,
596 const OFBool check)
597 {
598 OFString numericValue;
599 /* first, get the value from the element (need to cast away "const") */
600 OFCondition result = OFconst_cast(DcmElement &, delem).getOFString(numericValue, pos);
601 if (result.good())
602 {
603 /* then, check and set the value */
604 result = setNumericValue(numericValue, check);
605 }
606 return result;
607 }
608
609
setNumericValue(DcmItem & dataset,const DcmTagKey & tagKey,const unsigned long pos,const OFBool check)610 OFCondition DSRNumericMeasurementValue::setNumericValue(DcmItem &dataset,
611 const DcmTagKey &tagKey,
612 const unsigned long pos,
613 const OFBool check)
614 {
615 OFString numericValue;
616 /* first, get the element value from the dataset */
617 OFCondition result = DSRTypes::getStringValueFromDataset(dataset, tagKey, numericValue, pos);
618 if (result.good())
619 {
620 /* then, check and set the value */
621 result = setNumericValue(numericValue, check);
622 }
623 return result;
624 }
625
626
setMeasurementUnit(const DSRCodedEntryValue & measurementUnit,const OFBool check)627 OFCondition DSRNumericMeasurementValue::setMeasurementUnit(const DSRCodedEntryValue &measurementUnit,
628 const OFBool check)
629 {
630 OFCondition result = EC_Normal;
631 if (check)
632 {
633 /* check whether the passed value is valid */
634 result = checkMeasurementUnit(measurementUnit);
635 } else {
636 /* make sure that the mandatory values are non-empty */
637 if (measurementUnit.isEmpty())
638 result = EC_IllegalParameter;
639 }
640 if (result.good())
641 MeasurementUnit = measurementUnit;
642 return result;
643 }
644
645
setNumericValueQualifier(const DSRCodedEntryValue & valueQualifier,const OFBool check)646 OFCondition DSRNumericMeasurementValue::setNumericValueQualifier(const DSRCodedEntryValue &valueQualifier,
647 const OFBool check)
648 {
649 OFCondition result = EC_Normal;
650 /* check whether the passed value is valid */
651 if (check)
652 result = checkNumericValueQualifier(valueQualifier);
653 if (result.good())
654 ValueQualifier = valueQualifier;
655 return result;
656 }
657
658
setFloatingPointRepresentation(const Float64 floatingPoint,const OFBool)659 OFCondition DSRNumericMeasurementValue::setFloatingPointRepresentation(const Float64 floatingPoint,
660 const OFBool /*check*/)
661 {
662 /* make sure that only a single value is stored */
663 return FloatingPointValue.putFloat64Array(&floatingPoint, 1);
664 }
665
666
setRationalRepresentation(const Sint32 rationalNumerator,const Uint32 rationalDenominator,const OFBool check)667 OFCondition DSRNumericMeasurementValue::setRationalRepresentation(const Sint32 rationalNumerator,
668 const Uint32 rationalDenominator,
669 const OFBool check)
670 {
671 OFCondition result = EC_Normal;
672 /* check whether the passed values are valid */
673 if (check)
674 result = checkRationalRepresentation(rationalNumerator, rationalDenominator);
675 if (result.good())
676 {
677 /* make sure that only a single value is stored */
678 RationalNumeratorValue.putSint32Array(&rationalNumerator, 1);
679 RationalDenominatorValue.putUint32Array(&rationalDenominator, 1);
680 }
681 return result;
682 }
683
684
removeFloatingPointRepresentation()685 void DSRNumericMeasurementValue::removeFloatingPointRepresentation()
686 {
687 FloatingPointValue.clear();
688 }
689
690
removeRationalRepresentation()691 void DSRNumericMeasurementValue::removeRationalRepresentation()
692 {
693 RationalNumeratorValue.clear();
694 RationalDenominatorValue.clear();
695 }
696
697
checkNumericValue(const OFString & numericValue) const698 OFCondition DSRNumericMeasurementValue::checkNumericValue(const OFString &numericValue) const
699 {
700 /* numeric value should never be empty */
701 return numericValue.empty() ? SR_EC_InvalidValue
702 : DcmDecimalString::checkStringValue(numericValue, "1");
703 }
704
705
checkMeasurementUnit(const DSRCodedEntryValue & measurementUnit) const706 OFCondition DSRNumericMeasurementValue::checkMeasurementUnit(const DSRCodedEntryValue &measurementUnit) const
707 {
708 /* measurement unit should never be empty */
709 return measurementUnit.isEmpty() ? SR_EC_InvalidValue
710 : measurementUnit.checkCurrentValue();
711 }
712
713
checkNumericValueQualifier(const DSRCodedEntryValue & valueQualifier) const714 OFCondition DSRNumericMeasurementValue::checkNumericValueQualifier(const DSRCodedEntryValue &valueQualifier) const
715 {
716 /* numeric value qualifier might be empty */
717 return valueQualifier.isEmpty() ? EC_Normal
718 : valueQualifier.checkCurrentValue();
719 }
720
721
checkRationalRepresentation(const Sint32,const Uint32 rationalDenominator) const722 OFCondition DSRNumericMeasurementValue::checkRationalRepresentation(const Sint32 /*rationalNumerator*/,
723 const Uint32 rationalDenominator) const
724 {
725 /* avoid "division by zero" */
726 return (rationalDenominator == 0) ? SR_EC_InvalidValue
727 : EC_Normal;
728 }
729
730
checkCurrentValue() const731 OFCondition DSRNumericMeasurementValue::checkCurrentValue() const
732 {
733 OFCondition result = checkNumericValue(NumericValue);
734 if (result.good())
735 result = checkMeasurementUnit(MeasurementUnit);
736 if (result.good())
737 result = checkNumericValueQualifier(ValueQualifier);
738 if (result.good())
739 {
740 Sint32 numeratorValue;
741 Uint32 denominatorValue;
742 result = getRationalRepresentation(numeratorValue, denominatorValue);
743 if (result.good())
744 result = checkRationalRepresentation(numeratorValue, denominatorValue);
745 else if (result == SR_EC_RepresentationNotAvailable)
746 result = EC_Normal;
747 }
748 return result;
749 }
750
751
752 // output operators
753
operator <<(STD_NAMESPACE ostream & stream,const DSRNumericMeasurementValue & numericMeasurement)754 STD_NAMESPACE ostream &operator<<(STD_NAMESPACE ostream &stream,
755 const DSRNumericMeasurementValue &numericMeasurement)
756 {
757 numericMeasurement.print(stream, 0 /*flags*/);
758 return stream;
759 }
760