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