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