comparison Framework/Layers/SeriesFrameRendererFactory.cpp @ 0:351ab0da0150

initial commit
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 14 Oct 2016 15:34:11 +0200
parents
children ff1e935768e7
comparison
equal deleted inserted replaced
-1:000000000000 0:351ab0da0150
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 *
6 * This program is free software: you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * In addition, as a special exception, the copyright holders of this
12 * program give permission to link the code of its release with the
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
14 * that use the same license as the "OpenSSL" library), and distribute
15 * the linked executables. You must obey the GNU General Public License
16 * in all respects for all of the code used other than "OpenSSL". If you
17 * modify file(s) with this exception, you may extend this exception to
18 * your version of the file(s), but you are not obligated to do so. If
19 * you do not wish to do so, delete this exception statement from your
20 * version. If you delete this exception statement from all source files
21 * in the program, then also delete it here.
22 *
23 * This program is distributed in the hope that it will be useful, but
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
26 * General Public License for more details.
27 *
28 * You should have received a copy of the GNU General Public License
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
30 **/
31
32
33 #include "SeriesFrameRendererFactory.h"
34
35 #include "FrameRenderer.h"
36 #include "../Orthanc/Core/OrthancException.h"
37
38 namespace OrthancStone
39 {
40 void SeriesFrameRendererFactory::ReadCurrentFrameDataset(size_t frame)
41 {
42 if (currentDataset_.get() != NULL &&
43 (fast_ || currentFrame_ == frame))
44 {
45 // The frame has not changed since the previous call, no need to
46 // update the DICOM dataset
47 return;
48 }
49
50 currentDataset_.reset(loader_->DownloadDicom(frame));
51 currentFrame_ = frame;
52
53 if (currentDataset_.get() == NULL)
54 {
55 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
56 }
57 }
58
59
60 void SeriesFrameRendererFactory::GetCurrentPixelSpacing(double& spacingX,
61 double& spacingY) const
62 {
63 if (currentDataset_.get() == NULL)
64 {
65 // There was no previous call "ReadCurrentFrameDataset()"
66 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
67 }
68
69 currentDataset_->GetPixelSpacing(spacingX, spacingY);
70 }
71
72
73 double SeriesFrameRendererFactory::GetCurrentSliceThickness() const
74 {
75 if (currentDataset_.get() == NULL)
76 {
77 // There was no previous call "ReadCurrentFrameDataset()"
78 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
79 }
80
81 if (currentDataset_->HasTag(DICOM_TAG_SLICE_THICKNESS))
82 {
83 return currentDataset_->GetFloatValue(DICOM_TAG_SLICE_THICKNESS);
84 }
85 else
86 {
87 // Some arbitrary large slice thickness
88 return std::numeric_limits<double>::infinity();
89 }
90 }
91
92
93 SeriesFrameRendererFactory::SeriesFrameRendererFactory(ISeriesLoader* loader, // Takes ownership
94 bool fast) :
95 loader_(loader),
96 currentFrame_(0),
97 fast_(fast)
98 {
99 if (loader == NULL)
100 {
101 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
102 }
103 }
104
105
106 bool SeriesFrameRendererFactory::GetExtent(double& x1,
107 double& y1,
108 double& x2,
109 double& y2,
110 const SliceGeometry& viewportSlice)
111 {
112 if (currentDataset_.get() == NULL)
113 {
114 // There has been no previous call to
115 // "CreateLayerRenderer". Read some arbitrary DICOM frame, the
116 // one at the middle of the series.
117 unsigned int depth = loader_->GetGeometry().GetSliceCount();
118 ReadCurrentFrameDataset(depth / 2);
119 }
120
121 double spacingX, spacingY;
122 GetCurrentPixelSpacing(spacingX, spacingY);
123
124 return FrameRenderer::ComputeFrameExtent(x1, y1, x2, y2,
125 viewportSlice,
126 loader_->GetGeometry().GetSlice(0),
127 loader_->GetWidth(),
128 loader_->GetHeight(),
129 spacingX, spacingY);
130 }
131
132
133 ILayerRenderer* SeriesFrameRendererFactory::CreateLayerRenderer(const SliceGeometry& viewportSlice)
134 {
135 size_t closest;
136 double distance;
137
138 bool isOpposite;
139 if (!GeometryToolbox::IsParallelOrOpposite(isOpposite, loader_->GetGeometry().GetNormal(), viewportSlice.GetNormal()) ||
140 !loader_->GetGeometry().ComputeClosestSlice(closest, distance, viewportSlice.GetOrigin()))
141 {
142 // Unable to compute the slice in the series that is the
143 // closest to the slice displayed by the viewport
144 return NULL;
145 }
146
147 ReadCurrentFrameDataset(closest);
148 assert(currentDataset_.get() != NULL);
149
150 double spacingX, spacingY;
151 GetCurrentPixelSpacing(spacingX, spacingY);
152
153 if (distance <= GetCurrentSliceThickness() / 2.0)
154 {
155 SliceGeometry frameSlice(*currentDataset_);
156 return FrameRenderer::CreateRenderer(loader_->DownloadFrame(closest),
157 viewportSlice,
158 frameSlice,
159 *currentDataset_,
160 spacingX, spacingY,
161 true);
162 }
163 else
164 {
165 // The closest slice of the series is too far away from the
166 // slice displayed by the viewport
167 return NULL;
168 }
169 }
170
171
172 ISliceableVolume& SeriesFrameRendererFactory::GetSourceVolume() const
173 {
174 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls);
175 }
176 }