PACS System 0.1.0
PACS DICOM system library
Loading...
Searching...
No Matches
imaging_document_consumer.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2021-2025, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
12
13#include <algorithm>
14#include <sstream>
15
17
18using namespace kcenon::pacs::core;
19
20// =============================================================================
21// KOS-specific DICOM Tags (for reference parsing)
22// =============================================================================
23
24namespace consumer_tags {
25
27constexpr dicom_tag referenced_series_sequence{0x0008, 0x1115};
28constexpr dicom_tag referenced_sop_sequence{0x0008, 0x1199};
29constexpr dicom_tag referenced_sop_instance_uid{0x0008, 0x1155};
30
31} // namespace consumer_tags
32
33// =============================================================================
34// imaging_document_consumer Implementation
35// =============================================================================
36
40
42 [[maybe_unused]] const registry_query_params& params) const {
43
45
46 if (config_.registry_url.empty()) {
47 result.error_message = "XDS registry URL not configured";
48 return result;
49 }
50
51 // NOTE: Actual SOAP request to the XDS registry (ITI-18)
52 // would be implemented here using the network layer.
53 // The ITI-18 transaction uses SOAP/XML encoding with
54 // the AdhocQueryRequest/AdhocQueryResponse pattern.
55 result.success = true;
56
57 return result;
58}
59
61 [[maybe_unused]] const document_reference& doc_ref) const {
62
64
65 if (config_.repository_url.empty()) {
66 result.error_message = "XDS repository URL not configured";
67 return result;
68 }
69
70 // NOTE: Actual SOAP/MTOM request to the XDS repository (ITI-43)
71 // would be implemented here. The response contains the KOS
72 // document as an MTOM attachment.
73 result.success = true;
74
75 return result;
76}
77
79 const core::dicom_dataset& kos_dataset) const {
80
82 result.success = true;
83
84 // Parse Current Requested Procedure Evidence Sequence (0040,A375)
85 const auto* evidence_elem = kos_dataset.get(
87
88 if (!evidence_elem || !evidence_elem->is_sequence()) {
89 result.error_message = "KOS document does not contain evidence sequence";
90 result.success = false;
91 return result;
92 }
93
94 for (const auto& study_item : evidence_elem->sequence_items()) {
95 // Extract Study Instance UID
96 auto study_uid = study_item.get_string(tags::study_instance_uid);
97 if (!study_uid.empty()) {
98 if (std::find(result.referenced_study_uids.begin(),
99 result.referenced_study_uids.end(),
100 study_uid) == result.referenced_study_uids.end()) {
101 result.referenced_study_uids.push_back(study_uid);
102 }
103 }
104
105 // Parse Referenced Series Sequence
106 const auto* series_elem = study_item.get(
108 if (!series_elem || !series_elem->is_sequence()) {
109 continue;
110 }
111
112 for (const auto& series_item : series_elem->sequence_items()) {
113 auto series_uid = series_item.get_string(tags::series_instance_uid);
114 if (!series_uid.empty()) {
115 if (std::find(result.referenced_series_uids.begin(),
116 result.referenced_series_uids.end(),
117 series_uid) == result.referenced_series_uids.end()) {
118 result.referenced_series_uids.push_back(series_uid);
119 }
120 }
121
122 // Parse Referenced SOP Sequence
123 const auto* sop_elem = series_item.get(
125 if (!sop_elem || !sop_elem->is_sequence()) {
126 continue;
127 }
128
129 for (const auto& sop_item : sop_elem->sequence_items()) {
130 auto instance_uid = sop_item.get_string(
132 if (!instance_uid.empty()) {
133 result.referenced_instance_uids.push_back(instance_uid);
134 }
135 }
136 }
137 }
138
139 return result;
140}
141
143 const std::string& study_uid,
144 const std::string& series_uid,
145 const std::string& instance_uid) const {
146
147 std::ostringstream url;
148 url << config_.wado_rs_url;
149
150 // Ensure base URL doesn't end with '/'
151 if (!config_.wado_rs_url.empty() && config_.wado_rs_url.back() == '/') {
152 // Remove the trailing '/' already added
153 } else {
154 url << '/';
155 }
156
157 url << "studies/" << study_uid
158 << "/series/" << series_uid
159 << "/instances/" << instance_uid;
160
161 return url.str();
162}
163
166 return config_;
167}
168
173
174} // namespace kcenon::pacs::services::xds
auto get(dicom_tag tag) noexcept -> dicom_element *
Get a pointer to the element with the given tag.
void set_config(const imaging_document_consumer_config &config)
Set configuration.
const imaging_document_consumer_config & config() const noexcept
Get current configuration.
document_retrieval_result extract_references(const core::dicom_dataset &kos_dataset) const
Extract image references from a KOS dataset.
document_retrieval_result retrieve_document(const document_reference &doc_ref) const
Retrieve a specific document from the XDS repository.
registry_query_result query_registry(const registry_query_params &params) const
Query the XDS registry for imaging documents.
std::string build_wado_rs_url(const std::string &study_uid, const std::string &series_uid, const std::string &instance_uid) const
Build a WADO-RS URL for retrieving a specific instance.
Compile-time constants for commonly used DICOM tags.
IHE XDS-I.b Imaging Document Consumer Actor.
constexpr dicom_tag study_instance_uid
Study Instance UID.
constexpr dicom_tag series_instance_uid
Series Instance UID.
Document reference returned from a registry query.
std::vector< std::string > referenced_study_uids
Instance references extracted from the KOS.
Configuration for the Imaging Document Consumer actor.
std::string wado_rs_url
WADO-RS base URL for image retrieval (alternative to C-MOVE)
std::string registry_url
XDS Registry endpoint URL for queries (ITI-18)
std::string repository_url
XDS Repository endpoint URL for document retrieval (ITI-43)
Query parameters for XDS registry stored query (ITI-18)