changeset 3055:71ac4f28176f db-changes

compatibility layer seems to be working
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 21 Dec 2018 13:36:30 +0100
parents 3638de45a08c
children 6c5d4281da4a
files OrthancServer/Search/Compatibility/DatabaseLookup.cpp OrthancServer/Search/DatabaseConstraint.h OrthancServer/Search/DicomTagConstraint.cpp OrthancServer/Search/DicomTagConstraint.h
diffstat 4 files changed, 171 insertions(+), 21 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancServer/Search/Compatibility/DatabaseLookup.cpp	Fri Dec 21 12:45:24 2018 +0100
+++ b/OrthancServer/Search/Compatibility/DatabaseLookup.cpp	Fri Dec 21 13:36:30 2018 +0100
@@ -42,6 +42,55 @@
 {
   namespace Compatibility
   {
+    namespace
+    {
+      // Anonymous namespace to avoid clashes between compiler modules
+      class MainTagsConstraints : boost::noncopyable
+      {
+      private:
+        std::vector<DicomTagConstraint*>  constraints_;
+
+      public:
+        ~MainTagsConstraints()
+        {
+          for (size_t i = 0; i < constraints_.size(); i++)
+          {
+            assert(constraints_[i] != NULL);
+            delete constraints_[i];
+          }
+        }
+
+        void Reserve(size_t n)
+        {
+          constraints_.reserve(n);
+        }
+
+        size_t GetSize() const
+        {
+          return constraints_.size();
+        }
+
+        DicomTagConstraint& GetConstraint(size_t i) const
+        {
+          if (i >= constraints_.size())
+          {
+            throw OrthancException(ErrorCode_ParameterOutOfRange);
+          }
+          else
+          {
+            assert(constraints_[i] != NULL);
+            return *constraints_[i];
+          }
+        }
+        
+        void Add(const DatabaseConstraint& constraint)
+        {
+          constraints_.push_back(new DicomTagConstraint(constraint));
+        }          
+      };
+    }
+    
+    
     static void ApplyIdentifierConstraint(SetOfResources& candidates,
                                           CompatibilityDatabaseWrapper& database,
                                           const DatabaseConstraint& constraint,
@@ -74,7 +123,6 @@
           break;
           
         case ConstraintType_List:
-        {
           for (size_t i = 0; i < constraint.GetValuesCount(); i++)
           {
             std::list<int64_t> tmp;
@@ -84,7 +132,6 @@
           }
 
           break;
-        }
           
         default:
           throw OrthancException(ErrorCode_InternalError);
@@ -120,6 +167,10 @@
       typedef std::set<const DatabaseConstraint*>  SetOfConstraints;
       typedef std::map<DicomTag, SetOfConstraints> Identifiers;
 
+      // (1) Select which constraints apply to this level, and split
+      // them between "identifier tags" constraints and "main DICOM
+      // tags" constraints
+
       Identifiers       identifiers;
       SetOfConstraints  mainTags;
       
@@ -138,15 +189,22 @@
         }
       }
 
+      
+      // (2) Apply the constraints over the identifiers
+      
       for (Identifiers::const_iterator it = identifiers.begin();
            it != identifiers.end(); ++it)
       {
+        // Check whether some range constraint over identifiers is
+        // present at this level
         const DatabaseConstraint* smaller = NULL;
         const DatabaseConstraint* greater = NULL;
         
         for (SetOfConstraints::const_iterator it2 = it->second.begin();
              it2 != it->second.end(); ++it2)
         {
+          assert(*it2 != NULL);
+        
           if ((*it2)->GetConstraintType() == ConstraintType_SmallerOrEqual)
           {
             smaller = *it2;
@@ -161,6 +219,7 @@
         if (smaller != NULL &&
             greater != NULL)
         {
+          // There is a range constraint: Apply it, as it is more efficient
           ApplyIdentifierRange(candidates, database, *smaller, *greater, level);
         }
         else
@@ -172,6 +231,7 @@
         for (SetOfConstraints::const_iterator it2 = it->second.begin();
              it2 != it->second.end(); ++it2)
         {
+          // Check to avoid applying twice the range constraint
           if (*it2 != smaller &&
               *it2 != greater)
           {
@@ -181,7 +241,51 @@
       }
 
 
-      // TODO - Fiter main DICOM tags
+      // (3) Apply the constraints over the main DICOM tags (no index
+      // here, so this is less efficient than filtering over the
+      // identifiers)
+      if (!mainTags.empty())
+      {
+        MainTagsConstraints c;
+        c.Reserve(mainTags.size());
+        
+        for (SetOfConstraints::const_iterator it = mainTags.begin();
+             it != mainTags.end(); ++it)
+        {
+          assert(*it != NULL);
+          c.Add(**it);
+        }
+
+        std::list<int64_t>  source;
+        candidates.Flatten(source);
+        candidates.Clear();
+
+        std::list<int64_t>  filtered;
+        for (std::list<int64_t>::const_iterator candidate = source.begin(); 
+             candidate != source.end(); ++candidate)
+        {
+          DicomMap tags;
+          database.GetMainDicomTags(tags, *candidate);
+
+          bool match = true;
+
+          for (size_t i = 0; i < c.GetSize(); i++)
+          {
+            if (!c.GetConstraint(i).IsMatch(tags))
+            {
+              match = false;
+              break;
+            }
+          }
+        
+          if (match)
+          {
+            filtered.push_back(*candidate);
+          }
+        }
+
+        candidates.Intersect(filtered);
+      }
     }
 
 
--- a/OrthancServer/Search/DatabaseConstraint.h	Fri Dec 21 12:45:24 2018 +0100
+++ b/OrthancServer/Search/DatabaseConstraint.h	Fri Dec 21 13:36:30 2018 +0100
@@ -91,5 +91,7 @@
     {
       return mandatory_;
     }
+
+    bool IsMatch(const DicomMap& dicom) const;
   };
 }
--- a/OrthancServer/Search/DicomTagConstraint.cpp	Fri Dec 21 12:45:24 2018 +0100
+++ b/OrthancServer/Search/DicomTagConstraint.cpp	Fri Dec 21 13:36:30 2018 +0100
@@ -36,6 +36,8 @@
 
 #include "../../Core/OrthancException.h"
 #include "../../Core/Toolbox.h"
+#include "../ServerToolbox.h"
+#include "DatabaseConstraint.h"
 
 #include <boost/regex.hpp>
 
@@ -94,6 +96,30 @@
   };
 
 
+  void DicomTagConstraint::AssignSingleValue(const std::string& value)
+  {
+    if (constraintType_ != ConstraintType_Wildcard &&
+        (value.find('*') != std::string::npos ||
+         value.find('?') != std::string::npos))
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    if (constraintType_ == ConstraintType_Equal ||
+        constraintType_ == ConstraintType_SmallerOrEqual ||
+        constraintType_ == ConstraintType_GreaterOrEqual ||
+        constraintType_ == ConstraintType_Wildcard)
+    {
+      values_.clear();
+      values_.insert(value);
+    }
+    else
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+  }
+
+
   DicomTagConstraint::DicomTagConstraint(const DicomTag& tag,
                                          ConstraintType type,
                                          const std::string& value,
@@ -104,24 +130,7 @@
     caseSensitive_(caseSensitive),
     mandatory_(mandatory)
   {
-    if (type == ConstraintType_Equal ||
-        type == ConstraintType_SmallerOrEqual ||
-        type == ConstraintType_GreaterOrEqual ||
-        type == ConstraintType_Wildcard)
-    {
-      values_.insert(value);
-    }
-    else
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
-
-    if (type != ConstraintType_Wildcard &&
-        (value.find('*') != std::string::npos ||
-         value.find('?') != std::string::npos))
-    {
-      throw OrthancException(ErrorCode_ParameterOutOfRange);
-    }
+    AssignSingleValue(value);
   }
 
 
@@ -141,6 +150,35 @@
   }
 
 
+  DicomTagConstraint::DicomTagConstraint(const DatabaseConstraint& constraint) :
+    tag_(constraint.GetTag()),
+    constraintType_(constraint.GetConstraintType()),
+    caseSensitive_(constraint.IsCaseSensitive()),
+    mandatory_(constraint.IsMandatory())
+  {
+    assert(constraint.IsIdentifier() ==
+           ServerToolbox::IsIdentifier(constraint.GetTag(), constraint.GetLevel()));
+    
+    if (constraint.IsIdentifier())
+    {
+      // This conversion is only available for main DICOM tags, not for identifers
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+    
+    if (constraintType_ == ConstraintType_List)
+    {
+      for (size_t i = 0; i < constraint.GetValuesCount(); i++)
+      {
+        AddValue(constraint.GetValue(i));
+      }
+    }
+    else
+    {
+      AssignSingleValue(constraint.GetSingleValue());
+    }
+  }
+
+
   void DicomTagConstraint::AddValue(const std::string& value)
   {
     if (constraintType_ != ConstraintType_List)
--- a/OrthancServer/Search/DicomTagConstraint.h	Fri Dec 21 12:45:24 2018 +0100
+++ b/OrthancServer/Search/DicomTagConstraint.h	Fri Dec 21 13:36:30 2018 +0100
@@ -40,6 +40,8 @@
 
 namespace Orthanc
 {
+  class DatabaseConstraint;
+  
   class DicomTagConstraint : public boost::noncopyable
   {
   private:
@@ -54,6 +56,8 @@
 
     boost::shared_ptr<RegularExpression>  regex_;
 
+    void AssignSingleValue(const std::string& value);
+
   public:
     DicomTagConstraint(const DicomTag& tag,
                        ConstraintType type,
@@ -67,6 +71,8 @@
                        bool caseSensitive,
                        bool mandatory);
 
+    DicomTagConstraint(const DatabaseConstraint& constraint);
+
     const DicomTag& GetTag() const
     {
       return tag_;