Mercurial > hg > orthanc
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 { |