changeset 2218:c098f0f16eb1

making subclasses Polygon and Structure uncopyable in DicomStructureSet
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 22 Apr 2025 18:09:13 +0200
parents ccafa8ffcc6a
children a10b7a6ec869
files OrthancStone/Sources/Toolbox/DicomStructureSet.cpp OrthancStone/Sources/Toolbox/DicomStructureSet.h
diffstat 2 files changed, 96 insertions(+), 55 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancStone/Sources/Toolbox/DicomStructureSet.cpp	Tue Apr 22 17:01:35 2025 +0200
+++ b/OrthancStone/Sources/Toolbox/DicomStructureSet.cpp	Tue Apr 22 18:09:13 2025 +0200
@@ -423,14 +423,27 @@
   }
 
   
+  DicomStructureSet::Structure::~Structure()
+  {
+    for (Polygons::iterator it = polygons_.begin(); it != polygons_.end(); ++it)
+    {
+      assert(*it != NULL);
+      delete *it;
+    }
+  }
+
+
   const DicomStructureSet::Structure& DicomStructureSet::GetStructure(size_t index) const
   {
     if (index >= structures_.size())
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-
-    return structures_[index];
+    else
+    {
+      assert(structures_[index] != NULL);
+      return *structures_[index];
+    }
   }
 
 
@@ -440,8 +453,11 @@
     {
       throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
     }
-
-    return structures_[index];
+    else
+    {
+      assert(structures_[index] != NULL);
+      return *structures_[index];
+    }
   }
 
   void DicomStructureSet::Setup(const IDicomDataset& tags)
@@ -486,18 +502,19 @@
 
         roiNumbersIndex[roiNumber] = i;
 
-        structures_[i].name_ = reader.GetStringValue
+        structures_[i] = new Structure();
+        structures_[i]->name_ = reader.GetStringValue
           (Orthanc::DicomPath(DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE, i, DICOM_TAG_ROI_NAME), "No name");
-        structures_[i].interpretation_ = "No interpretation";
+        structures_[i]->interpretation_ = "No interpretation";
 
-        if (structureNamesIndex_.find(structures_[i].name_) == structureNamesIndex_.end())
+        if (structureNamesIndex_.find(structures_[i]->name_) == structureNamesIndex_.end())
         {
-          structureNamesIndex_[structures_[i].name_] = i;
+          structureNamesIndex_[structures_[i]->name_] = i;
         }
         else
         {
           throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat,
-                                          "RT-STRUCT with twice the same name for a structure: " + structures_[i].name_);
+                                          "RT-STRUCT with twice the same name for a structure: " + structures_[i]->name_);
         }
       }
     }
@@ -535,7 +552,7 @@
             throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
           }
 
-          structures_[found->second].interpretation_ = interpretation;
+          structures_[found->second]->interpretation_ = interpretation;
         }
       }
     }
@@ -568,7 +585,7 @@
           throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
         }
 
-        Structure& target = structures_[found->second];
+        Structure& target = *structures_[found->second];
 
         Vector color;
         if (FastParseVector(color, tags, Orthanc::DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i,
@@ -676,8 +693,8 @@
             LOG(ERROR) << "WARNING. The following Dicom tag (Referenced SOP Instance UID) contains an empty value : // (3006,0039)[" << i << "] / (0x3006, 0x0040)[0] / (0x3006, 0x0016)[0] / (0x0008, 0x1155)";
           }
 
-          Polygon polygon(sopInstanceUid);
-          polygon.Reserve(countPoints);
+          std::unique_ptr<Polygon> polygon(new Polygon(sopInstanceUid));
+          polygon->Reserve(countPoints);
 
           for (size_t k = 0; k < countPoints; k++)
           {
@@ -685,10 +702,10 @@
             v[0] = points[3 * k];
             v[1] = points[3 * k + 1];
             v[2] = points[3 * k + 2];
-            polygon.AddPoint(v);
+            polygon->AddPoint(v);
           }
 
-          target.polygons_.push_back(polygon);
+          target.polygons_.push_back(polygon.release());
         }
       }
     }
@@ -713,6 +730,16 @@
 #endif
   
 
+  DicomStructureSet::~DicomStructureSet()
+  {
+    for (size_t i = 0; i < structures_.size(); i++)
+    {
+      assert(structures_[i] != NULL);
+      delete structures_[i];
+    }
+  }
+
+
   const std::string& DicomStructureSet::GetStructureName(size_t index) const
   {
     return GetStructure(index).name_;
@@ -734,13 +761,14 @@
     
   void DicomStructureSet::GetReferencedInstances(std::set<std::string>& instances) const
   {
-    for (Structures::const_iterator structure = structures_.begin();
-         structure != structures_.end(); ++structure)
+    for (size_t i = 0; i < structures_.size(); i++)
     {
-      for (Polygons::const_iterator polygon = structure->polygons_.begin();
-           polygon != structure->polygons_.end(); ++polygon)
+      assert(structures_[i] != NULL);
+      for (Polygons::const_iterator polygon = structures_[i]->polygons_.begin();
+           polygon != structures_[i]->polygons_.end(); ++polygon)
       {
-        instances.insert(polygon->GetSopInstanceUid());
+        assert(*polygon != NULL);
+        instances.insert((*polygon)->GetSopInstanceUid());
       }
     }
   }
@@ -784,13 +812,15 @@
         
       referencedSlices_[sopInstanceUid] = ReferencedSlice(seriesInstanceUid, geometry, thickness);
 
-      for (Structures::iterator structure = structures_.begin();
-           structure != structures_.end(); ++structure)
+      for (size_t i = 0; i < structures_.size(); i++)
       {
-        for (Polygons::iterator polygon = structure->polygons_.begin();
-             polygon != structure->polygons_.end(); ++polygon)
+        assert(structures_[i] != NULL);
+
+        for (Polygons::iterator polygon = structures_[i]->polygons_.begin();
+             polygon != structures_[i]->polygons_.end(); ++polygon)
         {
-          polygon->UpdateReferencedSlice(referencedSlices_);
+          assert(*polygon != NULL);
+          (*polygon)->UpdateReferencedSlice(referencedSlices_);
         }
       }
     }
@@ -827,15 +857,16 @@
 
   void DicomStructureSet::CheckReferencedSlices()
   {
-    for (Structures::iterator structure = structures_.begin();
-         structure != structures_.end(); ++structure)
+    for (size_t i = 0; i < structures_.size(); i++)
     {
-      for (Polygons::iterator polygon = structure->polygons_.begin();
-           polygon != structure->polygons_.end(); ++polygon)
+      assert(structures_[i] != NULL);
+      for (Polygons::iterator polygon = structures_[i]->polygons_.begin();
+           polygon != structures_[i]->polygons_.end(); ++polygon)
       {
-        if (!polygon->UpdateReferencedSlice(referencedSlices_))
+        assert(*polygon != NULL);
+        if (!(*polygon)->UpdateReferencedSlice(referencedSlices_))
         {
-          std::string sopInstanceUid = polygon->GetSopInstanceUid();
+          std::string sopInstanceUid = (*polygon)->GetSopInstanceUid();
           if (Orthanc::Toolbox::StripSpaces(sopInstanceUid) == "")
           {
             LOG(ERROR) << "DicomStructureSet::CheckReferencedSlices(): "
@@ -889,9 +920,10 @@
       for (Polygons::const_iterator polygon = structure.polygons_.begin();
            polygon != structure.polygons_.end(); ++polygon)
       {
-        const Points& points = polygon->GetPoints();
+        assert(*polygon != NULL);
+        const Points& points = (*polygon)->GetPoints();
         
-        if (polygon->IsOnSlice(cutting, GetEstimatedNormal(), GetEstimatedSliceThickness()) &&
+        if ((*polygon)->IsOnSlice(cutting, GetEstimatedNormal(), GetEstimatedSliceThickness()) &&
             !points.empty())
         {
           chains.push_back(std::vector<ScenePoint2D>());
@@ -955,7 +987,8 @@
       for (Polygons::const_iterator polygon = structure.polygons_.begin();
            polygon != structure.polygons_.end(); ++polygon)
       {
-        polygon->Project(rectangles, cutting, GetEstimatedNormal(), GetEstimatedSliceThickness());
+        assert(*polygon != NULL);
+        (*polygon)->Project(rectangles, cutting, GetEstimatedNormal(), GetEstimatedSliceThickness());
       }
 
       typedef std::list< std::vector<ScenePoint2D> >  Contours;
@@ -1009,12 +1042,13 @@
     // TODO - Could be optimized by adding a multimap on "Structure", mapping
     // from SOP Instance UID to polygons
     
-    for (Polygons::const_iterator it = structure.polygons_.begin();
-         it != structure.polygons_.end(); ++it)
+    for (Polygons::const_iterator polygon = structure.polygons_.begin();
+         polygon != structure.polygons_.end(); ++polygon)
     {
-      if (it->GetSopInstanceUid() == sopInstanceUid)
+      assert(*polygon != NULL);
+      if ((*polygon)->GetSopInstanceUid() == sopInstanceUid)
       {
-        target.push_back(it->GetPoints());
+        target.push_back((*polygon)->GetPoints());
       }
     }
   }
@@ -1031,13 +1065,16 @@
     unsigned int countPolygons = 0;
     for (size_t i = 0; i < structures_.size(); i++)
     {
-      const Polygons& polygons = structures_[i].polygons_;
+      assert(structures_[i] != NULL);
+      const Polygons& polygons = structures_[i]->polygons_;
 
-      for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it)
+      for (Polygons::const_iterator polygon = polygons.begin(); polygon != polygons.end(); ++polygon)
       {
+        assert(*polygon != NULL);
+
         countPolygons++;
-        
-        const Points& points = it->GetPoints();
+
+        const Points& points = (*polygon)->GetPoints();
         
         if (points.size() >= 3)
         {
@@ -1114,11 +1151,13 @@
     
     for (size_t i = 0; i < structures_.size(); i++)
     {
-      const Polygons& polygons = structures_[i].polygons_;
+      assert(structures_[i] != NULL);
+      const Polygons& polygons = structures_[i]->polygons_;
 
-      for (Polygons::const_iterator it = polygons.begin(); it != polygons.end(); ++it)
+      for (Polygons::const_iterator polygon = polygons.begin(); polygon != polygons.end(); ++polygon)
       {
-        const Points& points = it->GetPoints();
+        assert(*polygon != NULL);
+        const Points& points = (*polygon)->GetPoints();
         polygonsProjection.push_back(GeometryToolbox::ProjectAlongNormal(points[0], estimatedNormal_));
       }
     }
--- a/OrthancStone/Sources/Toolbox/DicomStructureSet.h	Tue Apr 22 17:01:35 2025 +0200
+++ b/OrthancStone/Sources/Toolbox/DicomStructureSet.h	Tue Apr 22 18:09:13 2025 +0200
@@ -72,7 +72,7 @@
     
     typedef std::vector<Vector>  Points;
 
-    class Polygon
+    class Polygon : public boost::noncopyable
     {
     private:
       std::string         sopInstanceUid_;
@@ -132,9 +132,9 @@
                    double estimatedSliceThickness) const;
     };
 
-    typedef std::list<Polygon>  Polygons;
+    typedef std::list<Polygon*>  Polygons;
 
-    struct Structure
+    struct Structure : public boost::noncopyable
     {
       std::string   name_;
       std::string   interpretation_;
@@ -142,17 +142,17 @@
       uint8_t       red_;
       uint8_t       green_;
       uint8_t       blue_;
+
+      ~Structure();
     };
 
-    typedef std::vector<Structure>         Structures;
     typedef std::map<std::string, size_t>  StructureNamesIndex;
 
-    Structures        structures_;
-    ReferencedSlices  referencedSlices_;
-    Vector            estimatedNormal_;
-    double            estimatedSliceThickness_;
-    StructureNamesIndex  structureNamesIndex_;
-    
+    std::vector<Structure*>  structures_;
+    ReferencedSlices         referencedSlices_;
+    Vector                   estimatedNormal_;
+    double                   estimatedSliceThickness_;
+    StructureNamesIndex      structureNamesIndex_;
 
     void Setup(const IDicomDataset& dataset);
     
@@ -176,6 +176,8 @@
     explicit DicomStructureSet(Orthanc::ParsedDicomFile& instance);
 #endif
 
+    ~DicomStructureSet();
+
     size_t GetStructuresCount() const
     {
       return structures_.size();