Mercurial > hg > orthanc-stone
comparison Framework/Loaders/DicomStructureSetLoader.cpp @ 1381:f4a06ad1580b
Branch broker is now the new default
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Wed, 22 Apr 2020 14:05:47 +0200 |
parents | 8a0a62189f46 0d6a01ffa1dd |
children | ffe9beb7c5d3 |
comparison
equal
deleted
inserted
replaced
1375:4431ffdcc2a4 | 1381:f4a06ad1580b |
---|---|
27 | 27 |
28 #include <Core/Toolbox.h> | 28 #include <Core/Toolbox.h> |
29 | 29 |
30 #include <algorithm> | 30 #include <algorithm> |
31 | 31 |
32 #if 0 | |
33 bool logbgo233 = false; | |
34 bool logbgo115 = false; | |
35 #endif | |
36 | |
37 namespace OrthancStone | 32 namespace OrthancStone |
38 { | 33 { |
39 | 34 |
40 #if 0 | 35 #if 0 |
41 void DumpDicomMap(std::ostream& o, const Orthanc::DicomMap& dicomMap) | 36 void DumpDicomMap(std::ostream& o, const Orthanc::DicomMap& dicomMap) |
65 State(that), | 60 State(that), |
66 instanceId_(instanceId) | 61 instanceId_(instanceId) |
67 { | 62 { |
68 } | 63 } |
69 | 64 |
70 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) | 65 virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) |
71 { | 66 { |
72 Json::Value tags; | 67 Json::Value tags; |
73 message.ParseJsonBody(tags); | 68 message.ParseJsonBody(tags); |
74 | 69 |
75 Orthanc::DicomMap dicom; | 70 Orthanc::DicomMap dicom; |
76 dicom.FromDicomAsJson(tags); | 71 dicom.FromDicomAsJson(tags); |
77 | 72 |
78 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); | 73 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); |
79 | 74 |
80 loader.content_->AddReferencedSlice(dicom); | 75 loader.content_->AddReferencedSlice(dicom); |
81 | |
82 loader.countProcessedInstances_ ++; | 76 loader.countProcessedInstances_ ++; |
83 assert(loader.countProcessedInstances_ <= loader.countReferencedInstances_); | 77 assert(loader.countProcessedInstances_ <= loader.countReferencedInstances_); |
78 | |
79 loader.revision_++; | |
80 loader.SetStructuresUpdated(); | |
84 | 81 |
85 if (loader.countProcessedInstances_ == loader.countReferencedInstances_) | 82 if (loader.countProcessedInstances_ == loader.countReferencedInstances_) |
86 { | 83 { |
87 // All the referenced instances have been loaded, finalize the RT-STRUCT | 84 // All the referenced instances have been loaded, finalize the RT-STRUCT |
88 loader.content_->CheckReferencedSlices(); | 85 loader.content_->CheckReferencedSlices(); |
105 State(that), | 102 State(that), |
106 sopInstanceUid_(sopInstanceUid) | 103 sopInstanceUid_(sopInstanceUid) |
107 { | 104 { |
108 } | 105 } |
109 | 106 |
110 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) | 107 virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) |
111 { | 108 { |
112 #if 0 | 109 #if 0 |
113 LOG(TRACE) << "DicomStructureSetLoader::LookupInstance::Handle() (SUCCESS)"; | 110 LOG(TRACE) << "DicomStructureSetLoader::LookupInstance::Handle() (SUCCESS)"; |
114 #endif | 111 #endif |
115 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); | 112 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); |
125 lookup[0]["ID"].type() != Json::stringValue || | 122 lookup[0]["ID"].type() != Json::stringValue || |
126 lookup[0]["Type"].asString() != "Instance") | 123 lookup[0]["Type"].asString() != "Instance") |
127 { | 124 { |
128 std::stringstream msg; | 125 std::stringstream msg; |
129 msg << "Unknown resource! message.GetAnswer() = " << message.GetAnswer() << " message.GetAnswerHeaders() = "; | 126 msg << "Unknown resource! message.GetAnswer() = " << message.GetAnswer() << " message.GetAnswerHeaders() = "; |
130 for (OrthancRestApiCommand::HttpHeaders::const_iterator it = message.GetAnswerHeaders().begin(); | 127 for (OrthancStone::OrthancRestApiCommand::HttpHeaders::const_iterator it = message.GetAnswerHeaders().begin(); |
131 it != message.GetAnswerHeaders().end(); ++it) | 128 it != message.GetAnswerHeaders().end(); ++it) |
132 { | 129 { |
133 msg << "\nkey: \"" << it->first << "\" value: \"" << it->second << "\"\n"; | 130 msg << "\nkey: \"" << it->first << "\" value: \"" << it->second << "\"\n"; |
134 } | 131 } |
135 const std::string msgStr = msg.str(); | 132 const std::string msgStr = msg.str(); |
138 } | 135 } |
139 | 136 |
140 const std::string instanceId = lookup[0]["ID"].asString(); | 137 const std::string instanceId = lookup[0]["ID"].asString(); |
141 | 138 |
142 { | 139 { |
143 std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 140 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); |
144 command->SetHttpHeader("Accept-Encoding", "gzip"); | 141 command->SetHttpHeader("Accept-Encoding", "gzip"); |
145 std::string uri = "/instances/" + instanceId + "/tags"; | 142 std::string uri = "/instances/" + instanceId + "/tags"; |
146 command->SetUri(uri); | 143 command->SetUri(uri); |
147 command->SetPayload(new AddReferencedInstance(loader, instanceId)); | 144 command->AcquirePayload(new AddReferencedInstance(loader, instanceId)); |
148 Schedule(command.release()); | 145 Schedule(command.release()); |
149 } | 146 } |
150 } | 147 } |
151 }; | 148 }; |
152 | 149 |
157 LoadStructure(DicomStructureSetLoader& that) : | 154 LoadStructure(DicomStructureSetLoader& that) : |
158 State(that) | 155 State(that) |
159 { | 156 { |
160 } | 157 } |
161 | 158 |
162 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) | 159 virtual void Handle(const OrthancStone::OrthancRestApiCommand::SuccessMessage& message) |
163 { | 160 { |
164 #if 0 | |
165 if (logbgo115) | |
166 LOG(TRACE) << "DicomStructureSetLoader::LoadStructure::Handle() (SUCCESS)"; | |
167 #endif | |
168 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); | 161 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); |
169 | 162 |
170 { | 163 { |
171 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); | 164 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); |
172 loader.content_.reset(new DicomStructureSet(dicom)); | 165 loader.content_.reset(new OrthancStone::DicomStructureSet(dicom)); |
173 size_t structureCount = loader.content_->GetStructuresCount(); | 166 size_t structureCount = loader.content_->GetStructuresCount(); |
174 loader.structureVisibility_.resize(structureCount); | 167 loader.structureVisibility_.resize(structureCount); |
175 bool everythingVisible = false; | 168 bool everythingVisible = false; |
176 if ((loader.initiallyVisibleStructures_.size() == 1) | 169 if ((loader.initiallyVisibleStructures_.size() == 1) |
177 && (loader.initiallyVisibleStructures_[0].size() == 1) | 170 && (loader.initiallyVisibleStructures_[0].size() == 1) |
225 static_cast<unsigned int>(nonEmptyInstances.size()); | 218 static_cast<unsigned int>(nonEmptyInstances.size()); |
226 | 219 |
227 for (std::set<std::string>::const_iterator | 220 for (std::set<std::string>::const_iterator |
228 it = nonEmptyInstances.begin(); it != nonEmptyInstances.end(); ++it) | 221 it = nonEmptyInstances.begin(); it != nonEmptyInstances.end(); ++it) |
229 { | 222 { |
230 std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 223 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); |
231 command->SetUri("/tools/lookup"); | 224 command->SetUri("/tools/lookup"); |
232 command->SetMethod(Orthanc::HttpMethod_Post); | 225 command->SetMethod(Orthanc::HttpMethod_Post); |
233 command->SetBody(*it); | 226 command->SetBody(*it); |
234 command->SetPayload(new LookupInstance(loader, *it)); | 227 command->AcquirePayload(new LookupInstance(loader, *it)); |
235 Schedule(command.release()); | 228 Schedule(command.release()); |
236 } | 229 } |
237 } | 230 } |
238 }; | 231 }; |
239 | 232 |
240 | 233 |
241 class DicomStructureSetLoader::Slice : public IExtractedSlice | 234 class DicomStructureSetLoader::Slice : public IExtractedSlice |
242 { | 235 { |
243 private: | 236 private: |
244 const DicomStructureSet& content_; | 237 const OrthancStone::DicomStructureSet& content_; |
245 uint64_t revision_; | 238 uint64_t revision_; |
246 bool isValid_; | 239 bool isValid_; |
247 std::vector<bool> visibility_; | 240 std::vector<bool> visibility_; |
248 | 241 |
249 public: | 242 public: |
255 structure set. | 248 structure set. |
256 In the first case (empty vector), all the structures are displayed. | 249 In the first case (empty vector), all the structures are displayed. |
257 In the second case, the visibility of each structure is defined by the | 250 In the second case, the visibility of each structure is defined by the |
258 content of the vector at the corresponding index. | 251 content of the vector at the corresponding index. |
259 */ | 252 */ |
260 Slice(const DicomStructureSet& content, | 253 Slice(const OrthancStone::DicomStructureSet& content, |
261 uint64_t revision, | 254 uint64_t revision, |
262 const CoordinateSystem3D& cuttingPlane, | 255 const OrthancStone::CoordinateSystem3D& cuttingPlane, |
263 std::vector<bool> visibility = std::vector<bool>()) | 256 std::vector<bool> visibility = std::vector<bool>()) |
264 : content_(content) | 257 : content_(content) |
265 , revision_(revision) | 258 , revision_(revision) |
266 , visibility_(visibility) | 259 , visibility_(visibility) |
267 { | 260 { |
268 ORTHANC_ASSERT((visibility_.size() == content_.GetStructuresCount()) | 261 ORTHANC_ASSERT((visibility_.size() == content_.GetStructuresCount()) |
269 || (visibility_.size() == 0u)); | 262 || (visibility_.size() == 0u)); |
270 | 263 |
271 bool opposite; | 264 bool opposite; |
272 | 265 |
273 const Vector normal = content.GetNormal(); | 266 const OrthancStone::Vector normal = content.GetNormal(); |
274 isValid_ = ( | 267 isValid_ = ( |
275 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetNormal()) || | 268 OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetNormal()) || |
276 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisX()) || | 269 OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisX()) || |
277 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisY())); | 270 OrthancStone::GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetAxisY())); |
278 } | 271 } |
279 | 272 |
280 virtual bool IsValid() | 273 virtual bool IsValid() |
281 { | 274 { |
282 return isValid_; | 275 return isValid_; |
285 virtual uint64_t GetRevision() | 278 virtual uint64_t GetRevision() |
286 { | 279 { |
287 return revision_; | 280 return revision_; |
288 } | 281 } |
289 | 282 |
290 virtual ISceneLayer* CreateSceneLayer(const ILayerStyleConfigurator* configurator, | 283 virtual OrthancStone::ISceneLayer* CreateSceneLayer( |
291 const CoordinateSystem3D& cuttingPlane) | 284 const OrthancStone::ILayerStyleConfigurator* configurator, |
285 const OrthancStone::CoordinateSystem3D& cuttingPlane) | |
292 { | 286 { |
293 assert(isValid_); | 287 assert(isValid_); |
294 | 288 |
295 std::unique_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer); | 289 std::unique_ptr<OrthancStone::PolylineSceneLayer> layer(new OrthancStone::PolylineSceneLayer); |
296 layer->SetThickness(2); | 290 layer->SetThickness(2); |
297 | 291 |
298 for (size_t i = 0; i < content_.GetStructuresCount(); i++) | 292 for (size_t i = 0; i < content_.GetStructuresCount(); i++) |
299 { | 293 { |
300 if ((visibility_.size() == 0) || visibility_.at(i)) | 294 if ((visibility_.size() == 0) || visibility_.at(i)) |
301 { | 295 { |
302 const Color& color = content_.GetStructureColor(i); | 296 const OrthancStone::Color& color = content_.GetStructureColor(i); |
303 | 297 |
304 #ifdef USE_BOOST_UNION_FOR_POLYGONS | 298 #ifdef USE_BOOST_UNION_FOR_POLYGONS |
305 std::vector< std::vector<Point2D> > polygons; | 299 std::vector< std::vector<OrthancStone::Point2D> > polygons; |
306 | 300 |
307 if (content_.ProjectStructure(polygons, i, cuttingPlane)) | 301 if (content_.ProjectStructure(polygons, i, cuttingPlane)) |
308 { | 302 { |
309 for (size_t j = 0; j < polygons.size(); j++) | 303 for (size_t j = 0; j < polygons.size(); j++) |
310 { | 304 { |
318 | 312 |
319 layer->AddChain(chain, true /* closed */, color); | 313 layer->AddChain(chain, true /* closed */, color); |
320 } | 314 } |
321 } | 315 } |
322 #else | 316 #else |
323 std::vector< std::pair<Point2D, Point2D> > segments; | 317 std::vector< std::pair<OrthancStone::Point2D, OrthancStone::Point2D> > segments; |
324 | 318 |
325 if (content_.ProjectStructure(segments, i, cuttingPlane)) | 319 if (content_.ProjectStructure(segments, i, cuttingPlane)) |
326 { | 320 { |
327 for (size_t j = 0; j < segments.size(); j++) | 321 for (size_t j = 0; j < segments.size(); j++) |
328 { | 322 { |
329 PolylineSceneLayer::Chain chain; | 323 OrthancStone::PolylineSceneLayer::Chain chain; |
330 chain.resize(2); | 324 chain.resize(2); |
331 | 325 |
332 chain[0] = ScenePoint2D(segments[j].first.x, segments[j].first.y); | 326 chain[0] = OrthancStone::ScenePoint2D(segments[j].first.x, segments[j].first.y); |
333 chain[1] = ScenePoint2D(segments[j].second.x, segments[j].second.y); | 327 chain[1] = OrthancStone::ScenePoint2D(segments[j].second.x, segments[j].second.y); |
334 | 328 |
335 layer->AddChain(chain, false /* NOT closed */, color); | 329 layer->AddChain(chain, false /* NOT closed */, color); |
336 } | 330 } |
337 } | 331 } |
338 #endif | 332 #endif |
342 return layer.release(); | 336 return layer.release(); |
343 } | 337 } |
344 }; | 338 }; |
345 | 339 |
346 | 340 |
347 DicomStructureSetLoader::DicomStructureSetLoader(IOracle& oracle, | 341 DicomStructureSetLoader::DicomStructureSetLoader( |
348 IObservable& oracleObservable) : | 342 OrthancStone::ILoadersContext& loadersContext) |
349 LoaderStateMachine(oracle, oracleObservable), | 343 : LoaderStateMachine(loadersContext) |
350 IObservable(oracleObservable.GetBroker()), | 344 , loadersContext_(loadersContext) |
351 revision_(0), | 345 , revision_(0) |
352 countProcessedInstances_(0), | 346 , countProcessedInstances_(0) |
353 countReferencedInstances_(0), | 347 , countReferencedInstances_(0) |
354 structuresReady_(false) | 348 , structuresReady_(false) |
355 { | 349 { |
356 } | 350 } |
351 | |
357 | 352 |
358 | 353 boost::shared_ptr<OrthancStone::DicomStructureSetLoader> DicomStructureSetLoader::Create(OrthancStone::ILoadersContext& loadersContext) |
354 { | |
355 boost::shared_ptr<DicomStructureSetLoader> obj( | |
356 new DicomStructureSetLoader( | |
357 loadersContext)); | |
358 obj->LoaderStateMachine::PostConstructor(); | |
359 return obj; | |
360 | |
361 } | |
362 | |
359 void DicomStructureSetLoader::SetStructureDisplayState(size_t structureIndex, bool display) | 363 void DicomStructureSetLoader::SetStructureDisplayState(size_t structureIndex, bool display) |
360 { | 364 { |
361 structureVisibility_.at(structureIndex) = display; | 365 structureVisibility_.at(structureIndex) = display; |
362 revision_++; | 366 revision_++; |
363 } | 367 } |
375 | 379 |
376 instanceId_ = instanceId; | 380 instanceId_ = instanceId; |
377 initiallyVisibleStructures_ = initiallyVisibleStructures; | 381 initiallyVisibleStructures_ = initiallyVisibleStructures; |
378 | 382 |
379 { | 383 { |
380 std::unique_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 384 std::unique_ptr<OrthancStone::OrthancRestApiCommand> command(new OrthancStone::OrthancRestApiCommand); |
381 command->SetHttpHeader("Accept-Encoding", "gzip"); | 385 command->SetHttpHeader("Accept-Encoding", "gzip"); |
382 | 386 |
383 std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050"; | 387 std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050"; |
384 | 388 |
385 command->SetUri(uri); | 389 command->SetUri(uri); |
386 command->SetPayload(new LoadStructure(*this)); | 390 command->AcquirePayload(new LoadStructure(*this)); |
387 Schedule(command.release()); | 391 Schedule(command.release()); |
388 } | 392 } |
389 } | 393 } |
390 | 394 |
391 | 395 |
392 IVolumeSlicer::IExtractedSlice* DicomStructureSetLoader::ExtractSlice(const CoordinateSystem3D& cuttingPlane) | 396 OrthancStone::IVolumeSlicer::IExtractedSlice* DicomStructureSetLoader::ExtractSlice(const OrthancStone::CoordinateSystem3D& cuttingPlane) |
393 { | 397 { |
394 if (content_.get() == NULL) | 398 if (content_.get() == NULL) |
395 { | 399 { |
396 // Geometry is not available yet | 400 // Geometry is not available yet |
397 return new IVolumeSlicer::InvalidSlice; | 401 return new OrthancStone::IVolumeSlicer::InvalidSlice; |
398 } | 402 } |
399 else | 403 else |
400 { | 404 { |
401 return new Slice(*content_, revision_, cuttingPlane, structureVisibility_); | 405 return new Slice(*content_, revision_, cuttingPlane, structureVisibility_); |
402 } | 406 } |
407 } | |
408 | |
409 void DicomStructureSetLoader::SetStructuresUpdated() | |
410 { | |
411 BroadcastMessage(DicomStructureSetLoader::StructuresUpdated(*this)); | |
403 } | 412 } |
404 | 413 |
405 void DicomStructureSetLoader::SetStructuresReady() | 414 void DicomStructureSetLoader::SetStructuresReady() |
406 { | 415 { |
407 ORTHANC_ASSERT(!structuresReady_); | 416 ORTHANC_ASSERT(!structuresReady_); |