Mercurial > hg > orthanc-stone
comparison Framework/Radiography/RadiographyWidget.cpp @ 413:18b707fb8620
reorganization
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Mon, 12 Nov 2018 17:17:25 +0100 |
parents | |
children | 751fb354149e b70e9be013e4 |
comparison
equal
deleted
inserted
replaced
412:71c16998fcc8 | 413:18b707fb8620 |
---|---|
1 /** | |
2 * Stone of Orthanc | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU Affero General Public License | |
9 * as published by the Free Software Foundation, either version 3 of | |
10 * the License, or (at your option) any later version. | |
11 * | |
12 * This program is distributed in the hope that it will be useful, but | |
13 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
15 * Affero General Public License for more details. | |
16 * | |
17 * You should have received a copy of the GNU Affero General Public License | |
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
19 **/ | |
20 | |
21 | |
22 #include "RadiographyWidget.h" | |
23 | |
24 #include <Core/Images/Image.h> | |
25 | |
26 | |
27 namespace OrthancStone | |
28 { | |
29 bool RadiographyWidget::RenderInternal(unsigned int width, | |
30 unsigned int height, | |
31 ImageInterpolation interpolation) | |
32 { | |
33 float windowCenter, windowWidth; | |
34 scene_.GetWindowingWithDefault(windowCenter, windowWidth); | |
35 | |
36 float x0 = windowCenter - windowWidth / 2.0f; | |
37 float x1 = windowCenter + windowWidth / 2.0f; | |
38 | |
39 if (windowWidth <= 0.001f) // Avoid division by zero at (*) | |
40 { | |
41 return false; | |
42 } | |
43 else | |
44 { | |
45 if (floatBuffer_.get() == NULL || | |
46 floatBuffer_->GetWidth() != width || | |
47 floatBuffer_->GetHeight() != height) | |
48 { | |
49 floatBuffer_.reset(new Orthanc::Image(Orthanc::PixelFormat_Float32, width, height, false)); | |
50 } | |
51 | |
52 if (cairoBuffer_.get() == NULL || | |
53 cairoBuffer_->GetWidth() != width || | |
54 cairoBuffer_->GetHeight() != height) | |
55 { | |
56 cairoBuffer_.reset(new CairoSurface(width, height)); | |
57 } | |
58 | |
59 scene_.Render(*floatBuffer_, GetView().GetMatrix(), interpolation); | |
60 | |
61 // Conversion from Float32 to BGRA32 (cairo). Very similar to | |
62 // GrayscaleFrameRenderer => TODO MERGE? | |
63 | |
64 Orthanc::ImageAccessor target; | |
65 cairoBuffer_->GetWriteableAccessor(target); | |
66 | |
67 float scaling = 255.0f / (x1 - x0); | |
68 | |
69 for (unsigned int y = 0; y < height; y++) | |
70 { | |
71 const float* p = reinterpret_cast<const float*>(floatBuffer_->GetConstRow(y)); | |
72 uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y)); | |
73 | |
74 for (unsigned int x = 0; x < width; x++, p++, q += 4) | |
75 { | |
76 uint8_t v = 0; | |
77 if (*p >= x1) | |
78 { | |
79 v = 255; | |
80 } | |
81 else if (*p <= x0) | |
82 { | |
83 v = 0; | |
84 } | |
85 else | |
86 { | |
87 // https://en.wikipedia.org/wiki/Linear_interpolation | |
88 v = static_cast<uint8_t>(scaling * (*p - x0)); // (*) | |
89 } | |
90 | |
91 if (invert_) | |
92 { | |
93 v = 255 - v; | |
94 } | |
95 | |
96 q[0] = v; | |
97 q[1] = v; | |
98 q[2] = v; | |
99 q[3] = 255; | |
100 } | |
101 } | |
102 | |
103 return true; | |
104 } | |
105 } | |
106 | |
107 | |
108 bool RadiographyWidget::RenderScene(CairoContext& context, | |
109 const ViewportGeometry& view) | |
110 { | |
111 cairo_t* cr = context.GetObject(); | |
112 | |
113 if (RenderInternal(context.GetWidth(), context.GetHeight(), interpolation_)) | |
114 { | |
115 // https://www.cairographics.org/FAQ/#paint_from_a_surface | |
116 cairo_save(cr); | |
117 cairo_identity_matrix(cr); | |
118 cairo_set_source_surface(cr, cairoBuffer_->GetObject(), 0, 0); | |
119 cairo_paint(cr); | |
120 cairo_restore(cr); | |
121 } | |
122 else | |
123 { | |
124 // https://www.cairographics.org/FAQ/#clear_a_surface | |
125 context.SetSourceColor(0, 0, 0); | |
126 cairo_paint(cr); | |
127 } | |
128 | |
129 if (hasSelection_) | |
130 { | |
131 scene_.DrawBorder(context, selectedLayer_, view.GetZoom()); | |
132 } | |
133 | |
134 return true; | |
135 } | |
136 | |
137 | |
138 RadiographyWidget::RadiographyWidget(MessageBroker& broker, | |
139 RadiographyScene& scene, | |
140 const std::string& name) : | |
141 WorldSceneWidget(name), | |
142 IObserver(broker), | |
143 scene_(scene), | |
144 invert_(false), | |
145 interpolation_(ImageInterpolation_Nearest), | |
146 hasSelection_(false), | |
147 selectedLayer_(0) // Dummy initialization | |
148 { | |
149 scene.RegisterObserverCallback( | |
150 new Callable<RadiographyWidget, RadiographyScene::GeometryChangedMessage> | |
151 (*this, &RadiographyWidget::OnGeometryChanged)); | |
152 | |
153 scene.RegisterObserverCallback( | |
154 new Callable<RadiographyWidget, RadiographyScene::ContentChangedMessage> | |
155 (*this, &RadiographyWidget::OnContentChanged)); | |
156 } | |
157 | |
158 | |
159 void RadiographyWidget::Select(size_t layer) | |
160 { | |
161 hasSelection_ = true; | |
162 selectedLayer_ = layer; | |
163 } | |
164 | |
165 | |
166 bool RadiographyWidget::LookupSelectedLayer(size_t& layer) | |
167 { | |
168 if (hasSelection_) | |
169 { | |
170 layer = selectedLayer_; | |
171 return true; | |
172 } | |
173 else | |
174 { | |
175 return false; | |
176 } | |
177 } | |
178 | |
179 | |
180 void RadiographyWidget::OnGeometryChanged(const RadiographyScene::GeometryChangedMessage& message) | |
181 { | |
182 LOG(INFO) << "Geometry has changed"; | |
183 FitContent(); | |
184 } | |
185 | |
186 | |
187 void RadiographyWidget::OnContentChanged(const RadiographyScene::ContentChangedMessage& message) | |
188 { | |
189 LOG(INFO) << "Content has changed"; | |
190 NotifyContentChanged(); | |
191 } | |
192 | |
193 | |
194 void RadiographyWidget::SetInvert(bool invert) | |
195 { | |
196 if (invert_ != invert) | |
197 { | |
198 invert_ = invert; | |
199 NotifyContentChanged(); | |
200 } | |
201 } | |
202 | |
203 | |
204 void RadiographyWidget::SwitchInvert() | |
205 { | |
206 invert_ = !invert_; | |
207 NotifyContentChanged(); | |
208 } | |
209 | |
210 | |
211 void RadiographyWidget::SetInterpolation(ImageInterpolation interpolation) | |
212 { | |
213 if (interpolation_ != interpolation) | |
214 { | |
215 interpolation_ = interpolation; | |
216 NotifyContentChanged(); | |
217 } | |
218 } | |
219 } |