Mercurial > hg > orthanc-stone
comparison Framework/Scene2DViewport/MeasureToolsToolbox.cpp @ 698:8b6adfb62a2f refactor-viewport-controller
Code is broken -- stashing ongoing work in a branch
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Wed, 15 May 2019 16:56:17 +0200 |
parents | |
children | c0fcb2757b0a 712ff6ff3c19 |
comparison
equal
deleted
inserted
replaced
660:cb3b76d16234 | 698:8b6adfb62a2f |
---|---|
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-2019 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 #include "MeasureToolsToolbox.h" | |
22 | |
23 #include <Framework/Scene2D/TextSceneLayer.h> | |
24 | |
25 #include <boost/math/constants/constants.hpp> | |
26 | |
27 namespace | |
28 { | |
29 double g_pi = boost::math::constants::pi<double>(); | |
30 } | |
31 | |
32 namespace OrthancStone | |
33 { | |
34 double RadiansToDegrees(double angleRad) | |
35 { | |
36 static const double factor = 180.0 / g_pi; | |
37 return angleRad * factor; | |
38 } | |
39 | |
40 void AddSquare(PolylineSceneLayer::Chain& chain, | |
41 const Scene2D& scene, | |
42 const ScenePoint2D& centerS, | |
43 const double& sideLength) | |
44 { | |
45 chain.clear(); | |
46 chain.reserve(4); | |
47 ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform()); | |
48 //TODO: take DPI into account | |
49 double handleLX = centerC.GetX() - sideLength / 2; | |
50 double handleTY = centerC.GetY() - sideLength / 2; | |
51 double handleRX = centerC.GetX() + sideLength / 2; | |
52 double handleBY = centerC.GetY() + sideLength / 2; | |
53 ScenePoint2D LTC(handleLX, handleTY); | |
54 ScenePoint2D RTC(handleRX, handleTY); | |
55 ScenePoint2D RBC(handleRX, handleBY); | |
56 ScenePoint2D LBC(handleLX, handleBY); | |
57 | |
58 ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform()); | |
59 ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform()); | |
60 ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform()); | |
61 ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform()); | |
62 | |
63 chain.push_back(startLT); | |
64 chain.push_back(startRT); | |
65 chain.push_back(startRB); | |
66 chain.push_back(startLB); | |
67 } | |
68 #if 0 | |
69 void AddArc( | |
70 PolylineSceneLayer::Chain& chain | |
71 , const Scene2D& scene | |
72 , const ScenePoint2D& p1 | |
73 , const ScenePoint2D& c | |
74 , const ScenePoint2D& p2 | |
75 , const double& radiusS | |
76 , const bool clockwise | |
77 , const int subdivisionsCount) | |
78 { | |
79 double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX()); | |
80 double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX()); | |
81 AddArc( | |
82 chain, scene, c, radiusS, p1cAngle, p2cAngle, | |
83 clockwise, subdivisionsCount); | |
84 } | |
85 #endif | |
86 | |
87 void AddShortestArc( | |
88 PolylineSceneLayer::Chain& chain | |
89 , const Scene2D& scene | |
90 , const ScenePoint2D& p1 | |
91 , const ScenePoint2D& c | |
92 , const ScenePoint2D& p2 | |
93 , const double& radiusS | |
94 , const int subdivisionsCount) | |
95 { | |
96 double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX()); | |
97 double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX()); | |
98 AddShortestArc( | |
99 chain, scene, c, radiusS, p1cAngle, p2cAngle, subdivisionsCount); | |
100 } | |
101 | |
102 void GetPositionOnBisectingLine( | |
103 ScenePoint2D& result | |
104 , const ScenePoint2D& p1 | |
105 , const ScenePoint2D& c | |
106 , const ScenePoint2D& p2 | |
107 , const double d) | |
108 { | |
109 // TODO: fix correct half-plane | |
110 double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX()); | |
111 double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX()); | |
112 double angle = 0.5*(p1cAngle + p2cAngle); | |
113 double unitVectorX = cos(angle); | |
114 double unitVectorY = sin(angle); | |
115 double posX = c.GetX() + d * unitVectorX; | |
116 double posY = c.GetX() + d * unitVectorY; | |
117 result = ScenePoint2D(posX, posY); | |
118 } | |
119 | |
120 void AddShortestArc( | |
121 PolylineSceneLayer::Chain& chain | |
122 , const Scene2D& scene | |
123 , const ScenePoint2D& centerS | |
124 , const double& radiusS | |
125 , const double startAngleRad | |
126 , const double endAngleRad | |
127 , const int subdivisionsCount) | |
128 { | |
129 // this gives a signed difference between angle which | |
130 // is the smallest difference (in magnitude) between | |
131 // the angles | |
132 double delta = NormalizeAngle(endAngleRad-startAngleRad); | |
133 | |
134 chain.clear(); | |
135 chain.reserve(subdivisionsCount + 1); | |
136 | |
137 double angleIncr = delta/static_cast<double>(subdivisionsCount); | |
138 | |
139 double theta = startAngleRad; | |
140 for (int i = 0; i < subdivisionsCount + 1; ++i) | |
141 { | |
142 double offsetX = radiusS * cos(theta); | |
143 double offsetY = radiusS * sin(theta); | |
144 double pointX = centerS.GetX() + offsetX; | |
145 double pointY = centerS.GetY() + offsetY; | |
146 chain.push_back(ScenePoint2D(pointX, pointY)); | |
147 theta += angleIncr; | |
148 } | |
149 } | |
150 | |
151 #if 0 | |
152 void AddArc( | |
153 PolylineSceneLayer::Chain& chain | |
154 , const Scene2D& scene | |
155 , const ScenePoint2D& centerS | |
156 , const double& radiusS | |
157 , const double startAngleRad | |
158 , const double endAngleRad | |
159 , const bool clockwise | |
160 , const int subdivisionsCount) | |
161 { | |
162 double startAngleRadN = NormalizeAngle(startAngleRad); | |
163 double endAngleRadN = NormalizeAngle(endAngleRad); | |
164 | |
165 double angle1Rad = std::min(startAngleRadN, endAngleRadN); | |
166 double angle2Rad = std::max(startAngleRadN, endAngleRadN); | |
167 | |
168 // now we are sure angle1Rad < angle2Rad | |
169 // this means that if we draw from 1 to 2, it will be clockwise ( | |
170 // increasing angles). | |
171 // let's fix this: | |
172 if (!clockwise) | |
173 { | |
174 angle2Rad -= 2 * g_pi; | |
175 // now we are sure angle2Rad < angle1Rad (since they were normalized) | |
176 // and, thus, going from 1 to 2 means the angle values will DECREASE, | |
177 // which is the definition of anticlockwise | |
178 } | |
179 | |
180 chain.clear(); | |
181 chain.reserve(subdivisionsCount + 1); | |
182 | |
183 double angleIncr = (angle2Rad - angle1Rad) | |
184 / static_cast<double>(subdivisionsCount); | |
185 | |
186 double theta = angle1Rad; | |
187 for (int i = 0; i < subdivisionsCount + 1; ++i) | |
188 { | |
189 double offsetX = radiusS * cos(theta); | |
190 double offsetY = radiusS * sin(theta); | |
191 double pointX = centerS.GetX() + offsetX; | |
192 double pointY = centerS.GetY() + offsetY; | |
193 chain.push_back(ScenePoint2D(pointX, pointY)); | |
194 theta += angleIncr; | |
195 } | |
196 } | |
197 #endif | |
198 | |
199 void AddCircle(PolylineSceneLayer::Chain& chain, | |
200 const Scene2D& scene, | |
201 const ScenePoint2D& centerS, | |
202 const double& radiusS, | |
203 const int numSubdivisions) | |
204 { | |
205 //ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform()); | |
206 //TODO: take DPI into account | |
207 | |
208 // TODO: automatically compute the number for segments for smooth | |
209 // display based on the radius in pixels. | |
210 | |
211 chain.clear(); | |
212 chain.reserve(numSubdivisions); | |
213 | |
214 double angleIncr = (2.0 * g_pi) | |
215 / static_cast<double>(numSubdivisions); | |
216 | |
217 double theta = 0; | |
218 for (int i = 0; i < numSubdivisions; ++i) | |
219 { | |
220 double offsetX = radiusS * cos(theta); | |
221 double offsetY = radiusS * sin(theta); | |
222 double pointX = centerS.GetX() + offsetX; | |
223 double pointY = centerS.GetY() + offsetY; | |
224 chain.push_back(ScenePoint2D(pointX, pointY)); | |
225 theta += angleIncr; | |
226 } | |
227 } | |
228 | |
229 double NormalizeAngle(double angle) | |
230 { | |
231 double retAngle = angle; | |
232 while (retAngle < -1.0*g_pi) | |
233 retAngle += 2 * g_pi; | |
234 while (retAngle >= g_pi) | |
235 retAngle -= 2 * g_pi; | |
236 return retAngle; | |
237 } | |
238 | |
239 double MeasureAngle(const ScenePoint2D& p1, const ScenePoint2D& c, const ScenePoint2D& p2) | |
240 { | |
241 double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX()); | |
242 double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX()); | |
243 double delta = p2cAngle - p1cAngle; | |
244 return NormalizeAngle(delta); | |
245 } | |
246 | |
247 | |
248 #if 0 | |
249 void AddEllipse(PolylineSceneLayer::Chain& chain, | |
250 const Scene2D& scene, | |
251 const ScenePoint2D& centerS, | |
252 const double& halfHAxis, | |
253 const double& halfVAxis) | |
254 { | |
255 chain.clear(); | |
256 chain.reserve(4); | |
257 ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform()); | |
258 //TODO: take DPI into account | |
259 double handleLX = centerC.GetX() - sideLength / 2; | |
260 double handleTY = centerC.GetY() - sideLength / 2; | |
261 double handleRX = centerC.GetX() + sideLength / 2; | |
262 double handleBY = centerC.GetY() + sideLength / 2; | |
263 ScenePoint2D LTC(handleLX, handleTY); | |
264 ScenePoint2D RTC(handleRX, handleTY); | |
265 ScenePoint2D RBC(handleRX, handleBY); | |
266 ScenePoint2D LBC(handleLX, handleBY); | |
267 | |
268 ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform()); | |
269 ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform()); | |
270 ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform()); | |
271 ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform()); | |
272 | |
273 chain.push_back(startLT); | |
274 chain.push_back(startRT); | |
275 chain.push_back(startRB); | |
276 chain.push_back(startLB); | |
277 } | |
278 #endif | |
279 | |
280 | |
281 namespace | |
282 { | |
283 /** | |
284 Helper function for outlined text rendering | |
285 */ | |
286 TextSceneLayer* GetOutlineTextLayer( | |
287 Scene2D& scene, int baseLayerIndex, int index) | |
288 { | |
289 assert(scene.HasLayer(baseLayerIndex)); | |
290 assert(index >= 0); | |
291 assert(index < 5); | |
292 | |
293 ISceneLayer * layer = &(scene.GetLayer(baseLayerIndex + index)); | |
294 TextSceneLayer * concreteLayer = dynamic_cast<TextSceneLayer*>(layer); | |
295 assert(concreteLayer != NULL); | |
296 return concreteLayer; | |
297 } | |
298 } | |
299 | |
300 void SetTextLayerOutlineProperties( | |
301 Scene2D& scene, int baseLayerIndex, const char* text, ScenePoint2D p) | |
302 { | |
303 double xoffsets[5] = { 2, 0, -2, 0, 0 }; | |
304 double yoffsets[5] = { 0, -2, 0, 2, 0 }; | |
305 | |
306 // get the scaling factor | |
307 const double pixelToScene = | |
308 scene.GetCanvasToSceneTransform().ComputeZoom(); | |
309 | |
310 for (int i = 0; i < 5; ++i) | |
311 { | |
312 TextSceneLayer* textLayer = GetOutlineTextLayer(scene, baseLayerIndex, i); | |
313 textLayer->SetText(text); | |
314 | |
315 if (i == 4) | |
316 textLayer->SetColor(0, 223, 81); | |
317 else | |
318 textLayer->SetColor(0, 56, 21); | |
319 | |
320 ScenePoint2D textAnchor; | |
321 //GetPositionOnBisectingLine( | |
322 // textAnchor, side1End_, center_, side2End_, 40.0*pixelToScene); | |
323 textLayer->SetPosition( | |
324 p.GetX() + xoffsets[i] * pixelToScene, | |
325 p.GetY() + yoffsets[i] * pixelToScene); | |
326 } | |
327 } | |
328 | |
329 | |
330 | |
331 | |
332 | |
333 | |
334 | |
335 | |
336 } |