# HG changeset patch # User Sebastien Jodogne # Date 1699460782 -3600 # Node ID 67db5afb305db33b7d2f6fef06b7224f9faf3f12 # Parent ec676dbe85acb0ae962c553e97212857a9474d90 partial integration dicom-sr->mainline diff -r ec676dbe85ac -r 67db5afb305d OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp --- a/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp Wed Nov 08 15:13:21 2023 +0100 +++ b/OrthancStone/Sources/Toolbox/DicomStructuredReport.cpp Wed Nov 08 17:26:22 2023 +0100 @@ -118,165 +118,138 @@ namespace OrthancStone { - void DicomStructuredReport::ReferencedInstance::AddFrame(unsigned int frame) + void DicomStructuredReport::Structure::Copy(const Structure& other) { - if (frame == 0) + if (other.HasFrameNumber()) + { + SetFrameNumber(other.GetFrameNumber()); + } + + if (other.HasProbabilityOfCancer()) + { + SetProbabilityOfCancer(other.GetProbabilityOfCancer()); + } + } + + + DicomStructuredReport::Structure::Structure(const std::string& sopInstanceUid) : + sopInstanceUid_(sopInstanceUid), + hasFrameNumber_(false), + hasProbabilityOfCancer_(false) + { + } + + + void DicomStructuredReport::Structure::SetFrameNumber(unsigned int frame) + { + hasFrameNumber_ = true; + frameNumber_ = frame; + } + + + void DicomStructuredReport::Structure::SetProbabilityOfCancer(float probability) + { + if (probability < 0 || + probability > 100) { throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } else { - frames_.insert(frame - 1); + hasProbabilityOfCancer_ = true; + probabilityOfCancer_ = probability; + } + } + + + unsigned int DicomStructuredReport::Structure::GetFrameNumber() const + { + if (hasFrameNumber_) + { + return frameNumber_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + } + + float DicomStructuredReport::Structure::GetProbabilityOfCancer() const + { + if (hasProbabilityOfCancer_) + { + return probabilityOfCancer_; + } + else + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); } } - class DicomStructuredReport::Structure : public boost::noncopyable + DicomStructuredReport::Point::Point(const std::string& sopInstanceUid, + double x, + double y) : + Structure(sopInstanceUid), + point_(x, y) { - private: - std::string sopInstanceUid_; - bool hasFrameNumber_; - unsigned int frameNumber_; - bool hasProbabilityOfCancer_; - float probabilityOfCancer_; - - public: - Structure(const std::string& sopInstanceUid) : - sopInstanceUid_(sopInstanceUid), - hasFrameNumber_(false), - hasProbabilityOfCancer_(false) - { - } + } - virtual ~Structure() - { - } - - void SetFrameNumber(unsigned int frame) - { - if (frame <= 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - else - { - hasFrameNumber_ = true; - frameNumber_ = frame - 1; - } - } - void SetProbabilityOfCancer(float probability) - { - if (probability < 0 || - probability > 100) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - else - { - hasProbabilityOfCancer_ = true; - probabilityOfCancer_ = probability; - } - } + DicomStructuredReport::Structure* DicomStructuredReport::Point::Clone() const + { + std::unique_ptr cloned(new Point(GetSopInstanceUid(), point_.GetX(), point_.GetY())); + cloned->Copy(*this); + return cloned.release(); + } - bool HasFrameNumber() const + + DicomStructuredReport::Polyline::Polyline(const std::string& sopInstanceUid, + const float* points, + unsigned long pointsCount) : + Structure(sopInstanceUid) + { + if (pointsCount % 2 != 0) { - return hasFrameNumber_; - } - - bool HasProbabilityOfCancer() const - { - return hasProbabilityOfCancer_; - } - - unsigned int GetFrameNumber() const - { - if (hasFrameNumber_) - { - return frameNumber_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } - float GetProbabilityOfCancer() const + points_.reserve(pointsCount / 2); + + for (unsigned long i = 0; i < pointsCount; i += 2) { - if (hasProbabilityOfCancer_) - { - return probabilityOfCancer_; - } - else - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); - } + points_.push_back(ScenePoint2D(points[i], points[i + 1])); } - }; + } - class DicomStructuredReport::Point : public Structure + DicomStructuredReport::Polyline::Polyline(const std::string& sopInstanceUid, + const std::vector& points) : + Structure(sopInstanceUid), + points_(points) { - private: - ScenePoint2D point_; - - public: - Point(const std::string& sopInstanceUid, - double x, - double y) : - Structure(sopInstanceUid), - point_(x, y) - { - } - - const ScenePoint2D& GetPoint() const - { - return point_; - } - }; + } - class DicomStructuredReport::Polyline : public Structure + DicomStructuredReport::Structure* DicomStructuredReport::Polyline::Clone() const { - private: - std::vector points_; + std::unique_ptr cloned(new Polyline(GetSopInstanceUid(), points_)); + cloned->Copy(*this); + return cloned.release(); + } - public: - Polyline(const std::string& sopInstanceUid, - const float* points, - unsigned long pointsCount) : - Structure(sopInstanceUid) - { - if (pointsCount % 2 != 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - points_.reserve(pointsCount / 2); - for (unsigned long i = 0; i < pointsCount; i += 2) - { - points_.push_back(ScenePoint2D(points[i], points[i + 1])); - } - } - - size_t GetSize() const + const ScenePoint2D& DicomStructuredReport::Polyline::GetPoint(size_t i) const + { + if (i >= points_.size()) { - return points_.size(); + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); } - - const ScenePoint2D& GetPoint(size_t i) const + else { - if (i >= points_.size()) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); - } - else - { - return points_[i]; - } + return points_[i]; } - }; + } void DicomStructuredReport::AddStructure(const std::string& sopInstanceUid, @@ -504,21 +477,22 @@ for (size_t m = 0; m < tokens.size(); m++) { uint32_t frame; - if (!Orthanc::SerializationToolbox::ParseUnsignedInteger32(frame, tokens[m])) + if (!Orthanc::SerializationToolbox::ParseUnsignedInteger32(frame, tokens[m]) || + frame <= 0) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } else { - AddStructure(sopInstanceUid, group, true, frame, hasProbabilityOfCancer, probabilityOfCancer); - instanceInformation->second->AddFrame(frame); + AddStructure(sopInstanceUid, group, true, frame - 1, hasProbabilityOfCancer, probabilityOfCancer); + instanceInformation->second->AddFrame(frame - 1); } } } else { AddStructure(sopInstanceUid, group, false, 0, hasProbabilityOfCancer, probabilityOfCancer); - instanceInformation->second->AddFrame(1); + instanceInformation->second->AddFrame(0); } } } @@ -531,9 +505,30 @@ } + DicomStructuredReport::DicomStructuredReport(const DicomStructuredReport& other) : + studyInstanceUid_(other.studyInstanceUid_), + seriesInstanceUid_(other.seriesInstanceUid_), + sopInstanceUid_(other.sopInstanceUid_), + orderedInstances_(other.orderedInstances_) + { + for (std::map::const_iterator + it = other.instancesInformation_.begin(); it != other.instancesInformation_.end(); ++it) + { + assert(it->second != NULL); + instancesInformation_[it->first] = new ReferencedInstance(*it->second); + } + + for (std::deque::const_iterator it = other.structures_.begin(); it != other.structures_.end(); ++it) + { + assert(*it != NULL); + structures_.push_back((*it)->Clone()); + } + } + + DicomStructuredReport::~DicomStructuredReport() { - for (std::list::iterator it = structures_.begin(); it != structures_.end(); ++it) + for (std::deque::iterator it = structures_.begin(); it != structures_.end(); ++it) { assert(*it != NULL); delete *it; @@ -598,4 +593,18 @@ } } } + + + const DicomStructuredReport::Structure& DicomStructuredReport::GetStructure(size_t index) const + { + if (index >= structures_.size()) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); + } + else + { + assert(structures_[index] != NULL); + return *structures_[index]; + } + } } diff -r ec676dbe85ac -r 67db5afb305d OrthancStone/Sources/Toolbox/DicomStructuredReport.h --- a/OrthancStone/Sources/Toolbox/DicomStructuredReport.h Wed Nov 08 15:13:21 2023 +0100 +++ b/OrthancStone/Sources/Toolbox/DicomStructuredReport.h Wed Nov 08 17:26:22 2023 +0100 @@ -31,9 +31,12 @@ # error Support for DCMTK must be enabled #endif +#include "../Scene2D/ScenePoint2D.h" + #include #include +#include #include #include @@ -41,12 +44,116 @@ { class DicomStructuredReport : public boost::noncopyable { + public: + enum StructureType + { + StructureType_Point, + StructureType_Polyline + }; + + class Structure : public boost::noncopyable + { + private: + std::string sopInstanceUid_; + bool hasFrameNumber_; + unsigned int frameNumber_; + bool hasProbabilityOfCancer_; + float probabilityOfCancer_; + + protected: + void Copy(const Structure& other); + + public: + Structure(const std::string& sopInstanceUid); + + virtual ~Structure() + { + } + + virtual Structure* Clone() const = 0; + + virtual StructureType GetType() const = 0; + + const std::string& GetSopInstanceUid() const + { + return sopInstanceUid_; + } + + void SetFrameNumber(unsigned int frame); + + void SetProbabilityOfCancer(float probability); + + bool HasFrameNumber() const + { + return hasFrameNumber_; + } + + bool HasProbabilityOfCancer() const + { + return hasProbabilityOfCancer_; + } + + unsigned int GetFrameNumber() const; + + float GetProbabilityOfCancer() const; + }; + + + class Point : public Structure + { + private: + ScenePoint2D point_; + + public: + Point(const std::string& sopInstanceUid, + double x, + double y); + + virtual Structure* Clone() const ORTHANC_OVERRIDE; + + virtual StructureType GetType() const ORTHANC_OVERRIDE + { + return StructureType_Point; + } + + const ScenePoint2D& GetPoint() const + { + return point_; + } + }; + + + class Polyline : public Structure + { + private: + std::vector points_; + + public: + Polyline(const std::string& sopInstanceUid, + const float* points, + unsigned long pointsCount); + + Polyline(const std::string& sopInstanceUid, + const std::vector& points); + + virtual Structure* Clone() const ORTHANC_OVERRIDE; + + virtual StructureType GetType() const ORTHANC_OVERRIDE + { + return StructureType_Polyline; + } + + size_t GetSize() const + { + return points_.size(); + } + + const ScenePoint2D& GetPoint(size_t i) const; + }; + + private: - class Structure; - class Point; - class Polyline; - - class ReferencedInstance : public boost::noncopyable + class ReferencedInstance { private: std::string studyInstanceUid_; @@ -79,7 +186,10 @@ return sopClassUid_; } - void AddFrame(unsigned int frame); + void AddFrame(unsigned int frame) + { + frames_.insert(frame); + } const std::set& GetFrames() const { @@ -100,7 +210,7 @@ std::string sopInstanceUid_; std::map instancesInformation_; std::vector orderedInstances_; - std::list structures_; + std::deque structures_; public: class ReferencedFrame @@ -154,6 +264,8 @@ DicomStructuredReport(Orthanc::ParsedDicomFile& dicom); + DicomStructuredReport(const DicomStructuredReport& other); // Copy constructor + ~DicomStructuredReport(); const std::string& GetStudyInstanceUid() const @@ -183,5 +295,12 @@ size_t i) const; void ExportReferencedFrames(std::list& frames) const; + + size_t GetStructuresCount() const + { + return structures_.size(); + } + + const Structure& GetStructure(size_t index) const; }; }