Mercurial > hg > orthanc-stone
annotate Framework/Loaders/DicomStructureSetLoader.cpp @ 937:86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Wed, 31 Jul 2019 10:24:09 +0200 |
parents | 401808e7ff2e |
children | bd979d435e9d |
rev | line source |
---|---|
815 | 1 /** |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2019 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "DicomStructureSetLoader.h" | |
23 | |
24 #include "../Scene2D/PolylineSceneLayer.h" | |
25 #include "../Toolbox/GeometryToolbox.h" | |
26 | |
27 namespace OrthancStone | |
28 { | |
29 class DicomStructureSetLoader::AddReferencedInstance : public LoaderStateMachine::State | |
30 { | |
31 private: | |
32 std::string instanceId_; | |
33 | |
34 public: | |
35 AddReferencedInstance(DicomStructureSetLoader& that, | |
36 const std::string& instanceId) : | |
37 State(that), | |
38 instanceId_(instanceId) | |
39 { | |
40 } | |
41 | |
42 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) | |
43 { | |
44 Json::Value tags; | |
45 message.ParseJsonBody(tags); | |
46 | |
47 Orthanc::DicomMap dicom; | |
48 dicom.FromDicomAsJson(tags); | |
49 | |
50 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); | |
51 loader.content_->AddReferencedSlice(dicom); | |
52 | |
53 loader.countProcessedInstances_ ++; | |
54 assert(loader.countProcessedInstances_ <= loader.countReferencedInstances_); | |
55 | |
56 if (loader.countProcessedInstances_ == loader.countReferencedInstances_) | |
57 { | |
58 // All the referenced instances have been loaded, finalize the RT-STRUCT | |
59 loader.content_->CheckReferencedSlices(); | |
60 loader.revision_++; | |
937
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
61 loader.SetStructuresReady(); |
815 | 62 } |
63 } | |
64 }; | |
65 | |
66 | |
67 // State that converts a "SOP Instance UID" to an Orthanc identifier | |
68 class DicomStructureSetLoader::LookupInstance : public LoaderStateMachine::State | |
69 { | |
70 private: | |
71 std::string sopInstanceUid_; | |
72 | |
73 public: | |
74 LookupInstance(DicomStructureSetLoader& that, | |
75 const std::string& sopInstanceUid) : | |
76 State(that), | |
77 sopInstanceUid_(sopInstanceUid) | |
78 { | |
79 } | |
80 | |
81 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) | |
82 { | |
83 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); | |
84 | |
85 Json::Value lookup; | |
86 message.ParseJsonBody(lookup); | |
87 | |
88 if (lookup.type() != Json::arrayValue || | |
89 lookup.size() != 1 || | |
90 !lookup[0].isMember("Type") || | |
91 !lookup[0].isMember("Path") || | |
92 lookup[0]["Type"].type() != Json::stringValue || | |
93 lookup[0]["ID"].type() != Json::stringValue || | |
94 lookup[0]["Type"].asString() != "Instance") | |
95 { | |
841
266e2b0b9abc
better error reporting in DicomStructureSetLoader + fixed POST request logic
Benjamin Golinvaux <bgo@osimis.io>
parents:
828
diff
changeset
|
96 std::stringstream msg; |
266e2b0b9abc
better error reporting in DicomStructureSetLoader + fixed POST request logic
Benjamin Golinvaux <bgo@osimis.io>
parents:
828
diff
changeset
|
97 msg << "Unknown resource! message.GetAnswer() = " << message.GetAnswer() << " message.GetAnswerHeaders() = "; |
842
2b245953b44b
removed some c++11 for older compilers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
841
diff
changeset
|
98 for (OrthancRestApiCommand::HttpHeaders::const_iterator it = message.GetAnswerHeaders().begin(); |
2b245953b44b
removed some c++11 for older compilers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
841
diff
changeset
|
99 it != message.GetAnswerHeaders().end(); ++it) |
841
266e2b0b9abc
better error reporting in DicomStructureSetLoader + fixed POST request logic
Benjamin Golinvaux <bgo@osimis.io>
parents:
828
diff
changeset
|
100 { |
842
2b245953b44b
removed some c++11 for older compilers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
841
diff
changeset
|
101 msg << "\nkey: \"" << it->first << "\" value: \"" << it->second << "\"\n"; |
841
266e2b0b9abc
better error reporting in DicomStructureSetLoader + fixed POST request logic
Benjamin Golinvaux <bgo@osimis.io>
parents:
828
diff
changeset
|
102 } |
842
2b245953b44b
removed some c++11 for older compilers
Sebastien Jodogne <s.jodogne@gmail.com>
parents:
841
diff
changeset
|
103 const std::string msgStr = msg.str(); |
841
266e2b0b9abc
better error reporting in DicomStructureSetLoader + fixed POST request logic
Benjamin Golinvaux <bgo@osimis.io>
parents:
828
diff
changeset
|
104 LOG(ERROR) << msgStr; |
815 | 105 throw Orthanc::OrthancException(Orthanc::ErrorCode_UnknownResource); |
106 } | |
107 | |
108 const std::string instanceId = lookup[0]["ID"].asString(); | |
109 | |
110 { | |
111 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
112 command->SetHttpHeader("Accept-Encoding", "gzip"); | |
113 command->SetUri("/instances/" + instanceId + "/tags"); | |
114 command->SetPayload(new AddReferencedInstance(loader, instanceId)); | |
115 Schedule(command.release()); | |
116 } | |
117 } | |
118 }; | |
119 | |
120 | |
121 class DicomStructureSetLoader::LoadStructure : public LoaderStateMachine::State | |
122 { | |
123 public: | |
124 LoadStructure(DicomStructureSetLoader& that) : | |
125 State(that) | |
126 { | |
127 } | |
128 | |
129 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) | |
130 { | |
131 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); | |
132 | |
133 { | |
134 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); | |
135 loader.content_.reset(new DicomStructureSet(dicom)); | |
136 } | |
137 | |
138 std::set<std::string> instances; | |
139 loader.content_->GetReferencedInstances(instances); | |
140 | |
828 | 141 loader.countReferencedInstances_ = static_cast<unsigned int>(instances.size()); |
815 | 142 |
143 for (std::set<std::string>::const_iterator | |
144 it = instances.begin(); it != instances.end(); ++it) | |
145 { | |
146 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
147 command->SetUri("/tools/lookup"); | |
148 command->SetMethod(Orthanc::HttpMethod_Post); | |
149 command->SetBody(*it); | |
150 command->SetPayload(new LookupInstance(loader, *it)); | |
841
266e2b0b9abc
better error reporting in DicomStructureSetLoader + fixed POST request logic
Benjamin Golinvaux <bgo@osimis.io>
parents:
828
diff
changeset
|
151 //LOG(TRACE) << "About to schedule a /tools/lookup POST request. URI = " << command->GetUri() << " Body size = " << (*it).size() << " Body = " << (*it) << "\n"; |
815 | 152 Schedule(command.release()); |
153 } | |
154 } | |
155 }; | |
156 | |
157 | |
158 class DicomStructureSetLoader::Slice : public IExtractedSlice | |
159 { | |
160 private: | |
161 const DicomStructureSet& content_; | |
162 uint64_t revision_; | |
163 bool isValid_; | |
164 | |
165 public: | |
166 Slice(const DicomStructureSet& content, | |
167 uint64_t revision, | |
168 const CoordinateSystem3D& cuttingPlane) : | |
169 content_(content), | |
170 revision_(revision) | |
171 { | |
172 bool opposite; | |
173 | |
174 const Vector normal = content.GetNormal(); | |
175 isValid_ = ( | |
176 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetNormal()) || | |
177 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisX()) || | |
178 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisY())); | |
179 } | |
180 | |
181 virtual bool IsValid() | |
182 { | |
183 return isValid_; | |
184 } | |
185 | |
186 virtual uint64_t GetRevision() | |
187 { | |
188 return revision_; | |
189 } | |
190 | |
191 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, | |
192 const CoordinateSystem3D& cuttingPlane) | |
193 { | |
194 assert(isValid_); | |
195 | |
196 std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer); | |
197 layer->SetThickness(2); | |
198 | |
199 for (size_t i = 0; i < content_.GetStructuresCount(); i++) | |
200 { | |
201 const Color& color = content_.GetStructureColor(i); | |
202 | |
203 std::vector< std::vector<DicomStructureSet::PolygonPoint> > polygons; | |
204 | |
205 if (content_.ProjectStructure(polygons, i, cuttingPlane)) | |
206 { | |
207 for (size_t j = 0; j < polygons.size(); j++) | |
208 { | |
209 PolylineSceneLayer::Chain chain; | |
210 chain.resize(polygons[j].size()); | |
211 | |
212 for (size_t k = 0; k < polygons[j].size(); k++) | |
213 { | |
214 chain[k] = ScenePoint2D(polygons[j][k].first, polygons[j][k].second); | |
215 } | |
216 | |
217 layer->AddChain(chain, true /* closed */, color); | |
218 } | |
219 } | |
220 } | |
221 | |
222 return layer.release(); | |
223 } | |
224 }; | |
225 | |
226 | |
227 DicomStructureSetLoader::DicomStructureSetLoader(IOracle& oracle, | |
228 IObservable& oracleObservable) : | |
937
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
229 IObservable(oracleObservable.GetBroker()), |
815 | 230 LoaderStateMachine(oracle, oracleObservable), |
231 revision_(0), | |
232 countProcessedInstances_(0), | |
937
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
233 countReferencedInstances_(0), |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
234 structuresReady_(false) |
815 | 235 { |
236 } | |
237 | |
238 | |
935
401808e7ff2e
Added traces in LoaderCache objects dtors + fuse to prevent dead weak ptrs to be calleds in VisitWdigets (in GuiAdapter.h)
Benjamin Golinvaux <bgo@osimis.io>
parents:
842
diff
changeset
|
239 DicomStructureSetLoader::~DicomStructureSetLoader() |
401808e7ff2e
Added traces in LoaderCache objects dtors + fuse to prevent dead weak ptrs to be calleds in VisitWdigets (in GuiAdapter.h)
Benjamin Golinvaux <bgo@osimis.io>
parents:
842
diff
changeset
|
240 { |
401808e7ff2e
Added traces in LoaderCache objects dtors + fuse to prevent dead weak ptrs to be calleds in VisitWdigets (in GuiAdapter.h)
Benjamin Golinvaux <bgo@osimis.io>
parents:
842
diff
changeset
|
241 LOG(TRACE) << "DicomStructureSetLoader::~DicomStructureSetLoader()"; |
401808e7ff2e
Added traces in LoaderCache objects dtors + fuse to prevent dead weak ptrs to be calleds in VisitWdigets (in GuiAdapter.h)
Benjamin Golinvaux <bgo@osimis.io>
parents:
842
diff
changeset
|
242 } |
401808e7ff2e
Added traces in LoaderCache objects dtors + fuse to prevent dead weak ptrs to be calleds in VisitWdigets (in GuiAdapter.h)
Benjamin Golinvaux <bgo@osimis.io>
parents:
842
diff
changeset
|
243 |
815 | 244 void DicomStructureSetLoader::LoadInstance(const std::string& instanceId) |
245 { | |
246 Start(); | |
247 | |
248 instanceId_ = instanceId; | |
249 | |
250 { | |
251 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
252 command->SetHttpHeader("Accept-Encoding", "gzip"); | |
253 command->SetUri("/instances/" + instanceId + "/tags?ignore-length=3006-0050"); | |
254 command->SetPayload(new LoadStructure(*this)); | |
255 Schedule(command.release()); | |
256 } | |
257 } | |
258 | |
259 | |
260 IVolumeSlicer::IExtractedSlice* DicomStructureSetLoader::ExtractSlice(const CoordinateSystem3D& cuttingPlane) | |
261 { | |
262 if (content_.get() == NULL) | |
263 { | |
264 // Geometry is not available yet | |
265 return new IVolumeSlicer::InvalidSlice; | |
266 } | |
267 else | |
268 { | |
269 return new Slice(*content_, revision_, cuttingPlane); | |
270 } | |
271 } | |
937
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
272 |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
273 void DicomStructureSetLoader::SetStructuresReady() |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
274 { |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
275 ORTHANC_ASSERT(!structuresReady_); |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
276 structuresReady_ = true; |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
277 BroadcastMessage(DicomStructureSetLoader::StructuresReady(*this)); |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
278 } |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
279 |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
280 bool DicomStructureSetLoader::AreStructuresReady() const |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
281 { |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
282 return structuresReady_; |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
283 } |
86ac61a040c9
Added getters and notifications to allow clients of the loaders (DicomStructureSetLoader, OrthancSeriesVolumeProgressiveLoader and OrthancMultiframeVolumeLoader) to know when the loading is finished + added ability for SDL event loop to execute a callback repeatedly (used to check the view loading state)
Benjamin Golinvaux <bgo@osimis.io>
parents:
935
diff
changeset
|
284 |
815 | 285 } |