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 {