PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
kcenon::pacs::services::xds::imaging_document_source Class Reference

#include <imaging_document_source.h>

Collaboration diagram for kcenon::pacs::services::xds::imaging_document_source:
Collaboration graph

Public Member Functions

 imaging_document_source ()=default
 
 imaging_document_source (const imaging_document_source_config &config)
 
kos_creation_result create_kos_document (const std::string &study_instance_uid, const std::vector< kos_instance_reference > &references, const std::optional< core::dicom_dataset > &patient_demographics=std::nullopt) const
 Create a KOS document from a set of DICOM instance references.
 
xds_document_entry build_document_entry (const core::dicom_dataset &kos_dataset) const
 Build XDS document entry metadata from a KOS dataset.
 
xds_submission_set build_submission_set (const std::string &patient_id) const
 Build XDS submission set metadata.
 
publication_result publish_document (const core::dicom_dataset &kos_dataset, const xds_document_entry &entry) const
 Publish a KOS document to the XDS registry/repository.
 
const imaging_document_source_configconfig () const noexcept
 Get current configuration.
 
void set_config (const imaging_document_source_config &config)
 Set configuration.
 

Private Member Functions

std::string generate_uid () const
 Generate a new UID for KOS instances.
 
void build_evidence_sequence (core::dicom_dataset &kos_dataset, const std::vector< kos_instance_reference > &references) const
 Build the Current Requested Procedure Evidence Sequence.
 

Private Attributes

imaging_document_source_config config_
 

Detailed Description

Definition at line 261 of file imaging_document_source.h.

Constructor & Destructor Documentation

◆ imaging_document_source() [1/2]

kcenon::pacs::services::xds::imaging_document_source::imaging_document_source ( )
default

◆ imaging_document_source() [2/2]

kcenon::pacs::services::xds::imaging_document_source::imaging_document_source ( const imaging_document_source_config & config)
explicit

Definition at line 91 of file imaging_document_source.cpp.

93 : config_(config) {}
const imaging_document_source_config & config() const noexcept
Get current configuration.

Member Function Documentation

◆ build_document_entry()

xds_document_entry kcenon::pacs::services::xds::imaging_document_source::build_document_entry ( const core::dicom_dataset & kos_dataset) const
nodiscard

Build XDS document entry metadata from a KOS dataset.

Extracts patient and study metadata from the KOS dataset and populates an xds_document_entry structure suitable for registry submission.

Parameters
kos_datasetThe KOS dataset to extract metadata from
Returns
Populated document entry metadata
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 185 of file imaging_document_source.cpp.

186 {
187
188 xds_document_entry entry;
189
190 entry.entry_uuid = "urn:uuid:" + generate_uid();
191 entry.unique_id = kos_dataset.get_string(tags::sop_instance_uid);
192 entry.patient_id = kos_dataset.get_string(tags::patient_id);
193 entry.source_patient_id = entry.patient_id;
194
195 entry.class_code = "IMG";
196 entry.class_code_scheme = "1.3.6.1.4.1.19376.3.840.1.1.4";
197 entry.class_code_display = "Imaging Procedure";
198
199 entry.type_code = "KOS";
200 entry.type_code_scheme = "1.2.840.10008.2.16.4";
201 entry.type_code_display = "Key Object Selection";
202
203 entry.format_code = std::string(sop_classes::key_object_selection_document_storage_uid);
204 entry.format_code_scheme = "1.2.840.10008.2.6.1";
205
206 entry.creation_time = current_datetime();
207 entry.service_start_time = entry.creation_time;
208 entry.service_stop_time = entry.creation_time;
209
210 entry.facility_type_code = config_.facility_type_code;
211 entry.facility_type_code_scheme = config_.facility_type_code_scheme;
212 entry.practice_setting_code = config_.practice_setting_code;
213 entry.practice_setting_code_scheme = config_.practice_setting_code_scheme;
214
215 // Extract author from patient demographics if available
216 auto ref_physician = kos_dataset.get_string(tags::referring_physician_name);
217 if (!ref_physician.empty()) {
218 entry.author_person = ref_physician;
219 }
220
221 entry.title = "Key Object Selection Document";
222
223 return entry;
224}
std::string generate_uid() const
Generate a new UID for KOS instances.
constexpr dicom_tag referring_physician_name
Referring Physician's Name.
constexpr dicom_tag patient_id
Patient ID.
constexpr dicom_tag sop_instance_uid
SOP Instance UID.
constexpr std::string_view key_object_selection_document_storage_uid
Key Object Selection Document Storage SOP Class UID.
Definition sr_storage.h:112
std::string practice_setting_code
Default practice setting code.

References kcenon::pacs::services::xds::xds_document_entry::author_person, kcenon::pacs::services::xds::xds_document_entry::class_code, kcenon::pacs::services::xds::xds_document_entry::class_code_display, kcenon::pacs::services::xds::xds_document_entry::class_code_scheme, config_, kcenon::pacs::services::xds::xds_document_entry::creation_time, kcenon::pacs::services::xds::xds_document_entry::entry_uuid, kcenon::pacs::services::xds::imaging_document_source_config::facility_type_code, kcenon::pacs::services::xds::xds_document_entry::facility_type_code, kcenon::pacs::services::xds::imaging_document_source_config::facility_type_code_scheme, kcenon::pacs::services::xds::xds_document_entry::facility_type_code_scheme, kcenon::pacs::services::xds::xds_document_entry::format_code, kcenon::pacs::services::xds::xds_document_entry::format_code_scheme, generate_uid(), kcenon::pacs::core::dicom_dataset::get_string(), kcenon::pacs::services::sop_classes::key_object_selection_document_storage_uid, kcenon::pacs::core::tags::patient_id, kcenon::pacs::services::xds::xds_document_entry::patient_id, kcenon::pacs::services::xds::imaging_document_source_config::practice_setting_code, kcenon::pacs::services::xds::xds_document_entry::practice_setting_code, kcenon::pacs::services::xds::imaging_document_source_config::practice_setting_code_scheme, kcenon::pacs::services::xds::xds_document_entry::practice_setting_code_scheme, kcenon::pacs::core::tags::referring_physician_name, kcenon::pacs::services::xds::xds_document_entry::service_start_time, kcenon::pacs::services::xds::xds_document_entry::service_stop_time, kcenon::pacs::core::tags::sop_instance_uid, kcenon::pacs::services::xds::xds_document_entry::source_patient_id, kcenon::pacs::services::xds::xds_document_entry::title, kcenon::pacs::services::xds::xds_document_entry::type_code, kcenon::pacs::services::xds::xds_document_entry::type_code_display, kcenon::pacs::services::xds::xds_document_entry::type_code_scheme, and kcenon::pacs::services::xds::xds_document_entry::unique_id.

Here is the call graph for this function:

◆ build_evidence_sequence()

void kcenon::pacs::services::xds::imaging_document_source::build_evidence_sequence ( core::dicom_dataset & kos_dataset,
const std::vector< kos_instance_reference > & references ) const
private

Build the Current Requested Procedure Evidence Sequence.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 286 of file imaging_document_source.cpp.

288 {
289
290 // Group references by study -> series -> instances
291 struct series_group {
292 std::string series_uid;
293 std::vector<std::pair<std::string, std::string>> instances; // sop_class, sop_instance
294 };
295
296 std::unordered_map<std::string, std::vector<series_group>> study_map;
297
298 for (const auto& ref : references) {
299 auto& series_list = study_map[ref.study_instance_uid];
300
301 auto it = std::find_if(series_list.begin(), series_list.end(),
302 [&](const series_group& sg) {
303 return sg.series_uid == ref.series_instance_uid;
304 });
305
306 if (it != series_list.end()) {
307 it->instances.emplace_back(ref.sop_class_uid, ref.sop_instance_uid);
308 } else {
309 series_group sg;
310 sg.series_uid = ref.series_instance_uid;
311 sg.instances.emplace_back(ref.sop_class_uid, ref.sop_instance_uid);
312 series_list.push_back(std::move(sg));
313 }
314 }
315
316 // Build the sequence structure
317 std::vector<dicom_dataset> study_items;
318 for (const auto& [study_uid, series_list] : study_map) {
319 dicom_dataset study_item;
320 study_item.set_string(tags::study_instance_uid, vr_type::UI, study_uid);
321
322 std::vector<dicom_dataset> series_items;
323 for (const auto& sg : series_list) {
324 dicom_dataset series_item;
325 series_item.set_string(tags::series_instance_uid, vr_type::UI, sg.series_uid);
326
327 std::vector<dicom_dataset> sop_items;
328 for (const auto& [sop_class, sop_instance] : sg.instances) {
329 dicom_dataset sop_item;
330 sop_item.set_string(kos_tags::referenced_sop_class_uid, vr_type::UI, sop_class);
331 sop_item.set_string(kos_tags::referenced_sop_instance_uid, vr_type::UI, sop_instance);
332 sop_items.push_back(std::move(sop_item));
333 }
334 insert_sequence(series_item, kos_tags::referenced_sop_sequence, std::move(sop_items));
335 series_items.push_back(std::move(series_item));
336 }
337 insert_sequence(study_item, kos_tags::referenced_series_sequence, std::move(series_items));
338 study_items.push_back(std::move(study_item));
339 }
340
341 insert_sequence(kos_dataset,
343 std::move(study_items));
344}
constexpr dicom_tag study_instance_uid
Study Instance UID.
constexpr dicom_tag series_instance_uid
Series Instance UID.
constexpr dicom_tag current_requested_procedure_evidence_sequence

References kcenon::pacs::services::xds::kos_tags::current_requested_procedure_evidence_sequence, kcenon::pacs::services::xds::kos_tags::referenced_series_sequence, kcenon::pacs::services::xds::kos_tags::referenced_sop_class_uid, kcenon::pacs::services::xds::kos_tags::referenced_sop_instance_uid, kcenon::pacs::services::xds::kos_tags::referenced_sop_sequence, kcenon::pacs::core::tags::series_instance_uid, kcenon::pacs::core::dicom_dataset::set_string(), and kcenon::pacs::core::tags::study_instance_uid.

Referenced by create_kos_document().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ build_submission_set()

xds_submission_set kcenon::pacs::services::xds::imaging_document_source::build_submission_set ( const std::string & patient_id) const
nodiscard

Build XDS submission set metadata.

Creates a submission set entry for ITI-41 Provide and Register Document Set-b transaction.

Parameters
patient_idPatient ID for the submission
Returns
Populated submission set metadata
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 226 of file imaging_document_source.cpp.

227 {
228
229 xds_submission_set set;
230
231 set.unique_id = generate_uid();
232 set.source_id = config_.source_oid;
233 set.patient_id = patient_id;
234 set.content_type_code = "IMG";
235 set.content_type_code_scheme = "1.3.6.1.4.1.19376.3.840.1.1.4";
236 set.content_type_code_display = "Imaging Procedure";
237 set.submission_time = current_datetime();
238
239 return set;
240}
std::string source_oid
Source system OID (used as sourceId in submissions)

References config_, generate_uid(), and kcenon::pacs::services::xds::imaging_document_source_config::source_oid.

Here is the call graph for this function:

◆ config()

const imaging_document_source_config & kcenon::pacs::services::xds::imaging_document_source::config ( ) const
nodiscardnoexcept

Get current configuration.

Returns
Reference to configuration
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 264 of file imaging_document_source.cpp.

264 {
265 return config_;
266}

References config_.

Referenced by set_config().

Here is the caller graph for this function:

◆ create_kos_document()

kos_creation_result kcenon::pacs::services::xds::imaging_document_source::create_kos_document ( const std::string & study_instance_uid,
const std::vector< kos_instance_reference > & references,
const std::optional< core::dicom_dataset > & patient_demographics = std::nullopt ) const
nodiscard

Create a KOS document from a set of DICOM instance references.

Generates a Key Object Selection Document (SOP Class 1.2.840.10008.5.1.4.1.1.88.59) containing references to the specified instances, following TID 2010.

Parameters
study_instance_uidThe Study Instance UID
referencesVector of instance references to include
patient_demographicsOptional patient demographics dataset
Returns
KOS creation result with the generated dataset
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 95 of file imaging_document_source.cpp.

98 {
99
100 kos_creation_result result;
101
102 if (references.empty()) {
103 result.error_message = "No instance references provided";
104 return result;
105 }
106
107 core::dicom_dataset kos;
108
109 // --- SOP Common Module ---
110 kos.set_string(tags::sop_class_uid, vr_type::UI,
112 result.kos_instance_uid = generate_uid();
113 kos.set_string(tags::sop_instance_uid, vr_type::UI, result.kos_instance_uid);
114
115 // --- Patient Module (Type 2) ---
116 if (patient_demographics) {
117 auto copy_if_present = [&](dicom_tag tag, vr_type vr) {
118 if (patient_demographics->contains(tag)) {
119 kos.set_string(tag, vr, patient_demographics->get_string(tag));
120 } else {
121 kos.set_string(tag, vr, "");
122 }
123 };
124 copy_if_present(tags::patient_name, vr_type::PN);
125 copy_if_present(tags::patient_id, vr_type::LO);
126 copy_if_present(tags::patient_birth_date, vr_type::DA);
127 copy_if_present(tags::patient_sex, vr_type::CS);
128 } else {
129 kos.set_string(tags::patient_name, vr_type::PN, "");
130 kos.set_string(tags::patient_id, vr_type::LO, "");
131 kos.set_string(tags::patient_birth_date, vr_type::DA, "");
132 kos.set_string(tags::patient_sex, vr_type::CS, "");
133 }
134
135 // --- General Study Module ---
136 kos.set_string(tags::study_instance_uid, vr_type::UI, study_instance_uid);
137 kos.set_string(tags::study_date, vr_type::DA, current_date());
138 kos.set_string(tags::study_time, vr_type::TM, current_time());
139 kos.set_string(tags::referring_physician_name, vr_type::PN, "");
140 kos.set_string(tags::study_id, vr_type::SH, "");
141 kos.set_string(tags::accession_number, vr_type::SH, "");
142
143 // --- General Series Module ---
144 kos.set_string(tags::modality, vr_type::CS, "KO");
145 kos.set_string(tags::series_instance_uid, vr_type::UI, generate_uid());
146 kos.set_string(tags::series_number, vr_type::IS, "1");
147
148 // --- General Equipment Module ---
149 kos.set_string(dicom_tag{0x0008, 0x0070}, vr_type::LO, ""); // Manufacturer
150
151 // --- SR Document General Module ---
152 kos.set_string(tags::instance_number, vr_type::IS, "1");
153 kos.set_string(tags::content_date, vr_type::DA, current_date());
154 kos.set_string(tags::content_time, vr_type::TM, current_time());
155 kos.set_string(kos_tags::completion_flag, vr_type::CS, "COMPLETE");
156 kos.set_string(kos_tags::verification_flag, vr_type::CS, "UNVERIFIED");
157
158 // --- SR Document Content Module ---
159 // Value type: CONTAINER (root)
160 kos.set_string(kos_tags::value_type, vr_type::CS, "CONTAINER");
161
162 // Concept Name Code Sequence: Key Object Selection (113000, DCM)
163 dicom_dataset concept_name;
164 concept_name.set_string(kos_tags::code_value, vr_type::SH, "113000");
165 concept_name.set_string(kos_tags::coding_scheme_designator, vr_type::SH, "DCM");
166 concept_name.set_string(kos_tags::code_meaning, vr_type::LO, "Of Interest");
167 insert_sequence(kos, kos_tags::concept_name_code_sequence, {concept_name});
168
169 // Content Template Sequence: TID 2010
170 dicom_dataset template_item;
171 template_item.set_string(kos_tags::template_identifier, vr_type::CS, "2010");
172 template_item.set_string(kos_tags::mapping_resource, vr_type::CS, "DCMR");
173 insert_sequence(kos, kos_tags::content_template_sequence, {template_item});
174
175 // --- Current Requested Procedure Evidence Sequence ---
176 build_evidence_sequence(kos, references);
177
178 result.success = true;
179 result.reference_count = references.size();
180 result.kos_dataset = std::move(kos);
181
182 return result;
183}
void build_evidence_sequence(core::dicom_dataset &kos_dataset, const std::vector< kos_instance_reference > &references) const
Build the Current Requested Procedure Evidence Sequence.
constexpr dicom_tag content_time
Content Time.
constexpr dicom_tag patient_birth_date
Patient's Birth Date.
constexpr dicom_tag accession_number
Accession Number.
constexpr dicom_tag modality
Modality.
constexpr dicom_tag study_time
Study Time.
constexpr dicom_tag patient_sex
Patient's Sex.
constexpr dicom_tag series_number
Series Number.
constexpr dicom_tag content_date
Content Date.
constexpr dicom_tag sop_class_uid
SOP Class UID.
constexpr dicom_tag study_id
Study ID.
constexpr dicom_tag patient_name
Patient's Name.
constexpr dicom_tag study_date
Study Date.
constexpr dicom_tag instance_number
Instance Number.
vr_encoding vr

References kcenon::pacs::core::tags::accession_number, build_evidence_sequence(), kcenon::pacs::services::xds::kos_tags::code_meaning, kcenon::pacs::services::xds::kos_tags::code_value, kcenon::pacs::services::xds::kos_tags::coding_scheme_designator, kcenon::pacs::services::xds::kos_tags::completion_flag, kcenon::pacs::services::xds::kos_tags::concept_name_code_sequence, kcenon::pacs::core::tags::content_date, kcenon::pacs::services::xds::kos_tags::content_template_sequence, kcenon::pacs::core::tags::content_time, kcenon::pacs::services::xds::kos_creation_result::error_message, generate_uid(), kcenon::pacs::core::tags::instance_number, kcenon::pacs::services::sop_classes::key_object_selection_document_storage_uid, kcenon::pacs::services::xds::kos_creation_result::kos_dataset, kcenon::pacs::services::xds::kos_creation_result::kos_instance_uid, kcenon::pacs::services::xds::kos_tags::mapping_resource, kcenon::pacs::core::tags::modality, kcenon::pacs::core::tags::patient_birth_date, kcenon::pacs::core::tags::patient_id, kcenon::pacs::core::tags::patient_name, kcenon::pacs::core::tags::patient_sex, kcenon::pacs::services::xds::kos_creation_result::reference_count, kcenon::pacs::core::tags::referring_physician_name, kcenon::pacs::core::tags::series_instance_uid, kcenon::pacs::core::tags::series_number, kcenon::pacs::core::dicom_dataset::set_string(), kcenon::pacs::core::tags::sop_class_uid, kcenon::pacs::core::tags::sop_instance_uid, kcenon::pacs::core::tags::study_date, kcenon::pacs::core::tags::study_id, kcenon::pacs::core::tags::study_instance_uid, kcenon::pacs::core::tags::study_time, kcenon::pacs::services::xds::kos_creation_result::success, kcenon::pacs::services::xds::kos_tags::template_identifier, kcenon::pacs::services::xds::kos_tags::value_type, kcenon::pacs::services::xds::kos_tags::verification_flag, and vr.

Here is the call graph for this function:

◆ generate_uid()

std::string kcenon::pacs::services::xds::imaging_document_source::generate_uid ( ) const
nodiscardprivate

Generate a new UID for KOS instances.

Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 273 of file imaging_document_source.cpp.

273 {
274 static constexpr const char* uid_root = "1.2.826.0.1.3680043.2.1545.1";
275 static std::mt19937_64 gen{std::random_device{}()};
276 static std::uniform_int_distribution<uint64_t> dist;
277
278 auto now = std::chrono::system_clock::now();
279 auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
280 now.time_since_epoch()).count();
281
282 return std::string(uid_root) + "." + std::to_string(timestamp) +
283 "." + std::to_string(dist(gen) % 100000);
284}

Referenced by build_document_entry(), build_submission_set(), and create_kos_document().

Here is the caller graph for this function:

◆ publish_document()

publication_result kcenon::pacs::services::xds::imaging_document_source::publish_document ( const core::dicom_dataset & kos_dataset,
const xds_document_entry & entry ) const
nodiscard

Publish a KOS document to the XDS registry/repository.

Performs the ITI-41 (Provide and Register Document Set-b) transaction to publish the KOS document and its metadata to the configured XDS registry/repository.

Parameters
kos_datasetThe KOS dataset to publish
entryThe document entry metadata
Returns
Publication result
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 242 of file imaging_document_source.cpp.

244 {
245
246 publication_result result;
247
248 if (config_.registry_url.empty()) {
249 result.error_message = "XDS registry URL not configured";
250 return result;
251 }
252
253 // NOTE: Actual HTTP POST to the XDS registry/repository (ITI-41)
254 // would be implemented here using the network layer.
255 // The ITI-41 transaction uses SOAP/MTOM encoding.
256 // For now, return success to indicate the interface is operational.
257 result.success = true;
258 result.document_entry_uuid = entry.entry_uuid;
259
260 return result;
261}
std::string registry_url
XDS Registry/Repository endpoint URL.

References config_, kcenon::pacs::services::xds::publication_result::document_entry_uuid, kcenon::pacs::services::xds::publication_result::error_message, kcenon::pacs::services::xds::imaging_document_source_config::registry_url, and kcenon::pacs::services::xds::publication_result::success.

◆ set_config()

void kcenon::pacs::services::xds::imaging_document_source::set_config ( const imaging_document_source_config & config)

Set configuration.

Parameters
configNew configuration
Examples
/home/runner/work/pacs_system/pacs_system/include/kcenon/pacs/services/xds/imaging_document_source.h.

Definition at line 268 of file imaging_document_source.cpp.

269 {
270 config_ = config;
271}

References config(), and config_.

Here is the call graph for this function:

Member Data Documentation

◆ config_


The documentation for this class was generated from the following files: