]> Creatis software - gdcm.git/blobdiff - src/gdcmSerieHelper.cxx
Typo
[gdcm.git] / src / gdcmSerieHelper.cxx
index cf592ea3ceb217d9a3ae0d3d4eaa513080e18bf3..06ffc2db18380350e524d34904f262e98c19f5e2 100644 (file)
@@ -3,8 +3,8 @@
   Program:   gdcm
   Module:    $RCSfile: gdcmSerieHelper.cxx,v $
   Language:  C++
-  Date:      $Date: 2005/07/29 15:07:16 $
-  Version:   $Revision: 1.16 $
+  Date:      $Date: 2005/10/26 06:23:37 $
+  Version:   $Revision: 1.31 $
                                                                                 
   Copyright (c) CREATIS (Centre de Recherche et d'Applications en Traitement de
   l'Image). All rights reserved. See Doc/License.txt or
 
 #include <math.h>
 #include <vector>
+#include <map>
 #include <algorithm>
+#include <stdio.h>  //for sscanf
 
 namespace gdcm 
 {
+//-----------------------------------------------------------------------------
 
 //-----------------------------------------------------------------------------
 // Constructor / Destructor
@@ -37,21 +40,8 @@ namespace gdcm
  */
 SerieHelper::SerieHelper()
 {
-   // For all the File lists of the gdcm::Serie
-   FileList *l = GetFirstCoherentFileList();
-   while (l)
-   { 
-      // For all the files of a File list
-      for (gdcm::FileList::iterator it  = l->begin();
-                              it != l->end(); 
-                            ++it)
-      {
-         delete *it;
-      }
-      l->clear();
-      delete l;;
-      l = GetNextCoherentFileList();
-   }
+   ClearAll();
+   UserLessThanFunction = 0;
    DirectOrder = true;
 }
 
@@ -60,20 +50,29 @@ SerieHelper::SerieHelper()
  */
 SerieHelper::~SerieHelper()
 {
-   // For all the Coherent File lists of the gdcm::Serie
-   FileList *l = GetFirstCoherentFileList();
+   ClearAll();
+}
+
+/**
+ * \brief  Preventively, clear everything at constructor time.
+ *         ( use it at destructor time.)
+ */
+void SerieHelper::ClearAll()
+{
+   // For all the 'Single SerieUID' Filesets that may already exist 
+   FileList *l = GetFirstSingleSerieUIDFileSet();
    while (l)
    { 
-      // For all the files of a Coherent File list
-      for (FileList::iterator it  = l->begin();
-                              it != l->end(); 
-                            ++it)
+      // For all the gdcm::File of a File set
+      for (gdcm::FileList::iterator it  = l->begin();
+                                    it != l->end(); 
+                                  ++it)
       {
-         delete *it;
+         (*it)->Delete(); // remove each entry
       }
       l->clear();
-      delete l;
-      l = GetNextCoherentFileList();
+      delete l;     // remove the container
+      l = GetNextSingleSerieUIDFileSet();
    }
 }
 
@@ -83,13 +82,13 @@ SerieHelper::~SerieHelper()
 
 // Public
 /**
- * \brief add a gdcm::File to the list corresponding to its Serie UID
+ * \brief add a gdcm::File to the Fileset corresponding to its Serie UID
  * @param   filename Name of the file to deal with
  */
 void SerieHelper::AddFileName(std::string const &filename)
 {
    // Create a DICOM file
-   File *header = new File ();
+   File *header = File::New();
    header->SetLoadMode(LoadMode);
    header->SetFileName( filename ); 
    header->Load();
@@ -97,37 +96,21 @@ void SerieHelper::AddFileName(std::string const &filename)
    if ( header->IsReadable() )
    {
       int allrules = 1;
-      // First step the user has defined a set of rules for the DICOM file
+      // First step : the user defined a set of rules for the DICOM file
       // he is looking for.
-      // make sure the file correspond to his set of rules:
+      // Make sure the file corresponds to his set of rules:
 
-/*
-      for(SerieRestrictions::iterator it = Restrictions.begin();
-          it != Restrictions.end();
-          ++it)
-      {
-         const Rule &r = *it;
-         // doesn't compile (no matching function...).
-         const std::string s;// = header->GetEntryValue( r.first );
-         if ( !Util::DicomStringEqual(s, r.second.c_str()) )
-         {
-           // Argh ! This rule is unmatch let's just quit
-           allrules = 0;
-           break;
-         }
-      }
-*/
-      // Just keep 'new style' for Rules
       std::string s;
       for(SerieExRestrictions::iterator it2 = ExRestrictions.begin();
           it2 != ExRestrictions.end();
           ++it2)
       {
          const ExRule &r = *it2;
-         s = header->GetEntryValue( r.group, r.elem );
+         s = header->GetEntryString( r.group, r.elem );
          if ( !Util::CompareDicomString(s, r.value.c_str(), r.op) )
          {
-           // Argh ! This rule is unmatch let's just quit
+           // Argh ! This rule is unmatched; let's just quit
+
            allrules = 0;
            break;
          }
@@ -135,40 +118,44 @@ void SerieHelper::AddFileName(std::string const &filename)
 
       if ( allrules ) // all rules are respected:
       {
-         // Allright ! we have a found a DICOM that match the user expectation. 
-         // Let's add it !
+         // Allright! we have a found a DICOM that matches the user expectation. 
+         // Let's add it!
 
          // 0020 000e UI REL Series Instance UID
-         const std::string &uid = header->GetEntryValue (0x0020, 0x000e);
+         const std::string &uid = header->GetEntryString(0x0020, 0x000e);
          // if uid == GDCM_UNFOUND then consistently we should find GDCM_UNFOUND
          // no need here to do anything special
 
-         if ( CoherentFileListHT.count(uid) == 0 )
+
+         if ( SingleSerieUIDFileSetHT.count(uid) == 0 )
          {
             gdcmDebugMacro(" New Serie UID :[" << uid << "]");
             // create a std::list in 'uid' position
-            CoherentFileListHT[uid] = new FileList;
+            SingleSerieUIDFileSetHT[uid] = new FileList;
          }
          // Current Serie UID and DICOM header seems to match; add the file:
-         CoherentFileListHT[uid]->push_back( header );
+         SingleSerieUIDFileSetHT[uid]->push_back( header );
       }
       else
       {
-         // at least one rule was unmatch we need to deallocate the file:
-         delete header;
+         // at least one rule was unmatched we need to deallocate the file:
+         header->Delete();
       }
    }
    else
    {
       gdcmWarningMacro("Could not read file: " << filename );
-      delete header;
+      header->Delete();
    }
 }
 
 /**
- * \brief add a gdcm::File to the first (and supposed to be unique) list
+ * \brief add a gdcm::File to the first (and supposed to be unique) file set
  *        of the gdcm::SerieHelper.
  * \warning : this method should be used by aware users only!
+ *           Passing a gdcm::File* has the same effect than passing a file name!
+ * \todo : decide which one is wrong (the method, or the commentary)!
+ *           the following comment doesn't match the method :-(
  *            User is supposed to know the files he want to deal with
  *           and consider them they belong to the same Serie
  *           (even if their Serie UID is different)
@@ -186,9 +173,9 @@ void SerieHelper::AddGdcmFile(File *header)
       // First step the user has defined a set of rules for the DICOM 
       // he is looking for.
       // make sure the file correspond to his set of rules:
-      for(SerieRestrictions::iterator it = Restrictions.begin();
-          it != Restrictions.end();
-          ++it)
+      for(SerieRestrictions::iterator it =  Restrictions.begin();
+                                      it != Restrictions.end();
+                                    ++it)
       {
          const Rule &r = *it;
          const std::string s;// = header->GetEntryValue( r.first );
@@ -208,14 +195,14 @@ void SerieHelper::AddGdcmFile(File *header)
          // Serie UID of the gdcm::File* may be different.
          // User is supposed to know what he wants
 
-         if ( CoherentFileListHT.count(uid) == 0 )
+         if ( SingleSerieUIDFileSetHT.count(uid) == 0 )
          {
             gdcmDebugMacro(" New Serie UID :[" << uid << "]");
             // create a std::list in 'uid' position
-            CoherentFileListHT[uid] = new FileList;
+            SingleSerieUIDFileSetHT[uid] = new FileList;
          }
          // Current Serie UID and DICOM header seems to match; add the file:
-         CoherentFileListHT[uid]->push_back( header );
+         SingleSerieUIDFileSetHT[uid]->push_back( header );
       }
          // Even if a rule was unmatch we don't deallocate the gdcm::File:
 }
@@ -226,6 +213,10 @@ void SerieHelper::AddGdcmFile(File *header)
  * directory which would have a particular EchoTime==4.0.
  * This method is a user level, value is not required to be formatted as a DICOM
  * string
+ * @param   group  Group number of the target tag.
+ * @param   elem Element number of the target tag.
+ * @param value value to be checked to exclude File
+ * @param op  operator we want to use to check
  */
 void SerieHelper::AddRestriction(uint16_t group, uint16_t elem, 
                                  std::string const &value, int op)
@@ -239,15 +230,6 @@ void SerieHelper::AddRestriction(uint16_t group, uint16_t elem,
 }
 
 #ifndef GDCM_LEGACY_REMOVE
-/**
- * \brief add a rules for restricting a DICOM file to be in the serie we are
- * trying to find. For example you can select only the DICOM file from a
- * directory which would have a particular EchoTime==4.0.
- * This method is a user level, value is not required to be formatted as a DICOM
- * string
- * @deprecated use : AddRestriction(uint16_t group, uint16_t elem, 
- *                                 std::string const &value, int op);
- */
 void SerieHelper::AddRestriction(TagKey const &key, std::string const &value)
 {
    Rule r;
@@ -260,7 +242,7 @@ void SerieHelper::AddRestriction(TagKey const &key, std::string const &value)
 /**
  * \brief Sets the root Directory
  * @param   dir Name of the directory to deal with
- * @param recursive whether we want explore recursively the Directory
+ * @param recursive whether we want explore recursively the root Directory
  */
 void SerieHelper::SetDirectory(std::string const &dir, bool recursive)
 {
@@ -275,64 +257,301 @@ void SerieHelper::SetDirectory(std::string const &dir, bool recursive)
 }
 
 /**
- * \brief Sorts the given File List
+ * \brief Sorts the given Fileset
  * \warning This could be implemented in a 'Strategy Pattern' approach
  *          But as I don't know how to do it, I leave it this way
- *          BTW, this is also a Strategy, I don't know this is the best approach :)
+ *          BTW, this is also a Strategy, I don't know this is 
+ *          the best approach :)
  */
-void SerieHelper::OrderFileList(FileList *coherentFileList)
+void SerieHelper::OrderFileList(FileList *fileSet)
 {
-   if ( ImagePositionPatientOrdering( coherentFileList ) )
+
+   if ( SerieHelper::UserLessThanFunction )
+   {
+      UserOrdering( fileSet );
+      return; 
+   }
+   else if ( ImagePositionPatientOrdering( fileSet ) )
    {
       return ;
    }
-   else if ( ImageNumberOrdering(coherentFileList ) )
+   else if ( ImageNumberOrdering(fileSet ) )
    {
       return ;
    }
    else  
    {
-      FileNameOrdering(coherentFileList );
+      FileNameOrdering(fileSet );
    }
 }
 
 /**
- * \brief   Get the first List while visiting the CoherentFileListHT
- * @return  The first FileList if found, otherwhise NULL
- */
+ * \brief Elementary coherence checking of the files with the same Serie UID
+ * Only sizes and pixel type are checked right now ...
+ */ 
+bool SerieHelper::IsCoherent(FileList *fileSet)
+{
+   if(fileSet->size() == 1)
+   return true;
+
+   FileList::const_iterator it = fileSet->begin();
+
+   int nX = (*it)->GetXSize();
+   int nY = (*it)->GetYSize();
+   int pixelSize = (*it)->GetPixelSize();
+
+   it ++;
+   for ( ;
+         it != fileSet->end();
+       ++it)
+   {
+      if ( (*it)->GetXSize() != nX )
+         return false;
+      if ( (*it)->GetYSize() != nY )
+         return false;
+      if ( (*it)->GetPixelSize() != pixelSize )
+         return false;
+      // probabely more is to be checked (?)
+   }
+   return true;
+}
+
+#ifndef GDCM_LEGACY_REMOVE
+
 FileList *SerieHelper::GetFirstCoherentFileList()
 {
-   ItListHt = CoherentFileListHT.begin();
-   if ( ItListHt != CoherentFileListHT.end() )
-      return ItListHt->second;
+   ItFileSetHt = SingleSerieUIDFileSetHT.begin();
+   if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
+      return ItFileSetHt->second;
    return NULL;
 }
 
+
+FileList *SerieHelper::GetNextCoherentFileList()
+{
+   gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end());
+  
+   ++ItFileSetHt;
+   if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
+      return ItFileSetHt->second;
+   return NULL;
+}
+
+
+FileList *SerieHelper::GetCoherentFileList(std::string SerieUID)
+{
+   if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 )
+      return 0;     
+   return SingleSerieUIDFileSetHT[SerieUID];
+}
+#endif
+
+
 /**
- * \brief   Get the next List while visiting the CoherentFileListHT
- * \note : meaningfull only if GetFirstCoherentFileList() already called
- * @return  The next FileList if found, otherwhise NULL
+ * \brief   Get the first Fileset while visiting the SingleSerieUIDFileSetmap
+ * @return  The first FileList (SingleSerieUIDFileSet) if found, otherwhise 0
  */
-FileList *SerieHelper::GetNextCoherentFileList()
+FileList *SerieHelper::GetFirstSingleSerieUIDFileSet()
 {
-   gdcmAssertMacro (ItListHt != CoherentFileListHT.end());
+   ItFileSetHt = SingleSerieUIDFileSetHT.begin();
+   if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
+      return ItFileSetHt->second;
+   return NULL;
+}
+
+/**
+ * \brief   Get the next Fileset while visiting the SingleSerieUIDFileSetmap
+ * \note : meaningfull only if GetNextSingleSerieUIDFileSet() already called 
+ * @return  The next FileList (SingleSerieUIDFileSet) if found, otherwhise 0
+ */
+FileList *SerieHelper::GetNextSingleSerieUIDFileSet()
+{
+   gdcmAssertMacro (ItFileSetHt != SingleSerieUIDFileSetHT.end());
   
-   ++ItListHt;
-   if ( ItListHt != CoherentFileListHT.end() )
-      return ItListHt->second;
+   ++ItFileSetHt;
+   if ( ItFileSetHt != SingleSerieUIDFileSetHT.end() )
+      return ItFileSetHt->second;
    return NULL;
 }
 
 /**
- * \brief   Get the Coherent Files list according to its Serie UID
- * @param SerieUID SerieUID
- * \return  pointer to the Coherent Files list if found, otherwhise NULL
+ * \brief   Get the SingleSerieUIDFileSet according to its Serie UID
+ * @param SerieUID SerieUID to retrieve
+ * \return pointer to the FileList (SingleSerieUIDFileSet) if found, otherwhise 0
  */
-FileList *SerieHelper::GetCoherentFileList(std::string SerieUID)
+FileList *SerieHelper::GetSingleSerieUIDFileSet(std::string SerieUID)
 {
-   if ( CoherentFileListHT.count(SerieUID) == 0 )
+   if ( SingleSerieUIDFileSetHT.count(SerieUID) == 0 )
       return 0;     
-   return CoherentFileListHT[SerieUID];
+   return SingleSerieUIDFileSetHT[SerieUID];
+}
+
+/**
+ * \brief   Splits a Single SerieUID Fileset according to the Orientations
+ * @param fileSet File Set to be splitted
+ * \return  std::map of 'Xcoherent' File sets
+ */
+
+XCoherentFileSetmap SerieHelper::SplitOnOrientation(FileList *fileSet)
+{
+   XCoherentFileSetmap CoherentFileSet;
+
+   int nb = fileSet->size();
+   if (nb == 0 )
+      return CoherentFileSet;
+   float iop[6];
+
+   std::string strOrient;
+   std::ostringstream ossOrient;   
+   FileList::const_iterator it = fileSet->begin();
+   it ++;
+   for ( ;
+         it != fileSet->end();
+       ++it)
+   {     
+      // Information is in :      
+      // 0020 0037 : Image Orientation (Patient) or
+      // 0020 0035 : Image Orientation (RET)
+
+      // Let's build again the 'cosines' string, to be sure of it's format      
+      (*it)->GetImageOrientationPatient(iop);
+
+      ossOrient << iop[0];      
+      for (int i = 1; i < 6; i++)
+      {
+        ossOrient << "\\";
+        ossOrient << iop[i]; 
+      }      
+      strOrient = ossOrient.str();
+      ossOrient.str("");
+      // FIXME : is it a 'cleaner' way to initialize an ostringstream? 
+
+      if ( CoherentFileSet.count(strOrient) == 0 )
+      {
+         gdcmDebugMacro(" New Orientation :[" << strOrient << "]");
+         // create a File set in 'orientation' position
+         CoherentFileSet[strOrient] = new FileList;
+      }
+      // Current Orientation and DICOM header match; add the file:
+      CoherentFileSet[strOrient]->push_back( (*it) );
+   } 
+   return CoherentFileSet;
+}
+
+/**
+ * \brief   Splits a 'Single SerieUID' Fileset according to the Positions
+ * @param fileSet File Set to be splitted
+ * \return  std::map of 'Xcoherent' File sets
+ */
+
+XCoherentFileSetmap SerieHelper::SplitOnPosition(FileList *fileSet)
+{
+   XCoherentFileSetmap CoherentFileSet;
+
+   int nb = fileSet->size();
+   if (nb == 0 )
+      return CoherentFileSet;
+   float pos[3];
+   std::string strImPos;  // read on disc
+   std::ostringstream ossPosition;
+   std::string strPosition; // re computed
+   FileList::const_iterator it = fileSet->begin();
+   it ++;
+   for ( ;
+         it != fileSet->end();
+       ++it)
+   {     
+      // Information is in :      
+      // 0020,0032 : Image Position Patient
+      // 0020,0030 : Image Position (RET)
+
+      strImPos = (*it)->GetEntryString(0x0020,0x0032);
+      if ( strImPos == GDCM_UNFOUND)
+      {
+         gdcmWarningMacro( "Unfound Image Position Patient (0020,0032)");
+         strImPos = (*it)->GetEntryString(0x0020,0x0030); // For ACR-NEMA images
+         if ( strImPos == GDCM_UNFOUND )
+         {
+            gdcmWarningMacro( "Unfound Image Position (RET) (0020,0030)");
+            // User wants to split on the 'Position'
+            // No 'Position' info found.
+            // We return an empty Htable !
+            return CoherentFileSet;
+         }  
+      }
+
+      if ( sscanf( strImPos.c_str(), "%f \\%f \\%f ", 
+                                              &pos[0], &pos[1], &pos[2]) != 3 )
+      {
+            gdcmWarningMacro( "Wrong number for Position : ["
+                       << strImPos << "]" );
+             return CoherentFileSet;
+      }
+
+      // Let's build again the 'position' string, to be sure of it's format      
+
+      ossPosition << pos[0];      
+      for (int i = 1; i < 3; i++)
+      {
+        ossPosition << "\\";
+        ossPosition << pos[i]; 
+      }      
+      strPosition = ossPosition.str();
+      
+      if ( CoherentFileSet.count(strPosition) == 0 )
+      {
+         gdcmDebugMacro(" New Position :[" << strPosition << "]");
+         // create a File set in 'position' position
+         CoherentFileSet[strPosition] = new FileList;
+      }
+      // Current Position and DICOM header match; add the file:
+      CoherentFileSet[strPosition]->push_back( (*it) );
+   }   
+   return CoherentFileSet;
+}
+
+/**
+ * \brief   Splits a 'Single SerieUID' File set Coherent according to the
+ *          value of a given Tag
+ * @param fileSet File Set to be splitted
+ * @param   group  group number of the target Element
+ * @param   elem element number of the target Element
+ * \return  std::map of 'Xcoherent' File sets
+ */
+
+XCoherentFileSetmap SerieHelper::SplitOnTagValue(FileList *fileSet, 
+                                               uint16_t group, uint16_t elem)
+{
+   XCoherentFileSetmap CoherentFileSet;
+
+   int nb = fileSet->size();
+   if (nb == 0 )
+      return CoherentFileSet;
+
+   std::string strTagValue;  // read on disc
+
+   FileList::const_iterator it = fileSet->begin();
+   it ++;
+   for ( ;
+         it != fileSet->end();
+       ++it)
+   {     
+      // Information is in :      
+      // 0020,0032 : Image Position Patient
+      // 0020,0030 : Image Position (RET)
+
+      strTagValue = (*it)->GetEntryString(group,elem);
+      
+      if ( CoherentFileSet.count(strTagValue) == 0 )
+      {
+         gdcmDebugMacro(" New Tag Value :[" << strTagValue << "]");
+         // create a File set in 'position' position
+         CoherentFileSet[strTagValue] = new FileList;
+      }
+      // Current Tag value and DICOM header match; add the file:
+      CoherentFileSet[strTagValue]->push_back( (*it) );
+   }
+   return CoherentFileSet;
 }
 
 //-----------------------------------------------------------------------------
@@ -345,8 +564,9 @@ FileList *SerieHelper::GetCoherentFileList(std::string SerieUID)
  *  We may order, considering :
  *   -# Image Position Patient
  *   -# Image Number
+ *   -# File Name
  *   -# More to come :-)
- * WARNING : FileList = std::vector<File* >
+ * \note : FileList = std::vector<File* >
  * @param fileList Coherent File list (same Serie UID) to sort
  * @return false only if the header is bugged !
  */
@@ -374,8 +594,8 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
       
          // You only have to do this once for all slices in the volume. Next, 
          // for each slice, calculate the distance along the slice normal 
-         // using the IPP tag ("dist" is initialized to zero before reading 
-         // the first slice) :
+         // using the IPP ("Image Position Patient") tag.
+         // ("dist" is initialized to zero before reading the first slice) :
          normal[0] = cosines[1]*cosines[5] - cosines[2]*cosines[4];
          normal[1] = cosines[2]*cosines[3] - cosines[0]*cosines[5];
          normal[2] = cosines[0]*cosines[4] - cosines[1]*cosines[3];
@@ -425,11 +645,11 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
 
    // Find out if min/max are coherent
    if ( min == max )
-     {
-     gdcmWarningMacro( "Looks like all images have the exact same image position."
-                       << "No PositionPatientOrdering sort performed" );
+   {
+     gdcmWarningMacro("Looks like all images have the exact same image position"
+                      << ". No PositionPatientOrdering sort performed" );
      return false;
-     }
+   }
 
    float step = (max - min)/(n - 1);
    int pos;
@@ -451,7 +671,8 @@ bool SerieHelper::ImagePositionPatientOrdering( FileList *fileList )
          CoherentFileVector[pos] = *it2;
       else
       {
-         gdcmWarningMacro( "At least 2 files with same position. No PositionPatientOrdering sort performed");
+         gdcmWarningMacro( "At least 2 files with same position."
+                        << " No PositionPatientOrdering sort performed");
          return false;
       }
    }
@@ -493,12 +714,13 @@ bool SerieHelper::ImageNumberGreaterThan(File *file1, File *file2)
 {
   return file1->GetImageNumber() > file2->GetImageNumber();
 }
+
 /**
  * \brief sorts the images, according to their Image Number
  * \note Works only on bona fide files  (i.e image number is a character string
  *                                      corresponding to an integer)
  *             within a bona fide serie (i.e image numbers are consecutive)
- * @param fileList Coherent File list (same Serie UID) to sort 
+ * @param fileList  File set (same Serie UID) to sort 
  * @return false if non bona fide stuff encountered
  */
 bool SerieHelper::ImageNumberOrdering(FileList *fileList) 
@@ -519,25 +741,28 @@ bool SerieHelper::ImageNumberOrdering(FileList *fileList)
    // Find out if image numbers are coherent (consecutive)
    if ( min == max || max == 0 || max >= (n+min) )
    {
-      gdcmWarningMacro( " 'Image numbers' not coherent. No ImageNumberOrdering sort performed.");
+      gdcmWarningMacro( " 'Image numbers' not coherent. "
+                        << " No ImageNumberOrdering sort performed.");
       return false;
    }
    if (DirectOrder) 
-      std::sort(fileList->begin(), fileList->end(), SerieHelper::ImageNumberLessThan );
+      std::sort(fileList->begin(), fileList->end(), 
+                                          SerieHelper::ImageNumberLessThan );
    else
-      std::sort(fileList->begin(), fileList->end(), SerieHelper::ImageNumberGreaterThan );
+      std::sort(fileList->begin(), fileList->end(),
+                                          SerieHelper::ImageNumberGreaterThan );
 
    return true;
 }
 
 bool SerieHelper::FileNameLessThan(File *file1, File *file2)
 {
-  return file1->GetFileName() < file2->GetFileName();
+   return file1->GetFileName() < file2->GetFileName();
 }
 
 bool SerieHelper::FileNameGreaterThan(File *file1, File *file2)
 {
-  return file1->GetFileName() > file2->GetFileName();
+   return file1->GetFileName() > file2->GetFileName();
 }
 /**
  * \brief sorts the images, according to their File Name
@@ -547,10 +772,28 @@ bool SerieHelper::FileNameGreaterThan(File *file1, File *file2)
 bool SerieHelper::FileNameOrdering(FileList *fileList)
 {
    if (DirectOrder) 
-      std::sort(fileList->begin(), fileList->end(), SerieHelper::FileNameLessThan);
+      std::sort(fileList->begin(), fileList->end(), 
+                                       SerieHelper::FileNameLessThan);
    else
-      std::sort(fileList->begin(), fileList->end(), SerieHelper::FileNameGreaterThan);
+      std::sort(fileList->begin(), fileList->end(), 
+                                       SerieHelper::FileNameGreaterThan);
+
+   return true;
+}
 
+/**
+ * \brief sorts the images, according to user supplied function
+ * @param fileList Coherent File list (same Serie UID) to sort
+ * @return false only if the header is bugged !
+ */
+bool SerieHelper::UserOrdering(FileList *fileList)
+{
+   std::sort(fileList->begin(), fileList->end(), 
+                                    SerieHelper::UserLessThanFunction);
+   if (!DirectOrder) 
+   {
+      std::reverse(fileList->begin(), fileList->end());
+   }
    return true;
 }
 
@@ -562,17 +805,17 @@ bool SerieHelper::FileNameOrdering(FileList *fileList)
 void SerieHelper::Print(std::ostream &os, std::string const &indent)
 {
    // For all the Coherent File lists of the gdcm::Serie
-   CoherentFileListmap::iterator itl = CoherentFileListHT.begin();
-   if ( itl == CoherentFileListHT.end() )
+   SingleSerieUIDFileSetmap::iterator itl = SingleSerieUIDFileSetHT.begin();
+   if ( itl == SingleSerieUIDFileSetHT.end() )
    {
-      gdcmWarningMacro( "No Coherent File list found" );
+      gdcmWarningMacro( "No SingleSerieUID File set found" );
       return;
    }
-   while (itl != CoherentFileListHT.end())
+   while (itl != SingleSerieUIDFileSetHT.end())
    { 
       os << "Serie UID :[" << itl->first << "]" << std::endl;
 
-      // For all the files of a Coherent File list
+      // For all the files of a SingleSerieUID File set
       for (FileList::iterator it =  (itl->second)->begin();
                                   it != (itl->second)->end(); 
                                 ++it)