File indexing completed on 2024-04-21 03:42:06

0001 /*
0002     KmPlot - a math. function plotter for the KDE-Desktop
0003 
0004     SPDX-FileCopyrightText: 2004 Fredrik Edemar <f_edemar@linux.se>
0005     SPDX-FileCopyrightText: 2006 David Saxton <david@bluehaze.org>
0006 
0007     This file is part of the KDE Project.
0008     KmPlot is part of the KDE-EDU Project.
0009 
0010     SPDX-License-Identifier: GPL-2.0-or-later
0011 
0012 */
0013 
0014 #include "functiontools.h"
0015 #include "ui_functiontools.h"
0016 #include "view.h"
0017 #include "xparser.h"
0018 #include <QDialogButtonBox>
0019 
0020 class FunctionToolsWidget : public QWidget, public Ui::FunctionTools
0021 {
0022 public:
0023     FunctionToolsWidget(QWidget *parent = nullptr)
0024         : QWidget(parent)
0025     {
0026         setupUi(this);
0027     }
0028 };
0029 
0030 // BEGIN class FunctionTools
0031 FunctionTools::FunctionTools(QWidget *parent)
0032     : QDialog(parent)
0033 {
0034     m_widget = new FunctionToolsWidget(this);
0035 
0036     QDialogButtonBox *buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
0037     connect(buttonBox, &QDialogButtonBox::rejected, this, &FunctionTools::reject);
0038     QVBoxLayout *dialogLayout = new QVBoxLayout(this);
0039     dialogLayout->addWidget(m_widget);
0040     dialogLayout->addWidget(buttonBox);
0041 
0042     init(CalculateArea);
0043 
0044     connect(m_widget->min, &EquationEdit::editingFinished, this, &FunctionTools::rangeEdited);
0045     connect(m_widget->max, &EquationEdit::editingFinished, this, &FunctionTools::rangeEdited);
0046     connect(m_widget->list, &QListWidget::currentRowChanged, this, &FunctionTools::equationSelected);
0047 }
0048 
0049 FunctionTools::~FunctionTools()
0050 {
0051 }
0052 
0053 void FunctionTools::init(Mode m)
0054 {
0055     m_mode = m;
0056 
0057     switch (m_mode) {
0058     case FindMinimum: {
0059         m_widget->rangeTitle->setText(i18n("Search between:"));
0060         setWindowTitle(i18nc("@title:window", "Find Minimum Point"));
0061         break;
0062     }
0063 
0064     case FindMaximum: {
0065         m_widget->rangeTitle->setText(i18n("Search between:"));
0066         setWindowTitle(i18nc("@title:window", "Find Maximum Point"));
0067         break;
0068     }
0069 
0070     case CalculateArea: {
0071         m_widget->rangeTitle->setText(i18n("Calculate the area between:"));
0072         setWindowTitle(i18nc("@title:window", "Area Under Graph"));
0073         break;
0074     }
0075     }
0076 
0077     m_widget->min->setText(XParser::self()->number(View::self()->m_xmin));
0078     m_widget->max->setText(XParser::self()->number(View::self()->m_xmax));
0079     m_widget->min->setFocus();
0080 
0081     updateEquationList();
0082     setEquation(EquationPair(View::self()->m_currentPlot, 0));
0083 }
0084 
0085 void FunctionTools::updateEquationList()
0086 {
0087     EquationPair previousEquation = equation();
0088 
0089     m_widget->list->clear();
0090     m_equations.clear();
0091 
0092     for (Function *function : qAsConst(XParser::self()->m_ufkt)) {
0093         if (function->type() != Function::Cartesian && function->type() != Function::Differential)
0094             continue;
0095 
0096         QList<Plot> plots = function->plots();
0097 
0098         for (int i = 0; i < function->eq.size(); ++i) {
0099             for (const Plot &plot : qAsConst(plots))
0100                 m_equations << EquationPair(plot, i);
0101         }
0102     }
0103 
0104     for (const EquationPair &eq : qAsConst(m_equations)) {
0105         Equation *equation = eq.first.function()->eq[eq.second];
0106         QListWidgetItem *item = new QListWidgetItem(equation->fstr(), m_widget->list);
0107         item->setForeground(eq.first.color());
0108     }
0109 
0110     setEquation(previousEquation);
0111 }
0112 
0113 EquationPair FunctionTools::equation() const
0114 {
0115     int row = m_widget->list->currentRow();
0116     if (row < 0 || row >= m_equations.size())
0117         return EquationPair();
0118     else
0119         return m_equations[row];
0120 }
0121 
0122 void FunctionTools::setEquation(const EquationPair &equation)
0123 {
0124     int row = m_equations.indexOf(equation);
0125     if (row < 0)
0126         row = 0;
0127     m_widget->list->setCurrentRow(row);
0128     equationSelected(row);
0129 }
0130 
0131 void FunctionTools::equationSelected(int equation)
0132 {
0133     if (equation < 0 || equation >= m_equations.size())
0134         return;
0135     EquationPair current = m_equations[equation];
0136 
0137     switch (m_mode) {
0138     case FindMinimum:
0139         findMinimum(current);
0140         break;
0141 
0142     case FindMaximum:
0143         findMaximum(current);
0144         break;
0145 
0146     case CalculateArea:
0147         calculateArea(current);
0148         break;
0149     }
0150 }
0151 
0152 void FunctionTools::rangeEdited()
0153 {
0154     switch (m_mode) {
0155     case FindMinimum:
0156         findMinimum(equation());
0157         break;
0158 
0159     case FindMaximum:
0160         findMaximum(equation());
0161         break;
0162 
0163     case CalculateArea:
0164         calculateArea(equation());
0165         break;
0166     }
0167 }
0168 
0169 void FunctionTools::findMinimum(const EquationPair &equation)
0170 {
0171     if (!equation.first.function())
0172         return;
0173 
0174     QPointF extremum = View::self()->findMinMaxValue(equation.first, View::Minimum, m_widget->min->value(), m_widget->max->value());
0175 
0176     m_widget->rangeResult->setText(i18n("Minimum is at x = %1, %2(x) = %3", extremum.x(), equation.first.function()->eq[0]->name(), extremum.y()));
0177 }
0178 
0179 void FunctionTools::findMaximum(const EquationPair &equation)
0180 {
0181     if (!equation.first.function())
0182         return;
0183 
0184     QPointF extremum = View::self()->findMinMaxValue(equation.first, View::Maximum, m_widget->min->value(), m_widget->max->value());
0185 
0186     m_widget->rangeResult->setText(i18n("Maximum is at x = %1, %2(x) = %3", extremum.x(), equation.first.function()->eq[0]->name(), extremum.y()));
0187 }
0188 
0189 void FunctionTools::calculateArea(const EquationPair &equation)
0190 {
0191     if (!equation.first.function())
0192         return;
0193 
0194     IntegralDrawSettings s;
0195     s.plot = equation.first;
0196     s.dmin = m_widget->min->value();
0197     s.dmax = m_widget->max->value();
0198 
0199     double area = View::self()->areaUnderGraph(s);
0200 
0201     m_widget->rangeResult->setText(i18n("Area is %1", area));
0202 }
0203 // END class FunctionTools
0204 
0205 #include "moc_functiontools.cpp"