Mercurial > hg > orthanc-stone
changeset 32:517c46f527cd
sync
line wrap: on
line diff
--- a/Framework/Layers/FrameRenderer.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Layers/FrameRenderer.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -226,7 +226,7 @@ ILayerRenderer* FrameRenderer::CreateRenderer(Orthanc::ImageAccessor* frame, const SliceGeometry& viewportSlice, const SliceGeometry& frameSlice, - const DicomDataset& dicom, + const OrthancPlugins::IDicomDataset& dicom, double pixelSpacingX, double pixelSpacingY, bool isFullQuality)
--- a/Framework/Layers/FrameRenderer.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Layers/FrameRenderer.h Mon Dec 19 11:00:23 2016 +0100 @@ -85,7 +85,7 @@ static ILayerRenderer* CreateRenderer(Orthanc::ImageAccessor* frame, const SliceGeometry& viewportSlice, const SliceGeometry& frameSlice, - const DicomDataset& dicom, + const OrthancPlugins::IDicomDataset& dicom, double pixelSpacingX, double pixelSpacingY, bool isFullQuality);
--- a/Framework/Layers/SeriesFrameRendererFactory.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Layers/SeriesFrameRendererFactory.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -34,6 +34,11 @@ #include "FrameRenderer.h" #include "../../Resources/Orthanc/Core/OrthancException.h" +#include "../../Resources/Orthanc/Core/Logging.h" +#include "../../Resources/Orthanc/Core/Toolbox.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h" + namespace OrthancStone { @@ -66,7 +71,7 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } - currentDataset_->GetPixelSpacing(spacingX, spacingY); + GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *currentDataset_); } @@ -77,16 +82,23 @@ // There was no previous call "ReadCurrentFrameDataset()" throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } - - if (currentDataset_->HasTag(DICOM_TAG_SLICE_THICKNESS)) + + try { - return currentDataset_->GetFloatValue(DICOM_TAG_SLICE_THICKNESS); + OrthancPlugins::DicomDatasetReader reader(*currentDataset_); + + double thickness; + if (reader.GetDoubleValue(thickness, OrthancPlugins::DICOM_TAG_SLICE_THICKNESS)) + { + return thickness; + } } - else + catch (ORTHANC_PLUGINS_EXCEPTION_CLASS& e) { - // Some arbitrary large slice thickness - return std::numeric_limits<double>::infinity(); } + + // Some arbitrary large slice thickness + return std::numeric_limits<double>::infinity(); }
--- a/Framework/Layers/SeriesFrameRendererFactory.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Layers/SeriesFrameRendererFactory.h Mon Dec 19 11:00:23 2016 +0100 @@ -42,10 +42,11 @@ { private: std::auto_ptr<ISeriesLoader> loader_; - std::auto_ptr<DicomDataset> currentDataset_; size_t currentFrame_; bool fast_; + std::auto_ptr<OrthancPlugins::IDicomDataset> currentDataset_; + void ReadCurrentFrameDataset(size_t frame); void GetCurrentPixelSpacing(double& spacingX,
--- a/Framework/Layers/SingleFrameRendererFactory.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Layers/SingleFrameRendererFactory.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -35,6 +35,8 @@ #include "FrameRenderer.h" #include "../Messaging/MessagingToolbox.h" #include "../../Resources/Orthanc/Core/OrthancException.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h" #include "../Toolbox/DicomFrameConverter.h" namespace OrthancStone @@ -43,27 +45,14 @@ const std::string& instanceId, unsigned int frame) : orthanc_(orthanc), - dicom_(orthanc, instanceId), instance_(instanceId), frame_(frame) { - DicomFrameConverter converter; - converter.ReadParameters(dicom_); - format_ = converter.GetExpectedPixelFormat(); - } - + dicom_.reset(new OrthancPlugins::FullOrthancDataset(orthanc, "/instances/" + instanceId + "/tags")); - SliceGeometry SingleFrameRendererFactory::GetSliceGeometry() - { - if (dicom_.HasTag(DICOM_TAG_IMAGE_POSITION_PATIENT) && - dicom_.HasTag(DICOM_TAG_IMAGE_ORIENTATION_PATIENT)) - { - return SliceGeometry(dicom_); - } - else - { - return SliceGeometry(); - } + DicomFrameConverter converter; + converter.ReadParameters(*dicom_); + format_ = converter.GetExpectedPixelFormat(); } @@ -75,8 +64,15 @@ { // Assume that PixelSpacingX == PixelSpacingY == 1 - unsigned int width = dicom_.GetUnsignedIntegerValue(DICOM_TAG_COLUMNS); - unsigned int height = dicom_.GetUnsignedIntegerValue(DICOM_TAG_ROWS); + OrthancPlugins::DicomDatasetReader reader(*dicom_); + + unsigned int width, height; + + if (!reader.GetUnsignedIntegerValue(width, OrthancPlugins::DICOM_TAG_COLUMNS) || + !reader.GetUnsignedIntegerValue(height, OrthancPlugins::DICOM_TAG_ROWS)) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } x1 = 0; y1 = 0; @@ -89,9 +85,9 @@ ILayerRenderer* SingleFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice) { - SliceGeometry frameSlice(dicom_); + SliceGeometry frameSlice(*dicom_); return FrameRenderer::CreateRenderer(MessagingToolbox::DecodeFrame(orthanc_, instance_, frame_, format_), - viewportSlice, frameSlice, dicom_, 1, 1, true); + viewportSlice, frameSlice, *dicom_, 1, 1, true); }
--- a/Framework/Layers/SingleFrameRendererFactory.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Layers/SingleFrameRendererFactory.h Mon Dec 19 11:00:23 2016 +0100 @@ -33,15 +33,16 @@ #pragma once #include "ILayerRendererFactory.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h" namespace OrthancStone { class SingleFrameRendererFactory : public ILayerRendererFactory { private: - OrthancPlugins::IOrthancConnection& orthanc_; + OrthancPlugins::IOrthancConnection& orthanc_; + std::auto_ptr<OrthancPlugins::IDicomDataset> dicom_; - DicomDataset dicom_; std::string instance_; unsigned int frame_; Orthanc::PixelFormat format_; @@ -51,12 +52,15 @@ const std::string& instanceId, unsigned int frame); - const DicomDataset& GetDataset() const + const OrthancPlugins::IDicomDataset& GetDataset() const { - return dicom_; + return *dicom_; } - SliceGeometry GetSliceGeometry(); + SliceGeometry GetSliceGeometry() + { + return SliceGeometry(*dicom_); + } virtual bool GetExtent(double& x1, double& y1,
--- a/Framework/Toolbox/DicomFrameConverter.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/DicomFrameConverter.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -32,6 +32,8 @@ #include "DicomFrameConverter.h" +#include "GeometryToolbox.h" + #include "../../Resources/Orthanc/Core/Images/Image.h" #include "../../Resources/Orthanc/Core/Images/ImageProcessing.h" #include "../../Resources/Orthanc/Core/OrthancException.h" @@ -71,33 +73,41 @@ } - void DicomFrameConverter::ReadParameters(const DicomDataset& dicom) + void DicomFrameConverter::ReadParameters(const OrthancPlugins::IDicomDataset& dicom) { SetDefaultParameters(); - if (dicom.HasTag(DICOM_TAG_WINDOW_CENTER)) + Vector c, w; + if (GeometryToolbox::ParseVector(c, dicom, OrthancPlugins::DICOM_TAG_WINDOW_CENTER) && + GeometryToolbox::ParseVector(c, dicom, OrthancPlugins::DICOM_TAG_WINDOW_WIDTH)) { - Vector c, w; - dicom.GetVectorValue(c, DICOM_TAG_WINDOW_CENTER); - dicom.GetVectorValue(w, DICOM_TAG_WINDOW_WIDTH); - - if (c.size() > 0 && w.size() > 0) + if (c.size() > 0 && + w.size() > 0) { defaultWindowCenter_ = static_cast<float>(c[0]); defaultWindowWidth_ = static_cast<float>(w[0]); } } - isSigned_ = (dicom.GetIntegerValue(DICOM_TAG_PIXEL_REPRESENTATION) == 1); // Type 1 tag, must be present + OrthancPlugins::DicomDatasetReader reader(dicom); - if (dicom.HasTag(DICOM_TAG_RESCALE_INTERCEPT)) + int tmp; + if (!reader.GetIntegerValue(tmp, OrthancPlugins::DICOM_TAG_PIXEL_REPRESENTATION)) { - rescaleIntercept_ = dicom.GetFloatValue(DICOM_TAG_RESCALE_INTERCEPT); - rescaleSlope_ = dicom.GetFloatValue(DICOM_TAG_RESCALE_SLOPE); + // Type 1 tag, must be present + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + isSigned_ = (tmp == 1); + + if (reader.GetFloatValue(rescaleIntercept_, OrthancPlugins::DICOM_TAG_RESCALE_INTERCEPT) && + reader.GetFloatValue(rescaleSlope_, OrthancPlugins::DICOM_TAG_RESCALE_SLOPE)) + { hasRescale_ = true; } - std::string photometric = dicom.GetStringValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION); // Type 1 tag, must be present + // Type 1 tag, must be present + std::string photometric = reader.GetMandatoryStringValue(OrthancPlugins::DICOM_TAG_PHOTOMETRIC_INTERPRETATION); photometric = Orthanc::Toolbox::StripSpaces(photometric); isColor_ = (photometric != "MONOCHROME1" && photometric != "MONOCHROME2");
--- a/Framework/Toolbox/DicomFrameConverter.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/DicomFrameConverter.h Mon Dec 19 11:00:23 2016 +0100 @@ -32,9 +32,10 @@ #pragma once -#include "DicomDataset.h" +#include "../../Resources/Orthanc/Core/Images/ImageAccessor.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h" -#include "../../Resources/Orthanc/Core/Images/ImageAccessor.h" +#include <memory> namespace OrthancStone { @@ -66,7 +67,7 @@ Orthanc::PixelFormat GetExpectedPixelFormat() const; - void ReadParameters(const DicomDataset& dicom); + void ReadParameters(const OrthancPlugins::IDicomDataset& dicom); float GetDefaultWindowCenter() const {
--- a/Framework/Toolbox/DicomStructureSet.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/DicomStructureSet.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -34,6 +34,7 @@ #include "../../Resources/Orthanc/Core/Logging.h" #include "../../Resources/Orthanc/Core/OrthancException.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h" #include "../Messaging/MessagingToolbox.h" #include <stdio.h> @@ -41,27 +42,17 @@ namespace OrthancStone { - static const Json::Value& GetSequence(const Json::Value& instance, - uint16_t group, - uint16_t element) - { - char buf[16]; - sprintf(buf, "%04x,%04x", group, element); - - if (instance.type() != Json::objectValue || - !instance.isMember(buf) || - instance[buf].type() != Json::objectValue || - !instance[buf].isMember("Type") || - !instance[buf].isMember("Value") || - instance[buf]["Type"].type() != Json::stringValue || - instance[buf]["Value"].type() != Json::arrayValue || - instance[buf]["Type"].asString() != "Sequence") - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); - } - - return instance[buf]["Value"]; - } + static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_GEOMETRIC_TYPE(0x3006, 0x0042); + static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_IMAGE_SEQUENCE(0x3006, 0x0016); + static const OrthancPlugins::DicomTag DICOM_TAG_CONTOUR_SEQUENCE(0x3006, 0x0040); + static const OrthancPlugins::DicomTag DICOM_TAG_NUMBER_OF_CONTOUR_POINTS(0x3006, 0x0046); + static const OrthancPlugins::DicomTag DICOM_TAG_REFERENCED_SOP_INSTANCE_UID(0x0008, 0x1155); + static const OrthancPlugins::DicomTag DICOM_TAG_ROI_CONTOUR_SEQUENCE(0x3006, 0x0039); + static const OrthancPlugins::DicomTag DICOM_TAG_ROI_DISPLAY_COLOR(0x3006, 0x002a); + static const OrthancPlugins::DicomTag DICOM_TAG_ROI_NAME(0x3006, 0x0026); + static const OrthancPlugins::DicomTag DICOM_TAG_RT_ROI_INTERPRETED_TYPE(0x3006, 0x00a4); + static const OrthancPlugins::DicomTag DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE(0x3006, 0x0080); + static const OrthancPlugins::DicomTag DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE(0x3006, 0x0020); static uint8_t ConvertColor(double v) @@ -83,17 +74,26 @@ SliceGeometry DicomStructureSet::ExtractSliceGeometry(double& sliceThickness, OrthancPlugins::IOrthancConnection& orthanc, - const Json::Value& contour) + const OrthancPlugins::IDicomDataset& tags, + size_t contourIndex, + size_t sliceIndex) { - const Json::Value& sequence = GetSequence(contour, 0x3006, 0x0016); + using namespace OrthancPlugins; - if (sequence.size() != 1) + size_t size; + if (!tags.GetSequenceSize(size, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, contourIndex, + DICOM_TAG_CONTOUR_SEQUENCE, sliceIndex, + DICOM_TAG_CONTOUR_IMAGE_SEQUENCE)) || + size != 1) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); } - DicomDataset contourImageSequence(sequence[0]); - std::string parentUid = contourImageSequence.GetStringValue(std::make_pair(0x0008, 0x1155)); + DicomDatasetReader reader(tags); + std::string parentUid = reader.GetMandatoryStringValue(DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, contourIndex, + DICOM_TAG_CONTOUR_SEQUENCE, sliceIndex, + DICOM_TAG_CONTOUR_IMAGE_SEQUENCE, 0, + DICOM_TAG_REFERENCED_SOP_INSTANCE_UID)); std::string post; orthanc.RestApiPost(post, "/tools/lookup", parentUid); @@ -135,32 +135,18 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } - Json::Value parentTags; - MessagingToolbox::RestApiGet(parentTags, orthanc, "/instances/" + tmp[0]["ID"].asString() + "/tags?simplify"); - - if (parentTags.type() != Json::objectValue || - !parentTags.isMember("ImageOrientationPatient") || - !parentTags.isMember("ImagePositionPatient") || - parentTags["ImageOrientationPatient"].type() != Json::stringValue || - parentTags["ImagePositionPatient"].type() != Json::stringValue) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } + FullOrthancDataset parentTags(orthanc, "/instances/" + tmp[0]["ID"].asString() + "/tags"); + SliceGeometry slice(parentTags); - SliceGeometry slice(parentTags["ImagePositionPatient"].asString(), - parentTags["ImageOrientationPatient"].asString()); - - sliceThickness = 1; // 1 mm by default - - if (parentTags.isMember("SliceThickness") && - parentTags["SliceThickness"].type() == Json::stringValue) + Vector v; + if (GeometryToolbox::ParseVector(v, parentTags, DICOM_TAG_SLICE_THICKNESS) && + v.size() > 0) { - Vector tmp; - GeometryToolbox::ParseVector(tmp, parentTags["SliceThickness"].asString()); - if (tmp.size() > 0) - { - sliceThickness = tmp[0]; - } + sliceThickness = v[0]; + } + else + { + sliceThickness = 1; // 1 mm by default } if (isFirst) @@ -201,68 +187,87 @@ DicomStructureSet::DicomStructureSet(OrthancPlugins::IOrthancConnection& orthanc, const std::string& instanceId) { - Json::Value instance; - MessagingToolbox::RestApiGet(instance, orthanc, "/instances/" + instanceId + "/tags"); - - Json::Value rtRoiObservationSequence = GetSequence(instance, 0x3006, 0x0080); - Json::Value roiContourSequence = GetSequence(instance, 0x3006, 0x0039); - Json::Value structureSetRoiSequence = GetSequence(instance, 0x3006, 0x0020); + using namespace OrthancPlugins; - Json::Value::ArrayIndex count = rtRoiObservationSequence.size(); - if (count != roiContourSequence.size() || - count != structureSetRoiSequence.size()) + FullOrthancDataset tags(orthanc, "/instances/" + instanceId + "/tags"); + DicomDatasetReader reader(tags); + + size_t count, tmp; + if (!tags.GetSequenceSize(count, DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE) || + !tags.GetSequenceSize(tmp, DICOM_TAG_ROI_CONTOUR_SEQUENCE) || + tmp != count || + !tags.GetSequenceSize(tmp, DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE) || + tmp != count) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } - - structures_.resize(count); - for (Json::Value::ArrayIndex i = 0; i < count; i++) - { - DicomDataset observation(rtRoiObservationSequence[i]); - DicomDataset roi(structureSetRoiSequence[i]); - DicomDataset content(roiContourSequence[i]); - structures_[i].interpretation_ = observation.GetStringValue(std::make_pair(0x3006, 0x00a4), "No interpretation"); - structures_[i].name_ = roi.GetStringValue(std::make_pair(0x3006, 0x0026), "No name"); - structures_[i].red_ = 255; - structures_[i].green_ = 0; - structures_[i].blue_ = 0; + structures_.resize(count); + for (size_t i = 0; i < count; i++) + { + structures_[i].interpretation_ = reader.GetStringValue(DicomPath(DICOM_TAG_RT_ROI_OBSERVATIONS_SEQUENCE, i, + DICOM_TAG_RT_ROI_INTERPRETED_TYPE), + "No interpretation"); - DicomDataset::Tag tag(0x3006, 0x002a); + structures_[i].name_ = reader.GetStringValue(DicomPath(DICOM_TAG_STRUCTURE_SET_ROI_SEQUENCE, i, + DICOM_TAG_ROI_NAME), + "No interpretation"); Vector color; - if (content.HasTag(tag)) + if (GeometryToolbox::ParseVector(color, tags, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, + DICOM_TAG_ROI_DISPLAY_COLOR)) && + color.size() == 3) { - content.GetVectorValue(color, tag); - if (color.size() == 3) - { - structures_[i].red_ = ConvertColor(color[0]); - structures_[i].green_ = ConvertColor(color[1]); - structures_[i].blue_ = ConvertColor(color[2]); - } + structures_[i].red_ = ConvertColor(color[0]); + structures_[i].green_ = ConvertColor(color[1]); + structures_[i].blue_ = ConvertColor(color[2]); + } + else + { + structures_[i].red_ = 255; + structures_[i].green_ = 0; + structures_[i].blue_ = 0; } - const Json::Value& slices = GetSequence(roiContourSequence[i], 0x3006, 0x0040); + size_t countSlices; + if (!tags.GetSequenceSize(countSlices, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, + DICOM_TAG_CONTOUR_SEQUENCE))) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } LOG(WARNING) << "New RT structure: \"" << structures_[i].name_ << "\" with interpretation \"" << structures_[i].interpretation_ - << "\" containing " << slices.size() << " slices (color: " + << "\" containing " << countSlices << " slices (color: " << static_cast<int>(structures_[i].red_) << "," << static_cast<int>(structures_[i].green_) << "," << static_cast<int>(structures_[i].blue_) << ")"; - for (Json::Value::ArrayIndex j = 0; j < slices.size(); j++) + for (size_t j = 0; j < countSlices; j++) { - DicomDataset slice(slices[j]); + unsigned int countPoints; - unsigned int npoints = slice.GetUnsignedIntegerValue(std::make_pair(0x3006, 0x0046)); - LOG(INFO) << "Parsing slice containing " << npoints << " vertices"; + if (!reader.GetUnsignedIntegerValue(countPoints, DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, + DICOM_TAG_CONTOUR_SEQUENCE, j, + DICOM_TAG_NUMBER_OF_CONTOUR_POINTS))) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + + LOG(INFO) << "Parsing slice containing " << countPoints << " vertices"; - if (slice.GetStringValue(std::make_pair(0x3006, 0x0042)) != "CLOSED_PLANAR") + std::string type = reader.GetMandatoryStringValue(DicomPath(DICOM_TAG_ROI_CONTOUR_SEQUENCE, i, + DICOM_TAG_CONTOUR_SEQUENCE, j, + DICOM_TAG_CONTOUR_GEOMETRIC_TYPE)); + if (type != "CLOSED_PLANAR") { + LOG(ERROR) << "Cannot handle contour with geometry type: " << type; throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); } + // The "CountourData" tag (3006,0050) is too large to be + // returned by the "/instances/{id}/tags" URI: Access it using + // the raw "/instances/{id}/content/{...}" endpoint std::string slicesData; orthanc.RestApiGet(slicesData, "/instances/" + instanceId + "/content/3006-0039/" + boost::lexical_cast<std::string>(i) + "/3006-0040/" + @@ -270,16 +275,16 @@ Vector points; if (!GeometryToolbox::ParseVector(points, slicesData) || - points.size() != 3 * npoints) + points.size() != 3 * countPoints) { throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); } Polygon polygon; - SliceGeometry geometry = ExtractSliceGeometry(polygon.sliceThickness_, orthanc, slices[j]); + SliceGeometry geometry = ExtractSliceGeometry(polygon.sliceThickness_, orthanc, tags, i, j); polygon.projectionAlongNormal_ = geometry.ProjectAlongNormal(geometry.GetOrigin()); - for (size_t k = 0; k < npoints; k++) + for (size_t k = 0; k < countPoints; k++) { Vector v(3); v[0] = points[3 * k];
--- a/Framework/Toolbox/DicomStructureSet.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/DicomStructureSet.h Mon Dec 19 11:00:23 2016 +0100 @@ -34,6 +34,7 @@ #include "SliceGeometry.h" #include "../Viewport/CairoContext.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h" #include <list> @@ -71,7 +72,9 @@ SliceGeometry ExtractSliceGeometry(double& sliceThickness, OrthancPlugins::IOrthancConnection& orthanc, - const Json::Value& contour); + const OrthancPlugins::IDicomDataset& tags, + size_t contourIndex, + size_t sliceIndex); const Structure& GetStructure(size_t index) const;
--- a/Framework/Toolbox/GeometryToolbox.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/GeometryToolbox.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -32,6 +32,7 @@ #include "GeometryToolbox.h" +#include "../../Resources/Orthanc/Core/Logging.h" #include "../../Resources/Orthanc/Core/OrthancException.h" #include "../../Resources/Orthanc/Core/Toolbox.h" @@ -77,6 +78,16 @@ } + bool ParseVector(Vector& target, + const OrthancPlugins::IDicomDataset& dataset, + const OrthancPlugins::DicomPath& tag) + { + std::string value; + return (dataset.GetStringValue(value, tag) && + ParseVector(target, value)); + } + + void AssignVector(Vector& v, double v1, double v2) @@ -347,5 +358,36 @@ return true; } } + + + void GetPixelSpacing(double& spacingX, + double& spacingY, + const OrthancPlugins::IDicomDataset& dicom) + { + Vector v; + + if (ParseVector(v, dicom, OrthancPlugins::DICOM_TAG_PIXEL_SPACING)) + { + if (v.size() != 2 || + v[0] <= 0 || + v[1] <= 0) + { + LOG(ERROR) << "Bad value for PixelSpacing tag"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat); + } + else + { + spacingX = v[0]; + spacingY = v[1]; + } + } + else + { + // The "PixelSpacing" is of type 1C: It could be absent, use + // default value in such a case + spacingX = 1; + spacingY = 1; + } + } } }
--- a/Framework/Toolbox/GeometryToolbox.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/GeometryToolbox.h Mon Dec 19 11:00:23 2016 +0100 @@ -34,6 +34,7 @@ #include <boost/numeric/ublas/vector.hpp> +#include "../../Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h" namespace OrthancStone { @@ -44,7 +45,11 @@ void Print(const Vector& v); bool ParseVector(Vector& target, - const std::string& value); + const std::string& s); + + bool ParseVector(Vector& target, + const OrthancPlugins::IDicomDataset& dataset, + const OrthancPlugins::DicomPath& tag); void AssignVector(Vector& v, double v1, @@ -107,5 +112,9 @@ const double& ymin, const double& xmax, const double& ymax); + + void GetPixelSpacing(double& spacingX, + double& spacingY, + const OrthancPlugins::IDicomDataset& dicom); }; }
--- a/Framework/Toolbox/ISeriesLoader.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/ISeriesLoader.h Mon Dec 19 11:00:23 2016 +0100 @@ -36,6 +36,7 @@ #include "IThreadSafety.h" #include "../../Resources/Orthanc/Core/Images/ImageAccessor.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h" namespace OrthancStone { @@ -51,7 +52,7 @@ virtual unsigned int GetHeight() = 0; - virtual DicomDataset* DownloadDicom(size_t index) = 0; + virtual OrthancPlugins::IDicomDataset* DownloadDicom(size_t index) = 0; // This downloads the frame from Orthanc. The resulting pixel // format must be Grayscale8, Grayscale16, SignedGrayscale16 or
--- a/Framework/Toolbox/OrthancSeriesLoader.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/OrthancSeriesLoader.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -37,6 +37,7 @@ #include "../../Resources/Orthanc/Core/Images/ImageProcessing.h" #include "../../Resources/Orthanc/Core/Logging.h" #include "../../Resources/Orthanc/Core/OrthancException.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h" #include "DicomFrameConverter.h" namespace OrthancStone @@ -361,28 +362,33 @@ geometry_.AddSlice(slices_->GetSlice(i).GetGeometry()); } - std::auto_ptr<DicomDataset> dataset(new DicomDataset(orthanc_, slices_->GetSlice(0).GetInstanceId())); - if (!dataset->HasTag(DICOM_TAG_ROWS) || - !dataset->HasTag(DICOM_TAG_COLUMNS)) + std::string uri = "/instances/" + slices_->GetSlice(0).GetInstanceId() + "/tags"; + + OrthancPlugins::FullOrthancDataset dataset(orthanc_, uri); + OrthancPlugins::DicomDatasetReader reader(dataset); + + if (!reader.GetUnsignedIntegerValue(width_, OrthancPlugins::DICOM_TAG_COLUMNS) || + !reader.GetUnsignedIntegerValue(height_, OrthancPlugins::DICOM_TAG_ROWS)) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InexistentTag); } DicomFrameConverter converter; - converter.ReadParameters(*dataset); - + converter.ReadParameters(dataset); format_ = converter.GetExpectedPixelFormat(); - width_ = dataset->GetUnsignedIntegerValue(DICOM_TAG_COLUMNS); - height_ = dataset->GetUnsignedIntegerValue(DICOM_TAG_ROWS); } - DicomDataset* OrthancSeriesLoader::DownloadDicom(size_t index) + OrthancPlugins::IDicomDataset* OrthancSeriesLoader::DownloadDicom(size_t index) { - std::auto_ptr<DicomDataset> dataset(new DicomDataset(orthanc_, slices_->GetSlice(index).GetInstanceId())); + std::string uri = "/instances/" + slices_->GetSlice(index).GetInstanceId() + "/tags"; - if (dataset->HasTag(DICOM_TAG_NUMBER_OF_FRAMES) && - dataset->GetUnsignedIntegerValue(DICOM_TAG_NUMBER_OF_FRAMES) != 1) + std::auto_ptr<OrthancPlugins::IDicomDataset> dataset(new OrthancPlugins::FullOrthancDataset(orthanc_, uri)); + OrthancPlugins::DicomDatasetReader reader(*dataset); + + unsigned int frames; + if (reader.GetUnsignedIntegerValue(frames, OrthancPlugins::DICOM_TAG_NUMBER_OF_FRAMES) && + frames != 1) { LOG(ERROR) << "One instance in this series has more than 1 frame"; throw Orthanc::OrthancException(Orthanc::ErrorCode_BadFileFormat);
--- a/Framework/Toolbox/OrthancSeriesLoader.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/OrthancSeriesLoader.h Mon Dec 19 11:00:23 2016 +0100 @@ -33,6 +33,7 @@ #pragma once #include "ISeriesLoader.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h" #include <boost/shared_ptr.hpp> @@ -81,7 +82,7 @@ return height_; } - virtual DicomDataset* DownloadDicom(size_t index); + virtual OrthancPlugins::IDicomDataset* DownloadDicom(size_t index); virtual Orthanc::ImageAccessor* DownloadFrame(size_t index);
--- a/Framework/Toolbox/SliceGeometry.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/SliceGeometry.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -119,13 +119,14 @@ } - SliceGeometry::SliceGeometry(const DicomDataset& dicom) + SliceGeometry::SliceGeometry(const OrthancPlugins::IDicomDataset& dicom) { - if (dicom.HasTag(DICOM_TAG_IMAGE_POSITION_PATIENT) && - dicom.HasTag(DICOM_TAG_IMAGE_ORIENTATION_PATIENT)) + std::string a, b; + + if (dicom.GetStringValue(a, OrthancPlugins::DICOM_TAG_IMAGE_POSITION_PATIENT) && + dicom.GetStringValue(b, OrthancPlugins::DICOM_TAG_IMAGE_ORIENTATION_PATIENT)) { - Setup(dicom.GetStringValue(DICOM_TAG_IMAGE_POSITION_PATIENT), - dicom.GetStringValue(DICOM_TAG_IMAGE_ORIENTATION_PATIENT)); + Setup(a, b); } else {
--- a/Framework/Toolbox/SliceGeometry.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Toolbox/SliceGeometry.h Mon Dec 19 11:00:23 2016 +0100 @@ -32,7 +32,8 @@ #pragma once -#include "DicomDataset.h" +#include "GeometryToolbox.h" +#include "../../Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h" namespace OrthancStone { @@ -62,7 +63,7 @@ const Vector& axisX, const Vector& axisY); - SliceGeometry(const DicomDataset& dicom); + SliceGeometry(const OrthancPlugins::IDicomDataset& dicom); SliceGeometry(const std::string& imagePositionPatient, const std::string& imageOrientationPatient)
--- a/Framework/Volumes/VolumeImage.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Volumes/VolumeImage.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -140,7 +140,7 @@ buffer_->SetAxialGeometry(loader_->GetGeometry().GetSlice(0)); double spacingX, spacingY; - referenceDataset_->GetPixelSpacing(spacingX, spacingY); + GeometryToolbox::GetPixelSpacing(spacingX, spacingY, *referenceDataset_); buffer_->SetVoxelDimensions(spacingX, spacingY, spacingZ); // These 3 values are only used to speed up the LayerFactory
--- a/Framework/Volumes/VolumeImage.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Framework/Volumes/VolumeImage.h Mon Dec 19 11:00:23 2016 +0100 @@ -64,16 +64,16 @@ private: - std::auto_ptr<ISeriesLoader> loader_; - std::auto_ptr<ImageBuffer3D> buffer_; - std::vector<boost::thread*> threads_; - bool started_; - bool continue_; - ObserversRegistry<ISliceableVolume> observers_; - bool loadingComplete_; - MessagingToolbox::Timestamp lastUpdate_; - std::auto_ptr<DicomDataset> referenceDataset_; - std::auto_ptr<IDownloadPolicy> policy_; + std::auto_ptr<ISeriesLoader> loader_; + std::auto_ptr<ImageBuffer3D> buffer_; + std::vector<boost::thread*> threads_; + bool started_; + bool continue_; + ObserversRegistry<ISliceableVolume> observers_; + bool loadingComplete_; + MessagingToolbox::Timestamp lastUpdate_; + std::auto_ptr<OrthancPlugins::IDicomDataset> referenceDataset_; + std::auto_ptr<IDownloadPolicy> policy_; std::auto_ptr<ParallelSlices> axialGeometry_; std::auto_ptr<ParallelSlices> coronalGeometry_;
--- a/Resources/CMake/OrthancStone.cmake Fri Dec 16 15:41:20 2016 +0100 +++ b/Resources/CMake/OrthancStone.cmake Mon Dec 19 11:00:23 2016 +0100 @@ -173,7 +173,6 @@ ${ORTHANC_STONE_DIR}/Framework/Layers/SingleFrameRendererFactory.cpp ${ORTHANC_STONE_DIR}/Framework/Messaging/MessagingToolbox.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/BinarySemaphore.cpp - ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomDataset.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomFrameConverter.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/DicomStructureSet.cpp ${ORTHANC_STONE_DIR}/Framework/Toolbox/DownloadStack.cpp
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -68,20 +68,31 @@ } - DicomDatasetReader::DicomDatasetReader(IDicomDataset* dataset) : // takes ownership + DicomDatasetReader::DicomDatasetReader(const IDicomDataset& dataset) : dataset_(dataset) { - if (dataset == NULL) + } + + + std::string DicomDatasetReader::GetStringValue(const DicomPath& path, + const std::string& defaultValue) const + { + std::string s; + if (dataset_.GetStringValue(s, path)) { - ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); + return s; + } + else + { + return defaultValue; } } - + std::string DicomDatasetReader::GetMandatoryStringValue(const DicomPath& path) const { std::string s; - if (dataset_->GetStringValue(s, path)) + if (dataset_.GetStringValue(s, path)) { return s; } @@ -92,12 +103,24 @@ } - int DicomDatasetReader::GetIntegerValue(const DicomPath& path) + template <typename T> + static bool GetValueInternal(T& target, + const IDicomDataset& dataset, + const DicomPath& path) { try { - std::string s = StripSpaces(GetMandatoryStringValue(path)); - return boost::lexical_cast<int>(s); + std::string s; + + if (dataset.GetStringValue(s, path)) + { + target = boost::lexical_cast<T>(StripSpaces(s)); + return true; + } + else + { + return false; + } } catch (boost::bad_lexical_cast&) { @@ -106,17 +129,44 @@ } - unsigned int DicomDatasetReader::GetUnsignedIntegerValue(const DicomPath& path) + bool DicomDatasetReader::GetIntegerValue(int& target, + const DicomPath& path) const { - int value = GetIntegerValue(path); + return GetValueInternal<int>(target, dataset_, path); + } + - if (value >= 0) + bool DicomDatasetReader::GetUnsignedIntegerValue(unsigned int& target, + const DicomPath& path) const + { + int value; + + if (!GetIntegerValue(value, path)) { - return static_cast<unsigned int>(value); + return false; + } + else if (value >= 0) + { + target = static_cast<unsigned int>(value); + return true; } else { ORTHANC_PLUGINS_THROW_EXCEPTION(ParameterOutOfRange); } } + + + bool DicomDatasetReader::GetFloatValue(float& target, + const DicomPath& path) const + { + return GetValueInternal<float>(target, dataset_, path); + } + + + bool DicomDatasetReader::GetDoubleValue(double& target, + const DicomPath& path) const + { + return GetValueInternal<double>(target, dataset_, path); + } }
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h Mon Dec 19 11:00:23 2016 +0100 @@ -35,26 +35,38 @@ #include "IDicomDataset.h" #include <memory> +#include <vector> namespace OrthancPlugins { class DicomDatasetReader : public boost::noncopyable { private: - std::auto_ptr<IDicomDataset> dataset_; + const IDicomDataset& dataset_; public: - DicomDatasetReader(IDicomDataset* dataset); // takes ownership + DicomDatasetReader(const IDicomDataset& dataset); - IDicomDataset& GetDataset() const + const IDicomDataset& GetDataset() const { - return *dataset_; + return dataset_; } + std::string GetStringValue(const DicomPath& path, + const std::string& defaultValue) const; + std::string GetMandatoryStringValue(const DicomPath& path) const; - int GetIntegerValue(const DicomPath& path); + bool GetIntegerValue(int& target, + const DicomPath& path) const; + + bool GetUnsignedIntegerValue(unsigned int& target, + const DicomPath& path) const; - unsigned int GetUnsignedIntegerValue(const DicomPath& path); + bool GetFloatValue(float& target, + const DicomPath& path) const; + + bool GetDoubleValue(double& target, + const DicomPath& path) const; }; }
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp Fri Dec 16 15:41:20 2016 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp Mon Dec 19 11:00:23 2016 +0100 @@ -49,20 +49,20 @@ } - DicomPath::DicomPath(const DicomTag& sequence, + DicomPath::DicomPath(DicomTag sequence, size_t index, - const DicomTag& tag) : + DicomTag tag) : finalTag_(tag) { AddToPrefix(sequence, index); } - DicomPath::DicomPath(const DicomTag& sequence1, + DicomPath::DicomPath(DicomTag sequence1, size_t index1, - const DicomTag& sequence2, + DicomTag sequence2, size_t index2, - const DicomTag& tag) : + DicomTag tag) : finalTag_(tag) { AddToPrefix(sequence1, index1); @@ -70,13 +70,13 @@ } - DicomPath::DicomPath(const DicomTag& sequence1, + DicomPath::DicomPath(DicomTag sequence1, size_t index1, - const DicomTag& sequence2, + DicomTag sequence2, size_t index2, - const DicomTag& sequence3, + DicomTag sequence3, size_t index3, - const DicomTag& tag) : + DicomTag tag) : finalTag_(tag) { AddToPrefix(sequence1, index1);
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h Mon Dec 19 11:00:23 2016 +0100 @@ -50,30 +50,30 @@ const Prefix& GetPrefixItem(size_t depth) const; public: - DicomPath(const DicomTag& finalTag) : + DicomPath(DicomTag finalTag) : finalTag_(finalTag) { } - DicomPath(const DicomTag& sequence, + DicomPath(DicomTag sequence, size_t index, - const DicomTag& tag); + DicomTag tag); - DicomPath(const DicomTag& sequence1, + DicomPath(DicomTag sequence1, size_t index1, - const DicomTag& sequence2, + DicomTag sequence2, size_t index2, - const DicomTag& tag); + DicomTag tag); - DicomPath(const DicomTag& sequence1, + DicomPath(DicomTag sequence1, size_t index1, - const DicomTag& sequence2, + DicomTag sequence2, size_t index2, - const DicomTag& sequence3, + DicomTag sequence3, size_t index3, - const DicomTag& tag); + DicomTag tag); - void AddToPrefix(const DicomTag& tag, + void AddToPrefix(DicomTag tag, size_t position) { prefix_.push_back(std::make_pair(tag, position));
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h Mon Dec 19 11:00:23 2016 +0100 @@ -77,19 +77,27 @@ static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101); + static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011); static const DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e); - static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011); + static const DicomTag DICOM_TAG_IMAGE_ORIENTATION_PATIENT(0x0020, 0x0037); + static const DicomTag DICOM_TAG_IMAGE_POSITION_PATIENT(0x0020, 0x0032); static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060); static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008); static const DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230); static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004); static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103); + static const DicomTag DICOM_TAG_PIXEL_SPACING(0x0028, 0x0030); static const DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a); - static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f); + static const DicomTag DICOM_TAG_RESCALE_INTERCEPT(0x0028, 0x1052); + static const DicomTag DICOM_TAG_RESCALE_SLOPE(0x0028, 0x1053); static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010); + static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f); + static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002); + static const DicomTag DICOM_TAG_SLICE_THICKNESS(0x0018, 0x0050); static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016); - static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002); static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006); static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007); static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010); + static const DicomTag DICOM_TAG_WINDOW_CENTER(0x0028, 0x1050); + static const DicomTag DICOM_TAG_WINDOW_WIDTH(0x0028, 0x1051); }
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h Fri Dec 16 15:41:20 2016 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h Mon Dec 19 11:00:23 2016 +0100 @@ -39,23 +39,23 @@ #if HAS_ORTHANC_EXCEPTION == 1 # include "../../../Core/OrthancException.h" -# define ORTHANC_PLUGINS_GET_ERROR_ENUMERATION ::Orthanc::ErrorCode -# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::Orthanc::ErrorCode_ ## code -# define ORTHANC_PLUGINS_GET_EXCEPTION_CLASS ::Orthanc::OrthancException +# define ORTHANC_PLUGINS_ERROR_ENUMERATION ::Orthanc::ErrorCode +# define ORTHANC_PLUGINS_EXCEPTION_CLASS ::Orthanc::OrthancException +# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::Orthanc::ErrorCode_ ## code #else # include <orthanc/OrthancCPlugin.h> -# define ORTHANC_PLUGINS_GET_ERROR_ENUMERATION ::OrthancPluginErrorCode -# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::OrthancPluginErrorCode_ ## code -# define ORTHANC_PLUGINS_GET_EXCEPTION_CLASS ::OrthancPlugins::PluginException +# define ORTHANC_PLUGINS_ERROR_ENUMERATION ::OrthancPluginErrorCode +# define ORTHANC_PLUGINS_EXCEPTION_CLASS ::OrthancPlugins::PluginException +# define ORTHANC_PLUGINS_GET_ERROR_CODE(code) ::OrthancPluginErrorCode_ ## code #endif #define ORTHANC_PLUGINS_THROW_PLUGIN_ERROR_CODE(code) \ - throw ORTHANC_PLUGINS_GET_EXCEPTION_CLASS(static_cast<ORTHANC_PLUGINS_GET_ERROR_ENUMERATION>(code)); + throw ORTHANC_PLUGINS_EXCEPTION_CLASS(static_cast<ORTHANC_PLUGINS_ERROR_ENUMERATION>(code)); #define ORTHANC_PLUGINS_THROW_EXCEPTION(code) \ - throw ORTHANC_PLUGINS_GET_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code)); + throw ORTHANC_PLUGINS_EXCEPTION_CLASS(ORTHANC_PLUGINS_GET_ERROR_CODE(code)); #define ORTHANC_PLUGINS_CHECK_ERROR(code) \