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/basegraphdraw.h"
22 
23 
BaseGraphDraw(Information * info)24 BaseGraphDraw::BaseGraphDraw(Information *info) : MathObjectDraw(info)
25 {
26     information = info;
27     leftMargin = 30;
28     rightMargin = 30;
29     topMargin = 20;
30     bottomMargin = 30;
31 
32     tangentDrawException = -1;
33     legendFontSize = 12;
34     legendState = false;
35     additionalMargin = 0;
36     bold = italic = underline = false;
37     numPrec = NUM_PREC;
38 
39     connect(information, SIGNAL(updateOccured()), this, SLOT(update()));
40 }
41 
setNumPrec(int prec)42 void BaseGraphDraw::setNumPrec(int prec)
43 {
44     numPrec = prec;
45     update();
46 }
47 
setBold(bool state)48 void BaseGraphDraw::setBold(bool state)
49 {
50     bold = state;
51     update();
52 }
53 
setUnderline(bool state)54 void BaseGraphDraw::setUnderline(bool state)
55 {
56     underline = state;
57     update();
58 }
59 
setItalic(bool state)60 void BaseGraphDraw::setItalic(bool state)
61 {
62     italic = state;
63     update();
64 }
65 
setlegendFontSize(int size)66 void BaseGraphDraw::setlegendFontSize(int size)
67 {
68     if(legendState)
69     {
70         leftMargin -= legendFontSize;
71         leftMargin += size;
72 
73         bottomMargin -= legendFontSize;
74         bottomMargin += size;
75 
76         additionalMargin = size + 10;
77     }
78 
79     legendFontSize = size;
80 
81     update();
82 }
83 
setLegendState(bool show)84 void BaseGraphDraw::setLegendState(bool show)
85 {
86     if(show && !legendState)
87     {
88         leftMargin += legendFontSize + 10;
89         bottomMargin += legendFontSize + 10;
90 
91         additionalMargin = legendFontSize + 10;
92 
93     }
94     else if(!show && legendState)
95     {
96        leftMargin -= legendFontSize + 10;
97        bottomMargin -= legendFontSize + 10;
98 
99        additionalMargin = 0;
100     }
101 
102     legendState = show;
103 
104     update();
105 }
106 
setXaxisLegend(QString legend)107 void BaseGraphDraw::setXaxisLegend(QString legend)
108 {
109     xLegend = legend;
110     update();
111 }
112 
setYaxisLegend(QString legend)113 void BaseGraphDraw::setYaxisLegend(QString legend)
114 {
115     yLegend = legend;
116     update();
117 }
118 
updateGraphRect()119 void BaseGraphDraw::updateGraphRect()
120 {
121     graphRectScaled.setWidth(figureRectScaled.width() - leftMargin - rightMargin);
122     graphRectScaled.setHeight(figureRectScaled.height() - topMargin - bottomMargin);
123     graphRectScaled.moveTopLeft(QPoint(0, 0)); // because painter is translated to its top-left corner
124 }
125 
paint()126 void BaseGraphDraw::paint()
127 {
128     updateGraphRect(); // must happen before the next instruction
129     updateCenterPosAndScaling();
130 
131     painter.translate(leftMargin, topMargin);
132 
133     drawBaseGraph();
134 
135     if(legendState)
136         writeLegends();
137 
138     painter.setClipRect(graphRectScaled);
139 
140     painter.translate(QPointF(centre.x, centre.y));
141 
142     funcValuesSaver->calculateAll(uniteX, uniteY, viewMapper);
143     recalculateRegVals();
144 
145     drawFunctions();
146     drawSequences();
147     drawStraightLines();
148     drawTangents();
149     drawStaticParEq();
150     drawRegressions();
151     drawData();
152 }
153 
writeLegends()154 void BaseGraphDraw::writeLegends()
155 {
156     font = information->getGraphSettings().estheticSettings.graphFont;
157     font.setPixelSize(legendFontSize);
158     font.setItalic(italic);
159     font.setBold(bold);
160     font.setUnderline(underline);
161 
162     painter.setFont(font);
163 
164     if(!xLegend.isEmpty())
165     {
166         int xLegendWidth = painter.fontMetrics().width(xLegend);
167 
168         QPoint startDrawPoint;
169         startDrawPoint.setX((graphRectScaled.width() - xLegendWidth)/2);
170         startDrawPoint.setY(graphRectScaled.height() + bottomMargin - 10);
171 
172         painter.drawText(startDrawPoint, xLegend);
173     }
174     if(!yLegend.isEmpty())
175     {
176         painter.rotate(-90);
177         int yLegendWidth = painter.fontMetrics().width(yLegend);
178         int yLegendHeight = legendFontSize + 6;
179 
180         QPoint startDrawPoint;
181         startDrawPoint.setX(- (graphRectScaled.height() - (graphRectScaled.height() - yLegendWidth)/2));
182         startDrawPoint.setY(-leftMargin + yLegendHeight);
183 
184         painter.drawText(startDrawPoint, yLegend);
185 
186         painter.rotate(90);
187     }
188 }
189 
drawAxisComponentsLinearX()190 void BaseGraphDraw::drawAxisComponentsLinearX()
191 {
192     painter.setFont(information->getGraphSettings().estheticSettings.graphFont);
193     QFontMetrics fontMetrics = painter.fontMetrics();
194 
195     double space, pos;
196     double Xpos;
197 
198     QString num;
199 
200     ZeLinAxisTicks xAxisTicks = viewMapper.getLinearAxisTicks(graphRectScaled.width(),
201                                                              viewMapper.getGraphRange().x,
202                                                              ZeAxisName::X,
203                                                              fontMetrics);
204 
205     const auto &axisSettings = information->getAxesSettings().x;
206     const auto &gridSettings = information->getGridSettings().alongX;
207 
208     for(ZeLinAxisTick &axisTick: xAxisTicks.ticks)
209     {
210         Xpos = axisTick.pos;
211 
212         if(fabs(Xpos) > 1)
213         {
214             if(gridSettings.showGrid)
215             {
216                 pen.setColor(gridSettings.gridColor);
217                 pen.setWidthF(0.5);
218                 painter.setPen(pen);
219                 painter.drawLine(QPointF(Xpos + centre.x, 0), QPointF(Xpos + centre.x, graphRectScaled.height()));
220             }
221             pen.setColor(axisSettings.color);
222             pen.setWidthF(axisSettings.lineWidth);
223             painter.setPen(pen);
224 
225             pos = Xpos + centre.x;
226 
227             painter.drawLine(QPointF(pos, 4), QPointF(pos, 0));
228             painter.drawLine(QPointF(pos, graphRectScaled.height()-4), QPointF(pos, graphRectScaled.height()));
229             num = QString::number(Xpos/uniteX, 'g', numPrec);
230             space = fontMetrics.width(num);
231             painter.drawText(QPointF(pos - space/2, graphRectScaled.height()+15), num);
232         }
233         else
234         {
235             pos = Xpos + centre.x;
236             space = fontMetrics.width("0");
237             painter.drawText(QPointF(pos - space/2, graphRectScaled.height()+15), "0");
238         }
239     }
240 }
241 
drawAxisComponentsLinearY()242 void BaseGraphDraw::drawAxisComponentsLinearY()
243 {
244     painter.setFont(information->getGraphSettings().estheticSettings.graphFont);
245     QFontMetrics fontMetrics = painter.fontMetrics();
246 
247     double space, pos, largestWidth;
248     double Ypos;
249 
250     QString num;
251 
252     ZeLinAxisTicks yAxisTicks = viewMapper.getLinearAxisTicks(graphRectScaled.height(),
253                                                              viewMapper.getGraphRange().y,
254                                                              ZeAxisName::Y,
255                                                              fontMetrics);
256 
257     const auto &axisSettings = information->getAxesSettings().y;
258     const auto &gridSettings = information->getGridSettings().alongY;
259 
260     for(ZeLinAxisTick &axisTick: yAxisTicks.ticks)
261     {
262         Ypos = axisTick.pos;
263 
264         if(fabs(Ypos) > 1)
265         {
266             if(gridSettings.showGrid)
267             {
268                 pen.setColor(gridSettings.gridColor);
269                 pen.setWidthF(0.5);
270                 painter.setPen(pen);
271                 painter.drawLine(QPointF(0, -Ypos + centre.y), QPointF(graphRectScaled.width(), -Ypos + centre.y));
272             }
273 
274             pen.setColor(axisSettings.color);
275             pen.setWidth(axisSettings.lineWidth);
276             painter.setPen(pen);
277 
278             pos = -Ypos + centre.y;
279 
280             painter.drawLine(QPointF(4, pos), QPointF(0, pos));
281             painter.drawLine(QPointF(graphRectScaled.width() - 4, pos), QPointF(graphRectScaled.width(), pos));
282 
283             num = QString::number(Ypos/uniteY, 'g', numPrec);
284             space = fontMetrics.width(num) + 5;
285 
286             if(space > largestWidth)
287                 largestWidth = space;
288 
289             painter.drawText(QPointF(-space, pos + fontMetrics.height() /2), num);
290         }
291         else
292         {
293             pos = -Ypos + centre.y;
294             space = fontMetrics.width("0") + 5;
295             painter.drawText(QPointF(-space, pos + fontMetrics.height()/2), "0");
296         }
297 
298         if(space > largestWidth)
299             largestWidth = space;
300     }
301 
302     if(leftMargin - additionalMargin - largestWidth > 8 || leftMargin - additionalMargin - largestWidth < 4)
303     {
304         leftMargin = largestWidth + additionalMargin + 6;
305         update();
306     }
307 }
308 
drawBaseGraph()309 void BaseGraphDraw::drawBaseGraph()
310 {
311     drawAxes();
312     if(information->getAxesSettings().x.axisType == ZeAxisType::LINEAR)
313         drawAxisComponentsLinearX();
314 
315     if(information->getAxesSettings().y.axisType == ZeAxisType::LINEAR)
316         drawAxisComponentsLinearY();
317 }
318 
drawAxes()319 void BaseGraphDraw::drawAxes()
320 {
321     const auto &graphRange = information->getGraphRange();
322     const auto &axesSettings = information->getAxesSettings();
323 
324     if(graphRange.y.min < 0 && graphRange.y.max > 0)
325     {
326         pen.setWidth(axesSettings.x.lineWidth);
327         pen.setColor(axesSettings.x.color);
328         painter.setPen(pen);
329         painter.setRenderHint(QPainter::Antialiasing, false);
330 
331         painter.drawLine(QPointF(0, centre.y), QPointF(graphRectScaled.width(), centre.y));
332     }
333     if(graphRange.x.min < 0 && graphRange.x.max > 0)
334     {
335         pen.setWidth(axesSettings.y.lineWidth);
336         pen.setColor(axesSettings.y.color);
337         painter.setPen(pen);
338         painter.setRenderHint(QPainter::Antialiasing, false);
339 
340         painter.drawLine(QPointF(centre.x, 0), QPointF(centre.x, graphRectScaled.height()));
341     }
342 
343     painter.drawRect(graphRectScaled);
344 }
345 
updateCenterPosAndScaling()346 void BaseGraphDraw::updateCenterPosAndScaling()
347 {
348     // TODO: update this method
349 
350     uniteY = double(graphRectScaled.height()) / viewMapper.getViewRect().height();
351     uniteX = double(graphRectScaled.width()) / viewMapper.getViewRect().width();
352 
353     double rapport = uniteY / uniteX;
354 
355     if(information->getAxesSettings().orthonormal)
356     {
357         // TODO
358     }
359 
360     centre.x = - viewMapper.getViewRect().left() * uniteX;
361     centre.y =  viewMapper.getViewRect().top() * uniteY;
362 }
363 
drawImage()364 QImage* BaseGraphDraw::drawImage()
365 {
366     //TODO: update this method
367 
368     viewSettings = information->getViewSettings();
369 
370     QImage *image = new QImage(size(), QImage::Format_RGB32);
371     image->fill(viewSettings.graph.estheticSettings.backgroundColor.rgb());
372 
373     painter.begin(image);
374     //trace du background
375 
376     pen.setColor(viewSettings.axes.x.color);
377     painter.setPen(pen);
378     painter.setRenderHint(QPainter::Antialiasing, false);
379 
380     painter.drawRect(leftMargin, topMargin, graphRectScaled.width(), graphRectScaled.height());
381 
382     painter.translate(leftMargin, topMargin);
383 
384     updateCenterPosAndScaling();
385     drawAxes();
386     drawBaseGraph();
387 
388     if(legendState)
389         writeLegends();
390 
391     painter.setClipRect(0,0,graphRectScaled.width(),graphRectScaled.height());
392 
393     painter.translate(QPointF(centre.x, centre.y));
394 
395     if(recalculate)
396     {
397         funcValuesSaver->calculateAll(uniteX, uniteY, viewMapper);
398         recalculateRegVals();
399     }
400 
401     drawFunctions();
402     drawSequences();
403     drawStraightLines();
404     drawStaticParEq();
405     drawRegressions();
406     drawData();
407 
408     painter.end();
409 
410     //*image = image->convertToFormat(QImage::Format_Indexed8, Qt::DiffuseDither);
411     return image;
412 }
413