comparison OrthancFramework/Sources/DicomParsing/FromDcmtkBridge.cpp @ 4515:8734caa12448

Improved precision of floating-point numbers in DICOM-as-JSON and DICOM summary
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 16 Feb 2021 14:42:04 +0100
parents 5b929e6b3c36
children 671ee7c1fd46
comparison
equal deleted inserted replaced
4514:5b929e6b3c36 4515:8734caa12448
189 return &dictionary_; 189 return &dictionary_;
190 } 190 }
191 }; 191 };
192 192
193 193
194 #define DCMTK_TO_CTYPE_CONVERTER(converter, cType, dcmtkType, getter) \ 194 ORTHANC_FORCE_INLINE
195 static std::string FloatToString(float v)
196 {
197 /**
198 * From "boost::lexical_cast" documentation: "For more involved
199 * conversions, such as where precision or formatting need tighter
200 * control than is offered by the default behavior of
201 * lexical_cast, the conventional stringstream approach is
202 * recommended."
203 * https://www.boost.org/doc/libs/1_65_0/doc/html/boost_lexical_cast.html
204 * http://www.gotw.ca/publications/mill19.htm
205 *
206 * The precision of 17 corresponds to "defaultRealPrecision" in JsonCpp:
207 * https://github.com/open-source-parsers/jsoncpp/blob/master/include/json/value.h
208 **/
209
210 //return boost::lexical_cast<std::string>(v); // This was used in Orthanc <= 1.9.0
211
212 std::ostringstream ss;
213 ss << std::setprecision(17) << v;
214 return ss.str();
215 }
216
217
218 ORTHANC_FORCE_INLINE
219 static std::string DoubleToString(double v)
220 {
221 //return boost::lexical_cast<std::string>(v); // This was used in Orthanc <= 1.9.0
222
223 std::ostringstream ss;
224 ss << std::setprecision(17) << v;
225 return ss.str();
226 }
227
228
229 #define DCMTK_TO_CTYPE_CONVERTER(converter, cType, dcmtkType, getter, toStringFunction) \
195 \ 230 \
196 struct converter \ 231 struct converter \
197 { \ 232 { \
198 typedef cType CType; \ 233 typedef cType CType; \
199 \ 234 \
235 ORTHANC_FORCE_INLINE \
200 static bool Apply(CType& result, \ 236 static bool Apply(CType& result, \
201 DcmElement& element, \ 237 DcmElement& element, \
202 size_t i) \ 238 size_t i) \
203 { \ 239 { \
204 return dynamic_cast<dcmtkType&>(element).getter(result, i).good(); \ 240 return dynamic_cast<dcmtkType&>(element).getter(result, i).good(); \
205 } \ 241 } \
242 \
243 ORTHANC_FORCE_INLINE \
244 static std::string ToString(CType value) \
245 { \
246 return toStringFunction(value); \
247 } \
206 }; 248 };
207 249
208 DCMTK_TO_CTYPE_CONVERTER(DcmtkToSint32Converter, Sint32, DcmSignedLong, getSint32) 250 DCMTK_TO_CTYPE_CONVERTER(DcmtkToSint32Converter, Sint32, DcmSignedLong, getSint32, boost::lexical_cast<std::string>)
209 DCMTK_TO_CTYPE_CONVERTER(DcmtkToSint16Converter, Sint16, DcmSignedShort, getSint16) 251 DCMTK_TO_CTYPE_CONVERTER(DcmtkToSint16Converter, Sint16, DcmSignedShort, getSint16, boost::lexical_cast<std::string>)
210 DCMTK_TO_CTYPE_CONVERTER(DcmtkToUint32Converter, Uint32, DcmUnsignedLong, getUint32) 252 DCMTK_TO_CTYPE_CONVERTER(DcmtkToUint32Converter, Uint32, DcmUnsignedLong, getUint32, boost::lexical_cast<std::string>)
211 DCMTK_TO_CTYPE_CONVERTER(DcmtkToUint16Converter, Uint16, DcmUnsignedShort, getUint16) 253 DCMTK_TO_CTYPE_CONVERTER(DcmtkToUint16Converter, Uint16, DcmUnsignedShort, getUint16, boost::lexical_cast<std::string>)
212 DCMTK_TO_CTYPE_CONVERTER(DcmtkToFloat32Converter, Float32, DcmFloatingPointSingle, getFloat32) 254 DCMTK_TO_CTYPE_CONVERTER(DcmtkToFloat32Converter, Float32, DcmFloatingPointSingle, getFloat32, FloatToString)
213 DCMTK_TO_CTYPE_CONVERTER(DcmtkToFloat64Converter, Float64, DcmFloatingPointDouble, getFloat64) 255 DCMTK_TO_CTYPE_CONVERTER(DcmtkToFloat64Converter, Float64, DcmFloatingPointDouble, getFloat64, DoubleToString)
214 256
215 257
216 template <typename F> 258 template <typename F>
217 static DicomValue* ApplyDcmtkToCTypeConverter(DcmElement& element) 259 static DicomValue* ApplyDcmtkToCTypeConverter(DcmElement& element)
218 { 260 {
224 { 266 {
225 size_t count = element.getLength() / sizeof(typename F::CType); 267 size_t count = element.getLength() / sizeof(typename F::CType);
226 std::vector<std::string> strings; 268 std::vector<std::string> strings;
227 for (size_t i = 0; i < count; i++) { 269 for (size_t i = 0; i < count; i++) {
228 if (f.Apply(value, element, i)) { 270 if (f.Apply(value, element, i)) {
229 strings.push_back(boost::lexical_cast<std::string>(value)); 271 strings.push_back(F::ToString(value));
230 } 272 }
231 } 273 }
232 return new DicomValue(boost::algorithm::join(strings, "\\"), false); 274 return new DicomValue(boost::algorithm::join(strings, "\\"), false);
233 } 275 }
234 else if (f.Apply(value, element, 0)) { 276 else if (f.Apply(value, element, 0)) {
235 return new DicomValue(boost::lexical_cast<std::string>(value), false); 277 return new DicomValue(F::ToString(value), false);
236 } 278 }
237 else { 279 else {
238 return new DicomValue; 280 return new DicomValue;
239 } 281 }
240 } 282 }
241
242 } 283 }
243 284
244 285
245 void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary) 286 void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary)
246 { 287 {