Mercurial > hg > orthanc-stone
comparison Framework/Deprecated/Radiography/RadiographyLayer.cpp @ 1398:c5403d52078c
moved Radiography into Deprecated
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Wed, 29 Apr 2020 20:43:09 +0200 |
parents | Framework/Radiography/RadiographyLayer.cpp@379c00958553 |
children | 30deba7bc8e2 |
comparison
equal
deleted
inserted
replaced
1397:1c2d065ba372 | 1398:c5403d52078c |
---|---|
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-2020 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 "RadiographyLayer.h" | |
23 | |
24 #include <Core/OrthancException.h> | |
25 | |
26 | |
27 namespace OrthancStone | |
28 { | |
29 static double Square(double x) | |
30 { | |
31 return x * x; | |
32 } | |
33 | |
34 | |
35 RadiographyLayer::Geometry::Geometry() : | |
36 hasCrop_(false), | |
37 flipVertical_(false), | |
38 flipHorizontal_(false), | |
39 panX_(0), | |
40 panY_(0), | |
41 angle_(0), | |
42 resizeable_(false), | |
43 pixelSpacingX_(1), | |
44 pixelSpacingY_(1) | |
45 { | |
46 | |
47 } | |
48 | |
49 void RadiographyLayer::Geometry::GetCrop(unsigned int &x, unsigned int &y, unsigned int &width, unsigned int &height) const | |
50 { | |
51 if (!hasCrop_) | |
52 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); // you should probably use RadiographyLayer::GetCrop() or at least call HasCrop() before | |
53 | |
54 x = cropX_; | |
55 y = cropY_; | |
56 width = cropWidth_; | |
57 height = cropHeight_; | |
58 } | |
59 | |
60 void RadiographyLayer::UpdateTransform() | |
61 { | |
62 // important to update transform_ before getting the center to use the right scaling !!! | |
63 transform_ = AffineTransform2D::CreateScaling(geometry_.GetScalingX(), geometry_.GetScalingY()); | |
64 | |
65 double centerX, centerY; | |
66 GetCenter(centerX, centerY); | |
67 | |
68 transform_ = AffineTransform2D::Combine( | |
69 AffineTransform2D::CreateOffset(geometry_.GetPanX(), geometry_.GetPanY()), | |
70 AffineTransform2D::CreateRotation(geometry_.GetAngle(), centerX, centerY), | |
71 transform_); | |
72 | |
73 transformInverse_ = AffineTransform2D::Invert(transform_); | |
74 } | |
75 | |
76 | |
77 void RadiographyLayer::AddToExtent(Extent2D& extent, | |
78 double x, | |
79 double y) const | |
80 { | |
81 GetTransform().Apply(x, y); | |
82 extent.AddPoint(x, y); | |
83 } | |
84 | |
85 bool RadiographyLayer::Contains(double x, | |
86 double y) const | |
87 { | |
88 GetTransformInverse().Apply(x, y); | |
89 | |
90 unsigned int cropX, cropY, cropWidth, cropHeight; | |
91 GetCrop(cropX, cropY, cropWidth, cropHeight); | |
92 | |
93 return (x >= cropX && x <= cropX + cropWidth && | |
94 y >= cropY && y <= cropY + cropHeight); | |
95 } | |
96 | |
97 | |
98 void RadiographyLayer::DrawBorders(CairoContext& context, | |
99 double zoom) | |
100 { | |
101 if (GetControlPointCount() < 3 ) | |
102 return; | |
103 | |
104 cairo_t* cr = context.GetObject(); | |
105 cairo_set_line_width(cr, 2.0 / zoom); | |
106 | |
107 ControlPoint cp; | |
108 GetControlPoint(cp, 0); | |
109 cairo_move_to(cr, cp.x, cp.y); | |
110 | |
111 for (size_t i = 0; i < GetControlPointCount(); i++) | |
112 { | |
113 GetControlPoint(cp, i); | |
114 cairo_line_to(cr, cp.x, cp.y); | |
115 } | |
116 | |
117 cairo_close_path(cr); | |
118 cairo_stroke(cr); | |
119 } | |
120 | |
121 | |
122 RadiographyLayer::RadiographyLayer(const RadiographyScene& scene) : | |
123 index_(0), | |
124 hasSize_(false), | |
125 width_(0), | |
126 height_(0), | |
127 prefferedPhotometricDisplayMode_(RadiographyPhotometricDisplayMode_Default), | |
128 scene_(scene) | |
129 { | |
130 UpdateTransform(); | |
131 } | |
132 | |
133 void RadiographyLayer::ResetCrop() | |
134 { | |
135 geometry_.ResetCrop(); | |
136 UpdateTransform(); | |
137 } | |
138 | |
139 void RadiographyLayer::SetPreferredPhotomotricDisplayMode(RadiographyPhotometricDisplayMode prefferedPhotometricDisplayMode) | |
140 { | |
141 prefferedPhotometricDisplayMode_ = prefferedPhotometricDisplayMode; | |
142 | |
143 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
144 } | |
145 | |
146 void RadiographyLayer::SetCrop(unsigned int x, | |
147 unsigned int y, | |
148 unsigned int width, | |
149 unsigned int height) | |
150 { | |
151 if (!hasSize_) | |
152 { | |
153 throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); | |
154 } | |
155 | |
156 if (x + width > width_ || | |
157 y + height > height_) | |
158 { | |
159 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
160 } | |
161 | |
162 geometry_.SetCrop(x, y, width, height); | |
163 UpdateTransform(); | |
164 | |
165 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
166 } | |
167 | |
168 void RadiographyLayer::SetGeometry(const Geometry& geometry) | |
169 { | |
170 geometry_ = geometry; | |
171 | |
172 if (hasSize_) | |
173 { | |
174 UpdateTransform(); | |
175 } | |
176 | |
177 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
178 } | |
179 | |
180 | |
181 void RadiographyLayer::GetCrop(unsigned int& x, | |
182 unsigned int& y, | |
183 unsigned int& width, | |
184 unsigned int& height) const | |
185 { | |
186 if (GetGeometry().HasCrop()) | |
187 { | |
188 GetGeometry().GetCrop(x, y, width, height); | |
189 } | |
190 else | |
191 { | |
192 x = 0; | |
193 y = 0; | |
194 width = width_; | |
195 height = height_; | |
196 } | |
197 } | |
198 | |
199 | |
200 void RadiographyLayer::SetAngle(double angle) | |
201 { | |
202 geometry_.SetAngle(angle); | |
203 UpdateTransform(); | |
204 | |
205 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
206 } | |
207 | |
208 void RadiographyLayer::SetFlipVertical(bool flip) | |
209 { | |
210 geometry_.SetFlipVertical(flip); | |
211 UpdateTransform(); | |
212 | |
213 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
214 } | |
215 | |
216 void RadiographyLayer::SetFlipHorizontal(bool flip) | |
217 { | |
218 geometry_.SetFlipHorizontal(flip); | |
219 UpdateTransform(); | |
220 | |
221 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
222 } | |
223 | |
224 void RadiographyLayer::SetSize(unsigned int width, | |
225 unsigned int height, | |
226 bool emitLayerEditedEvent) | |
227 { | |
228 hasSize_ = true; | |
229 width_ = width; | |
230 height_ = height; | |
231 | |
232 UpdateTransform(); | |
233 | |
234 if (emitLayerEditedEvent) | |
235 { | |
236 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
237 } | |
238 } | |
239 | |
240 Extent2D RadiographyLayer::GetSceneExtent(bool /*minimal*/) const | |
241 { | |
242 Extent2D extent; | |
243 | |
244 unsigned int x, y, width, height; | |
245 GetCrop(x, y, width, height); | |
246 | |
247 double dx = static_cast<double>(x); | |
248 double dy = static_cast<double>(y); | |
249 double dwidth = static_cast<double>(width); | |
250 double dheight = static_cast<double>(height); | |
251 | |
252 // AddToExtent transforms the coordinates from image to scene | |
253 AddToExtent(extent, dx, dy); | |
254 AddToExtent(extent, dx + dwidth, dy); | |
255 AddToExtent(extent, dx, dy + dheight); | |
256 AddToExtent(extent, dx + dwidth, dy + dheight); | |
257 | |
258 return extent; | |
259 } | |
260 | |
261 | |
262 bool RadiographyLayer::GetPixel(unsigned int& imageX, | |
263 unsigned int& imageY, | |
264 double sceneX, | |
265 double sceneY) const | |
266 { | |
267 if (width_ == 0 || | |
268 height_ == 0) | |
269 { | |
270 return false; | |
271 } | |
272 else | |
273 { | |
274 GetTransformInverse().Apply(sceneX, sceneY); | |
275 | |
276 int x = static_cast<int>(std::floor(sceneX)); | |
277 int y = static_cast<int>(std::floor(sceneY)); | |
278 | |
279 if (x < 0) | |
280 { | |
281 imageX = 0; | |
282 } | |
283 else if (x >= static_cast<int>(width_)) | |
284 { | |
285 imageX = width_; | |
286 } | |
287 else | |
288 { | |
289 imageX = static_cast<unsigned int>(x); | |
290 } | |
291 | |
292 if (y < 0) | |
293 { | |
294 imageY = 0; | |
295 } | |
296 else if (y >= static_cast<int>(height_)) | |
297 { | |
298 imageY = height_; | |
299 } | |
300 else | |
301 { | |
302 imageY = static_cast<unsigned int>(y); | |
303 } | |
304 | |
305 return true; | |
306 } | |
307 } | |
308 | |
309 | |
310 void RadiographyLayer::SetPan(double x, | |
311 double y) | |
312 { | |
313 geometry_.SetPan(x, y); | |
314 UpdateTransform(); | |
315 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
316 } | |
317 | |
318 | |
319 void RadiographyLayer::SetPixelSpacing(double x, | |
320 double y, | |
321 bool emitLayerEditedEvent) | |
322 { | |
323 geometry_.SetPixelSpacing(x, y); | |
324 UpdateTransform(); | |
325 if (emitLayerEditedEvent) | |
326 { | |
327 BroadcastMessage(RadiographyLayer::LayerEditedMessage(*this)); | |
328 } | |
329 } | |
330 | |
331 | |
332 void RadiographyLayer::GetCenter(double& centerX, | |
333 double& centerY) const | |
334 { | |
335 centerX = static_cast<double>(width_) / 2.0; | |
336 centerY = static_cast<double>(height_) / 2.0; | |
337 GetTransform().Apply(centerX, centerY); | |
338 } | |
339 | |
340 | |
341 | |
342 size_t RadiographyLayer::GetControlPointCount() const {return 4;} | |
343 | |
344 void RadiographyLayer::GetControlPoint(ControlPoint& cpScene /* out in scene coordinates */, | |
345 size_t index) const | |
346 { | |
347 unsigned int cropX, cropY, cropWidth, cropHeight; | |
348 GetCrop(cropX, cropY, cropWidth, cropHeight); | |
349 | |
350 ControlPoint cp; | |
351 switch (index) | |
352 { | |
353 case RadiographyControlPointType_TopLeftCorner: | |
354 cp = ControlPoint(cropX, cropY, RadiographyControlPointType_TopLeftCorner); | |
355 break; | |
356 | |
357 case RadiographyControlPointType_TopRightCorner: | |
358 cp = ControlPoint(cropX + cropWidth, cropY, RadiographyControlPointType_TopRightCorner); | |
359 break; | |
360 | |
361 case RadiographyControlPointType_BottomLeftCorner: | |
362 cp = ControlPoint(cropX, cropY + cropHeight, RadiographyControlPointType_BottomLeftCorner); | |
363 break; | |
364 | |
365 case RadiographyControlPointType_BottomRightCorner: | |
366 cp = ControlPoint(cropX + cropWidth, cropY + cropHeight, RadiographyControlPointType_BottomRightCorner); | |
367 break; | |
368 | |
369 default: | |
370 throw Orthanc::OrthancException(Orthanc::ErrorCode_ParameterOutOfRange); | |
371 } | |
372 | |
373 // transforms image coordinates into scene coordinates | |
374 GetTransform().Apply(cp.x, cp.y); | |
375 cpScene = cp; | |
376 } | |
377 | |
378 bool RadiographyLayer::LookupControlPoint(ControlPoint& cpScene /* out */, | |
379 double x, | |
380 double y, | |
381 double zoom, | |
382 double viewportDistance) const | |
383 { | |
384 double threshold = Square(viewportDistance / zoom); | |
385 | |
386 for (size_t i = 0; i < GetControlPointCount(); i++) | |
387 { | |
388 ControlPoint cp; | |
389 GetControlPoint(cp, i); | |
390 | |
391 double d = Square(cp.x - x) + Square(cp.y - y); | |
392 | |
393 if (d <= threshold) | |
394 { | |
395 cpScene = cp; | |
396 return true; | |
397 } | |
398 } | |
399 | |
400 return false; | |
401 } | |
402 } |