comparison OrthancServer/DicomProtocol/DicomUserConnection.cpp @ 1366:a3559b66fba7 query-retrieve

move primitives
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 22 May 2015 16:17:28 +0200
parents 111e23bb4904
children b22ba8c5edbe
comparison
equal deleted inserted replaced
1365:38ce915cb455 1366:a3559b66fba7
335 delete statusDetail; 335 delete statusDetail;
336 } 336 }
337 } 337 }
338 338
339 339
340 namespace
341 {
342 struct FindPayload
343 {
344 DicomFindAnswers* answers;
345 std::string level;
346 };
347 }
348
349
340 static void FindCallback( 350 static void FindCallback(
341 /* in */ 351 /* in */
342 void *callbackData, 352 void *callbackData,
343 T_DIMSE_C_FindRQ *request, /* original find request */ 353 T_DIMSE_C_FindRQ *request, /* original find request */
344 int responseCount, 354 int responseCount,
345 T_DIMSE_C_FindRSP *response, /* pending response received */ 355 T_DIMSE_C_FindRSP *response, /* pending response received */
346 DcmDataset *responseIdentifiers /* pending response identifiers */ 356 DcmDataset *responseIdentifiers /* pending response identifiers */
347 ) 357 )
348 { 358 {
349 DicomFindAnswers& answers = *reinterpret_cast<DicomFindAnswers*>(callbackData); 359 FindPayload& payload = *reinterpret_cast<FindPayload*>(callbackData);
350 360
351 if (responseIdentifiers != NULL) 361 if (responseIdentifiers != NULL)
352 { 362 {
353 DicomMap m; 363 DicomMap m;
354 FromDcmtkBridge::Convert(m, *responseIdentifiers); 364 FromDcmtkBridge::Convert(m, *responseIdentifiers);
355 answers.Add(m); 365
366 if (!m.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL))
367 {
368 m.SetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL, payload.level);
369 }
370
371 payload.answers->Add(m);
356 } 372 }
357 } 373 }
358 374
359 void DicomUserConnection::Find(DicomFindAnswers& result, 375 void DicomUserConnection::Find(DicomFindAnswers& result,
360 FindRootModel model, 376 FindRootModel model,
361 const DicomMap& fields) 377 const DicomMap& fields)
362 { 378 {
363 CheckIsOpen(); 379 CheckIsOpen();
364 380
381 FindPayload payload;
382 payload.answers = &result;
383
365 const char* sopClass; 384 const char* sopClass;
366 std::auto_ptr<DcmDataset> dataset(ToDcmtkBridge::Convert(fields)); 385 std::auto_ptr<DcmDataset> dataset(ToDcmtkBridge::Convert(fields));
367 switch (model) 386 switch (model)
368 { 387 {
369 case FindRootModel_Patient: 388 case FindRootModel_Patient:
389 payload.level = "PATIENT";
370 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT"); 390 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT");
371 sopClass = UID_FINDPatientRootQueryRetrieveInformationModel; 391 sopClass = UID_FINDPatientRootQueryRetrieveInformationModel;
372 392
373 // Accession number 393 // Accession number
374 if (!fields.HasTag(0x0008, 0x0050)) 394 if (!fields.HasTag(0x0008, 0x0050))
379 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0010, 0x0020), ""); 399 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0010, 0x0020), "");
380 400
381 break; 401 break;
382 402
383 case FindRootModel_Study: 403 case FindRootModel_Study:
404 payload.level = "STUDY";
384 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY"); 405 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY");
385 sopClass = UID_FINDStudyRootQueryRetrieveInformationModel; 406 sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
386 407
387 // Accession number 408 // Accession number
388 if (!fields.HasTag(0x0008, 0x0050)) 409 if (!fields.HasTag(0x0008, 0x0050))
393 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000d), ""); 414 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000d), "");
394 415
395 break; 416 break;
396 417
397 case FindRootModel_Series: 418 case FindRootModel_Series:
419 payload.level = "SERIES";
398 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES"); 420 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES");
399 sopClass = UID_FINDStudyRootQueryRetrieveInformationModel; 421 sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
400 422
401 // Accession number 423 // Accession number
402 if (!fields.HasTag(0x0008, 0x0050)) 424 if (!fields.HasTag(0x0008, 0x0050))
411 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000e), ""); 433 DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000e), "");
412 434
413 break; 435 break;
414 436
415 case FindRootModel_Instance: 437 case FindRootModel_Instance:
438 payload.level = "INSTANCE";
416 if (manufacturer_ == ModalityManufacturer_ClearCanvas || 439 if (manufacturer_ == ModalityManufacturer_ClearCanvas ||
417 manufacturer_ == ModalityManufacturer_Dcm4Chee) 440 manufacturer_ == ModalityManufacturer_Dcm4Chee)
418 { 441 {
419 // This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo@gmail.com>. 442 // This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo@gmail.com>.
420 // https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J 443 // https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J
465 request.Priority = DIMSE_PRIORITY_MEDIUM; 488 request.Priority = DIMSE_PRIORITY_MEDIUM;
466 489
467 T_DIMSE_C_FindRSP response; 490 T_DIMSE_C_FindRSP response;
468 DcmDataset* statusDetail = NULL; 491 DcmDataset* statusDetail = NULL;
469 OFCondition cond = DIMSE_findUser(pimpl_->assoc_, presID, &request, dataset.get(), 492 OFCondition cond = DIMSE_findUser(pimpl_->assoc_, presID, &request, dataset.get(),
470 FindCallback, &result, 493 FindCallback, &payload,
471 /*opt_blockMode*/ DIMSE_BLOCKING, 494 /*opt_blockMode*/ DIMSE_BLOCKING,
472 /*opt_dimse_timeout*/ pimpl_->dimseTimeout_, 495 /*opt_dimse_timeout*/ pimpl_->dimseTimeout_,
473 &response, &statusDetail); 496 &response, &statusDetail);
474 497
475 if (statusDetail) 498 if (statusDetail)
532 555
533 Find(result, FindRootModel_Instance, s); 556 Find(result, FindRootModel_Instance, s);
534 } 557 }
535 558
536 559
537 void DicomUserConnection::Move(const std::string& targetAet, 560 void DicomUserConnection::MoveInternal(const std::string& targetAet,
538 const DicomMap& fields) 561 const DicomMap& fields)
539 { 562 {
540 CheckIsOpen(); 563 CheckIsOpen();
541 564
542 const char* sopClass = UID_MOVEStudyRootQueryRetrieveInformationModel; 565 const char* sopClass = UID_MOVEStudyRootQueryRetrieveInformationModel;
543 std::auto_ptr<DcmDataset> dataset(ToDcmtkBridge::Convert(fields)); 566 std::auto_ptr<DcmDataset> dataset(ToDcmtkBridge::Convert(fields));
828 &status, NULL)); 851 &status, NULL));
829 return status == STATUS_Success; 852 return status == STATUS_Success;
830 } 853 }
831 854
832 855
833 void DicomUserConnection::MoveSeries(const std::string& targetAet, 856 static void TestAndCopyTag(DicomMap& result,
834 const DicomMap& findResult) 857 const DicomMap& source,
835 { 858 const DicomTag& tag)
836 DicomMap simplified; 859 {
837 simplified.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, findResult.GetValue(DICOM_TAG_STUDY_INSTANCE_UID)); 860 if (!source.HasTag(tag))
838 simplified.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, findResult.GetValue(DICOM_TAG_SERIES_INSTANCE_UID)); 861 {
839 Move(targetAet, simplified); 862 throw OrthancException(ErrorCode_BadRequest);
863 }
864 else
865 {
866 result.SetValue(tag, source.GetValue(tag));
867 }
868 }
869
870
871 void DicomUserConnection::Move(const std::string& targetAet,
872 const DicomMap& findResult)
873 {
874 if (!findResult.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL))
875 {
876 throw OrthancException(ErrorCode_InternalError);
877 }
878
879 const std::string tmp = findResult.GetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL).AsString();
880 ResourceType level = StringToResourceType(tmp.c_str());
881
882 DicomMap move;
883 switch (level)
884 {
885 case ResourceType_Patient:
886 TestAndCopyTag(move, findResult, DICOM_TAG_PATIENT_ID);
887 break;
888
889 case ResourceType_Study:
890 TestAndCopyTag(move, findResult, DICOM_TAG_STUDY_INSTANCE_UID);
891 break;
892
893 case ResourceType_Series:
894 TestAndCopyTag(move, findResult, DICOM_TAG_STUDY_INSTANCE_UID);
895 TestAndCopyTag(move, findResult, DICOM_TAG_SERIES_INSTANCE_UID);
896 break;
897
898 case ResourceType_Instance:
899 TestAndCopyTag(move, findResult, DICOM_TAG_STUDY_INSTANCE_UID);
900 TestAndCopyTag(move, findResult, DICOM_TAG_SERIES_INSTANCE_UID);
901 TestAndCopyTag(move, findResult, DICOM_TAG_SOP_INSTANCE_UID);
902 break;
903
904 default:
905 throw OrthancException(ErrorCode_InternalError);
906 }
907
908 MoveInternal(targetAet, move);
909 }
910
911
912 void DicomUserConnection::MovePatient(const std::string& targetAet,
913 const std::string& patientId)
914 {
915 DicomMap query;
916 query.SetValue(DICOM_TAG_PATIENT_ID, patientId);
917 MoveInternal(targetAet, query);
918 }
919
920 void DicomUserConnection::MoveStudy(const std::string& targetAet,
921 const std::string& studyUid)
922 {
923 DicomMap query;
924 query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid);
925 MoveInternal(targetAet, query);
840 } 926 }
841 927
842 void DicomUserConnection::MoveSeries(const std::string& targetAet, 928 void DicomUserConnection::MoveSeries(const std::string& targetAet,
843 const std::string& studyUid, 929 const std::string& studyUid,
844 const std::string& seriesUid) 930 const std::string& seriesUid)
845 { 931 {
846 DicomMap map; 932 DicomMap query;
847 map.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid); 933 query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid);
848 map.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid); 934 query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid);
849 Move(targetAet, map); 935 MoveInternal(targetAet, query);
850 }
851
852 void DicomUserConnection::MoveInstance(const std::string& targetAet,
853 const DicomMap& findResult)
854 {
855 DicomMap simplified;
856 simplified.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, findResult.GetValue(DICOM_TAG_STUDY_INSTANCE_UID));
857 simplified.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, findResult.GetValue(DICOM_TAG_SERIES_INSTANCE_UID));
858 simplified.SetValue(DICOM_TAG_SOP_INSTANCE_UID, findResult.GetValue(DICOM_TAG_SOP_INSTANCE_UID));
859 Move(targetAet, simplified);
860 } 936 }
861 937
862 void DicomUserConnection::MoveInstance(const std::string& targetAet, 938 void DicomUserConnection::MoveInstance(const std::string& targetAet,
863 const std::string& studyUid, 939 const std::string& studyUid,
864 const std::string& seriesUid, 940 const std::string& seriesUid,
865 const std::string& instanceUid) 941 const std::string& instanceUid)
866 { 942 {
867 DicomMap map; 943 DicomMap query;
868 map.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid); 944 query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid);
869 map.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid); 945 query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid);
870 map.SetValue(DICOM_TAG_SOP_INSTANCE_UID, instanceUid); 946 query.SetValue(DICOM_TAG_SOP_INSTANCE_UID, instanceUid);
871 Move(targetAet, map); 947 MoveInternal(targetAet, query);
872 } 948 }
873 949
874 950
875 void DicomUserConnection::SetTimeout(uint32_t seconds) 951 void DicomUserConnection::SetTimeout(uint32_t seconds)
876 { 952 {