comparison Samples/Common/MeasureToolsToolbox.cpp @ 645:1e9ed656318e

Merge + ongoing measure work
author Benjamin Golinvaux <bgo@osimis.io>
date Mon, 13 May 2019 15:12:56 +0200
parents
children 62f6ff016085
comparison
equal deleted inserted replaced
644:f939f449482c 645:1e9ed656318e
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 <boost/math/constants/constants.hpp>
24
25 namespace
26 {
27 double g_pi = boost::math::constants::pi<double>();
28 }
29
30 namespace OrthancStone
31 {
32
33 void AddSquare(PolylineSceneLayer::Chain& chain,
34 const Scene2D& scene,
35 const ScenePoint2D& centerS,
36 const double& sideLength)
37 {
38 chain.clear();
39 chain.reserve(4);
40 ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
41 //TODO: take DPI into account
42 double handleLX = centerC.GetX() - sideLength / 2;
43 double handleTY = centerC.GetY() - sideLength / 2;
44 double handleRX = centerC.GetX() + sideLength / 2;
45 double handleBY = centerC.GetY() + sideLength / 2;
46 ScenePoint2D LTC(handleLX, handleTY);
47 ScenePoint2D RTC(handleRX, handleTY);
48 ScenePoint2D RBC(handleRX, handleBY);
49 ScenePoint2D LBC(handleLX, handleBY);
50
51 ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
52 ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
53 ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
54 ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
55
56 chain.push_back(startLT);
57 chain.push_back(startRT);
58 chain.push_back(startRB);
59 chain.push_back(startLB);
60 }
61
62 void AddArc(
63 PolylineSceneLayer::Chain& chain
64 , const Scene2D& scene
65 , const ScenePoint2D& p1
66 , const ScenePoint2D& c
67 , const ScenePoint2D& p2
68 , const double& radiusS
69 , const bool clockwise
70 , const int subdivisionsCount)
71 {
72 double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
73 double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
74 AddArc(
75 chain, scene, c, radiusS, p1cAngle, p2cAngle,
76 clockwise, subdivisionsCount);
77 }
78
79 double RadiansToDegrees(double angleRad)
80 {
81 static const double factor = 180.0 / g_pi;
82 return angleRad * factor;
83 }
84
85 void GetPositionOnBisectingLine(
86 ScenePoint2D& result
87 , const ScenePoint2D& p1
88 , const ScenePoint2D& c
89 , const ScenePoint2D& p2
90 , const double d)
91 {
92 // TODO: fix correct half-plane
93 double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
94 double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
95 double angle = 0.5*(p1cAngle + p2cAngle);
96 double unitVectorX = cos(angle);
97 double unitVectorY = sin(angle);
98 double posX = c.GetX() + d * unitVectorX;
99 double posY = c.GetX() + d * unitVectorY;
100 result = ScenePoint2D(posX, posY);
101 }
102
103 void AddArc(
104 PolylineSceneLayer::Chain& chain
105 , const Scene2D& scene
106 , const ScenePoint2D& centerS
107 , const double& radiusS
108 , const double startAngleRad
109 , const double endAngleRad
110 , const bool clockwise
111 , const int subdivisionsCount)
112 {
113 double startAngleRadN = NormalizeAngle(startAngleRad);
114 double endAngleRadN = NormalizeAngle(endAngleRad);
115
116 double angle1Rad = std::min(startAngleRadN, endAngleRadN);
117 double angle2Rad = std::max(startAngleRadN, endAngleRadN);
118
119 // now we are sure angle1Rad < angle2Rad
120 // this means that if we draw from 1 to 2, it will be clockwise (
121 // increasing angles).
122 // let's fix this:
123 if (!clockwise)
124 {
125 angle2Rad -= 2 * g_pi;
126 // now we are sure angle2Rad < angle1Rad (since they were normalized)
127 // and, thus, going from 1 to 2 means the angle values will DECREASE,
128 // which is the definition of anticlockwise
129 }
130
131 chain.clear();
132 chain.reserve(subdivisionsCount + 1);
133
134 double angleIncr = (angle2Rad - angle1Rad)
135 / static_cast<double>(subdivisionsCount);
136
137 double theta = angle1Rad;
138 for (int i = 0; i < subdivisionsCount + 1; ++i)
139 {
140 double offsetX = radiusS * cos(theta);
141 double offsetY = radiusS * sin(theta);
142 double pointX = centerS.GetX() + offsetX;
143 double pointY = centerS.GetY() + offsetY;
144 chain.push_back(ScenePoint2D(pointX, pointY));
145 theta += angleIncr;
146 }
147 }
148
149 void AddCircle(PolylineSceneLayer::Chain& chain,
150 const Scene2D& scene,
151 const ScenePoint2D& centerS,
152 const double& radiusS,
153 const int numSubdivisions)
154 {
155 //ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
156 //TODO: take DPI into account
157
158 // TODO: automatically compute the number for segments for smooth
159 // display based on the radius in pixels.
160
161 chain.clear();
162 chain.reserve(numSubdivisions);
163
164 double angleIncr = (2.0 * g_pi)
165 / static_cast<double>(numSubdivisions);
166
167 double theta = 0;
168 for (int i = 0; i < numSubdivisions; ++i)
169 {
170 double offsetX = radiusS * cos(theta);
171 double offsetY = radiusS * sin(theta);
172 double pointX = centerS.GetX() + offsetX;
173 double pointY = centerS.GetY() + offsetY;
174 chain.push_back(ScenePoint2D(pointX, pointY));
175 theta += angleIncr;
176 }
177 }
178
179 double NormalizeAngle(double angle)
180 {
181 double retAngle = angle;
182 while (retAngle < 0)
183 retAngle += 2 * g_pi;
184 while (retAngle >= 2 * g_pi)
185 retAngle -= 2 * g_pi;
186 return retAngle;
187 }
188
189 double MeasureAngle(const ScenePoint2D& p1, const ScenePoint2D& c, const ScenePoint2D& p2)
190 {
191 double p1cAngle = atan2(p1.GetY() - c.GetY(), p1.GetX() - c.GetX());
192 double p2cAngle = atan2(p2.GetY() - c.GetY(), p2.GetX() - c.GetX());
193 double delta = p2cAngle - p1cAngle;
194 return NormalizeAngle(delta);
195 }
196
197
198 #if 0
199 void AddEllipse(PolylineSceneLayer::Chain& chain,
200 const Scene2D& scene,
201 const ScenePoint2D& centerS,
202 const double& halfHAxis,
203 const double& halfVAxis)
204 {
205 chain.clear();
206 chain.reserve(4);
207 ScenePoint2D centerC = centerS.Apply(scene.GetSceneToCanvasTransform());
208 //TODO: take DPI into account
209 double handleLX = centerC.GetX() - sideLength / 2;
210 double handleTY = centerC.GetY() - sideLength / 2;
211 double handleRX = centerC.GetX() + sideLength / 2;
212 double handleBY = centerC.GetY() + sideLength / 2;
213 ScenePoint2D LTC(handleLX, handleTY);
214 ScenePoint2D RTC(handleRX, handleTY);
215 ScenePoint2D RBC(handleRX, handleBY);
216 ScenePoint2D LBC(handleLX, handleBY);
217
218 ScenePoint2D startLT = LTC.Apply(scene.GetCanvasToSceneTransform());
219 ScenePoint2D startRT = RTC.Apply(scene.GetCanvasToSceneTransform());
220 ScenePoint2D startRB = RBC.Apply(scene.GetCanvasToSceneTransform());
221 ScenePoint2D startLB = LBC.Apply(scene.GetCanvasToSceneTransform());
222
223 chain.push_back(startLT);
224 chain.push_back(startRT);
225 chain.push_back(startRB);
226 chain.push_back(startLB);
227 }
228 #endif
229 }