changeset 3194:47ef29168698

support of value multiplicity in ITagVisitor
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 05 Feb 2019 18:34:27 +0100
parents c6cfd502bf79
children 880e4161c312
files Core/DicomParsing/DicomModification.cpp Core/DicomParsing/FromDcmtkBridge.cpp Core/DicomParsing/ITagVisitor.h UnitTestsSources/DicomMapTests.cpp
diffstat 4 files changed, 191 insertions(+), 86 deletions(-) [+]
line wrap: on
line diff
--- a/Core/DicomParsing/DicomModification.cpp	Tue Feb 05 17:00:45 2019 +0100
+++ b/Core/DicomParsing/DicomModification.cpp	Tue Feb 05 18:34:27 2019 +0100
@@ -95,27 +95,27 @@
     {
     }
 
-    virtual void VisitInteger(const std::vector<DicomTag>& parentTags,
-                              const std::vector<size_t>& parentIndexes,
-                              const DicomTag& tag,
-                              ValueRepresentation vr,
-                              int64_t value)
+    virtual void VisitIntegers(const std::vector<DicomTag>& parentTags,
+                               const std::vector<size_t>& parentIndexes,
+                               const DicomTag& tag,
+                               ValueRepresentation vr,
+                               const std::vector<int64_t>& values)
     {
     }
 
-    virtual void VisitDouble(const std::vector<DicomTag>& parentTags,
-                             const std::vector<size_t>& parentIndexes,
-                             const DicomTag& tag,
-                             ValueRepresentation vr,
-                             double value)
+    virtual void VisitDoubles(const std::vector<DicomTag>& parentTags,
+                              const std::vector<size_t>& parentIndexes,
+                              const DicomTag& tag,
+                              ValueRepresentation vr,
+                              const std::vector<double>& value)
     {
     }
 
-    virtual void VisitAttribute(const std::vector<DicomTag>& parentTags,
-                                const std::vector<size_t>& parentIndexes,
-                                const DicomTag& tag,
-                                ValueRepresentation vr,
-                                const DicomTag& value)
+    virtual void VisitAttributes(const std::vector<DicomTag>& parentTags,
+                                 const std::vector<size_t>& parentIndexes,
+                                 const DicomTag& tag,
+                                 ValueRepresentation vr,
+                                 const std::vector<DicomTag>& value)
     {
     }
 
--- a/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Feb 05 17:00:45 2019 +0100
+++ b/Core/DicomParsing/FromDcmtkBridge.cpp	Tue Feb 05 18:34:27 2019 +0100
@@ -2265,67 +2265,121 @@
       
         case EVR_SL:  // signed long
         {
-          Sint32 f;
-          if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good())
+          DcmSignedLong& content = dynamic_cast<DcmSignedLong&>(element);
+
+          std::vector<int64_t> values;
+          values.reserve(content.getVM());
+
+          for (unsigned long i = 0; i < content.getVM(); i++)
           {
-            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+            Sint32 f;
+            if (content.getSint32(f, i).good())
+            {
+              values.push_back(f);
+            }
           }
 
+          visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values);
           break;
         }
 
         case EVR_SS:  // signed short
         {
-          Sint16 f;
-          if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good())
+          DcmSignedShort& content = dynamic_cast<DcmSignedShort&>(element);
+
+          std::vector<int64_t> values;
+          values.reserve(content.getVM());
+
+          for (unsigned long i = 0; i < content.getVM(); i++)
           {
-            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+            Sint16 f;
+            if (content.getSint16(f, i).good())
+            {
+              values.push_back(f);
+            }
           }
 
+          visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values);
           break;
         }
 
         case EVR_UL:  // unsigned long
         {
-          Uint32 f;
-          if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good())
+          DcmUnsignedLong& content = dynamic_cast<DcmUnsignedLong&>(element);
+
+          std::vector<int64_t> values;
+          values.reserve(content.getVM());
+
+          for (unsigned long i = 0; i < content.getVM(); i++)
           {
-            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+            Uint32 f;
+            if (content.getUint32(f, i).good())
+            {
+              values.push_back(f);
+            }
           }
 
+          visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values);
           break;
         }
 
         case EVR_US:  // unsigned short
         {
-          Uint16 f;
-          if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good())
+          DcmUnsignedShort& content = dynamic_cast<DcmUnsignedShort&>(element);
+
+          std::vector<int64_t> values;
+          values.reserve(content.getVM());
+
+          for (unsigned long i = 0; i < content.getVM(); i++)
           {
-            visitor.VisitInteger(parentTags, parentIndexes, tag, vr, f);
+            Uint16 f;
+            if (content.getUint16(f, i).good())
+            {
+              values.push_back(f);
+            }
           }
 
+          visitor.VisitIntegers(parentTags, parentIndexes, tag, vr, values);
           break;
         }
 
         case EVR_FL:  // float single-precision
         {
-          Float32 f;
-          if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good())
+          DcmFloatingPointSingle& content = dynamic_cast<DcmFloatingPointSingle&>(element);
+
+          std::vector<double> values;
+          values.reserve(content.getVM());
+
+          for (unsigned long i = 0; i < content.getVM(); i++)
           {
-            visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f);
+            Float32 f;
+            if (content.getFloat32(f, i).good())
+            {
+              values.push_back(f);
+            }
           }
 
+          visitor.VisitDoubles(parentTags, parentIndexes, tag, vr, values);
           break;
         }
 
         case EVR_FD:  // float double-precision
         {
-          Float64 f;
-          if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good())
+          DcmFloatingPointDouble& content = dynamic_cast<DcmFloatingPointDouble&>(element);
+
+          std::vector<double> values;
+          values.reserve(content.getVM());
+
+          for (unsigned long i = 0; i < content.getVM(); i++)
           {
-            visitor.VisitDouble(parentTags, parentIndexes, tag, vr, f);
+            Float64 f;
+            if (content.getFloat64(f, i).good())
+            {
+              values.push_back(f);
+            }
           }
 
+          visitor.VisitDoubles(parentTags, parentIndexes, tag, vr, values);
           break;
         }
 
@@ -2336,13 +2390,22 @@
 
         case EVR_AT:
         {
-          DcmTagKey tagKey;
-          if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tagKey, 0).good())
+          DcmAttributeTag& content = dynamic_cast<DcmAttributeTag&>(element);
+
+          std::vector<DicomTag> values;
+          values.reserve(content.getVM());
+
+          for (unsigned long i = 0; i < content.getVM(); i++)
           {
-            DicomTag t(tagKey.getGroup(), tagKey.getElement());
-            visitor.VisitAttribute(parentTags, parentIndexes, tag, vr, t);
+            DcmTagKey f;
+            if (content.getTagVal(f, i).good())
+            {
+              DicomTag t(f.getGroup(), f.getElement());
+              values.push_back(t);
+            }
           }
 
+          visitor.VisitAttributes(parentTags, parentIndexes, tag, vr, values);
           break;
         }
 
--- a/Core/DicomParsing/ITagVisitor.h	Tue Feb 05 17:00:45 2019 +0100
+++ b/Core/DicomParsing/ITagVisitor.h	Tue Feb 05 18:34:27 2019 +0100
@@ -65,23 +65,23 @@
                              const void* data,
                              size_t size) = 0;
 
-    virtual void VisitInteger(const std::vector<DicomTag>& parentTags,
+    virtual void VisitIntegers(const std::vector<DicomTag>& parentTags,
+                               const std::vector<size_t>& parentIndexes,
+                               const DicomTag& tag,
+                               ValueRepresentation vr,
+                               const std::vector<int64_t>& values) = 0;
+
+    virtual void VisitDoubles(const std::vector<DicomTag>& parentTags,
                               const std::vector<size_t>& parentIndexes,
                               const DicomTag& tag,
                               ValueRepresentation vr,
-                              int64_t value) = 0;
+                              const std::vector<double>& values) = 0;
 
-    virtual void VisitDouble(const std::vector<DicomTag>& parentTags,
-                             const std::vector<size_t>& parentIndexes,
-                             const DicomTag& tag,
-                             ValueRepresentation vr,
-                             double value) = 0;
-
-    virtual void VisitAttribute(const std::vector<DicomTag>& parentTags,
-                                const std::vector<size_t>& parentIndexes,
-                                const DicomTag& tag,
-                                ValueRepresentation vr,
-                                const DicomTag& value) = 0;
+    virtual void VisitAttributes(const std::vector<DicomTag>& parentTags,
+                                 const std::vector<size_t>& parentIndexes,
+                                 const DicomTag& tag,
+                                 ValueRepresentation vr,
+                                 const std::vector<DicomTag>& values) = 0;
 
     virtual Action VisitString(std::string& newValue,
                                const std::vector<DicomTag>& parentTags,
--- a/UnitTestsSources/DicomMapTests.cpp	Tue Feb 05 17:00:45 2019 +0100
+++ b/UnitTestsSources/DicomMapTests.cpp	Tue Feb 05 18:34:27 2019 +0100
@@ -557,6 +557,8 @@
 
 #if 0
 
+#include <boost/math/special_functions/round.hpp>
+
 namespace Orthanc
 {
   class DicomJsonVisitor : public ITagVisitor
@@ -636,7 +638,35 @@
         (*node) [t] = Json::objectValue;
         return (*node) [t];
       }
-    }                              
+    }
+
+    static Json::Value FormatInteger(int64_t value)
+    {
+      if (value < 0)
+      {
+        return Json::Value(static_cast<int32_t>(value));
+      }
+      else
+      {
+        return Json::Value(static_cast<uint32_t>(value));
+      }
+    }
+
+    static Json::Value FormatDouble(double value)
+    {
+      long long a = boost::math::llround<double>(value);
+
+      double d = fabs(value - static_cast<double>(a));
+
+      if (d <= std::numeric_limits<double>::epsilon() * 100.0)
+      {
+        return FormatInteger(a);
+      }
+      else
+      {
+        return Json::Value(value);
+      }
+    }
 
   public:
     DicomJsonVisitor()
@@ -664,6 +694,8 @@
                               const DicomTag& tag,
                               ValueRepresentation vr) ORTHANC_OVERRIDE
     {
+      Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
+      node["vr"] = EnumerationToString(vr);
     }
 
     virtual void VisitBinary(const std::vector<DicomTag>& parentTags,
@@ -681,11 +713,11 @@
       }
     }
 
-    virtual void VisitInteger(const std::vector<DicomTag>& parentTags,
-                              const std::vector<size_t>& parentIndexes,
-                              const DicomTag& tag,
-                              ValueRepresentation vr,
-                              int64_t value) ORTHANC_OVERRIDE
+    virtual void VisitIntegers(const std::vector<DicomTag>& parentTags,
+                               const std::vector<size_t>& parentIndexes,
+                               const DicomTag& tag,
+                               ValueRepresentation vr,
+                               const std::vector<int64_t>& values) ORTHANC_OVERRIDE
     {
       if (vr != ValueRepresentation_NotSupported)
       {
@@ -693,23 +725,20 @@
         node["vr"] = EnumerationToString(vr);
 
         Json::Value content = Json::arrayValue;
-        if (value < 0)
+        for (size_t i = 0; i < values.size(); i++)
         {
-          content.append(static_cast<int32_t>(value));
+          content.append(FormatInteger(values[i]));
         }
-        else
-        {
-          content.append(static_cast<uint32_t>(value));
-        }
+
         node["Value"] = content;
       }
     }
 
-    virtual void VisitDouble(const std::vector<DicomTag>& parentTags,
-                             const std::vector<size_t>& parentIndexes,
-                             const DicomTag& tag,
-                             ValueRepresentation vr,
-                             double value) ORTHANC_OVERRIDE
+    virtual void VisitDoubles(const std::vector<DicomTag>& parentTags,
+                              const std::vector<size_t>& parentIndexes,
+                              const DicomTag& tag,
+                              ValueRepresentation vr,
+                              const std::vector<double>& values) ORTHANC_OVERRIDE
     {
       if (vr != ValueRepresentation_NotSupported)
       {
@@ -717,21 +746,26 @@
         node["vr"] = EnumerationToString(vr);
 
         Json::Value content = Json::arrayValue;
-        content.append(value);
+        for (size_t i = 0; i < values.size(); i++)
+        {
+          content.append(FormatDouble(values[i]));
+        }
         node["Value"] = content;
       }
     }
 
-    virtual void VisitAttribute(const std::vector<DicomTag>& parentTags,
-                                const std::vector<size_t>& parentIndexes,
-                                const DicomTag& tag,
-                                ValueRepresentation vr,
-                                const DicomTag& value) ORTHANC_OVERRIDE
+    virtual void VisitAttributes(const std::vector<DicomTag>& parentTags,
+                                 const std::vector<size_t>& parentIndexes,
+                                 const DicomTag& tag,
+                                 ValueRepresentation vr,
+                                 const std::vector<DicomTag>& values) ORTHANC_OVERRIDE
     {
       if (vr != ValueRepresentation_NotSupported)
       {
         Json::Value& node = CreateNode(parentTags, parentIndexes, tag);
         node["vr"] = EnumerationToString(vr);
+
+        
       }
     }
 
@@ -768,27 +802,30 @@
               case ValueRepresentation_IntegerString:
               {
                 int64_t value = boost::lexical_cast<int64_t>(tokens[i]);
-                if (value < 0)
-                {
-                  node["Value"].append(static_cast<int32_t>(value));
-                }
-                else
-                {
-                  node["Value"].append(static_cast<uint32_t>(value));
-                }
+                node["Value"].append(FormatInteger(value));
                 break;
               }
               
               case ValueRepresentation_DecimalString:
               {
                 double value = boost::lexical_cast<double>(tokens[i]);
-                node["Value"].append(value);
+                node["Value"].append(FormatDouble(value));
                 break;
               }
               
               default:
+              {
+                size_t l = tokens[i].size();
+
+                if (l > 0 &&
+                    tokens[i][l - 1] == '\0')
+                {
+                  tokens[i] = tokens[i].substr(0, l - 1);
+                }
+
                 node["Value"].append(tokens[i]);
                 break;
+              }
             }
           }
           catch (boost::bad_lexical_cast&)
@@ -808,11 +845,16 @@
 
 /* 
 
-   cd /home/jodogne/Subversion/orthanc/s/dcmtk-3.6.2/i/bin
-   DCMDICTPATH=/home/jodogne/Downloads/dcmtk-3.6.2/dcmdata/data/dicom.dic ./dcm2json ~/Subversion/orthanc-tests/Database/DummyCT.dcm  | python -mjson.tool > /tmp/a.json
+cat << EOF > /tmp/tutu.py
+import json
+import sys
+j = json.loads(sys.stdin.read().decode("utf-8-sig"))
+print(json.dumps(j, indent=4, sort_keys=True, ensure_ascii=False).encode('utf-8'))
+EOF
 
-   make -j4 && ./UnitTests --gtest_filter=DicomWeb* && python -mjson.tool /tmp/tutu.json > /tmp/b.json
-   diff /tmp/a.json /tmp/b.json
+DCMDICTPATH=/home/jodogne/Downloads/dcmtk-3.6.2/dcmdata/data/dicom.dic /home/jodogne/Downloads/dcmtk-3.6.2/i/bin/dcm2json ~/Subversion/orthanc-tests/Database/DummyCT.dcm | tr -d '\0' | sed 's/\\u0000//g' | sed 's/\.0$//' | python /tmp/tutu.py | grep -v 'InlineBinary' > /tmp/a.json
+
+make -j4 && ./UnitTests --gtest_filter=DicomWeb* && python /tmp/tutu.py < /tmp/tutu.json > /tmp/b.json && diff -i /tmp/a.json /tmp/b.json
 
 */