Mercurial > hg > orthanc
changeset 80:6212bf978584
status of series
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Thu, 20 Sep 2012 15:18:12 +0200 |
parents | 297bad4e1019 |
children | 0ec5e2e327b1 |
files | Core/DicomFormat/DicomIntegerPixelAccessor.cpp Core/DicomFormat/DicomMap.cpp Core/DicomFormat/DicomMap.h Core/DicomFormat/DicomTag.cpp Core/DicomFormat/DicomTag.h Core/SQLite/Statement.cpp Core/SQLite/Statement.h NEWS OrthancExplorer/explorer.js OrthancServer/DicomProtocol/DicomUserConnection.cpp OrthancServer/FromDcmtkBridge.cpp OrthancServer/OrthancRestApi.cpp OrthancServer/PrepareDatabase.sql OrthancServer/ServerIndex.cpp |
diffstat | 14 files changed, 240 insertions(+), 113 deletions(-) [+] |
line wrap: on
line diff
--- a/Core/DicomFormat/DicomIntegerPixelAccessor.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/Core/DicomFormat/DicomIntegerPixelAccessor.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -67,7 +67,7 @@ frame_ = 0; try { - numberOfFrames_ = boost::lexical_cast<unsigned int>(values.GetValue(DicomTag::NUMBER_OF_FRAMES).AsString()); + numberOfFrames_ = boost::lexical_cast<unsigned int>(values.GetValue(DICOM_TAG_NUMBER_OF_FRAMES).AsString()); } catch (OrthancException) {
--- a/Core/DicomFormat/DicomMap.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/Core/DicomFormat/DicomMap.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -36,7 +36,7 @@ DicomTag(0x0010, 0x0030), // PatientBirthDate DicomTag(0x0010, 0x0040), // PatientSex DicomTag(0x0010, 0x1000), // OtherPatientIDs - DicomTag::PATIENT_ID + DICOM_TAG_PATIENT_ID }; static DicomTag studyTags[] = @@ -47,8 +47,8 @@ DicomTag(0x0008, 0x0030), // StudyTime DicomTag(0x0008, 0x1030), // StudyDescription DicomTag(0x0020, 0x0010), // StudyID - DicomTag::ACCESSION_NUMBER, - DicomTag::STUDY_INSTANCE_UID + DICOM_TAG_ACCESSION_NUMBER, + DICOM_TAG_STUDY_INSTANCE_UID }; static DicomTag seriesTags[] = @@ -64,9 +64,11 @@ DicomTag(0x0018, 0x0024), // SequenceName DicomTag(0x0018, 0x1030), // ProtocolName DicomTag(0x0020, 0x0011), // SeriesNumber - DicomTag::IMAGES_IN_ACQUISITION, - DicomTag::NUMBER_OF_SLICES, - DicomTag::SERIES_INSTANCE_UID + DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES, + DICOM_TAG_IMAGES_IN_ACQUISITION, + DICOM_TAG_NUMBER_OF_FRAMES, + DICOM_TAG_NUMBER_OF_SLICES, + DICOM_TAG_SERIES_INSTANCE_UID }; static DicomTag instanceTags[] = @@ -74,11 +76,9 @@ DicomTag(0x0008, 0x0012), // InstanceCreationDate DicomTag(0x0008, 0x0013), // InstanceCreationTime DicomTag(0x0020, 0x0012), // AcquisitionNumber - DicomTag::CARDIAC_NUMBER_OF_IMAGES, - DicomTag::IMAGE_INDEX, - DicomTag::INSTANCE_NUMBER, - DicomTag::NUMBER_OF_FRAMES, - DicomTag::SOP_INSTANCE_UID + DICOM_TAG_IMAGE_INDEX, + DICOM_TAG_INSTANCE_NUMBER, + DICOM_TAG_SOP_INSTANCE_UID }; @@ -160,6 +160,7 @@ } + DicomMap* DicomMap::Clone() const { std::auto_ptr<DicomMap> result(new DicomMap); @@ -175,15 +176,30 @@ const DicomValue& DicomMap::GetValue(const DicomTag& tag) const { + const DicomValue* value = TestAndGetValue(tag); + + if (value) + { + return *value; + } + else + { + throw OrthancException("Inexistent tag"); + } + } + + + const DicomValue* DicomMap::TestAndGetValue(const DicomTag& tag) const + { Map::const_iterator it = map_.find(tag); if (it == map_.end()) { - throw OrthancException("Inexistent tag"); + return NULL; } else { - return *it->second; + return it->second; } } @@ -219,25 +235,25 @@ void DicomMap::SetupFindStudyTemplate(DicomMap& result) { SetupFindTemplate(result, studyTags, sizeof(studyTags) / sizeof(DicomTag)); - result.SetValue(DicomTag::ACCESSION_NUMBER, ""); - result.SetValue(DicomTag::PATIENT_ID, ""); + result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); + result.SetValue(DICOM_TAG_PATIENT_ID, ""); } void DicomMap::SetupFindSeriesTemplate(DicomMap& result) { SetupFindTemplate(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag)); - result.SetValue(DicomTag::ACCESSION_NUMBER, ""); - result.SetValue(DicomTag::PATIENT_ID, ""); - result.SetValue(DicomTag::STUDY_INSTANCE_UID, ""); + result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); + result.SetValue(DICOM_TAG_PATIENT_ID, ""); + result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, ""); } void DicomMap::SetupFindInstanceTemplate(DicomMap& result) { SetupFindTemplate(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag)); - result.SetValue(DicomTag::ACCESSION_NUMBER, ""); - result.SetValue(DicomTag::PATIENT_ID, ""); - result.SetValue(DicomTag::STUDY_INSTANCE_UID, ""); - result.SetValue(DicomTag::SERIES_INSTANCE_UID, ""); + result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); + result.SetValue(DICOM_TAG_PATIENT_ID, ""); + result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, ""); + result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, ""); }
--- a/Core/DicomFormat/DicomMap.h Thu Sep 20 13:47:54 2012 +0200 +++ b/Core/DicomFormat/DicomMap.h Thu Sep 20 15:18:12 2012 +0200 @@ -109,6 +109,13 @@ const DicomValue& GetValue(const DicomTag& tag) const; + const DicomValue* TestAndGetValue(uint16_t group, uint16_t element) const + { + return TestAndGetValue(DicomTag(group, element)); + } + + const DicomValue* TestAndGetValue(const DicomTag& tag) const; + void Remove(const DicomTag& tag); void ExtractPatientInformation(DicomMap& result) const;
--- a/Core/DicomFormat/DicomTag.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/Core/DicomFormat/DicomTag.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -58,21 +58,4 @@ sprintf(b, "%04x,%04x", group_, element_); return std::string(b); } - - - const DicomTag DicomTag::ACCESSION_NUMBER = DicomTag(0x0008, 0x0050); - const DicomTag DicomTag::SOP_INSTANCE_UID = DicomTag(0x0008, 0x0018); - const DicomTag DicomTag::PATIENT_ID = DicomTag(0x0010, 0x0020); - const DicomTag DicomTag::SERIES_INSTANCE_UID = DicomTag(0x0020, 0x000e); - const DicomTag DicomTag::STUDY_INSTANCE_UID = DicomTag(0x0020, 0x000d); - const DicomTag DicomTag::PIXEL_DATA = DicomTag(0x7fe0, 0x0010); - - const DicomTag DicomTag::INSTANCE_NUMBER = DicomTag(0x0020, 0x0013); - const DicomTag DicomTag::IMAGE_INDEX = DicomTag(0x0054, 0x1330); - - const DicomTag DicomTag::NUMBER_OF_SLICES = DicomTag(0x0054, 0x0081); - const DicomTag DicomTag::NUMBER_OF_FRAMES = DicomTag(0x0028, 0x0008); - const DicomTag DicomTag::CARDIAC_NUMBER_OF_IMAGES = DicomTag(0x0018, 0x1090); - const DicomTag DicomTag::IMAGES_IN_ACQUISITION = DicomTag(0x0020, 0x1002); - }
--- a/Core/DicomFormat/DicomTag.h Thu Sep 20 13:47:54 2012 +0200 +++ b/Core/DicomFormat/DicomTag.h Thu Sep 20 15:18:12 2012 +0200 @@ -57,21 +57,21 @@ std::string Format() const; friend std::ostream& operator<< (std::ostream& o, const DicomTag& tag); - - // Aliases for the most useful tags - static const DicomTag ACCESSION_NUMBER; - static const DicomTag SOP_INSTANCE_UID; - static const DicomTag PATIENT_ID; - static const DicomTag SERIES_INSTANCE_UID; - static const DicomTag STUDY_INSTANCE_UID; - static const DicomTag PIXEL_DATA; + }; - static const DicomTag INSTANCE_NUMBER; - static const DicomTag IMAGE_INDEX; + // Aliases for the most useful tags + static const DicomTag DICOM_TAG_ACCESSION_NUMBER(0x0008, 0x0050); + static const DicomTag DICOM_TAG_SOP_INSTANCE_UID(0x0008, 0x0018); + static const DicomTag DICOM_TAG_PATIENT_ID(0x0010, 0x0020); + static const DicomTag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e); + static const DicomTag DICOM_TAG_STUDY_INSTANCE_UID(0x0020, 0x000d); + static const DicomTag DICOM_TAG_PIXEL_DATA(0x7fe0, 0x0010); - static const DicomTag NUMBER_OF_SLICES; - static const DicomTag NUMBER_OF_FRAMES; - static const DicomTag CARDIAC_NUMBER_OF_IMAGES; - static const DicomTag IMAGES_IN_ACQUISITION; - }; + static const DicomTag DICOM_TAG_IMAGE_INDEX(0x0054, 0x1330); + static const DicomTag DICOM_TAG_INSTANCE_NUMBER(0x0020, 0x0013); + + static const DicomTag DICOM_TAG_NUMBER_OF_SLICES(0x0054, 0x0081); + static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008); + static const DicomTag DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES(0x0018, 0x1090); + static const DicomTag DICOM_TAG_IMAGES_IN_ACQUISITION(0x0020, 0x1002); }
--- a/Core/SQLite/Statement.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/Core/SQLite/Statement.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -215,6 +215,11 @@ return COLUMN_TYPE_NULL; } + bool Statement::ColumnIsNull(int col) const + { + return sqlite3_column_type(GetStatement(), col) == SQLITE_NULL; + } + bool Statement::ColumnBool(int col) const { return !!ColumnInt(col);
--- a/Core/SQLite/Statement.h Thu Sep 20 13:47:54 2012 +0200 +++ b/Core/SQLite/Statement.h Thu Sep 20 15:18:12 2012 +0200 @@ -137,6 +137,7 @@ ColumnType GetDeclaredColumnType(int col) const; // These all take a 0-based argument index. + bool ColumnIsNull(int col) const ; bool ColumnBool(int col) const; int ColumnInt(int col) const; int64_t ColumnInt64(int col) const;
--- a/NEWS Thu Sep 20 13:47:54 2012 +0200 +++ b/NEWS Thu Sep 20 15:18:12 2012 +0200 @@ -1,6 +1,7 @@ Pending changes in the mainline =============================== +* Status of series Version 0.2.0 (2012/09/16)
--- a/OrthancExplorer/explorer.js Thu Sep 20 13:47:54 2012 +0200 +++ b/OrthancExplorer/explorer.js Thu Sep 20 15:18:12 2012 +0200 @@ -85,8 +85,7 @@ } - -function SortOnDicomTag(arr, tag, isInteger, reverse) +function Sort(arr, fieldExtractor, isInteger, reverse) { var defaultValue; if (isInteger) @@ -95,8 +94,8 @@ defaultValue = ''; arr.sort(function(a, b) { - var ta = a.MainDicomTags[tag]; - var tb = b.MainDicomTags[tag]; + var ta = fieldExtractor(a); + var tb = fieldExtractor(b); var order; if (ta == undefined) @@ -129,6 +128,14 @@ } +function SortOnDicomTag(arr, tag, isInteger, reverse) +{ + return Sort(arr, function(a) { + return a.MainDicomTags[tag]; + }, isInteger, reverse); +} + + function GetSingleResource(type, uuid, callback) { @@ -266,9 +273,21 @@ function FormatSeries(series, link, isReverse) { - var s = ('<h3>{0}</h3>{1}' + - '<span class="ui-li-count">{2}</span>').format + var c; + if (series.Instances.length == series.ExpectedNumberOfInstances) + { + c = series.ExpectedNumberOfInstances; + } + else + { + c = series.Instances.length + '/' + series.ExpectedNumberOfInstances; + } + + var s = ('<h3>{0}</h3>' + + '<p><em>Status: <strong>{1}</strong></em></p>{2}' + + '<span class="ui-li-count">{3}</span>').format (series.MainDicomTags.SeriesDescription, + series.Status, FormatMainDicomTags(series.MainDicomTags, [ "SeriesDescription", "SeriesTime", @@ -276,7 +295,7 @@ "ImagesInAcquisition", "SeriesDate" ]), - series.Instances.length + c ); return CompleteFormatting(s, link, isReverse); @@ -286,7 +305,7 @@ function FormatInstance(instance, link, isReverse) { var s = ('<h3>Instance {0}</h3>{1}').format - (instance.MainDicomTags.InstanceNumber, + (instance.IndexInSeries, FormatMainDicomTags(instance.MainDicomTags, [ "AcquisitionNumber", "InstanceNumber", @@ -390,7 +409,7 @@ GetSingleResource('studies', series.ParentStudy, function(study) { GetSingleResource('patients', study.ParentPatient, function(patient) { GetMultipleResources('instances', series.Instances, function(instances) { - SortOnDicomTag(instances, 'InstanceNumber', true, false); + Sort(instances, function(x) { return x.IndexInSeries; }, true, false); $('#series-info li').remove(); $('#series-info') @@ -622,7 +641,7 @@ if ($.mobile.pageData) { GetSingleResource('series', $.mobile.pageData.uuid, function(series) { GetMultipleResources('instances', series.Instances, function(instances) { - SortOnDicomTag(instances, 'InstanceNumber', true, false); + Sort(instances, function(x) { return x.IndexInSeries; }, true, false); var images = []; for (var i = 0; i < instances.length; i++) {
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -355,8 +355,8 @@ DicomMap s; fields.ExtractStudyInformation(s); - s.CopyTagIfExists(fields, DicomTag::PATIENT_ID); - s.CopyTagIfExists(fields, DicomTag::ACCESSION_NUMBER); + s.CopyTagIfExists(fields, DICOM_TAG_PATIENT_ID); + s.CopyTagIfExists(fields, DICOM_TAG_ACCESSION_NUMBER); Find(result, FindRootModel_Study, s); } @@ -368,9 +368,9 @@ DicomMap s; fields.ExtractSeriesInformation(s); - s.CopyTagIfExists(fields, DicomTag::PATIENT_ID); - s.CopyTagIfExists(fields, DicomTag::ACCESSION_NUMBER); - s.CopyTagIfExists(fields, DicomTag::STUDY_INSTANCE_UID); + s.CopyTagIfExists(fields, DICOM_TAG_PATIENT_ID); + s.CopyTagIfExists(fields, DICOM_TAG_ACCESSION_NUMBER); + s.CopyTagIfExists(fields, DICOM_TAG_STUDY_INSTANCE_UID); Find(result, FindRootModel_Series, s); } @@ -382,10 +382,10 @@ DicomMap s; fields.ExtractInstanceInformation(s); - s.CopyTagIfExists(fields, DicomTag::PATIENT_ID); - s.CopyTagIfExists(fields, DicomTag::ACCESSION_NUMBER); - s.CopyTagIfExists(fields, DicomTag::STUDY_INSTANCE_UID); - s.CopyTagIfExists(fields, DicomTag::SERIES_INSTANCE_UID); + s.CopyTagIfExists(fields, DICOM_TAG_PATIENT_ID); + s.CopyTagIfExists(fields, DICOM_TAG_ACCESSION_NUMBER); + s.CopyTagIfExists(fields, DICOM_TAG_STUDY_INSTANCE_UID); + s.CopyTagIfExists(fields, DICOM_TAG_SERIES_INSTANCE_UID); Find(result, FindRootModel_Instance, s); } @@ -594,8 +594,8 @@ const DicomMap& findResult) { DicomMap simplified; - simplified.SetValue(DicomTag::STUDY_INSTANCE_UID, findResult.GetValue(DicomTag::STUDY_INSTANCE_UID)); - simplified.SetValue(DicomTag::SERIES_INSTANCE_UID, findResult.GetValue(DicomTag::SERIES_INSTANCE_UID)); + simplified.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, findResult.GetValue(DICOM_TAG_STUDY_INSTANCE_UID)); + simplified.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, findResult.GetValue(DICOM_TAG_SERIES_INSTANCE_UID)); Move(targetAet, simplified); } @@ -604,8 +604,8 @@ const std::string& seriesUid) { DicomMap map; - map.SetValue(DicomTag::STUDY_INSTANCE_UID, studyUid); - map.SetValue(DicomTag::SERIES_INSTANCE_UID, seriesUid); + map.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid); + map.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid); Move(targetAet, map); } @@ -613,9 +613,9 @@ const DicomMap& findResult) { DicomMap simplified; - simplified.SetValue(DicomTag::STUDY_INSTANCE_UID, findResult.GetValue(DicomTag::STUDY_INSTANCE_UID)); - simplified.SetValue(DicomTag::SERIES_INSTANCE_UID, findResult.GetValue(DicomTag::SERIES_INSTANCE_UID)); - simplified.SetValue(DicomTag::SOP_INSTANCE_UID, findResult.GetValue(DicomTag::SOP_INSTANCE_UID)); + simplified.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, findResult.GetValue(DICOM_TAG_STUDY_INSTANCE_UID)); + simplified.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, findResult.GetValue(DICOM_TAG_SERIES_INSTANCE_UID)); + simplified.SetValue(DICOM_TAG_SOP_INSTANCE_UID, findResult.GetValue(DICOM_TAG_SOP_INSTANCE_UID)); Move(targetAet, simplified); } @@ -625,9 +625,9 @@ const std::string& instanceUid) { DicomMap map; - map.SetValue(DicomTag::STUDY_INSTANCE_UID, studyUid); - map.SetValue(DicomTag::SERIES_INSTANCE_UID, seriesUid); - map.SetValue(DicomTag::SOP_INSTANCE_UID, instanceUid); + map.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid); + map.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid); + map.SetValue(DICOM_TAG_SOP_INSTANCE_UID, instanceUid); Move(targetAet, map); }
--- a/OrthancServer/FromDcmtkBridge.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/OrthancServer/FromDcmtkBridge.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -454,7 +454,7 @@ FromDcmtkBridge::Convert(m, dataset); DcmElement* e; - if (dataset.findAndGetElement(ToDcmtkBridge::Convert(DicomTag::PIXEL_DATA), e).good() && + if (dataset.findAndGetElement(ToDcmtkBridge::Convert(DICOM_TAG_PIXEL_DATA), e).good() && e != NULL) { Uint8* pixData = NULL;
--- a/OrthancServer/OrthancRestApi.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/OrthancServer/OrthancRestApi.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -219,8 +219,8 @@ return false; } - if (m.GetValue(DicomTag::ACCESSION_NUMBER).AsString().size() <= 2 && - m.GetValue(DicomTag::PATIENT_ID).AsString().size() <= 2) + if (m.GetValue(DICOM_TAG_ACCESSION_NUMBER).AsString().size() <= 2 && + m.GetValue(DICOM_TAG_PATIENT_ID).AsString().size() <= 2) { return false; } @@ -242,9 +242,9 @@ return false; } - if ((m.GetValue(DicomTag::ACCESSION_NUMBER).AsString().size() <= 2 && - m.GetValue(DicomTag::PATIENT_ID).AsString().size() <= 2) || - m.GetValue(DicomTag::STUDY_INSTANCE_UID).AsString().size() <= 2) + if ((m.GetValue(DICOM_TAG_ACCESSION_NUMBER).AsString().size() <= 2 && + m.GetValue(DICOM_TAG_PATIENT_ID).AsString().size() <= 2) || + m.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString().size() <= 2) { return false; } @@ -281,7 +281,7 @@ { return false; } - m.CopyTagIfExists(patients.GetAnswer(i), DicomTag::PATIENT_ID); + m.CopyTagIfExists(patients.GetAnswer(i), DICOM_TAG_PATIENT_ID); DicomFindAnswers studies; c.FindStudy(studies, m); @@ -299,8 +299,8 @@ { return false; } - m.CopyTagIfExists(studies.GetAnswer(j), DicomTag::PATIENT_ID); - m.CopyTagIfExists(studies.GetAnswer(j), DicomTag::STUDY_INSTANCE_UID); + m.CopyTagIfExists(studies.GetAnswer(j), DICOM_TAG_PATIENT_ID); + m.CopyTagIfExists(studies.GetAnswer(j), DICOM_TAG_STUDY_INSTANCE_UID); DicomFindAnswers series; c.FindSeries(series, m);
--- a/OrthancServer/PrepareDatabase.sql Thu Sep 20 13:47:54 2012 +0200 +++ b/OrthancServer/PrepareDatabase.sql Thu Sep 20 15:18:12 2012 +0200 @@ -18,7 +18,7 @@ uuid TEXT PRIMARY KEY, parentStudy TEXT REFERENCES Studies(uuid) ON DELETE CASCADE, dicomSeries TEXT, - numberOfInstances INTEGER + expectedNumberOfInstances INTEGER ); CREATE TABLE Instances( @@ -29,7 +29,7 @@ fileSize INTEGER, jsonUuid TEXT, distantAet TEXT, - instanceIndex INTEGER + indexInSeries INTEGER ); CREATE TABLE MainDicomTags(
--- a/OrthancServer/ServerIndex.cpp Thu Sep 20 13:47:54 2012 +0200 +++ b/OrthancServer/ServerIndex.cpp Thu Sep 20 15:18:12 2012 +0200 @@ -231,7 +231,7 @@ { std::string instanceUuid = Toolbox::GenerateUuid(); - SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Instances VALUES(?, ?, ?, ?, ?, ?, ?)"); + SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Instances VALUES(?, ?, ?, ?, ?, ?, ?, ?)"); s.BindString(0, instanceUuid); s.BindString(1, parentSeriesUuid); s.BindString(2, dicomInstance); @@ -239,6 +239,18 @@ s.BindInt64(4, fileSize); s.BindString(5, jsonUuid); s.BindString(6, distantAet); + + const DicomValue* indexInSeries; + if ((indexInSeries = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL || + (indexInSeries = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL) + { + s.BindInt(7, boost::lexical_cast<unsigned int>(indexInSeries->AsString())); + } + else + { + s.BindNull(7); + } + s.Run(); RecordChange("instances", instanceUuid); @@ -283,7 +295,20 @@ s.BindString(0, seriesUuid); s.BindString(1, parentStudyUuid); s.BindString(2, dicomSeries); - s.BindNull(3); + + const DicomValue* expectedNumberOfInstances; + if ((expectedNumberOfInstances = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_FRAMES)) != NULL || + (expectedNumberOfInstances = dicomSummary.TestAndGetValue(DICOM_TAG_NUMBER_OF_SLICES)) != NULL || + (expectedNumberOfInstances = dicomSummary.TestAndGetValue(DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES)) != NULL || + (expectedNumberOfInstances = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGES_IN_ACQUISITION)) != NULL) + { + s.BindInt(3, boost::lexical_cast<unsigned int>(expectedNumberOfInstances->AsString())); + } + else + { + s.BindNull(3); + } + s.Run(); RecordChange("series", seriesUuid); @@ -354,7 +379,7 @@ const DicomMap& dicomSummary) { std::string patientUuid = Toolbox::GenerateUuid(); - std::string dicomPatientId = dicomSummary.GetValue(DicomTag::PATIENT_ID).AsString(); + std::string dicomPatientId = dicomSummary.GetValue(DICOM_TAG_PATIENT_ID).AsString(); SQLite::Statement s(db_, SQLITE_FROM_HERE, "INSERT INTO Patients VALUES(?, ?)"); s.BindString(0, patientUuid); @@ -474,10 +499,10 @@ { boost::mutex::scoped_lock scoped_lock(mutex_); - std::string dicomPatientId = dicomSummary.GetValue(DicomTag::PATIENT_ID).AsString(); - std::string dicomInstance = dicomSummary.GetValue(DicomTag::SOP_INSTANCE_UID).AsString(); - std::string dicomSeries = dicomSummary.GetValue(DicomTag::SERIES_INSTANCE_UID).AsString(); - std::string dicomStudy = dicomSummary.GetValue(DicomTag::STUDY_INSTANCE_UID).AsString(); + std::string dicomPatientId = dicomSummary.GetValue(DICOM_TAG_PATIENT_ID).AsString(); + std::string dicomInstance = dicomSummary.GetValue(DICOM_TAG_SOP_INSTANCE_UID).AsString(); + std::string dicomSeries = dicomSummary.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).AsString(); + std::string dicomStudy = dicomSummary.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).AsString(); try { @@ -584,31 +609,60 @@ SeriesStatus ServerIndex::GetSeriesStatus(const std::string& seriesUuid) { - int numberOfSlices; - if (!GetMainDicomIntTag(numberOfSlices, seriesUuid, DicomTag::NUMBER_OF_SLICES) || - numberOfSlices < 0) + SQLite::Statement s1(db_, SQLITE_FROM_HERE, "SELECT expectedNumberOfInstances FROM Series WHERE uuid=?"); + s1.BindString(0, seriesUuid); + if (!s1.Step()) + { + return SeriesStatus_Unknown; + } + + int numberOfInstances = s1.ColumnInt(0); + if (numberOfInstances < 0) { return SeriesStatus_Unknown; } - // Loop over the instances of the series - //std::set< + std::set<int> instances; + SQLite::Statement s2(db_, SQLITE_FROM_HERE, "SELECT indexInSeries FROM Instances WHERE parentSeries=?"); + s2.BindString(0, seriesUuid); + while (s2.Step()) + { + int index = s2.ColumnInt(0); + if (index <= 0 || index > numberOfInstances) + { + // Out-of-range instance index + return SeriesStatus_Inconsistent; + } - // TODO - return SeriesStatus_Unknown; + if (instances.find(index) != instances.end()) + { + // Twice the same instance index + return SeriesStatus_Inconsistent; + } + + instances.insert(index); + } + + for (int i = 1; i <= numberOfInstances; i++) + { + if (instances.find(i) == instances.end()) + { + return SeriesStatus_Missing; + } + } + + return SeriesStatus_Complete; } - - bool ServerIndex::GetInstance(Json::Value& result, const std::string& instanceUuid) { assert(result.type() == Json::objectValue); boost::mutex::scoped_lock scoped_lock(mutex_); - SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT parentSeries, dicomInstance, fileSize, fileUuid FROM Instances WHERE uuid=?"); + SQLite::Statement s(db_, SQLITE_FROM_HERE, "SELECT parentSeries, dicomInstance, fileSize, fileUuid, indexInSeries FROM Instances WHERE uuid=?"); s.BindString(0, instanceUuid); if (!s.Step()) { @@ -621,6 +675,16 @@ result["FileSize"] = s.ColumnInt(2); // TODO switch to 64bit with JsonCpp 0.6? result["FileUuid"] = s.ColumnString(3); MainDicomTagsToJson(result, instanceUuid); + + if (s.ColumnIsNull(4)) + { + result["IndexInSeries"] = -1; + } + else + { + result["IndexInSeries"] = s.ColumnInt(4); + } + return true; } } @@ -632,7 +696,7 @@ assert(result.type() == Json::objectValue); boost::mutex::scoped_lock scoped_lock(mutex_); - SQLite::Statement s1(db_, SQLITE_FROM_HERE, "SELECT parentStudy, dicomSeries FROM Series WHERE uuid=?"); + SQLite::Statement s1(db_, SQLITE_FROM_HERE, "SELECT parentStudy, dicomSeries, expectedNumberOfInstances FROM Series WHERE uuid=?"); s1.BindString(0, seriesUuid); if (!s1.Step()) { @@ -653,6 +717,37 @@ result["Instances"] = instances; + if (s1.ColumnIsNull(2)) + { + result["ExpectedNumberOfInstances"] = -1; + } + else + { + result["ExpectedNumberOfInstances"] = s1.ColumnInt(2); + } + + SeriesStatus status = GetSeriesStatus(seriesUuid); + + switch (status) + { + case SeriesStatus_Complete: + result["Status"] = "Complete"; + break; + + case SeriesStatus_Missing: + result["Status"] = "Missing"; + break; + + case SeriesStatus_Inconsistent: + result["Status"] = "Inconsistent"; + break; + + default: + case SeriesStatus_Unknown: + result["Status"] = "Unknown"; + break; + } + return true; }