Mercurial > hg > orthanc-stone
comparison Framework/Loaders/DicomStructureSetLoader.cpp @ 1019:29f5f2031310
Added a way to specificy which structures are to be initially displayed (the
default being ALL structures displayed) + the loader maintains a list of
structure display state, that can be modified continuously + the cache now takes
the initial list of structure into account for computing the entry + added methods
to change the loaded structure visibility + disabled the alternate loaders
(DicomStructureSetLoader2 and friends) + disabled corresponding tests
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Fri, 27 Sep 2019 13:32:05 +0200 |
parents | 4f28d9459e31 |
children | 7014c2397b45 |
comparison
equal
deleted
inserted
replaced
1018:58eed6bbcabb | 1019:29f5f2031310 |
---|---|
22 #include "DicomStructureSetLoader.h" | 22 #include "DicomStructureSetLoader.h" |
23 | 23 |
24 #include "../Scene2D/PolylineSceneLayer.h" | 24 #include "../Scene2D/PolylineSceneLayer.h" |
25 #include "../Toolbox/GeometryToolbox.h" | 25 #include "../Toolbox/GeometryToolbox.h" |
26 | 26 |
27 #include <algorithm> | |
28 | |
27 #if 0 | 29 #if 0 |
28 bool logbgo233 = false; | 30 bool logbgo233 = false; |
29 bool logbgo115 = false; | 31 bool logbgo115 = false; |
30 #endif | 32 #endif |
31 | 33 |
151 public: | 153 public: |
152 LoadStructure(DicomStructureSetLoader& that) : | 154 LoadStructure(DicomStructureSetLoader& that) : |
153 State(that) | 155 State(that) |
154 { | 156 { |
155 } | 157 } |
156 | 158 |
157 | |
158 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) | 159 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) |
159 { | 160 { |
160 #if 0 | 161 #if 0 |
161 if (logbgo115) | 162 if (logbgo115) |
162 LOG(TRACE) << "DicomStructureSetLoader::LoadStructure::Handle() (SUCCESS)"; | 163 LOG(TRACE) << "DicomStructureSetLoader::LoadStructure::Handle() (SUCCESS)"; |
164 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); | 165 DicomStructureSetLoader& loader = GetLoader<DicomStructureSetLoader>(); |
165 | 166 |
166 { | 167 { |
167 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); | 168 OrthancPlugins::FullOrthancDataset dicom(message.GetAnswer()); |
168 loader.content_.reset(new DicomStructureSet(dicom)); | 169 loader.content_.reset(new DicomStructureSet(dicom)); |
170 size_t structureCount = loader.content_->GetStructuresCount(); | |
171 loader.structureVisibility_.resize(structureCount); | |
172 for (size_t i = 0; i < structureCount; ++i) | |
173 { | |
174 // if nothing is specified in the ctor, this means we want everything visible | |
175 if (loader.initiallyVisibleStructures_.size() == 0) | |
176 { | |
177 loader.structureVisibility_.at(i) = true; | |
178 } | |
179 else | |
180 { | |
181 // otherwise, we only enable visibility for those structures whose | |
182 // names are mentioned in the initiallyVisibleStructures_ array | |
183 const std::string& structureName = loader.content_->GetStructureName(i); | |
184 | |
185 std::vector<std::string>::iterator foundIt = | |
186 std::find( | |
187 loader.initiallyVisibleStructures_.begin(), | |
188 loader.initiallyVisibleStructures_.end(), | |
189 structureName); | |
190 std::vector<std::string>::iterator endIt = loader.initiallyVisibleStructures_.end(); | |
191 if (foundIt != endIt) | |
192 loader.structureVisibility_.at(i) = true; | |
193 else | |
194 loader.structureVisibility_.at(i) = false; | |
195 } | |
196 } | |
169 } | 197 } |
170 | 198 |
171 // Some (admittedly invalid) Dicom files have empty values in the | 199 // Some (admittedly invalid) Dicom files have empty values in the |
172 // 0008,1155 tag. We try our best to cope with this. | 200 // 0008,1155 tag. We try our best to cope with this. |
173 std::set<std::string> instances; | 201 std::set<std::string> instances; |
202 { | 230 { |
203 private: | 231 private: |
204 const DicomStructureSet& content_; | 232 const DicomStructureSet& content_; |
205 uint64_t revision_; | 233 uint64_t revision_; |
206 bool isValid_; | 234 bool isValid_; |
235 std::vector<bool> visibility_; | |
207 | 236 |
208 public: | 237 public: |
238 /** | |
239 The visibility vector must either: | |
240 - be empty | |
241 or | |
242 - contain the same number of items as the number of structures in the | |
243 structure set. | |
244 In the first case (empty vector), all the structures are displayed. | |
245 In the second case, the visibility of each structure is defined by the | |
246 content of the vector at the corresponding index. | |
247 */ | |
209 Slice(const DicomStructureSet& content, | 248 Slice(const DicomStructureSet& content, |
210 uint64_t revision, | 249 uint64_t revision, |
211 const CoordinateSystem3D& cuttingPlane) : | 250 const CoordinateSystem3D& cuttingPlane, |
212 content_(content), | 251 std::vector<bool> visibility = std::vector<bool>()) |
213 revision_(revision) | 252 : content_(content) |
214 { | 253 , revision_(revision) |
254 , visibility_(visibility) | |
255 { | |
256 ORTHANC_ASSERT((visibility_.size() == content_.GetStructuresCount()) | |
257 || (visibility_.size() == 0u)); | |
258 | |
215 bool opposite; | 259 bool opposite; |
216 | 260 |
217 const Vector normal = content.GetNormal(); | 261 const Vector normal = content.GetNormal(); |
218 isValid_ = ( | 262 isValid_ = ( |
219 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetNormal()) || | 263 GeometryToolbox::IsParallelOrOpposite(opposite, normal, cuttingPlane.GetNormal()) || |
239 std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer); | 283 std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer); |
240 layer->SetThickness(2); | 284 layer->SetThickness(2); |
241 | 285 |
242 for (size_t i = 0; i < content_.GetStructuresCount(); i++) | 286 for (size_t i = 0; i < content_.GetStructuresCount(); i++) |
243 { | 287 { |
244 const Color& color = content_.GetStructureColor(i); | 288 if ((visibility_.size() == 0) || visibility_.at(i)) |
289 { | |
290 const Color& color = content_.GetStructureColor(i); | |
245 | 291 |
246 #ifdef USE_BOOST_UNION_FOR_POLYGONS | 292 #ifdef USE_BOOST_UNION_FOR_POLYGONS |
247 std::vector< std::vector<Point2D> > polygons; | 293 std::vector< std::vector<Point2D> > polygons; |
248 | 294 |
249 if (content_.ProjectStructure(polygons, i, cuttingPlane)) | 295 if (content_.ProjectStructure(polygons, i, cuttingPlane)) |
250 { | |
251 for (size_t j = 0; j < polygons.size(); j++) | |
252 { | 296 { |
253 PolylineSceneLayer::Chain chain; | 297 for (size_t j = 0; j < polygons.size(); j++) |
254 chain.resize(polygons[j].size()); | |
255 | |
256 for (size_t k = 0; k < polygons[j].size(); k++) | |
257 { | 298 { |
258 chain[k] = ScenePoint2D(polygons[j][k].x, polygons[j][k].y); | 299 PolylineSceneLayer::Chain chain; |
259 } | 300 chain.resize(polygons[j].size()); |
260 | 301 |
261 layer->AddChain(chain, true /* closed */, color); | 302 for (size_t k = 0; k < polygons[j].size(); k++) |
262 } | 303 { |
304 chain[k] = ScenePoint2D(polygons[j][k].x, polygons[j][k].y); | |
305 } | |
306 | |
307 layer->AddChain(chain, true /* closed */, color); | |
308 } | |
263 } | 309 } |
264 #else | 310 #else |
265 std::vector< std::pair<Point2D, Point2D> > segments; | 311 std::vector< std::pair<Point2D, Point2D> > segments; |
266 | 312 |
267 if (content_.ProjectStructure(segments, i, cuttingPlane)) | 313 if (content_.ProjectStructure(segments, i, cuttingPlane)) |
268 { | |
269 for (size_t j = 0; j < segments.size(); j++) | |
270 { | 314 { |
271 PolylineSceneLayer::Chain chain; | 315 for (size_t j = 0; j < segments.size(); j++) |
272 chain.resize(2); | 316 { |
273 | 317 PolylineSceneLayer::Chain chain; |
274 chain[0] = ScenePoint2D(segments[j].first.x, segments[j].first.y); | 318 chain.resize(2); |
275 chain[1] = ScenePoint2D(segments[j].second.x, segments[j].second.y); | 319 |
276 | 320 chain[0] = ScenePoint2D(segments[j].first.x, segments[j].first.y); |
277 layer->AddChain(chain, false /* NOT closed */, color); | 321 chain[1] = ScenePoint2D(segments[j].second.x, segments[j].second.y); |
322 | |
323 layer->AddChain(chain, false /* NOT closed */, color); | |
324 } | |
278 } | 325 } |
326 #endif | |
279 } | 327 } |
280 #endif | |
281 } | 328 } |
282 | 329 |
283 return layer.release(); | 330 return layer.release(); |
284 } | 331 } |
285 }; | 332 }; |
295 structuresReady_(false) | 342 structuresReady_(false) |
296 { | 343 { |
297 } | 344 } |
298 | 345 |
299 | 346 |
347 void DicomStructureSetLoader::SetStructureDisplayState(size_t structureIndex, bool display) | |
348 { | |
349 structureVisibility_.at(structureIndex) = display; | |
350 revision_++; | |
351 } | |
352 | |
300 DicomStructureSetLoader::~DicomStructureSetLoader() | 353 DicomStructureSetLoader::~DicomStructureSetLoader() |
301 { | 354 { |
302 LOG(TRACE) << "DicomStructureSetLoader::~DicomStructureSetLoader()"; | 355 LOG(TRACE) << "DicomStructureSetLoader::~DicomStructureSetLoader()"; |
303 } | 356 } |
304 | 357 |
305 void DicomStructureSetLoader::LoadInstance(const std::string& instanceId) | 358 void DicomStructureSetLoader::LoadInstance( |
359 const std::string& instanceId, | |
360 const std::vector<std::string>& initiallyVisibleStructures) | |
306 { | 361 { |
307 Start(); | 362 Start(); |
308 | 363 |
309 instanceId_ = instanceId; | 364 instanceId_ = instanceId; |
310 | 365 initiallyVisibleStructures_ = initiallyVisibleStructures; |
366 | |
311 { | 367 { |
312 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 368 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
313 command->SetHttpHeader("Accept-Encoding", "gzip"); | 369 command->SetHttpHeader("Accept-Encoding", "gzip"); |
314 | 370 |
315 std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050"; | 371 std::string uri = "/instances/" + instanceId + "/tags?ignore-length=3006-0050"; |
328 // Geometry is not available yet | 384 // Geometry is not available yet |
329 return new IVolumeSlicer::InvalidSlice; | 385 return new IVolumeSlicer::InvalidSlice; |
330 } | 386 } |
331 else | 387 else |
332 { | 388 { |
333 return new Slice(*content_, revision_, cuttingPlane); | 389 return new Slice(*content_, revision_, cuttingPlane, structureVisibility_); |
334 } | 390 } |
335 } | 391 } |
336 | 392 |
337 void DicomStructureSetLoader::SetStructuresReady() | 393 void DicomStructureSetLoader::SetStructuresReady() |
338 { | 394 { |