Mercurial > hg > orthanc-stl
comparison Sources/Plugin.cpp @ 7:e3e59de705f6
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 18 Jul 2023 15:10:21 +0200 |
parents | c02d12eb34d4 |
children | d1267c6c33e1 |
comparison
equal
deleted
inserted
replaced
6:c02d12eb34d4 | 7:e3e59de705f6 |
---|---|
1014 buffer.Flatten(target); | 1014 buffer.Flatten(target); |
1015 } | 1015 } |
1016 | 1016 |
1017 | 1017 |
1018 bool EncodeStructureSetMesh(std::string& stl, | 1018 bool EncodeStructureSetMesh(std::string& stl, |
1019 const StructureSet& structureSet, | 1019 vtkImageData* volume, |
1020 const std::set<std::string>& roiNames, | |
1021 unsigned int resolution, | 1020 unsigned int resolution, |
1022 bool smooth) | 1021 bool smooth) |
1023 { | 1022 { |
1024 if (!structureSet.HasGeometry()) | 1023 if (volume == NULL) |
1025 { | 1024 { |
1026 return false; | 1025 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); |
1027 } | |
1028 | |
1029 if (resolution < 1) | |
1030 { | |
1031 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
1032 } | |
1033 | |
1034 if (!IsNear(1, structureSet.GetSlicesNormal().ComputeNorm())) | |
1035 { | |
1036 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1037 } | |
1038 | |
1039 // TODO - Axes could be retrieved from the referenced CT volume | |
1040 Vector3D axisX(1, 0, 0); | |
1041 Vector3D axisY = Vector3D::CrossProduct(structureSet.GetSlicesNormal(), axisX); | |
1042 | |
1043 if (!IsNear(1, axisX.ComputeNorm()) || | |
1044 !IsNear(1, axisY.ComputeNorm())) | |
1045 { | |
1046 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1047 } | |
1048 | |
1049 Extent2D extent; | |
1050 for (size_t i = 0; i < structureSet.GetPolygonsCount(); i++) | |
1051 { | |
1052 structureSet.GetPolygon(i).Add(extent, axisX, axisY); | |
1053 } | |
1054 | |
1055 const int depth = structureSet.GetSlicesCount(); | |
1056 | |
1057 vtkNew<vtkImageData> volume; | |
1058 volume->SetDimensions(resolution, resolution, depth); | |
1059 volume->AllocateScalars(VTK_UNSIGNED_CHAR, 1); | |
1060 | |
1061 assert(sizeof(unsigned char) == 1); | |
1062 memset(volume->GetScalarPointer(), 0, resolution * resolution * depth); | |
1063 | |
1064 for (size_t i = 0; i < structureSet.GetPolygonsCount(); i++) | |
1065 { | |
1066 const StructurePolygon& polygon = structureSet.GetPolygon(i); | |
1067 if (roiNames.find(polygon.GetRoiName()) == roiNames.end()) | |
1068 { | |
1069 // This polygon doesn't correspond to a ROI of interest | |
1070 continue; | |
1071 } | |
1072 | |
1073 size_t j; | |
1074 if (!structureSet.LookupSliceIndex(j, polygon)) | |
1075 { | |
1076 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1077 } | |
1078 | |
1079 std::vector<Orthanc::ImageProcessing::ImagePoint> points; | |
1080 points.reserve(polygon.GetPointsCount()); | |
1081 for (size_t j = 0; j < polygon.GetPointsCount(); j++) | |
1082 { | |
1083 const Vector3D& point = polygon.GetPoint(j); | |
1084 double x = (Vector3D::DotProduct(point, axisX) - extent.GetMinX()) / extent.GetWidth() * static_cast<double>(resolution); | |
1085 double y = (Vector3D::DotProduct(point, axisY) - extent.GetMinY()) / extent.GetHeight() * static_cast<double>(resolution); | |
1086 points.push_back(Orthanc::ImageProcessing::ImagePoint(static_cast<int32_t>(std::floor(x)), | |
1087 static_cast<int32_t>(std::floor(y)))); | |
1088 } | |
1089 | |
1090 Orthanc::ImageAccessor slice; | |
1091 slice.AssignWritable(Orthanc::PixelFormat_Grayscale8, resolution, resolution, resolution /* pitch */, | |
1092 reinterpret_cast<uint8_t*>(volume->GetScalarPointer()) + j * resolution * resolution); | |
1093 | |
1094 XorFiller filler(slice); | |
1095 Orthanc::ImageProcessing::FillPolygon(filler, points); | |
1096 } | 1026 } |
1097 | 1027 |
1098 vtkNew<vtkImageResize> resize; | 1028 vtkNew<vtkImageResize> resize; |
1099 resize->SetOutputDimensions(resolution, resolution, resolution); | 1029 resize->SetOutputDimensions(resolution, resolution, resolution); |
1100 resize->SetInputData(volume.Get()); | 1030 resize->SetInputData(volume); |
1101 resize->Update(); | 1031 resize->Update(); |
1102 | |
1103 resize->GetOutput()->SetSpacing( | |
1104 extent.GetWidth() / static_cast<double>(resolution), | |
1105 extent.GetHeight() / static_cast<double>(resolution), | |
1106 (structureSet.GetMaxProjectionAlongNormal() - structureSet.GetMinProjectionAlongNormal()) / static_cast<double>(resolution)); | |
1107 | |
1108 // TODO | |
1109 // resize->GetOutput()->SetOrigin() | |
1110 | 1032 |
1111 vtkNew<vtkImageConstantPad> padding; | 1033 vtkNew<vtkImageConstantPad> padding; |
1112 padding->SetConstant(0); | 1034 padding->SetConstant(0); |
1113 padding->SetOutputNumberOfScalarComponents(1); | 1035 padding->SetOutputNumberOfScalarComponents(1); |
1114 padding->SetOutputWholeExtent(-1, resolution, -1, resolution, -1, resolution); | 1036 padding->SetOutputWholeExtent(-1, resolution, -1, resolution, -1, resolution); |
1153 | 1075 |
1154 return true; | 1076 return true; |
1155 } | 1077 } |
1156 | 1078 |
1157 | 1079 |
1080 bool EncodeStructureSetMesh(std::string& stl, | |
1081 const StructureSet& structureSet, | |
1082 const std::set<std::string>& roiNames, | |
1083 unsigned int resolution, | |
1084 bool smooth) | |
1085 { | |
1086 if (!structureSet.HasGeometry()) | |
1087 { | |
1088 return false; | |
1089 } | |
1090 | |
1091 if (resolution < 1) | |
1092 { | |
1093 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
1094 } | |
1095 | |
1096 if (!IsNear(1, structureSet.GetSlicesNormal().ComputeNorm())) | |
1097 { | |
1098 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1099 } | |
1100 | |
1101 // TODO - Axes could be retrieved from the referenced CT volume | |
1102 Vector3D axisX(1, 0, 0); | |
1103 Vector3D axisY = Vector3D::CrossProduct(structureSet.GetSlicesNormal(), axisX); | |
1104 | |
1105 if (!IsNear(1, axisX.ComputeNorm()) || | |
1106 !IsNear(1, axisY.ComputeNorm())) | |
1107 { | |
1108 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1109 } | |
1110 | |
1111 Extent2D extent; | |
1112 for (size_t i = 0; i < structureSet.GetPolygonsCount(); i++) | |
1113 { | |
1114 structureSet.GetPolygon(i).Add(extent, axisX, axisY); | |
1115 } | |
1116 | |
1117 const int depth = structureSet.GetSlicesCount(); | |
1118 | |
1119 vtkNew<vtkImageData> volume; | |
1120 volume->SetDimensions(resolution, resolution, depth); | |
1121 volume->AllocateScalars(VTK_UNSIGNED_CHAR, 1); | |
1122 | |
1123 assert(sizeof(unsigned char) == 1); | |
1124 memset(volume->GetScalarPointer(), 0, resolution * resolution * depth); | |
1125 | |
1126 for (size_t i = 0; i < structureSet.GetPolygonsCount(); i++) | |
1127 { | |
1128 const StructurePolygon& polygon = structureSet.GetPolygon(i); | |
1129 if (roiNames.find(polygon.GetRoiName()) == roiNames.end()) | |
1130 { | |
1131 // This polygon doesn't correspond to a ROI of interest | |
1132 continue; | |
1133 } | |
1134 | |
1135 size_t j; | |
1136 if (!structureSet.LookupSliceIndex(j, polygon)) | |
1137 { | |
1138 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); | |
1139 } | |
1140 | |
1141 std::vector<Orthanc::ImageProcessing::ImagePoint> points; | |
1142 points.reserve(polygon.GetPointsCount()); | |
1143 for (size_t j = 0; j < polygon.GetPointsCount(); j++) | |
1144 { | |
1145 const Vector3D& point = polygon.GetPoint(j); | |
1146 double x = (Vector3D::DotProduct(point, axisX) - extent.GetMinX()) / extent.GetWidth() * static_cast<double>(resolution); | |
1147 double y = (Vector3D::DotProduct(point, axisY) - extent.GetMinY()) / extent.GetHeight() * static_cast<double>(resolution); | |
1148 points.push_back(Orthanc::ImageProcessing::ImagePoint(static_cast<int32_t>(std::floor(x)), | |
1149 static_cast<int32_t>(std::floor(y)))); | |
1150 } | |
1151 | |
1152 Orthanc::ImageAccessor slice; | |
1153 slice.AssignWritable(Orthanc::PixelFormat_Grayscale8, resolution, resolution, resolution /* pitch */, | |
1154 reinterpret_cast<uint8_t*>(volume->GetScalarPointer()) + j * resolution * resolution); | |
1155 | |
1156 XorFiller filler(slice); | |
1157 Orthanc::ImageProcessing::FillPolygon(filler, points); | |
1158 } | |
1159 | |
1160 volume->SetSpacing( | |
1161 extent.GetWidth() / static_cast<double>(resolution), | |
1162 extent.GetHeight() / static_cast<double>(resolution), | |
1163 (structureSet.GetMaxProjectionAlongNormal() - structureSet.GetMinProjectionAlongNormal()) / static_cast<double>(depth)); | |
1164 | |
1165 // TODO | |
1166 // volume->SetOrigin() | |
1167 | |
1168 return EncodeStructureSetMesh(stl, volume.Get(), resolution, smooth); | |
1169 } | |
1170 | |
1171 | |
1158 static Orthanc::ParsedDicomFile* LoadInstance(const std::string& instanceId) | 1172 static Orthanc::ParsedDicomFile* LoadInstance(const std::string& instanceId) |
1159 { | 1173 { |
1160 std::string dicom; | 1174 std::string dicom; |
1161 | 1175 |
1162 if (!OrthancPlugins::RestApiGetString(dicom, "/instances/" + instanceId + "/file", false)) | 1176 if (!OrthancPlugins::RestApiGetString(dicom, "/instances/" + instanceId + "/file", false)) |
1216 { | 1230 { |
1217 AddDefaultTagValue(target, Orthanc::DicomTag(tag.getGroup(), tag.getElement()), value); | 1231 AddDefaultTagValue(target, Orthanc::DicomTag(tag.getGroup(), tag.getElement()), value); |
1218 } | 1232 } |
1219 | 1233 |
1220 | 1234 |
1221 void Encode(OrthancPluginRestOutput* output, | 1235 static void CallCreateDicom(Json::Value& answer, |
1222 const char* url, | 1236 const std::string& stl, |
1223 const OrthancPluginHttpRequest* request) | 1237 const Json::Value& body, |
1238 const std::string& parentStudy, | |
1239 const std::string& defaultSeriesDescription, | |
1240 const std::string& defaultFrameOfReferenceUid, | |
1241 const std::string& defaultTitle) | |
1242 { | |
1243 static const char* const KEY_TAGS = "Tags"; | |
1244 | |
1245 Json::Value normalized = Json::objectValue; | |
1246 | |
1247 if (body.isMember(KEY_TAGS)) | |
1248 { | |
1249 const Json::Value& tags = body[KEY_TAGS]; | |
1250 | |
1251 if (tags.type() != Json::objectValue) | |
1252 { | |
1253 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest, "Tags must be provided as a JSON object"); | |
1254 } | |
1255 | |
1256 std::vector<std::string> keys = tags.getMemberNames(); | |
1257 for (size_t i = 0; i < keys.size(); i++) | |
1258 { | |
1259 const Orthanc::DicomTag tag = Orthanc::FromDcmtkBridge::ParseTag(keys[i]); | |
1260 normalized[tag.Format()] = tags[keys[i]]; | |
1261 } | |
1262 } | |
1263 | |
1264 if (!normalized.isMember(Orthanc::DICOM_TAG_SERIES_DESCRIPTION.Format())) | |
1265 { | |
1266 normalized[Orthanc::DICOM_TAG_SERIES_DESCRIPTION.Format()] = defaultSeriesDescription; | |
1267 } | |
1268 | |
1269 AddDefaultTagValue(normalized, Orthanc::DICOM_TAG_SERIES_NUMBER, "1"); | |
1270 AddDefaultTagValue(normalized, Orthanc::DICOM_TAG_FRAME_OF_REFERENCE_UID, defaultFrameOfReferenceUid); | |
1271 AddDefaultTagValue(normalized, Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1"); | |
1272 | |
1273 AddDefaultTagValue(normalized, DCM_BurnedInAnnotation, "NO"); | |
1274 AddDefaultTagValue(normalized, DCM_DeviceSerialNumber, ORTHANC_STL_VERSION); | |
1275 AddDefaultTagValue(normalized, DCM_DocumentTitle, defaultTitle); | |
1276 AddDefaultTagValue(normalized, DCM_Manufacturer, "Orthanc STL plugin"); | |
1277 AddDefaultTagValue(normalized, DCM_ManufacturerModelName, "Orthanc STL plugin"); | |
1278 AddDefaultTagValue(normalized, DCM_PositionReferenceIndicator, ""); | |
1279 AddDefaultTagValue(normalized, DCM_SoftwareVersions, ORTHANC_STL_VERSION); | |
1280 AddDefaultTagValue(normalized, DCM_ConceptNameCodeSequence, ""); | |
1281 | |
1282 std::string date, time; | |
1283 Orthanc::SystemToolbox::GetNowDicom(date, time, true /* use UTC time (not local time) */); | |
1284 AddDefaultTagValue(normalized, DCM_AcquisitionDateTime, date + time); | |
1285 | |
1286 const Orthanc::DicomTag MEASUREMENT_UNITS_CODE_SEQUENCE(DCM_MeasurementUnitsCodeSequence.getGroup(), | |
1287 DCM_MeasurementUnitsCodeSequence.getElement()); | |
1288 | |
1289 if (!normalized.isMember(MEASUREMENT_UNITS_CODE_SEQUENCE.Format())) | |
1290 { | |
1291 Json::Value item; | |
1292 item["CodeValue"] = "mm"; | |
1293 item["CodingSchemeDesignator"] = "UCUM"; | |
1294 item["CodeMeaning"] = defaultTitle; | |
1295 | |
1296 normalized[MEASUREMENT_UNITS_CODE_SEQUENCE.Format()].append(item); | |
1297 } | |
1298 | |
1299 std::string content; | |
1300 Orthanc::Toolbox::EncodeDataUriScheme(content, Orthanc::MIME_STL, stl); | |
1301 | |
1302 Json::Value create; | |
1303 create["Content"] = content; | |
1304 create["Parent"] = parentStudy; | |
1305 create["Tags"] = normalized; | |
1306 | |
1307 if (!OrthancPlugins::RestApiPost(answer, "/tools/create-dicom", create.toStyledString(), false)) | |
1308 { | |
1309 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest, "Cannot create DICOM from STL"); | |
1310 } | |
1311 } | |
1312 | |
1313 | |
1314 void EncodeStructureSet(OrthancPluginRestOutput* output, | |
1315 const char* url, | |
1316 const OrthancPluginHttpRequest* request) | |
1224 { | 1317 { |
1225 static const char* const KEY_INSTANCE = "Instance"; | 1318 static const char* const KEY_INSTANCE = "Instance"; |
1226 static const char* const KEY_RESOLUTION = "Resolution"; | 1319 static const char* const KEY_RESOLUTION = "Resolution"; |
1227 static const char* const KEY_ROI_NAMES = "RoiNames"; | 1320 static const char* const KEY_ROI_NAMES = "RoiNames"; |
1228 static const char* const KEY_SMOOTH = "Smooth"; | 1321 static const char* const KEY_SMOOTH = "Smooth"; |
1229 static const char* const KEY_TAGS = "Tags"; | |
1230 | 1322 |
1231 if (request->method != OrthancPluginHttpMethod_Post) | 1323 if (request->method != OrthancPluginHttpMethod_Post) |
1232 { | 1324 { |
1233 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "POST"); | 1325 OrthancPluginSendMethodNotAllowed(OrthancPlugins::GetGlobalContext(), output, "POST"); |
1234 return; | 1326 return; |
1260 { | 1352 { |
1261 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot encode STL"); | 1353 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat, "Cannot encode STL"); |
1262 } | 1354 } |
1263 else | 1355 else |
1264 { | 1356 { |
1265 std::string content; | 1357 std::string seriesDescription; |
1266 Orthanc::Toolbox::EncodeDataUriScheme(content, "model/stl", stl); | 1358 |
1267 | 1359 if (dicom->GetTagValue(seriesDescription, Orthanc::DICOM_TAG_SERIES_DESCRIPTION)) |
1268 Json::Value normalized = Json::objectValue; | 1360 { |
1269 | 1361 seriesDescription += ": "; |
1270 if (body.isMember(KEY_TAGS)) | 1362 } |
1271 { | 1363 else |
1272 const Json::Value& tags = body[KEY_TAGS]; | 1364 { |
1273 if (tags.type() != Json::objectValue) | 1365 seriesDescription.clear(); |
1274 { | 1366 } |
1275 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest, "Tags must be provided as a JSON object"); | 1367 |
1276 } | 1368 bool first = true; |
1277 | 1369 for (std::set<std::string>::const_iterator it = roiNames.begin(); it != roiNames.end(); ++it) |
1278 std::vector<std::string> keys = tags.getMemberNames(); | 1370 { |
1279 for (size_t i = 0; i < keys.size(); i++) | 1371 if (first) |
1280 { | 1372 { |
1281 const Orthanc::DicomTag tag = Orthanc::FromDcmtkBridge::ParseTag(keys[i]); | 1373 first = false; |
1282 normalized[tag.Format()] = tags[keys[i]]; | |
1283 } | |
1284 } | |
1285 | |
1286 if (!normalized.isMember(Orthanc::DICOM_TAG_SERIES_DESCRIPTION.Format())) | |
1287 { | |
1288 std::string description; | |
1289 | |
1290 if (dicom->GetTagValue(description, Orthanc::DICOM_TAG_SERIES_DESCRIPTION)) | |
1291 { | |
1292 description += ": "; | |
1293 } | 1374 } |
1294 else | 1375 else |
1295 { | 1376 { |
1296 description.clear(); | 1377 seriesDescription += ", "; |
1297 } | 1378 } |
1298 | 1379 |
1299 bool first = true; | 1380 seriesDescription += *it; |
1300 for (std::set<std::string>::const_iterator it = roiNames.begin(); it != roiNames.end(); ++it) | 1381 } |
1301 { | 1382 |
1302 if (first) | 1383 std::string frameOfReferenceUid; |
1303 { | |
1304 first = false; | |
1305 } | |
1306 else | |
1307 { | |
1308 description += ", "; | |
1309 } | |
1310 | |
1311 description += *it; | |
1312 } | |
1313 | |
1314 normalized[Orthanc::DICOM_TAG_SERIES_DESCRIPTION.Format()] = description; | |
1315 } | |
1316 | |
1317 AddDefaultTagValue(normalized, Orthanc::DICOM_TAG_SERIES_NUMBER, "1"); | |
1318 | |
1319 std::string s; | |
1320 if (structureSet.HasFrameOfReferenceUid()) | 1384 if (structureSet.HasFrameOfReferenceUid()) |
1321 { | 1385 { |
1322 s = structureSet.GetFrameOfReferenceUid(); | 1386 frameOfReferenceUid = structureSet.GetFrameOfReferenceUid(); |
1323 } | 1387 } |
1324 else | 1388 else |
1325 { | 1389 { |
1326 s = Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Instance); | 1390 frameOfReferenceUid = Orthanc::FromDcmtkBridge::GenerateUniqueIdentifier(Orthanc::ResourceType_Instance); |
1327 } | 1391 } |
1328 | |
1329 AddDefaultTagValue(normalized, Orthanc::DICOM_TAG_FRAME_OF_REFERENCE_UID, s); | |
1330 AddDefaultTagValue(normalized, Orthanc::DICOM_TAG_INSTANCE_NUMBER, "1"); | |
1331 | |
1332 const std::string title = "STL model generated from DICOM RT-STRUCT"; | |
1333 | |
1334 AddDefaultTagValue(normalized, DCM_BurnedInAnnotation, "NO"); | |
1335 AddDefaultTagValue(normalized, DCM_DeviceSerialNumber, ORTHANC_STL_VERSION); | |
1336 AddDefaultTagValue(normalized, DCM_DocumentTitle, title); | |
1337 AddDefaultTagValue(normalized, DCM_Manufacturer, "Orthanc STL plugin"); | |
1338 AddDefaultTagValue(normalized, DCM_ManufacturerModelName, "Orthanc STL plugin"); | |
1339 AddDefaultTagValue(normalized, DCM_PositionReferenceIndicator, ""); | |
1340 AddDefaultTagValue(normalized, DCM_SoftwareVersions, ORTHANC_STL_VERSION); | |
1341 AddDefaultTagValue(normalized, DCM_ConceptNameCodeSequence, ""); | |
1342 | |
1343 std::string date, time; | |
1344 Orthanc::SystemToolbox::GetNowDicom(date, time, true /* use UTC time (not local time) */); | |
1345 AddDefaultTagValue(normalized, DCM_AcquisitionDateTime, date + time); | |
1346 | |
1347 const Orthanc::DicomTag MEASUREMENT_UNITS_CODE_SEQUENCE(DCM_MeasurementUnitsCodeSequence.getGroup(), | |
1348 DCM_MeasurementUnitsCodeSequence.getElement()); | |
1349 | |
1350 if (!normalized.isMember(MEASUREMENT_UNITS_CODE_SEQUENCE.Format())) | |
1351 { | |
1352 Json::Value item; | |
1353 item["CodeValue"] = "mm"; | |
1354 item["CodingSchemeDesignator"] = "UCUM"; | |
1355 item["CodeMeaning"] = title; | |
1356 | |
1357 normalized[MEASUREMENT_UNITS_CODE_SEQUENCE.Format()].append(item); | |
1358 } | |
1359 | |
1360 Json::Value create; | |
1361 create["Content"] = content; | |
1362 create["Parent"] = structureSet.HashStudy(); | |
1363 create["Tags"] = normalized; | |
1364 | 1392 |
1365 Json::Value answer; | 1393 Json::Value answer; |
1366 if (OrthancPlugins::RestApiPost(answer, "/tools/create-dicom", create.toStyledString(), false)) | 1394 CallCreateDicom(answer, stl, body, structureSet.HashStudy(), seriesDescription, |
1367 { | 1395 frameOfReferenceUid, "STL model generated from DICOM RT-STRUCT"); |
1368 std::string s = answer.toStyledString(); | 1396 |
1369 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), Orthanc::MIME_JSON); | 1397 std::string s = answer.toStyledString(); |
1370 } | 1398 OrthancPluginAnswerBuffer(OrthancPlugins::GetGlobalContext(), output, s.c_str(), s.size(), Orthanc::MIME_JSON); |
1371 else | |
1372 { | |
1373 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadRequest, "Cannot create DICOM from STL"); | |
1374 } | |
1375 } | 1399 } |
1376 } | 1400 } |
1377 | 1401 |
1378 | 1402 |
1379 void ExtractStl(OrthancPluginRestOutput* output, | 1403 void ExtractStl(OrthancPluginRestOutput* output, |
1536 OrthancPlugins::RegisterRestCallback<ExtractStl>("/instances/([0-9a-f-]+)/stl", true); | 1560 OrthancPlugins::RegisterRestCallback<ExtractStl>("/instances/([0-9a-f-]+)/stl", true); |
1537 OrthancPlugins::RegisterRestCallback<ListStructures>("/stl/rt-struct/([0-9a-f-]+)", true); | 1561 OrthancPlugins::RegisterRestCallback<ListStructures>("/stl/rt-struct/([0-9a-f-]+)", true); |
1538 | 1562 |
1539 if (hasCreateDicomStl_) | 1563 if (hasCreateDicomStl_) |
1540 { | 1564 { |
1541 OrthancPlugins::RegisterRestCallback<Encode>("/stl/encode", true); | 1565 OrthancPlugins::RegisterRestCallback<EncodeStructureSet>("/stl/encode", true); |
1542 } | 1566 } |
1543 | 1567 |
1544 // Extend the default Orthanc Explorer with custom JavaScript for STL | 1568 // Extend the default Orthanc Explorer with custom JavaScript for STL |
1545 std::string explorer; | 1569 std::string explorer; |
1546 | 1570 |