1 /*
2 Copyright 2006-2019 The QElectroTech Team
3 This file is part of QElectroTech.
4
5 QElectroTech is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 2 of the License, or
8 (at your option) any later version.
9
10 QElectroTech is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "qetgraphicshandlerutility.h"
19 #include <QPainterPath>
20
21
22 /**
23 * @brief QetGraphicsHandlerUtility::pointsForRect
24 * Return the keys points of the rectangle, stored in a vector.
25 * The points in the vector are stored like this :
26 * **********
27 * 0---1---2
28 * | |
29 * 3 4
30 * | |
31 * 5---6---7
32 * ************
33 * @param rect
34 * @return
35 */
pointsForRect(const QRectF & rect)36 QVector<QPointF> QetGraphicsHandlerUtility::pointsForRect(const QRectF &rect)
37 {
38 QVector<QPointF> vector;
39 QPointF point;
40 vector << rect.topLeft();//*****Top left
41 point = rect.center();
42 point.setY(rect.top());
43 vector << point;//**************Middle top
44 vector << rect.topRight();//****Top right
45 point = rect.center();
46 point.setX(rect.left());
47 vector << point;//**************Middle left
48 point.setX(rect.right());
49 vector << point;//**************Middle right
50 vector << rect.bottomLeft();//**Bottom left
51 point = rect.center();
52 point.setY(rect.bottom());
53 vector << point;//*************Middle bottom
54 vector << rect.bottomRight();//*Bottom right
55 return vector;
56 }
57
58 /**
59 * @brief QetGraphicsHandlerUtility::pointsForLine
60 * The point that define a line in a QVector.
61 * there is two points.
62 * @param line
63 * @return
64 */
pointsForLine(const QLineF & line)65 QVector<QPointF> QetGraphicsHandlerUtility::pointsForLine(const QLineF &line) {
66 return (QVector<QPointF> {line.p1(), line.p2()});
67 }
68
69 /**
70 * @brief QetGraphicsHandlerUtility::pointsForArc
71 * Return the points for the given arc.
72 * The first value in the vector is the start point, the second the end point.
73 * @param rect
74 * @param start_angle : start angle in degree
75 * @param span_angle : span angle in degree;
76 * @return
77 */
pointsForArc(const QRectF & rect,qreal start_angle,qreal span_angle)78 QVector<QPointF> QetGraphicsHandlerUtility::pointsForArc(const QRectF &rect, qreal start_angle, qreal span_angle)
79 {
80 QVector<QPointF> vector;
81 QPainterPath path;
82 path.arcTo(rect, start_angle, 0);
83 vector.append(path.currentPosition());
84 path.arcTo(rect, start_angle, span_angle);
85 vector.append(path.currentPosition());
86 return vector;
87
88 }
89
90 /**
91 * @brief QetGraphicsHandlerUtility::rectForPosAtIndex
92 * Return a rectangle after modification of the point '@pos' at index '@index' of original rectangle '@old_rect'.
93 * @param old_rect - the rectangle befor modification
94 * @param pos - the new position of a key point
95 * @param index - the index of the key point to modifie see QetGraphicsHandlerUtility::pointsForRect to know
96 * the index of each keys points of a rectangle)
97 * @return : the rectangle with modification. If index is lower than 0 or higher than 7, this method return old_rect.
98 */
rectForPosAtIndex(const QRectF & old_rect,const QPointF & pos,int index)99 QRectF QetGraphicsHandlerUtility::rectForPosAtIndex(const QRectF &old_rect, const QPointF &pos, int index)
100 {
101 if (index < 0 || index > 7) return old_rect;
102
103 QRectF rect = old_rect;
104 if (index == 0) rect.setTopLeft(pos);
105 else if (index == 1) rect.setTop(pos.y());
106 else if (index == 2) rect.setTopRight(pos);
107 else if (index == 3) rect.setLeft(pos.x());
108 else if (index == 4) rect.setRight(pos.x());
109 else if (index == 5) rect.setBottomLeft(pos);
110 else if (index == 6) rect.setBottom(pos.y());
111 else if (index == 7) rect.setBottomRight(pos);
112
113 return rect;
114 }
115
116 /**
117 * @brief QetGraphicsHandlerUtility::mirrorRectForPosAtIndex
118 * Return a rectangle after modification of the point '@pos' at index '@index' of original rectangle '@old_rect'.
119 * the opposite edge is modified inversely (like a mirror)
120 * @param old_rect : the rectangle befor modification
121 * @param pos : the new position of a key point
122 * @param index : the index of the key point to modifie see QetGraphicsHandlerUtility::pointsForRect to know
123 * the index of each keys points of a rectangle)
124 * @return : the rectangle with modification. If index is lower than 0 or higher than 7, this method return old_rect.
125 */
mirrorRectForPosAtIndex(const QRectF & old_rect,const QPointF & pos,int index)126 QRectF QetGraphicsHandlerUtility::mirrorRectForPosAtIndex(const QRectF &old_rect, const QPointF &pos, int index)
127 {
128 if (index < 0 || index > 7) return old_rect;
129
130 QRectF rect = old_rect;
131 QPointF center = rect.center();
132
133 if (index == 0) {
134 qreal x = pos.x() + (pos.x() - rect.topLeft().x());
135 qreal y = pos.y() + (pos.y() - rect.topLeft().y());
136 rect.setTopLeft(QPointF(x,y));
137 }
138 else if (index == 1) {
139 qreal y = pos.y() + (pos.y() - rect.topLeft().y());
140 rect.setTop(y);
141 }
142 else if (index == 2) {
143 qreal x = pos.x() + (pos.x() - rect.topRight().x());
144 qreal y = pos.y() + (pos.y() - rect.topLeft().y());
145 rect.setTopRight(QPointF(x,y));
146 }
147 else if (index == 3) {
148 qreal x = pos.x() + (pos.x() - rect.left());
149 rect.setLeft(x);
150 }
151 else if (index == 4) {
152 qreal x = pos.x() + (pos.x() - rect.right());
153 rect.setRight(x);
154 }
155 else if (index == 5) {
156 qreal x = pos.x() + (pos.x() - rect.bottomLeft().x());
157 qreal y = pos.y() + (pos.y() - rect.bottomLeft().y());
158 rect.setBottomLeft(QPointF(x,y));
159 }
160 else if (index == 6) {
161 qreal y = pos.y() + (pos.y() - rect.bottom());
162 rect.setBottom(y);
163 }
164 else if (index == 7) {
165 qreal x = pos.x() + (pos.x() - rect.bottomRight().x());
166 qreal y = pos.y() + (pos.y() - rect.bottomRight().y());
167 rect.setBottomRight(QPointF(x,y));
168 }
169
170 rect.moveCenter(center);
171 return rect;
172 }
173
174 /**
175 * @brief QetGraphicsHandlerUtility::lineForPosAtIndex
176 * Return a line after modification of @pos at index @index of @old_line.
177 * @param old_line
178 * @param pos
179 * @param index
180 * @return
181 */
lineForPosAtIndex(const QLineF & old_line,const QPointF & pos,int index)182 QLineF QetGraphicsHandlerUtility::lineForPosAtIndex(const QLineF &old_line, const QPointF &pos, int index) {
183 QLineF line = old_line;
184 index == 0 ? line.setP1(pos) : line.setP2(pos);
185 return line;
186 }
187
188 /**
189 * @brief QetGraphicsHandlerUtility::polygonForInsertPoint
190 * @param old_polygon : the polygon which we insert a new point.
191 * @param closed : polygon is closed or not
192 * @param pos : the pos where the new point must be added
193 * @return the new polygon
194 */
polygonForInsertPoint(const QPolygonF & old_polygon,bool closed,const QPointF & pos)195 QPolygonF QetGraphicsHandlerUtility::polygonForInsertPoint(const QPolygonF &old_polygon, bool closed, const QPointF &pos)
196 {
197 qreal max_angle = 0;
198 int index = 0;
199
200 for (int i=1 ; i<old_polygon.size() ; i++)
201 {
202 QPointF A = old_polygon.at(i-1);
203 QPointF B = old_polygon.at(i);
204 QLineF line_a(A, pos);
205 QLineF line_b(pos, B);
206 qreal angle = line_a.angleTo(line_b);
207 if(angle<180)
208 angle = 360-angle;
209
210 if (i==1)
211 {
212 max_angle = angle;
213 index=i;
214 }
215 if (angle > max_angle)
216 {
217 max_angle = angle;
218 index=i;
219 }
220 }
221 //Special case when polygon is close
222 if (closed)
223 {
224 QLineF line_a(old_polygon.last(), pos);
225 QLineF line_b(pos, old_polygon.first());
226
227 qreal angle = line_a.angleTo(line_b);
228 if (angle<180)
229 angle = 360-angle;
230
231 if (angle > max_angle)
232 {
233 max_angle = angle;
234 index=old_polygon.size();
235 }
236 }
237
238 QPolygonF polygon = old_polygon;
239 polygon.insert(index, pos);
240 return polygon;
241 }
242
243 /**
244 * @brief QetGraphicsHandlerUtility::pointForRadiusRect
245 * @param rect the rectangle.
246 * @param xRadius : x radius
247 * @param yRadius : y radius
248 * @param mode : absolute or relative size: NOTE this argument is not used, this function always compute with relative size.
249 * @return the points of x and y radius of a rounded rect.
250 * The points are always based on the top right corner of the rect.
251 * the first point of vector is X the second Y
252 */
pointForRadiusRect(const QRectF & rect,qreal xRadius,qreal yRadius,Qt::SizeMode mode)253 QVector<QPointF> QetGraphicsHandlerUtility::pointForRadiusRect(const QRectF &rect, qreal xRadius, qreal yRadius, Qt::SizeMode mode)
254 {
255 QVector<QPointF> v;
256
257 if(mode == Qt::AbsoluteSize)
258 {
259 QPointF X = rect.topRight();
260 X.rx() -= xRadius;
261 v << X;
262
263 QPointF Y = rect.topRight();
264 Y.ry() += yRadius;
265 v << Y;
266 }
267 else
268 {
269 qreal half_width = rect.width()/2;
270 qreal x_percent = std::min(xRadius, 100.00)/100;
271 QPointF X(rect.right() - half_width*x_percent,
272 rect.top());
273 v << X;
274
275 qreal half_height = rect.height()/2;
276 qreal y_percent = std::min(yRadius, 100.00)/100;
277 QPointF Y(rect.right(),
278 rect.top()+ half_height*y_percent);
279 v << Y;
280 }
281
282 return v;
283 }
284
285 /**
286 * @brief QetGraphicsHandlerUtility::radiusForPosAtIndex
287 * @param rect the rectangle
288 * @param pos : the pos of the new radius
289 * @param index : index of radius 0=X 1=Y
290 * @param mode
291 * @return
292 */
radiusForPosAtIndex(const QRectF & rect,const QPointF & pos,int index,Qt::SizeMode mode)293 qreal QetGraphicsHandlerUtility::radiusForPosAtIndex(const QRectF &rect, const QPointF &pos, int index, Qt::SizeMode mode)
294 {
295 if (mode == Qt::AbsoluteSize)
296 {
297 if (index == 0)
298 {
299 QPointF tr = rect.topRight();
300 qreal x = tr.x() - pos.x();
301 if (x < 0) {
302 x = 0;
303 }
304 else if (x > rect.width()/2) {
305 x = rect.width()/2;
306 }
307
308 return x;
309 }
310 else if (index == 1)
311 {
312 QPointF tr = rect.topRight();
313 qreal y = pos.y() - tr.y();
314 if (y < 0) {
315 y = 0;
316 }
317 else if (y > rect.height()/2) {
318 y = rect.height()/2;
319 }
320
321 return y;
322 }
323 else {
324 return 0;
325 }
326 }
327 else
328 {
329 if(index == 0) //X
330 {
331 if (pos.x() < rect.center().x()) {
332 return 100;
333 }
334 else if (pos.x() > rect.right()) {
335 return 0;
336 }
337 else {
338 return (100 - percentageInRange(rect.center().x(), rect.right(), pos.x()));
339 }
340 }
341 else if (index == 1) //Y
342 {
343 if (pos.y() < rect.top()) {
344 return 0;
345 }
346 else if (pos.y() > rect.center().y()) {
347 return 100;
348 }
349 else {
350 return percentageInRange(rect.top(), rect.center().y(), pos.y());
351 }
352 }
353 else {
354 return 0;
355 }
356 }
357 }
358
percentageInRange(qreal min,qreal max,qreal value)359 qreal QetGraphicsHandlerUtility::percentageInRange(qreal min, qreal max, qreal value) {
360 return ((value - min) * 100) / (max - min);
361 }
362
363