comparison Framework/Layers/FrameRenderer.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 "FrameRenderer.h"
34
35 #include "GrayscaleFrameRenderer.h"
36 #include "ColorFrameRenderer.h"
37
38 #include "../Orthanc/Core/OrthancException.h"
39
40 namespace OrthancStone
41 {
42 static bool ComputePixelTransform(cairo_matrix_t& target,
43 const SliceGeometry& viewportSlice,
44 const SliceGeometry& frameSlice,
45 double pixelSpacingX,
46 double pixelSpacingY)
47 {
48 bool isOpposite;
49 if (!GeometryToolbox::IsParallelOrOpposite(isOpposite, viewportSlice.GetNormal(), frameSlice.GetNormal()))
50 {
51 return false;
52 }
53 else
54 {
55 double x0, y0, x1, y1, x2, y2;
56 viewportSlice.ProjectPoint(x0, y0, frameSlice.GetOrigin()
57 - 0.5 * pixelSpacingX * frameSlice.GetAxisX()
58 - 0.5 * pixelSpacingY * frameSlice.GetAxisY());
59 viewportSlice.ProjectPoint(x1, y1, frameSlice.GetOrigin()
60 + 0.5 * pixelSpacingX * frameSlice.GetAxisX()
61 - 0.5 * pixelSpacingY * frameSlice.GetAxisY());
62 viewportSlice.ProjectPoint(x2, y2, frameSlice.GetOrigin()
63 - 0.5 * pixelSpacingX * frameSlice.GetAxisX()
64 + 0.5 * pixelSpacingY * frameSlice.GetAxisY());
65
66 /**
67 * Now we solve the system of linear equations Ax + b = x', given:
68 * A [0 ; 0] + b = [x0 ; y0]
69 * A [1 ; 0] + b = [x1 ; y1]
70 * A [0 ; 1] + b = [x2 ; y2]
71 * <=>
72 * b = [x0 ; y0]
73 * A [1 ; 0] = [x1 ; y1] - b = [x1 - x0 ; y1 - y0]
74 * A [0 ; 1] = [x2 ; y2] - b = [x2 - x0 ; y2 - y0]
75 * <=>
76 * b = [x0 ; y0]
77 * [a11 ; a21] = [x1 - x0 ; y1 - y0]
78 * [a12 ; a22] = [x2 - x0 ; y2 - y0]
79 **/
80
81 cairo_matrix_init(&target, x1 - x0, y1 - y0, x2 - x0, y2 - y0, x0, y0);
82
83 return true;
84 }
85 }
86
87
88 FrameRenderer::FrameRenderer(const SliceGeometry& viewportSlice,
89 const SliceGeometry& frameSlice,
90 double pixelSpacingX,
91 double pixelSpacingY,
92 bool isFullQuality) :
93 viewportSlice_(viewportSlice),
94 frameSlice_(frameSlice),
95 pixelSpacingX_(pixelSpacingX),
96 pixelSpacingY_(pixelSpacingY),
97 isFullQuality_(isFullQuality)
98 {
99 }
100
101
102 bool FrameRenderer::ComputeFrameExtent(double& x1,
103 double& y1,
104 double& x2,
105 double& y2,
106 const SliceGeometry& viewportSlice,
107 const SliceGeometry& frameSlice,
108 unsigned int frameWidth,
109 unsigned int frameHeight,
110 double pixelSpacingX,
111 double pixelSpacingY)
112 {
113 bool isOpposite;
114 if (!GeometryToolbox::IsParallelOrOpposite(isOpposite, viewportSlice.GetNormal(), frameSlice.GetNormal()))
115 {
116 return false;
117 }
118 else
119 {
120 cairo_matrix_t transform;
121 if (!ComputePixelTransform(transform, viewportSlice, frameSlice, pixelSpacingX, pixelSpacingY))
122 {
123 return true;
124 }
125
126 x1 = 0;
127 y1 = 0;
128 cairo_matrix_transform_point(&transform, &x1, &y1);
129
130 x2 = frameWidth;
131 y2 = frameHeight;
132 cairo_matrix_transform_point(&transform, &x2, &y2);
133
134 if (x1 > x2)
135 {
136 std::swap(x1, x2);
137 }
138
139 if (y1 > y2)
140 {
141 std::swap(y1, y2);
142 }
143
144 return true;
145 }
146 }
147
148
149 bool FrameRenderer::RenderLayer(CairoContext& context,
150 const ViewportGeometry& view)
151 {
152 if (!style_.visible_)
153 {
154 return true;
155 }
156
157 if (display_.get() == NULL)
158 {
159 if (!ComputePixelTransform(transform_, viewportSlice_, frameSlice_, pixelSpacingX_, pixelSpacingY_))
160 {
161 return true;
162 }
163
164 display_.reset(GenerateDisplay(style_));
165 }
166
167 assert(display_.get() != NULL);
168
169 cairo_t *cr = context.GetObject();
170
171 cairo_save(cr);
172
173 cairo_transform(cr, &transform_);
174 //cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
175 cairo_set_source_surface(cr, display_->GetObject(), 0, 0);
176
177 switch (style_.interpolation_)
178 {
179 case ImageInterpolation_Nearest:
180 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_NEAREST);
181 break;
182
183 case ImageInterpolation_Linear:
184 cairo_pattern_set_filter(cairo_get_source(cr), CAIRO_FILTER_BILINEAR);
185 break;
186
187 default:
188 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange);
189 }
190
191 cairo_paint_with_alpha(cr, style_.alpha_);
192
193 if (style_.drawGrid_)
194 {
195 context.SetSourceColor(style_.drawColor_);
196 cairo_set_line_width(cr, 0.5 / view.GetZoom());
197
198 for (unsigned int x = 0; x <= display_->GetWidth(); x++)
199 {
200 cairo_move_to(cr, x, 0);
201 cairo_line_to(cr, x, display_->GetHeight());
202 }
203
204 for (unsigned int y = 0; y <= display_->GetHeight(); y++)
205 {
206 cairo_move_to(cr, 0, y);
207 cairo_line_to(cr, display_->GetWidth(), y);
208 }
209
210 cairo_stroke(cr);
211 }
212
213 cairo_restore(cr);
214
215 return true;
216 }
217
218
219 void FrameRenderer::SetLayerStyle(const RenderStyle& style)
220 {
221 style_ = style;
222 display_.reset(NULL);
223 }
224
225
226 ILayerRenderer* FrameRenderer::CreateRenderer(Orthanc::ImageAccessor* frame,
227 const SliceGeometry& viewportSlice,
228 const SliceGeometry& frameSlice,
229 const DicomDataset& dicom,
230 double pixelSpacingX,
231 double pixelSpacingY,
232 bool isFullQuality)
233 {
234 std::auto_ptr<Orthanc::ImageAccessor> protect(frame);
235
236 if (frame->GetFormat() == Orthanc::PixelFormat_RGB24)
237 {
238 return new ColorFrameRenderer(protect.release(), viewportSlice, frameSlice,
239 pixelSpacingX, pixelSpacingY, isFullQuality);
240 }
241 else
242 {
243 DicomFrameConverter converter;
244 converter.ReadParameters(dicom);
245 return new GrayscaleFrameRenderer(protect.release(), converter, viewportSlice, frameSlice,
246 pixelSpacingX, pixelSpacingY, isFullQuality);
247 }
248 }
249 }