1 /****************************************************************************
2 ** Copyright (c) 2019, Adel Kara Slimane <adel.ks@zegrapher.com>
3 **
4 ** This file is part of ZeGrapher's source code.
5 **
6 ** ZeGrapher is free software: you may copy, redistribute and/or modify it
7 ** under the terms of the GNU General Public License as published by the
8 ** Free Software Foundation, either version 3 of the License, or (at your
9 ** option) any later version.
10 **
11 ** This file is distributed in the hope that it will be useful, but
12 ** WITHOUT ANY WARRANTY; without even the implied warranty of
13 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ** General Public License for more details.
15 **
16 ** You should have received a copy of the GNU General Public License
17 ** along with this program. If not, see <http://www.gnu.org/licenses/>.
18 **
19 ****************************************************************************/
20
21 #include "GraphDraw/mathobjectdraw.h"
22 #include <iostream>
23
24 using namespace std;
25
MathObjectDraw(Information * info)26 MathObjectDraw::MathObjectDraw(Information *info)
27 {
28 information = info;
29
30 coef = sqrt(3)/2;
31
32 setMinimumSize(QSize(200, 200));
33 viewSettings = info->getViewSettings();
34
35 pen.setCapStyle(Qt::RoundCap);
36 brush.setStyle(Qt::SolidPattern);
37
38 straightLines = info->getStraightLinesList();
39 tangents = info->getTangentsList();
40 parEqs = info->getParEqsList();
41 funcs = info->getFuncsList();
42 seqs = info->getSeqsList();
43
44 moving = false;
45 tangentDrawException = -1;
46
47 funcValuesSaver = new FuncValuesSaver(info->getFuncsList(), viewSettings.graph.estheticSettings.distanceBetweenPoints);
48
49 connect(information, SIGNAL(regressionAdded(Regression*)), this, SLOT(addRegSaver(Regression*)));
50 connect(information, SIGNAL(regressionRemoved(Regression*)), this, SLOT(delRegSaver(Regression*)));
51 connect(information, SIGNAL(viewSettingsChanged()), this, SLOT(updateSettingsVals()));
52 }
53
updateSettingsVals()54 void MathObjectDraw::updateSettingsVals()
55 {
56 viewSettings = information->getViewSettings();
57 funcValuesSaver->setPixelStep(viewSettings.graph.estheticSettings.distanceBetweenPoints);
58 }
59
addRegSaver(Regression * reg)60 void MathObjectDraw::addRegSaver(Regression *reg)
61 {
62 regValuesSavers << RegressionValuesSaver(viewSettings.graph.estheticSettings.distanceBetweenPoints, reg);
63 recalculate = true;
64 repaint();
65 }
66
delRegSaver(Regression * reg)67 void MathObjectDraw::delRegSaver(Regression *reg)
68 {
69 for(int i = 0 ; i < regValuesSavers.size() ; i++)
70 if(regValuesSavers[i].getRegression() == reg)
71 regValuesSavers.removeAt(i);
72 recalculate = false;
73 repaint();
74 }
75
drawRhombus(QPointF pt,double w)76 void MathObjectDraw::drawRhombus(QPointF pt, double w)
77 {
78 QPolygonF polygon;
79 polygon << pt + QPointF(-w,0) << pt + QPointF(0,w) << pt + QPointF(w,0) << pt + QPointF(0,-w);
80
81 painter.drawPolygon(polygon);
82 }
83
drawDisc(QPointF pt,double w)84 void MathObjectDraw::drawDisc(QPointF pt, double w)
85 {
86 painter.drawEllipse(pt, w, w);
87 }
88
drawSquare(QPointF pt,double w)89 void MathObjectDraw::drawSquare(QPointF pt, double w)
90 {
91 painter.setRenderHint(QPainter::Antialiasing, false);
92
93 QRectF rect;
94 rect.setTopLeft(pt + QPointF(-w,-w));
95 rect.setBottomRight(pt + QPointF(w,w));
96
97 painter.drawRect(rect);
98 }
99
drawTriangle(QPointF pt,double w)100 void MathObjectDraw::drawTriangle(QPointF pt, double w)
101 {
102 w*=2;
103 QPolygonF polygon;
104 double d = w*coef;
105 double b = w/2;
106
107 polygon << pt + QPointF(0, -w) << pt + QPointF(d, b) << pt + QPointF(-d,b);
108
109 painter.drawPolygon(polygon);
110 }
111
drawCross(QPointF pt,double w)112 void MathObjectDraw::drawCross(QPointF pt, double w)
113 {
114 painter.setRenderHint(QPainter::Antialiasing, false);
115
116 pen.setWidth(w);
117
118 painter.drawLine(pt+QPointF(0,2*w), pt+QPointF(0, -2*w));
119 painter.drawLine(pt+QPointF(-2*w, 0), pt+QPointF(2*w, 0));
120 }
121
drawDataSet(int id,int width)122 void MathObjectDraw::drawDataSet(int id, int width)
123 {
124 QList<QPointF> list = information->getDataList(id);
125 DataStyle style = information->getDataStyle(id);
126
127
128 pen.setColor(style.color);
129 painter.setPen(pen);
130
131 if(style.drawLines)
132 {
133 QPolygonF polygon;
134 pen.setStyle(style.lineStyle);
135 painter.setPen(pen);
136 painter.drawPolyline(polygon.fromList(list));
137 pen.setStyle(Qt::SolidLine);
138 painter.setPen(pen);
139 }
140
141 brush.setColor(style.color);
142 painter.setBrush(brush);
143
144 if(style.drawPoints)
145 {
146 for(int i = 0 ; i < list.size() ; i++)
147 switch(style.pointStyle)
148 {
149 case PointStyle::Rhombus:
150 drawRhombus(list[i], width);
151 break;
152 case PointStyle::Disc:
153 drawDisc(list[i], width);
154 break;
155 case PointStyle::Square:
156 drawSquare(list[i], width);
157 break;
158 case PointStyle::Triangle:
159 drawTriangle(list[i], width);
160 break;
161 case PointStyle::Cross:
162 drawCross(list[i], width);
163 break;
164 }
165 }
166
167
168 }
169
drawData()170 void MathObjectDraw::drawData()
171 {
172 for(int i = 0 ; i < information->getDataListsCount(); i++)
173 {
174 if(information->getDataStyle(i).draw)
175 drawDataSet(i, viewSettings.graph.estheticSettings.curvesThickness + 2);
176 }
177 }
178
drawCurve(int width,QColor color,const QPolygonF & curve)179 void MathObjectDraw::drawCurve(int width, QColor color, const QPolygonF &curve)
180 {
181 pen.setWidth(width);
182 pen.setColor(color);
183 painter.setPen(pen);
184
185 painter.drawPolyline(curve);
186
187 }
188
drawCurve(int width,QColor color,const QList<QPolygonF> & curves)189 void MathObjectDraw::drawCurve(int width, QColor color, const QList<QPolygonF> &curves)
190 {
191 for(QPolygonF curve: curves)
192 drawCurve(width, color, curve);
193 }
194
drawRegressions()195 void MathObjectDraw::drawRegressions()
196 {
197 painter.setRenderHint(QPainter::Antialiasing, viewSettings.graph.estheticSettings.smoothing && !moving);
198
199 for(int reg = 0 ; reg < regValuesSavers.size() ; reg++)
200 {
201 if(information->getRegression(reg)->getDrawState())
202 {
203 for(int curve = 0 ; curve < regValuesSavers[reg].getCurves().size() ; curve++)
204 {
205 drawCurve(viewSettings.graph.estheticSettings.curvesThickness, information->getRegression(reg)->getColor(),
206 regValuesSavers[reg].getCurves().at(curve));
207 }
208 }
209 }
210 }
211
recalculateRegVals()212 void MathObjectDraw::recalculateRegVals()
213 {
214 for(auto ®ValSaver : regValuesSavers)
215 {
216 regValSaver.recalculate(Point{uniteX, uniteY}, viewMapper);
217 }
218 }
219
220
drawFunctions()221 void MathObjectDraw::drawFunctions()
222 {
223 painter.setRenderHint(QPainter::Antialiasing, viewSettings.graph.estheticSettings.smoothing && !moving);
224
225 for(int func = 0 ; func < funcs.size(); func++)
226 {
227 if(!funcs[func]->getDrawState())
228 continue;
229
230 for(int curve = 0 ; curve < funcValuesSaver->getFuncDrawsNum(func) ; curve++)
231 drawCurve(viewSettings.graph.estheticSettings.curvesThickness, funcs[func]->getColorSaver()->getColor(curve), funcValuesSaver->getCurve(func, curve));
232 }
233 }
234
drawOneSequence(int i,int width)235 void MathObjectDraw::drawOneSequence(int i, int width)
236 {
237 if(viewMapper.getXmax() <= seqs[0]->get_nMin() ||
238 trunc(viewMapper.getXmax()) <= viewMapper.getXmin() ||
239 !seqs[i]->getDrawState())
240 return;
241
242 painter.setRenderHint(QPainter::Antialiasing, viewSettings.graph.estheticSettings.smoothing && !moving);
243 pen.setWidth(width);
244
245 QPointF point;
246 double posX;
247
248 double viewXmin = viewMapper.getViewRect().left();
249 double viewXmax = viewMapper.getViewRect().right();
250
251 double Xmin = viewMapper.getXmin();
252 double Xmax = viewMapper.getXmax();
253
254 if(Xmin > seqs[0]->get_nMin())
255 posX = viewXmin;
256 else posX = viewMapper.unitToViewX(seqs[0]->get_nMin());
257
258 double step = 1;
259
260 if(uniteX < 1)
261 step = 5 * trunc(1/uniteX);
262
263
264 double result;
265 bool ok = true;
266 int end = seqs[i]->getDrawsNum();
267
268 ColorSaver *colorSaver = seqs[i]->getColorSaver();
269
270
271 for(int k = 0; k < end; k++)
272 {
273 pen.setColor(colorSaver->getColor(k));
274 painter.setPen(pen);
275
276 for(double pos = posX; pos < viewXmax; pos += step)
277 {
278 result = seqs[i]->getSeqValue(trunc(viewMapper.unitToViewX(pos)), ok, k);
279
280 if(!ok || !std::isnormal(result))
281 return;
282
283 point.setX(pos);
284 point.setY(result);
285 painter.drawPoint(point);
286 }
287 }
288 }
289
drawSequences()290 void MathObjectDraw::drawSequences()
291 {
292 for(int i = 0 ; i < seqs.size() ; i++)
293 drawOneSequence(i, viewSettings.graph.estheticSettings.curvesThickness + 3);
294 }
295
drawOneTangent(int i)296 void MathObjectDraw::drawOneTangent(int i)
297 {
298 if(!tangents->at(i)->isTangentValid())
299 return;
300
301 painter.setRenderHint(QPainter::Antialiasing, viewSettings.graph.estheticSettings.smoothing && !moving);
302
303 tangents->at(i)->calculateTangentPoints(uniteX, uniteY);
304
305 TangentPoints tangentPoints;
306
307 pen.setColor(tangents->at(i)->getColor());
308
309 pen.setWidth(viewSettings.graph.estheticSettings.curvesThickness);
310 painter.setPen(pen);
311
312 tangentPoints = tangents->at(i)->getCaracteristicPoints();
313 painter.drawLine(QPointF(viewMapper.unitToViewX(tangentPoints.left.x), viewMapper.unitToViewY(tangentPoints.left.y)),
314 QPointF(viewMapper.unitToViewX(tangentPoints.right.x), viewMapper.unitToViewY(tangentPoints.right.y)));
315
316 pen.setWidth(viewSettings.graph.estheticSettings.curvesThickness + 3);
317 painter.setPen(pen);
318
319 painter.drawPoint(QPointF(viewMapper.unitToViewX(tangentPoints.left.x), viewMapper.unitToViewY(tangentPoints.left.y)));
320 painter.drawPoint(QPointF(viewMapper.unitToViewX(tangentPoints.center.x), viewMapper.unitToViewY(tangentPoints.center.y)));
321 painter.drawPoint(QPointF(viewMapper.unitToViewX(tangentPoints.right.x), viewMapper.unitToViewY(tangentPoints.right.y)));
322 }
323
drawTangents()324 void MathObjectDraw::drawTangents()
325 {
326 for(int i = 0 ; i < tangents->size(); i++)
327 {
328 if(i != tangentDrawException)
329 drawOneTangent(i);
330 }
331 }
332
drawStraightLines()333 void MathObjectDraw::drawStraightLines()
334 {
335 pen.setWidth(viewSettings.graph.estheticSettings.curvesThickness);
336 QPointF pt1, pt2;
337
338 painter.setRenderHint(QPainter::Antialiasing, viewSettings.graph.estheticSettings.smoothing && !moving);
339
340 for(int i = 0 ; i < straightLines->size(); i++)
341 {
342 if(!straightLines->at(i)->isValid())
343 continue;
344
345 pen.setColor(straightLines->at(i)->getColor());
346 painter.setPen(pen);
347
348 if(straightLines->at(i)->isVertical())
349 {
350 pt1.setX(viewMapper.unitToViewX(straightLines->at(i)->getVerticalPos()));
351 pt1.setY(viewMapper.getViewRect().top());
352
353 pt2.setX(viewMapper.unitToViewX(straightLines->at(i)->getVerticalPos()));
354 pt2.setY(viewMapper.getViewRect().bottom());
355 }
356 else
357 {
358 pt1.setX(viewMapper.getViewRect().left());
359 pt1.setY(viewMapper.unitToViewY(straightLines->at(i)->getY(viewMapper.getXmin())));
360
361 pt2.setX(viewMapper.getViewRect().right());
362 pt2.setY(viewMapper.unitToViewY(straightLines->at(i)->getY(viewMapper.getXmax())));
363 }
364
365 painter.drawLine(pt1, pt2);
366 }
367 }
368
drawStaticParEq()369 void MathObjectDraw::drawStaticParEq()
370 {
371 QList< QList<Point> > *list;
372 QPolygonF polygon;
373 Point point;
374 ColorSaver *colorSaver;
375
376 pen.setWidth(viewSettings.graph.estheticSettings.curvesThickness);
377 painter.setRenderHint(QPainter::Antialiasing, viewSettings.graph.estheticSettings.smoothing && !moving);
378 painter.setPen(pen);
379
380 for(int i = 0; i < parEqs->size(); i++)
381 {
382 if(!parEqs->at(i)->getDrawState() || parEqs->at(i)->isAnimated())
383 continue;
384
385 list = parEqs->at(i)->getPointsList();
386 colorSaver = parEqs->at(i)->getColorSaver();
387
388 for(int curve = 0; curve < list->size(); curve++)
389 {
390 pen.setColor(colorSaver->getColor(curve));
391 painter.setPen(pen);
392
393 polygon.clear();
394
395 for(int pos = 0 ; pos < list->at(curve).size(); pos ++)
396 {
397 point = list->at(curve).at(pos);
398 polygon << QPointF(viewMapper.unitToViewX(point.x), viewMapper.unitToViewY(point.y));
399 }
400
401 painter.drawPolyline(polygon);
402 }
403 }
404 }
405
406
~MathObjectDraw()407 MathObjectDraw::~MathObjectDraw()
408 {
409 delete funcValuesSaver;
410 }
411