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 &regValSaver : 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