# HG changeset patch # User Benjamin Golinvaux # Date 1559045926 -7200 # Node ID f38c1fc08655e5ebd5229bbc3140ad9876a6fa13 # Parent 7efcbae4717ec24bc1c87445d2be47726a532d81# Parent d3197e0e321dd98fca74c69dd6fa9d7a9aefed31 Merge diff -r d3197e0e321d -r f38c1fc08655 Framework/Scene2D/LookupTableTextureSceneLayer.cpp --- a/Framework/Scene2D/LookupTableTextureSceneLayer.cpp Tue May 28 14:09:46 2019 +0200 +++ b/Framework/Scene2D/LookupTableTextureSceneLayer.cpp Tue May 28 14:18:46 2019 +0200 @@ -63,9 +63,9 @@ for (size_t i = 0; i < 256; i++) { - rgb[3 * i] = i; - rgb[3 * i + 1] = i; - rgb[3 * i + 2] = i; + rgb[3 * i] = static_cast(i); + rgb[3 * i + 1] = static_cast(i); + rgb[3 * i + 2] = static_cast(i); } SetLookupTableRgb(rgb); diff -r d3197e0e321d -r f38c1fc08655 Framework/StoneInitialization.cpp --- a/Framework/StoneInitialization.cpp Tue May 28 14:09:46 2019 +0200 +++ b/Framework/StoneInitialization.cpp Tue May 28 14:18:46 2019 +0200 @@ -31,6 +31,10 @@ # include "../Applications/Sdl/SdlWindow.h" #endif +#if ORTHANC_ENABLE_CURL == 1 +#include +#endif + namespace OrthancStone { #if ORTHANC_ENABLE_LOGGING_PLUGIN == 1 @@ -48,6 +52,10 @@ #if ORTHANC_ENABLE_SDL == 1 OrthancStone::SdlWindow::GlobalInitialize(); #endif + +#if ORTHANC_ENABLE_CURL == 1 + Orthanc::HttpClient::GlobalInitialize(); +#endif } void StoneFinalize() diff -r d3197e0e321d -r f38c1fc08655 Framework/Volumes/VolumeImageGeometry.h --- a/Framework/Volumes/VolumeImageGeometry.h Tue May 28 14:09:46 2019 +0200 +++ b/Framework/Volumes/VolumeImageGeometry.h Tue May 28 14:18:46 2019 +0200 @@ -115,6 +115,15 @@ bool DetectProjection(VolumeProjection& projection, const Vector& planeNormal) const; + /** + Being given a cutting plane, this method will determine if it is an + axial, sagittal or coronal cut and returns + the slice number corresponding to this cut. + + If the cutting plane is not parallel to the tree x = 0, y = 0 or z = 0 + planes, it is considered as arbitrary and the method returns false. + Otherwise, it returns true. + */ bool DetectSlice(VolumeProjection& projection, unsigned int& slice, const CoordinateSystem3D& plane) const; diff -r d3197e0e321d -r f38c1fc08655 Samples/Sdl/Loader.cpp --- a/Samples/Sdl/Loader.cpp Tue May 28 14:09:46 2019 +0200 +++ b/Samples/Sdl/Loader.cpp Tue May 28 14:18:46 2019 +0200 @@ -193,10 +193,24 @@ } }; - + /** + This interface is implemented by objects representing 3D volume data and + that are able to return an object that represent a slice of their data + and are able to create the corresponding visual representation. + */ class IVolumeSlicer : public boost::noncopyable { public: + /** + This interface is implemented by objects representing a slice of + volume data and that are able to create a 2D layer to display a this + slice. + + The CreateSceneLayer factory method is called with an optional + configurator that possibly impacts the ISceneLayer subclass that is + created (for instance, if a LUT must be applied on the texture when + displaying it) + */ class IExtractedSlice : public boost::noncopyable { public: @@ -204,9 +218,18 @@ { } + /** + Invalid slices are created when the data is not ready yet or if the + cut is outside of the available geometry. + */ virtual bool IsValid() = 0; - // Must be a cheap call + /** + This retrieves the *revision* that gets incremented every time the + underlying object undergoes a mutable operation (that it, changes its + state). + This **must** be a cheap call. + */ virtual uint64_t GetRevision() = 0; // This call can take some time @@ -214,7 +237,9 @@ const CoordinateSystem3D& cuttingPlane) = 0; }; - + /** + See IExtractedSlice.IsValid() + */ class InvalidSlice : public IExtractedSlice { public: @@ -240,13 +265,21 @@ { } + /** + This method is implemented by the objects representing volumetric data + and must returns an IExtractedSlice subclass that contains all the data + needed to, later one, create its visual representation through + CreateSceneLayer. + Subclasses a.o.: ExtractedSlice, Slice, InvalidSlice + */ virtual IExtractedSlice* ExtractSlice(const CoordinateSystem3D& cuttingPlane) = 0; }; - - - // This class combines a 3D image buffer, a 3D volume geometry and - // information about the DICOM parameters of the series. + /** + This class combines a 3D image buffer, a 3D volume geometry and + information about the DICOM parameters of the series. + (MPR means MultiPlanar Reconstruction) + */ class DicomVolumeImage : public boost::noncopyable { public: @@ -341,8 +374,11 @@ } }; - - + /** + Implements the IVolumeSlicer on Dicom volume data when the cutting plane + that is supplied to the slicer is either axial, sagittal or coronal. + Arbitrary planes are *not* supported + */ class DicomVolumeImageMPRSlicer : public IVolumeSlicer { public: @@ -371,6 +407,10 @@ } public: + /** + The constructor initializes the type of projection (axial, sagittal or + coronal) and the corresponding slice index, from the cutting plane. + */ Slice(const DicomVolumeImage& volume, const CoordinateSystem3D& cuttingPlane) : volume_(volume) @@ -609,6 +649,7 @@ } // WARNING: The payload of "slices" must be of class "DicomInstanceParameters" + // (called with the slices created in LoadGeometry) void ComputeGeometry(SlicesSorter& slices) { Clear(); @@ -706,7 +747,9 @@ else { // For coronal and sagittal projections, we take the global - // revision of the volume + // revision of the volume because even if a single slice changes, + // this means the projection will yield a different result --> + // we must increase the revision as soon as any slice changes return that_.volume_->GetRevision(); } } @@ -778,7 +821,9 @@ } } - + /** + This is called in response to GET "/series/XXXXXXXXXXXXX/instances-tags" + */ void LoadGeometry(const OrthancRestApiCommand::SuccessMessage& message) { Json::Value body; @@ -802,6 +847,7 @@ std::auto_ptr instance(new DicomInstanceParameters(dicom)); instance->SetOrthancInstanceIdentifier(instances[i]); + // the 3D plane corresponding to the slice CoordinateSystem3D geometry = instance->GetGeometry(); slices.AddSlice(geometry, instance.release()); } @@ -823,7 +869,7 @@ volume_->SetDicomParameters(parameters); volume_->GetPixelData().Clear(); - strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter(slicesCount), BEST_QUALITY)); + strategy_.reset(new BasicFetchingStrategy(sorter_->CreateSorter(static_cast(slicesCount)), BEST_QUALITY)); assert(simultaneousDownloads_ != 0); for (unsigned int i = 0; i < simultaneousDownloads_; i++) @@ -975,7 +1021,12 @@ }; - + /** + This class is supplied with Oracle commands and will schedule up to + simultaneousDownloads_ of them at the same time, then will schedule the + rest once slots become available. It is used, a.o., by the + OrtancMultiframeVolumeLoader class. + */ class LoaderStateMachine : public IObserver { protected: @@ -1316,7 +1367,13 @@ { return; } - + /* + 1.2.840.10008.1.2 Implicit VR Endian: Default Transfer Syntax for DICOM + 1.2.840.10008.1.2.1 Explicit VR Little Endian + 1.2.840.10008.1.2.2 Explicit VR Big Endian + + See https://www.dicomlibrary.com/dicom/transfer-syntax/ + */ if (transferSyntaxUid_ == "1.2.840.10008.1.2" || transferSyntaxUid_ == "1.2.840.10008.1.2.1" || transferSyntaxUid_ == "1.2.840.10008.1.2.2") @@ -1799,6 +1856,8 @@ if (content_.ProjectStructure(polygons, i, cuttingPlane)) { + printf(">> %d\n", static_cast(polygons.size())); + for (size_t j = 0; j < polygons.size(); j++) { PolylineSceneLayer::Chain chain; @@ -2378,6 +2437,12 @@ // 2017-11-17-Anonymized +#if 0 + // BGO data + ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT + doseLoader->LoadInstance("830a69ff-8e4b5ee3-b7f966c8-bccc20fb-d322dceb"); // RT-DOSE + //rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT +#else //ctLoader->LoadSeries("cb3ea4d1-d08f3856-ad7b6314-74d88d77-60b05618"); // CT //doseLoader->LoadInstance("41029085-71718346-811efac4-420e2c15-d39f99b6"); // RT-DOSE //rtstructLoader->LoadInstance("83d9c0c3-913a7fee-610097d7-cbf0522d-fd75bee6"); // RT-STRUCT @@ -2386,7 +2451,7 @@ ctLoader->LoadSeries("a04ecf01-79b2fc33-58239f7e-ad9db983-28e81afa"); // CT doseLoader->LoadInstance("eac822ef-a395f94e-e8121fe0-8411fef8-1f7bffad"); // RT-DOSE rtstructLoader->LoadInstance("54460695-ba3885ee-ddf61ac0-f028e31d-a6e474d9"); // RT-STRUCT - +#endif // 2015-01-28-Multiframe //doseLoader->LoadInstance("88f71e2a-5fad1c61-96ed14d6-5b3d3cf7-a5825279"); // Multiframe CT