Mercurial > hg > orthanc-stone
comparison Samples/Sdl/Loader.cpp @ 795:bc20e4c417ec
refactoring OrthancMultiframeVolumeLoader using LoaderStateMachine
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 28 May 2019 13:02:56 +0200 |
parents | 04f518ebd132 |
children | d3197e0e321d 98a89b116b62 |
comparison
equal
deleted
inserted
replaced
794:04f518ebd132 | 795:bc20e4c417ec |
---|---|
987 State(LoaderStateMachine& that) : | 987 State(LoaderStateMachine& that) : |
988 that_(that) | 988 that_(that) |
989 { | 989 { |
990 } | 990 } |
991 | 991 |
992 void Schedule(OracleCommandWithPayload* command) | 992 State(const State& currentState) : |
993 that_(currentState.that_) | |
994 { | |
995 } | |
996 | |
997 void Schedule(OracleCommandWithPayload* command) const | |
993 { | 998 { |
994 that_.Schedule(command); | 999 that_.Schedule(command); |
995 } | 1000 } |
1001 | |
1002 template <typename T> | |
1003 T& GetLoader() const | |
1004 { | |
1005 return dynamic_cast<T&>(that_); | |
1006 } | |
996 | 1007 |
997 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const | 1008 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const |
998 { | 1009 { |
999 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); | 1010 throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); |
1000 } | 1011 } |
1011 }; | 1022 }; |
1012 | 1023 |
1013 void Schedule(OracleCommandWithPayload* command) | 1024 void Schedule(OracleCommandWithPayload* command) |
1014 { | 1025 { |
1015 std::auto_ptr<OracleCommandWithPayload> protection(command); | 1026 std::auto_ptr<OracleCommandWithPayload> protection(command); |
1027 | |
1028 if (command == NULL) | |
1029 { | |
1030 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | |
1031 } | |
1016 | 1032 |
1017 if (!command->HasPayload()) | 1033 if (!command->HasPayload()) |
1018 { | 1034 { |
1019 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, | 1035 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange, |
1020 "The payload must contain the next state"); | 1036 "The payload must contain the next state"); |
1021 } | 1037 } |
1022 | 1038 |
1023 pendingCommands_.push_back(protection.release()); | 1039 pendingCommands_.push_back(protection.release()); |
1040 Step(); | |
1024 } | 1041 } |
1025 | 1042 |
1026 void Start() | 1043 void Start() |
1027 { | 1044 { |
1028 if (active_) | 1045 if (active_) |
1029 { | 1046 { |
1030 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 1047 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
1031 } | 1048 } |
1049 | |
1050 active_ = true; | |
1032 | 1051 |
1033 for (size_t i = 0; i < simultaneousDownloads_; i++) | 1052 for (size_t i = 0; i < simultaneousDownloads_; i++) |
1034 { | 1053 { |
1035 Step(); | 1054 Step(); |
1036 } | 1055 } |
1037 } | 1056 } |
1038 | 1057 |
1039 private: | 1058 private: |
1040 void Step() | 1059 void Step() |
1041 { | 1060 { |
1042 if (!pendingCommands_.empty()) | 1061 if (!pendingCommands_.empty() && |
1062 activeCommands_ < simultaneousDownloads_) | |
1043 { | 1063 { |
1044 oracle_.Schedule(*this, pendingCommands_.front()); | 1064 oracle_.Schedule(*this, pendingCommands_.front()); |
1045 pendingCommands_.pop_front(); | 1065 pendingCommands_.pop_front(); |
1046 } | 1066 |
1047 } | 1067 activeCommands_++; |
1048 | 1068 } |
1049 void Handle(const OrthancRestApiCommand::SuccessMessage& message) | 1069 } |
1070 | |
1071 void Clear() | |
1072 { | |
1073 for (PendingCommands::iterator it = pendingCommands_.begin(); | |
1074 it != pendingCommands_.end(); ++it) | |
1075 { | |
1076 delete *it; | |
1077 } | |
1078 } | |
1079 | |
1080 void HandleException(const OracleCommandExceptionMessage& message) | |
1081 { | |
1082 LOG(ERROR) << "Error in the state machine, stopping all processing"; | |
1083 Clear(); | |
1084 } | |
1085 | |
1086 template <typename T> | |
1087 void Handle(const T& message) | |
1050 { | 1088 { |
1051 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message); | 1089 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message); |
1052 Step(); | 1090 activeCommands_--; |
1053 } | |
1054 | |
1055 void Handle(const GetOrthancImageCommand::SuccessMessage& message) | |
1056 { | |
1057 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message); | |
1058 Step(); | |
1059 } | |
1060 | |
1061 void Handle(const GetOrthancWebViewerJpegCommand::SuccessMessage& message) | |
1062 { | |
1063 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message); | |
1064 Step(); | 1091 Step(); |
1065 } | 1092 } |
1066 | 1093 |
1067 typedef std::list<IOracleCommand*> PendingCommands; | 1094 typedef std::list<IOracleCommand*> PendingCommands; |
1068 | 1095 |
1069 IOracle& oracle_; | 1096 IOracle& oracle_; |
1070 bool active_; | 1097 bool active_; |
1071 unsigned int simultaneousDownloads_; | 1098 unsigned int simultaneousDownloads_; |
1072 PendingCommands pendingCommands_; | 1099 PendingCommands pendingCommands_; |
1100 unsigned int activeCommands_; | |
1073 | 1101 |
1074 public: | 1102 public: |
1075 LoaderStateMachine(IOracle& oracle, | 1103 LoaderStateMachine(IOracle& oracle, |
1076 IObservable& oracleObservable) : | 1104 IObservable& oracleObservable) : |
1077 IObserver(oracleObservable.GetBroker()), | 1105 IObserver(oracleObservable.GetBroker()), |
1078 oracle_(oracle), | 1106 oracle_(oracle), |
1079 active_(false), | 1107 active_(false), |
1080 simultaneousDownloads_(4) | 1108 simultaneousDownloads_(4), |
1109 activeCommands_(0) | |
1081 { | 1110 { |
1082 oracleObservable.RegisterObserverCallback( | 1111 oracleObservable.RegisterObserverCallback( |
1083 new Callable<LoaderStateMachine, OrthancRestApiCommand::SuccessMessage> | 1112 new Callable<LoaderStateMachine, OrthancRestApiCommand::SuccessMessage> |
1084 (*this, &LoaderStateMachine::Handle)); | 1113 (*this, &LoaderStateMachine::Handle<OrthancRestApiCommand::SuccessMessage>)); |
1085 | 1114 |
1086 oracleObservable.RegisterObserverCallback( | 1115 oracleObservable.RegisterObserverCallback( |
1087 new Callable<LoaderStateMachine, GetOrthancImageCommand::SuccessMessage> | 1116 new Callable<LoaderStateMachine, GetOrthancImageCommand::SuccessMessage> |
1088 (*this, &LoaderStateMachine::Handle)); | 1117 (*this, &LoaderStateMachine::Handle<GetOrthancImageCommand::SuccessMessage>)); |
1089 | 1118 |
1090 oracleObservable.RegisterObserverCallback( | 1119 oracleObservable.RegisterObserverCallback( |
1091 new Callable<LoaderStateMachine, GetOrthancWebViewerJpegCommand::SuccessMessage> | 1120 new Callable<LoaderStateMachine, GetOrthancWebViewerJpegCommand::SuccessMessage> |
1092 (*this, &LoaderStateMachine::Handle)); | 1121 (*this, &LoaderStateMachine::Handle<GetOrthancWebViewerJpegCommand::SuccessMessage>)); |
1122 | |
1123 oracleObservable.RegisterObserverCallback( | |
1124 new Callable<LoaderStateMachine, OracleCommandExceptionMessage> | |
1125 (*this, &LoaderStateMachine::HandleException)); | |
1093 } | 1126 } |
1094 | 1127 |
1095 virtual ~LoaderStateMachine() | 1128 virtual ~LoaderStateMachine() |
1096 { | 1129 { |
1097 for (PendingCommands::iterator it = pendingCommands_.begin(); | 1130 Clear(); |
1098 it != pendingCommands_.end(); ++it) | 1131 } |
1099 { | 1132 |
1100 delete *it; | 1133 bool IsActive() const |
1101 } | 1134 { |
1102 } | 1135 return active_; |
1103 | 1136 } |
1104 virtual void SetSimultaneousDownloads(unsigned int count) | 1137 |
1138 void SetSimultaneousDownloads(unsigned int count) | |
1105 { | 1139 { |
1106 if (active_) | 1140 if (active_) |
1107 { | 1141 { |
1108 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 1142 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); |
1109 } | 1143 } |
1119 }; | 1153 }; |
1120 | 1154 |
1121 | 1155 |
1122 | 1156 |
1123 class OrthancMultiframeVolumeLoader : | 1157 class OrthancMultiframeVolumeLoader : |
1124 public IObserver, | 1158 public LoaderStateMachine, |
1125 public IObservable | 1159 public IObservable |
1126 { | 1160 { |
1127 private: | 1161 private: |
1128 class State : public Orthanc::IDynamicObject | |
1129 { | |
1130 private: | |
1131 OrthancMultiframeVolumeLoader& that_; | |
1132 | |
1133 protected: | |
1134 void Schedule(OrthancRestApiCommand* command) const | |
1135 { | |
1136 that_.oracle_.Schedule(that_, command); | |
1137 } | |
1138 | |
1139 OrthancMultiframeVolumeLoader& GetTarget() const | |
1140 { | |
1141 return that_; | |
1142 } | |
1143 | |
1144 public: | |
1145 State(OrthancMultiframeVolumeLoader& that) : | |
1146 that_(that) | |
1147 { | |
1148 } | |
1149 | |
1150 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const = 0; | |
1151 }; | |
1152 | |
1153 void Handle(const OrthancRestApiCommand::SuccessMessage& message) | |
1154 { | |
1155 dynamic_cast<const State&>(message.GetOrigin().GetPayload()).Handle(message); | |
1156 } | |
1157 | |
1158 | |
1159 class LoadRTDoseGeometry : public State | 1162 class LoadRTDoseGeometry : public State |
1160 { | 1163 { |
1161 private: | 1164 private: |
1162 std::auto_ptr<Orthanc::DicomMap> dicom_; | 1165 std::auto_ptr<Orthanc::DicomMap> dicom_; |
1163 | 1166 |
1169 { | 1172 { |
1170 if (dicom == NULL) | 1173 if (dicom == NULL) |
1171 { | 1174 { |
1172 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 1175 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
1173 } | 1176 } |
1177 | |
1174 } | 1178 } |
1175 | 1179 |
1176 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const | 1180 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const |
1177 { | 1181 { |
1178 // Complete the DICOM tags with just-received "Grid Frame Offset Vector" | 1182 // Complete the DICOM tags with just-received "Grid Frame Offset Vector" |
1179 std::string s = Orthanc::Toolbox::StripSpaces(message.GetAnswer()); | 1183 std::string s = Orthanc::Toolbox::StripSpaces(message.GetAnswer()); |
1180 dicom_->SetValue(Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, s, false); | 1184 dicom_->SetValue(Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR, s, false); |
1181 | 1185 |
1182 GetTarget().SetGeometry(*dicom_); | 1186 GetLoader<OrthancMultiframeVolumeLoader>().SetGeometry(*dicom_); |
1183 } | 1187 } |
1184 }; | 1188 }; |
1185 | 1189 |
1186 | 1190 |
1187 static std::string GetSopClassUid(const Orthanc::DicomMap& dicom) | 1191 static std::string GetSopClassUid(const Orthanc::DicomMap& dicom) |
1207 { | 1211 { |
1208 } | 1212 } |
1209 | 1213 |
1210 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const | 1214 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const |
1211 { | 1215 { |
1216 OrthancMultiframeVolumeLoader& loader = GetLoader<OrthancMultiframeVolumeLoader>(); | |
1217 | |
1212 Json::Value body; | 1218 Json::Value body; |
1213 message.ParseJsonBody(body); | 1219 message.ParseJsonBody(body); |
1214 | 1220 |
1215 if (body.type() != Json::objectValue) | 1221 if (body.type() != Json::objectValue) |
1216 { | 1222 { |
1224 { | 1230 { |
1225 // Download the "Grid Frame Offset Vector" DICOM tag, that is | 1231 // Download the "Grid Frame Offset Vector" DICOM tag, that is |
1226 // mandatory for RT-DOSE, but is too long to be returned by default | 1232 // mandatory for RT-DOSE, but is too long to be returned by default |
1227 | 1233 |
1228 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 1234 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
1229 command->SetUri("/instances/" + GetTarget().GetInstanceId() + "/content/" + | 1235 command->SetUri("/instances/" + loader.GetInstanceId() + "/content/" + |
1230 Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR.Format()); | 1236 Orthanc::DICOM_TAG_GRID_FRAME_OFFSET_VECTOR.Format()); |
1231 command->SetPayload(new LoadRTDoseGeometry(GetTarget(), dicom.release())); | 1237 command->SetPayload(new LoadRTDoseGeometry(loader, dicom.release())); |
1232 | 1238 |
1233 Schedule(command.release()); | 1239 Schedule(command.release()); |
1234 } | 1240 } |
1235 else | 1241 else |
1236 { | 1242 { |
1237 GetTarget().SetGeometry(*dicom); | 1243 loader.SetGeometry(*dicom); |
1238 } | 1244 } |
1239 } | 1245 } |
1240 }; | 1246 }; |
1241 | 1247 |
1242 | 1248 |
1249 { | 1255 { |
1250 } | 1256 } |
1251 | 1257 |
1252 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const | 1258 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const |
1253 { | 1259 { |
1254 GetTarget().SetTransferSyntax(message.GetAnswer()); | 1260 GetLoader<OrthancMultiframeVolumeLoader>().SetTransferSyntax(message.GetAnswer()); |
1255 } | 1261 } |
1256 }; | 1262 }; |
1257 | 1263 |
1258 | 1264 |
1259 class LoadUncompressedPixelData : public State | 1265 class LoadUncompressedPixelData : public State |
1264 { | 1270 { |
1265 } | 1271 } |
1266 | 1272 |
1267 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const | 1273 virtual void Handle(const OrthancRestApiCommand::SuccessMessage& message) const |
1268 { | 1274 { |
1269 GetTarget().SetUncompressedPixelData(message.GetAnswer()); | 1275 GetLoader<OrthancMultiframeVolumeLoader>().SetUncompressedPixelData(message.GetAnswer()); |
1270 } | 1276 } |
1271 }; | 1277 }; |
1272 | 1278 |
1273 | 1279 |
1274 | 1280 |
1275 boost::shared_ptr<DicomVolumeImage> volume_; | 1281 boost::shared_ptr<DicomVolumeImage> volume_; |
1276 IOracle& oracle_; | |
1277 bool active_; | |
1278 std::string instanceId_; | 1282 std::string instanceId_; |
1279 std::string transferSyntaxUid_; | 1283 std::string transferSyntaxUid_; |
1280 | 1284 |
1281 | 1285 |
1282 const std::string& GetInstanceId() const | 1286 const std::string& GetInstanceId() const |
1283 { | 1287 { |
1284 if (active_) | 1288 if (IsActive()) |
1285 { | 1289 { |
1286 return instanceId_; | 1290 return instanceId_; |
1287 } | 1291 } |
1288 else | 1292 else |
1289 { | 1293 { |
1307 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 1311 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
1308 command->SetHttpHeader("Accept-Encoding", "gzip"); | 1312 command->SetHttpHeader("Accept-Encoding", "gzip"); |
1309 command->SetUri("/instances/" + instanceId_ + "/content/" + | 1313 command->SetUri("/instances/" + instanceId_ + "/content/" + |
1310 Orthanc::DICOM_TAG_PIXEL_DATA.Format() + "/0"); | 1314 Orthanc::DICOM_TAG_PIXEL_DATA.Format() + "/0"); |
1311 command->SetPayload(new LoadUncompressedPixelData(*this)); | 1315 command->SetPayload(new LoadUncompressedPixelData(*this)); |
1312 oracle_.Schedule(*this, command.release()); | 1316 Schedule(command.release()); |
1313 } | 1317 } |
1314 else | 1318 else |
1315 { | 1319 { |
1316 throw Orthanc::OrthancException( | 1320 throw Orthanc::OrthancException( |
1317 Orthanc::ErrorCode_NotImplemented, | 1321 Orthanc::ErrorCode_NotImplemented, |
1449 | 1453 |
1450 public: | 1454 public: |
1451 OrthancMultiframeVolumeLoader(const boost::shared_ptr<DicomVolumeImage>& volume, | 1455 OrthancMultiframeVolumeLoader(const boost::shared_ptr<DicomVolumeImage>& volume, |
1452 IOracle& oracle, | 1456 IOracle& oracle, |
1453 IObservable& oracleObservable) : | 1457 IObservable& oracleObservable) : |
1454 IObserver(oracleObservable.GetBroker()), | 1458 LoaderStateMachine(oracle, oracleObservable), |
1455 IObservable(oracleObservable.GetBroker()), | 1459 IObservable(oracleObservable.GetBroker()), |
1456 volume_(volume), | 1460 volume_(volume) |
1457 oracle_(oracle), | |
1458 active_(false) | |
1459 { | 1461 { |
1460 if (volume.get() == NULL) | 1462 if (volume.get() == NULL) |
1461 { | 1463 { |
1462 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); | 1464 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
1463 } | 1465 } |
1464 | |
1465 oracleObservable.RegisterObserverCallback( | |
1466 new Callable<OrthancMultiframeVolumeLoader, OrthancRestApiCommand::SuccessMessage> | |
1467 (*this, &OrthancMultiframeVolumeLoader::Handle)); | |
1468 } | 1466 } |
1469 | 1467 |
1470 | 1468 |
1471 void LoadInstance(const std::string& instanceId) | 1469 void LoadInstance(const std::string& instanceId) |
1472 { | 1470 { |
1473 if (active_) | 1471 Start(); |
1474 { | 1472 |
1475 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | 1473 instanceId_ = instanceId; |
1476 } | 1474 |
1477 else | 1475 { |
1478 { | 1476 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
1479 active_ = true; | 1477 command->SetHttpHeader("Accept-Encoding", "gzip"); |
1480 instanceId_ = instanceId; | 1478 command->SetUri("/instances/" + instanceId + "/tags"); |
1481 | 1479 command->SetPayload(new LoadGeometry(*this)); |
1482 { | 1480 Schedule(command.release()); |
1483 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | 1481 } |
1484 command->SetHttpHeader("Accept-Encoding", "gzip"); | 1482 |
1485 command->SetUri("/instances/" + instanceId + "/tags"); | 1483 { |
1486 command->SetPayload(new LoadGeometry(*this)); | 1484 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); |
1487 oracle_.Schedule(*this, command.release()); | 1485 command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax"); |
1488 } | 1486 command->SetPayload(new LoadTransferSyntax(*this)); |
1489 | 1487 Schedule(command.release()); |
1490 { | |
1491 std::auto_ptr<OrthancRestApiCommand> command(new OrthancRestApiCommand); | |
1492 command->SetUri("/instances/" + instanceId + "/metadata/TransferSyntax"); | |
1493 command->SetPayload(new LoadTransferSyntax(*this)); | |
1494 oracle_.Schedule(*this, command.release()); | |
1495 } | |
1496 } | 1488 } |
1497 } | 1489 } |
1498 }; | 1490 }; |
1499 | 1491 |
1500 | 1492 |
2026 void Handle(const OrthancStone::DicomVolumeImage::GeometryReadyMessage& message) | 2018 void Handle(const OrthancStone::DicomVolumeImage::GeometryReadyMessage& message) |
2027 { | 2019 { |
2028 printf("Geometry ready\n"); | 2020 printf("Geometry ready\n"); |
2029 | 2021 |
2030 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry(); | 2022 //plane_ = message.GetOrigin().GetGeometry().GetSagittalGeometry(); |
2031 plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry(); | 2023 //plane_ = message.GetOrigin().GetGeometry().GetAxialGeometry(); |
2032 //plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry(); | 2024 plane_ = message.GetOrigin().GetGeometry().GetCoronalGeometry(); |
2033 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); | 2025 plane_.SetOrigin(message.GetOrigin().GetGeometry().GetCoordinates(0.5f, 0.5f, 0.5f)); |
2034 | 2026 |
2035 Refresh(); | 2027 Refresh(); |
2036 } | 2028 } |
2037 | 2029 |
2284 | 2276 |
2285 | 2277 |
2286 // 2017-11-17-Anonymized | 2278 // 2017-11-17-Anonymized |
2287 //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT | 2279 //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT |
2288 doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE | 2280 doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE |
2289 rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT | 2281 //rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT |
2290 | 2282 |
2291 // 2015-01-28-Multiframe | 2283 // 2015-01-28-Multiframe |
2292 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT | 2284 //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT |
2293 | 2285 |
2294 // Delphine | 2286 // Delphine |