Mercurial > hg > orthanc
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 { |