File indexing completed on 2024-04-21 03:41:38

0001 /*
0002     SPDX-FileCopyrightText: 2010 Luca Tringali <TRINGALINVENT@libero.it>
0003 
0004     SPDX-License-Identifier: GPL-2.0-or-later
0005 */
0006 
0007 #include "titrationCalculator.h"
0008 
0009 #include <cctype>
0010 #include <cfloat>
0011 #include <cmath>
0012 #include <cstdio>
0013 #include <cstdlib>
0014 #include <cstring>
0015 #include <fstream>
0016 #include <iostream>
0017 
0018 #include <QFileDialog>
0019 #include <QMessageBox>
0020 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0021 #include <QScriptClass>
0022 #include <QScriptEngine>
0023 #include <QScriptValue>
0024 #endif
0025 #include <QVarLengthArray>
0026 
0027 #include <KLocalizedString>
0028 
0029 #include "prefs.h"
0030 
0031 using namespace std;
0032 
0033 titrationCalculator::titrationCalculator(QWidget *parent)
0034     : QWidget(parent)
0035 {
0036     xmin = 0;
0037     xmax = 50;
0038     ymin = 0;
0039     ymax = 50;
0040     width = int(xmax - xmin);
0041 
0042     uid.setupUi(this);
0043     uid.tabWidget->setTabText(0, i18n("Experimental values"));
0044     uid.tabWidget->setTabText(1, i18n("Theoretical equations"));
0045     uid.tab->setFocus();
0046     plot();
0047 
0048     connect(uid.pushButton, &QAbstractButton::clicked, this, &titrationCalculator::on_pushButton_clicked);
0049     connect(uid.xmin, SIGNAL(valueChanged(double)), this, SLOT(on_xmin_valueChanged(double)));
0050     connect(uid.xmax, SIGNAL(valueChanged(double)), this, SLOT(on_xmax_valueChanged(double)));
0051     connect(uid.ymin, SIGNAL(valueChanged(double)), this, SLOT(on_ymin_valueChanged(double)));
0052     connect(uid.ymax, SIGNAL(valueChanged(double)), this, SLOT(on_ymax_valueChanged(double)));
0053 
0054     connect(uid.saveimage, &QAbstractButton::clicked, this, &titrationCalculator::on_actionSave_image_triggered);
0055     connect(uid.open, &QAbstractButton::clicked, this, &titrationCalculator::on_actionOpen_triggered);
0056     connect(uid.save, &QAbstractButton::clicked, this, &titrationCalculator::on_actionSave_triggered);
0057     connect(uid.newfile, &QAbstractButton::clicked, this, &titrationCalculator::on_actionNew_triggered);
0058     connect(uid.rapidhelp, &QAbstractButton::clicked, this, &titrationCalculator::on_actionRapid_Help_triggered);
0059 }
0060 
0061 titrationCalculator::~titrationCalculator() = default;
0062 
0063 void titrationCalculator::plot()
0064 {
0065     width = int(xmax - xmin);
0066     // now I'm preparing the kplot widget
0067     uid.kplotwidget->removeAllPlotObjects();
0068     uid.kplotwidget->setLimits(xmin, xmax, ymin, ymax); // now I need to set the limits of the plot
0069 
0070     auto kpor = new KPlotObject(Qt::red, KPlotObject::Lines);
0071     auto kpog = new KPlotObject(Qt::green, KPlotObject::Lines);
0072     auto kpob = new KPlotObject(Qt::blue, KPlotObject::Lines);
0073     redplot = QStringLiteral("<polyline points=\"");
0074     greenplot = QStringLiteral("<polyline points=\"");
0075     blueplot = QStringLiteral("<polyline points=\"");
0076 
0077     if (!uid.tableWidget->item(0, 0) || uid.tableWidget->item(0, 0)->text().isEmpty()) {
0078         // go on
0079     } else {
0080         char yvalue[80];
0081         int tmpy = 0;
0082         for (int i = 0; i < uid.tableWidget->rowCount(); ++i) {
0083             if (!uid.tableWidget->item(i, 0) || uid.tableWidget->item(i, 0)->text().isEmpty()) {
0084                 break;
0085             } else {
0086                 if (uid.tableWidget->item(i, 0)->data(Qt::DisplayRole).toString() == uid.yaxis->text()) {
0087                     QString yvalueq = uid.tableWidget->item(i, 1)->data(Qt::DisplayRole).toString();
0088                     QByteArray ba = yvalueq.toLatin1();
0089                     char *yvaluen = ba.data();
0090                     strcpy(yvalue, yvaluen);
0091                     tmpy = 1;
0092                 }
0093             }
0094         }
0095         QString mreporto;
0096         int iter = 0;
0097         if (uid.xaxis->text().isEmpty() || uid.xaxis->text() == QLatin1String(" ")) {
0098             uid.xaxis->setText(i18n("nothing"));
0099         }
0100         if (tmpy == 0) {
0101             QMessageBox::critical(this, i18n("Error"), i18n("Unable to find an equation for Y-axis variable."));
0102         } else {
0103             // now we have to solve the system of equations NOTE:yvalue contains the equation of Y-axis variable
0104             // we iterates the process until you have an equation in one only unknown variable or a numeric expression
0105             mreporto = solve(yvalue);
0106             while (end == 0 || lettere == 1) {
0107                 QByteArray ba = mreporto.toLatin1();
0108                 char *tmreport = ba.data();
0109                 ++iter;
0110                 if (end == 1 || lettere == 0) {
0111                     break;
0112                 }
0113                 if (iter > 100) {
0114                     break; // preventing from an endless iteration
0115                 }
0116                 mreporto = solve(tmreport);
0117             }
0118         }
0119         // if (mreporto!="") uid.note->setText("Theoretical Curve: "+mreporto);
0120         if (!mreporto.isEmpty()) {
0121             uid.note->setText(i18n("Theoretical curve") + ": " + mreporto);
0122             for (int i = int(xmin); i < int(xmax); ++i) {
0123 #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
0124                 double id = i;
0125                 QScriptEngine myEngine;
0126                 QByteArray ban = mreporto.toLatin1();
0127                 char *tmreporto = ban.data();
0128 
0129                 QString istr;
0130                 istr.append(QStringLiteral("%1").arg((id)));
0131                 // now i'm using QScript language to solve the expression
0132                 // in a future we can consider to change it supporting some backends, but it's really complex
0133                 QString myscript = solvex(tmreporto, istr);
0134                 QScriptValue three = myEngine.evaluate(myscript);
0135 
0136                 double tvalue = three.toNumber();
0137                 kpor->addPoint(id, tvalue);
0138                 redplot = redplot + ' ' + QString::number((id * 10) + 5).replace(QChar(','), QChar('.')) + ','
0139                     + QString::number((ymax - tvalue) * 10).replace(QChar(','), QChar('.'));
0140 #else
0141 #pragma "NEED TO PORT QTSCRIPT";
0142 #endif
0143             }
0144         }
0145         temponu = 0;
0146     } // here ends the equations mode
0147 
0148     // uid.tableWidget_2->sortItems(1, Qt::AscendingOrder); //seems that the sorting doesn't work correctly
0149     if (!uid.tableWidget_2->item(0, 0) || uid.tableWidget_2->item(0, 0)->text().isEmpty()) {
0150         // go on
0151     } else {
0152         // now we can plot the values
0153         double a, b, c, d, xval;
0154         QVarLengthArray<double, 64> px(uid.tableWidget_2->rowCount());
0155         QVarLengthArray<double, 64> py(uid.tableWidget_2->rowCount());
0156         int totaldata = 0;
0157         for (int i = 0; i < uid.tableWidget_2->rowCount(); ++i) {
0158             if (!uid.tableWidget_2->item(i, 0) || uid.tableWidget_2->item(i, 0)->text().isEmpty()) {
0159                 break;
0160             } else {
0161                 ++totaldata;
0162                 kpob->addPoint(uid.tableWidget_2->item(i, 1)->data(Qt::DisplayRole).toDouble(),
0163                                uid.tableWidget_2->item(i, 0)->data(Qt::DisplayRole).toDouble());
0164                 py[i] = uid.tableWidget_2->item(i, 0)->data(Qt::DisplayRole).toDouble();
0165                 px[i] = uid.tableWidget_2->item(i, 1)->data(Qt::DisplayRole).toDouble();
0166                 blueplot = blueplot + ' '
0167                     + QString::number((uid.tableWidget_2->item(i, 1)->data(Qt::DisplayRole).toDouble() * 10) + 5).replace(QChar(','), QChar('.')) + ','
0168                     + QString::number((ymax - uid.tableWidget_2->item(i, 0)->data(Qt::DisplayRole).toDouble()) * 10).replace(QChar(','), QChar('.'));
0169             }
0170         }
0171         a = py[totaldata - 1] - py[0];
0172         b = 4 / (px[totaldata - 1] - px[0]);
0173         d = 0;
0174         if (a > 0) {
0175             d = py[0] + (a / 2);
0176         } else if (a < 0) {
0177             d = py[totaldata - 1] - (a / 2);
0178         }
0179         double cn = 0.0;
0180         int th = 0;
0181         for (int i = 1; i < (totaldata - 1); ++i) {
0182             // now i'm using the value of the points to fit the curve
0183             double ci = ((setttanh((py[i] - d) / a)) / b) - px[i];
0184             if ((ci * 0) == 0) {
0185                 cn = cn + ci;
0186                 ++th;
0187             }
0188         }
0189         // c = cn/(th); it doesn't wok, but i found out this little hack. The strange thing is that in the standalone application it works fine.
0190         c = cn / (th * 2);
0191         // THIS IS THE PLOT OF APPROXIMATED CURVE
0192         for (int i = int(xmin); i < (int(xmax)); ++i) {
0193             double id = i;
0194             xval = (a * tanh(b * (id + c))) + d;
0195             kpog->addPoint(id, xval);
0196             greenplot = greenplot + ' ' + QString::number((id * 10) + 5).replace(QChar(','), QChar('.')) + ','
0197                 + QString::number((ymax - xval) * 10).replace(QChar(','), QChar('.'));
0198         }
0199         // THIS IS THE EQUIVALENCE POINT (THE INFLECTION OF THE CURVE)
0200         QString es = QString::number(-c);
0201         QString as = QString::number(a);
0202         QString bs = QString::number(b);
0203         QString cs = QString::number(c);
0204         QString ds = QString::number(d);
0205         QString tempon = uid.note->toPlainText() + QChar('\n');
0206         if (temponu != 0) {
0207             tempon = QLatin1String("");
0208         }
0209         uid.note->setText(tempon + '\n' + i18n("Approximated curve") + ": " + as + "*tanh(" + bs + "*(x+" + cs + "))+" + ds + '\n' + i18n("Equivalence point")
0210                           + ": " + es);
0211     } // here ends the experimental values mode
0212 
0213     uid.kplotwidget->addPlotObject(kpor);
0214     uid.kplotwidget->addPlotObject(kpog);
0215     uid.kplotwidget->addPlotObject(kpob);
0216 
0217     redplot = redplot + R"(" style="stroke:red;fill:none"/> )";
0218     blueplot = blueplot + R"(" style="stroke:blue;fill:none"/> )";
0219     greenplot = greenplot + R"(" style="stroke:green;fill:none"/> )";
0220 }
0221 
0222 double titrationCalculator::setttanh(double x)
0223 {
0224     double temp;
0225     temp = log((1 + x) / (1 - x)) / 2;
0226     return temp;
0227 }
0228 
0229 QString titrationCalculator::solve(char *yvalue)
0230 {
0231     QString mreport;
0232     lettere = 0;
0233     // now we have to solve the system of equations
0234     // yvalue contains the equation of Y-axis variable
0235     QString tempy = QLatin1String("");
0236     end = 1;
0237     mreport = QLatin1String("");
0238     QString tempyval;
0239     QString ptem;
0240     for (int i = 0; strlen(yvalue) + 1; ++i) {
0241         if (!(yvalue[i] == 'q' || yvalue[i] == 'w' || yvalue[i] == 'e' || yvalue[i] == 'r' || yvalue[i] == 't' || yvalue[i] == 'y' || yvalue[i] == 'u'
0242               || yvalue[i] == 'i' || yvalue[i] == 'o' || yvalue[i] == 'p' || yvalue[i] == 'a' || yvalue[i] == 's' || yvalue[i] == 'd' || yvalue[i] == 'f'
0243               || yvalue[i] == 'g' || yvalue[i] == 'h' || yvalue[i] == 'j' || yvalue[i] == 'k' || yvalue[i] == 'l' || yvalue[i] == 'z' || yvalue[i] == 'x'
0244               || yvalue[i] == 'c' || yvalue[i] == 'v' || yvalue[i] == 'b' || yvalue[i] == 'n' || yvalue[i] == 'm' || yvalue[i] == '+' || yvalue[i] == '-'
0245               || yvalue[i] == '^' || yvalue[i] == '*' || yvalue[i] == '/' || yvalue[i] == '(' || yvalue[i] == ')' || yvalue[i] == 'Q' || yvalue[i] == 'W'
0246               || yvalue[i] == 'E' || yvalue[i] == 'R' || yvalue[i] == 'T' || yvalue[i] == 'Y' || yvalue[i] == 'U' || yvalue[i] == 'I' || yvalue[i] == 'O'
0247               || yvalue[i] == 'P' || yvalue[i] == 'A' || yvalue[i] == 'S' || yvalue[i] == 'D' || yvalue[i] == 'F' || yvalue[i] == 'G' || yvalue[i] == 'H'
0248               || yvalue[i] == 'J' || yvalue[i] == 'K' || yvalue[i] == 'L' || yvalue[i] == 'Z' || yvalue[i] == 'X' || yvalue[i] == 'C' || yvalue[i] == 'V'
0249               || yvalue[i] == 'B' || yvalue[i] == 'N' || yvalue[i] == 'M' || yvalue[i] == '1' || yvalue[i] == '2' || yvalue[i] == '3' || yvalue[i] == '4'
0250               || yvalue[i] == '5' || yvalue[i] == '6' || yvalue[i] == '7' || yvalue[i] == '8' || yvalue[i] == '9' || yvalue[i] == '0' || yvalue[i] == '.'
0251               || yvalue[i] == ',')) {
0252             break; // if current value is not a permitted value, this means that something is wrong
0253         }
0254         if (yvalue[i] == 'q' || yvalue[i] == 'w' || yvalue[i] == 'e' || yvalue[i] == 'r' || yvalue[i] == 't' || yvalue[i] == 'y' || yvalue[i] == 'u'
0255             || yvalue[i] == 'i' || yvalue[i] == 'o' || yvalue[i] == 'p' || yvalue[i] == 'a' || yvalue[i] == 's' || yvalue[i] == 'd' || yvalue[i] == 'f'
0256             || yvalue[i] == 'g' || yvalue[i] == 'h' || yvalue[i] == 'j' || yvalue[i] == 'k' || yvalue[i] == 'l' || yvalue[i] == 'z' || yvalue[i] == 'x'
0257             || yvalue[i] == 'c' || yvalue[i] == 'v' || yvalue[i] == 'b' || yvalue[i] == 'n' || yvalue[i] == 'm' || yvalue[i] == 'Q' || yvalue[i] == 'W'
0258             || yvalue[i] == 'E' || yvalue[i] == 'R' || yvalue[i] == 'T' || yvalue[i] == 'Y' || yvalue[i] == 'U' || yvalue[i] == 'I' || yvalue[i] == 'O'
0259             || yvalue[i] == 'P' || yvalue[i] == 'A' || yvalue[i] == 'S' || yvalue[i] == 'D' || yvalue[i] == 'F' || yvalue[i] == 'G' || yvalue[i] == 'H'
0260             || yvalue[i] == 'J' || yvalue[i] == 'K' || yvalue[i] == 'L' || yvalue[i] == 'Z' || yvalue[i] == 'X' || yvalue[i] == 'C' || yvalue[i] == 'V'
0261             || yvalue[i] == 'B' || yvalue[i] == 'N' || yvalue[i] == 'M' || yvalue[i] == '.' || yvalue[i] == ',') {
0262             lettere = 1; // if lettere == 0 then the equation contains only mnumbers
0263         }
0264         if (yvalue[i] == '+' || yvalue[i] == '-' || yvalue[i] == '^' || yvalue[i] == '*' || yvalue[i] == '/' || yvalue[i] == '(' || yvalue[i] == ')'
0265             || yvalue[i] == '1' || yvalue[i] == '2' || yvalue[i] == '3' || yvalue[i] == '4' || yvalue[i] == '5' || yvalue[i] == '6' || yvalue[i] == '7'
0266             || yvalue[i] == '8' || yvalue[i] == '9' || yvalue[i] == '0' || yvalue[i] == '.' || yvalue[i] == ',') {
0267             tempyval = tempyval + QString(yvalue[i]);
0268         } else {
0269             tempy = tempy + QString(yvalue[i]);
0270             for (int i = 0; i < uid.tableWidget->rowCount(); ++i) {
0271                 QTableWidgetItem *titem = uid.tableWidget->item(i, 0);
0272                 QTableWidgetItem *titemo = uid.tableWidget->item(i, 1);
0273                 if (!titem || titem->text().isEmpty()) {
0274                     break;
0275                 } else {
0276                     if (tempy == uid.xaxis->text()) {
0277                         tempyval = uid.xaxis->text();
0278                         tempy = QLatin1String("");
0279                     }
0280                     if (titem->data(Qt::DisplayRole).toString() == tempy) {
0281                         QString yvaluerq = titemo->data(Qt::DisplayRole).toString();
0282                         QByteArray ba = yvaluerq.toLatin1();
0283                         char *yvalure = ba.data();
0284                         tempyval = QChar('(') + QString(yvalure) + QChar(')');
0285                         tempy = QLatin1String("");
0286                         end = 1;
0287                     }
0288                     if (tempy != uid.xaxis->text()) {
0289                         if (yvalue[i] == '+' || yvalue[i] == '-' || yvalue[i] == '^' || yvalue[i] == '*' || yvalue[i] == '/' || yvalue[i] == '('
0290                             || yvalue[i] == ')' || yvalue[i] == '1' || yvalue[i] == '2' || yvalue[i] == '3' || yvalue[i] == '4' || yvalue[i] == '5'
0291                             || yvalue[i] == '6' || yvalue[i] == '7' || yvalue[i] == '8' || yvalue[i] == '9' || yvalue[i] == '0' || yvalue[i] == '.'
0292                             || yvalue[i] == ',') {
0293                             // actually nothing
0294                         } else {
0295                             end = 0;
0296                         }
0297                     }
0298                 }
0299             }
0300         } // simbol end
0301         if (!tempyval.isEmpty()) {
0302             mreport = mreport + tempyval;
0303         }
0304         tempyval = QLatin1String("");
0305     }
0306     return mreport;
0307 }
0308 
0309 QString titrationCalculator::solvex(char *yvalue, const QString &dnum)
0310 {
0311     QString mreport = QLatin1String("");
0312     lettere = 0;
0313     // now we have to solve the system of equations
0314     // yvalue contains the equation of Y-axis variable
0315     // Remember that the function to elevate to power is Math.pow(b,e)
0316     QString tempy;
0317     QString tempyold;
0318     QString tempyolda = QLatin1String("");
0319     int olda = 0;
0320     end = 1;
0321     QString tempyval;
0322     tempy = QLatin1String("");
0323     for (int i = 0; strlen(yvalue) + 1; ++i) {
0324         if (!(yvalue[i] == 'q' || yvalue[i] == 'w' || yvalue[i] == 'e' || yvalue[i] == 'r' || yvalue[i] == 't' || yvalue[i] == 'y' || yvalue[i] == 'u'
0325               || yvalue[i] == 'i' || yvalue[i] == 'o' || yvalue[i] == 'p' || yvalue[i] == 'a' || yvalue[i] == 's' || yvalue[i] == 'd' || yvalue[i] == 'f'
0326               || yvalue[i] == 'g' || yvalue[i] == 'h' || yvalue[i] == 'j' || yvalue[i] == 'k' || yvalue[i] == 'l' || yvalue[i] == 'z' || yvalue[i] == 'x'
0327               || yvalue[i] == 'c' || yvalue[i] == 'v' || yvalue[i] == 'b' || yvalue[i] == 'n' || yvalue[i] == 'm' || yvalue[i] == '+' || yvalue[i] == '-'
0328               || yvalue[i] == '^' || yvalue[i] == '*' || yvalue[i] == '/' || yvalue[i] == '(' || yvalue[i] == ')' || yvalue[i] == 'Q' || yvalue[i] == 'W'
0329               || yvalue[i] == 'E' || yvalue[i] == 'R' || yvalue[i] == 'T' || yvalue[i] == 'Y' || yvalue[i] == 'U' || yvalue[i] == 'I' || yvalue[i] == 'O'
0330               || yvalue[i] == 'P' || yvalue[i] == 'A' || yvalue[i] == 'S' || yvalue[i] == 'D' || yvalue[i] == 'F' || yvalue[i] == 'G' || yvalue[i] == 'H'
0331               || yvalue[i] == 'J' || yvalue[i] == 'K' || yvalue[i] == 'L' || yvalue[i] == 'Z' || yvalue[i] == 'X' || yvalue[i] == 'C' || yvalue[i] == 'V'
0332               || yvalue[i] == 'B' || yvalue[i] == 'N' || yvalue[i] == 'M' || yvalue[i] == '1' || yvalue[i] == '2' || yvalue[i] == '3' || yvalue[i] == '4'
0333               || yvalue[i] == '5' || yvalue[i] == '6' || yvalue[i] == '7' || yvalue[i] == '8' || yvalue[i] == '9' || yvalue[i] == '0' || yvalue[i] == '.'
0334               || yvalue[i] == ',')) {
0335             break; // if current value is not a permitted value, this means that something is wrong
0336         }
0337         if (yvalue[i] == 'q' || yvalue[i] == 'w' || yvalue[i] == 'e' || yvalue[i] == 'r' || yvalue[i] == 't' || yvalue[i] == 'y' || yvalue[i] == 'u'
0338             || yvalue[i] == 'i' || yvalue[i] == 'o' || yvalue[i] == 'p' || yvalue[i] == 'a' || yvalue[i] == 's' || yvalue[i] == 'd' || yvalue[i] == 'f'
0339             || yvalue[i] == 'g' || yvalue[i] == 'h' || yvalue[i] == 'j' || yvalue[i] == 'k' || yvalue[i] == 'l' || yvalue[i] == 'z' || yvalue[i] == 'x'
0340             || yvalue[i] == 'c' || yvalue[i] == 'v' || yvalue[i] == 'b' || yvalue[i] == 'n' || yvalue[i] == 'm' || yvalue[i] == 'Q' || yvalue[i] == 'W'
0341             || yvalue[i] == 'E' || yvalue[i] == 'R' || yvalue[i] == 'T' || yvalue[i] == 'Y' || yvalue[i] == 'U' || yvalue[i] == 'I' || yvalue[i] == 'O'
0342             || yvalue[i] == 'P' || yvalue[i] == 'A' || yvalue[i] == 'S' || yvalue[i] == 'D' || yvalue[i] == 'F' || yvalue[i] == 'G' || yvalue[i] == 'H'
0343             || yvalue[i] == 'J' || yvalue[i] == 'K' || yvalue[i] == 'L' || yvalue[i] == 'Z' || yvalue[i] == 'X' || yvalue[i] == 'C' || yvalue[i] == 'V'
0344             || yvalue[i] == 'B' || yvalue[i] == 'N' || yvalue[i] == 'M' || yvalue[i] == '.' || yvalue[i] == ',') {
0345             tempy = tempy + yvalue[i]; // if lettere == 0 then the equation contains only mnumbers
0346         }
0347         if (yvalue[i] == '+' || yvalue[i] == '-' || yvalue[i] == '^' || yvalue[i] == '*' || yvalue[i] == '/' || yvalue[i] == '(' || yvalue[i] == ')'
0348             || yvalue[i] == '1' || yvalue[i] == '2' || yvalue[i] == '3' || yvalue[i] == '4' || yvalue[i] == '5' || yvalue[i] == '6' || yvalue[i] == '7'
0349             || yvalue[i] == '8' || yvalue[i] == '9' || yvalue[i] == '0' || yvalue[i] == '.' || yvalue[i] == ',') {
0350             if (!tempyolda.isEmpty()) {
0351                 tempy = tempy + yvalue[i];
0352                 if (tempyolda == uid.xaxis->text()) {
0353                     tempyolda = dnum;
0354                 }
0355                 tempyval = tempyval + QStringLiteral("Math.pow(") + tempyolda + QChar(',') + tempy + QChar(')');
0356                 tempyolda = QLatin1String("");
0357                 tempyold = QLatin1String("");
0358                 olda = 1;
0359             }
0360             if (yvalue[i] == '^') {
0361                 tempyolda = tempyold;
0362             } else {
0363                 tempyold = QLatin1String("");
0364                 if (((olda != 1) && (yvalue[i + 1] != '^'))
0365                     || (yvalue[i] == '+' || yvalue[i] == '-' || yvalue[i] == '^' || yvalue[i] == '*' || yvalue[i] == '/' || yvalue[i] == '('
0366                         || yvalue[i] == ')')) {
0367                     tempyval = tempyval + QString(yvalue[i]);
0368                 }
0369             }
0370 
0371         } else {
0372             if (!tempyolda.isEmpty()) {
0373                 tempyval = tempyval + QStringLiteral("Math.pow(") + tempyolda + QChar(',') + tempy + QChar(')');
0374                 tempyolda = QLatin1String("");
0375                 tempyold = QLatin1String("");
0376                 olda = 1;
0377             }
0378             if ((tempy == uid.xaxis->text()) && (!tempyolda.isEmpty())) {
0379                 if (yvalue[i + 1] != '^') {
0380                     tempyval = tempyval + dnum;
0381                 }
0382                 tempyold = tempy;
0383                 tempy = QLatin1String("");
0384             }
0385         } // simbol end
0386         if (!tempyval.isEmpty()) {
0387             mreport = mreport + tempyval;
0388         }
0389         tempyval = QLatin1String("");
0390     }
0391     // QMessageBox::information(this, "report", mreport);
0392     return mreport;
0393 }
0394 
0395 void titrationCalculator::on_xmin_valueChanged(double val)
0396 {
0397     xmin = val;
0398     on_pushButton_clicked(); // please take note that calling directly the plot() function will give a wrong value for equivalence point
0399 }
0400 
0401 void titrationCalculator::on_xmax_valueChanged(double val)
0402 {
0403     xmax = val;
0404     on_pushButton_clicked(); // please take note that calling directly the plot() function will give a wrong value for equivalence point
0405 }
0406 
0407 void titrationCalculator::on_ymin_valueChanged(double val)
0408 {
0409     ymin = val;
0410     on_pushButton_clicked(); // please take note that calling directly the plot() function will give a wrong value for equivalence point
0411 }
0412 
0413 void titrationCalculator::on_ymax_valueChanged(double val)
0414 {
0415     ymax = val;
0416     on_pushButton_clicked(); // please take note that calling directly the plot() function will give a wrong value for equivalence point
0417 }
0418 
0419 void titrationCalculator::on_pushButton_clicked()
0420 {
0421     plot();
0422 }
0423 
0424 void titrationCalculator::on_actionRapid_Help_triggered()
0425 {
0426     on_actionNew_triggered();
0427     // now I'm going to fill the tables with the example values
0428 
0429     // table1
0430     QTableWidgetItem *titemo = uid.tableWidget->item(0, 0);
0431     titemo->setText(QStringLiteral("A"));
0432     titemo = uid.tableWidget->item(0, 1);
0433     titemo->setText(QStringLiteral("(C*D)/(B*K)"));
0434     titemo = uid.tableWidget->item(1, 0);
0435     titemo->setText(QStringLiteral("K"));
0436     titemo = uid.tableWidget->item(1, 1);
0437     titemo->setText(QStringLiteral("10^-3"));
0438     titemo = uid.tableWidget->item(2, 0);
0439     titemo->setText(QStringLiteral("C"));
0440     titemo = uid.tableWidget->item(2, 1);
0441     titemo->setText(QStringLiteral("OH"));
0442     titemo = uid.tableWidget->item(3, 0);
0443     titemo->setText(QStringLiteral("OH"));
0444     titemo = uid.tableWidget->item(3, 1);
0445     titemo->setText(QStringLiteral("(10^-14)/H"));
0446     titemo = uid.tableWidget->item(4, 0);
0447     titemo->setText(QStringLiteral("H"));
0448     titemo = uid.tableWidget->item(4, 1);
0449     titemo->setText(QStringLiteral("10^-4"));
0450     titemo = uid.tableWidget->item(5, 0);
0451     titemo->setText(QStringLiteral("B"));
0452     titemo = uid.tableWidget->item(5, 1);
0453     titemo->setText(QStringLiteral("6*(10^-2)"));
0454     // xaxis
0455     uid.xaxis->setText(QStringLiteral("D"));
0456     // yaxis
0457     uid.yaxis->setText(QStringLiteral("A"));
0458     // table2
0459     titemo = uid.tableWidget_2->item(0, 0);
0460     titemo->setText(QStringLiteral("7,19"));
0461     titemo = uid.tableWidget_2->item(0, 1);
0462     titemo->setText(QStringLiteral("30"));
0463     titemo = uid.tableWidget_2->item(1, 0);
0464     titemo->setText(QStringLiteral("7,64"));
0465     titemo = uid.tableWidget_2->item(1, 1);
0466     titemo->setText(QStringLiteral("30,5"));
0467     titemo = uid.tableWidget_2->item(2, 0);
0468     titemo->setText(QStringLiteral("10,02"));
0469     titemo = uid.tableWidget_2->item(2, 1);
0470     titemo->setText(QStringLiteral("31"));
0471     titemo = uid.tableWidget_2->item(3, 0);
0472     titemo->setText(QStringLiteral("10,45"));
0473     titemo = uid.tableWidget_2->item(3, 1);
0474     titemo->setText(QStringLiteral("31,5"));
0475 
0476     // I think it's better if I don't give so much information here.
0477     //  This information could be included into kalzium help, but I don't know how to do
0478     // QMessageBox::information(this, "IceeQt Rapid Help", "There are two ways to use IceeQt:\n\nTheoretical Equations\n Here you can fill the table with the
0479     // equations you have previously obtained for the chemical equilibria. FOR EXAMPLE if you have this reaction A + B -> C + D then you will have the equation
0480     // K=(C*D)/(A*B) so you must write 'K' in the Parameter column and '(C*D)/(A*B)' in the Value column. If you want to assign a known value to a parameter you
0481     // can simply write the numeric value in the Value field. FOR EXAMPLE you can use the system \nA=(C*D)/(B*K) \nK=10^-3 \nC=OH \nOH=(10^-14)/H \nH=10^-4
0482     // \nB=6*(10^-2) \nThen you have to write D as X axis and A as Y axis: so you will find out how the concentration of A change in function of D
0483     // concentration.\nPlease don't use parenthesis for exponents: 10^-3 is correct, while 10^(-3) is wrong. \n\nExperimental Values\n You can use this program
0484     // to draw the plot of your experimental data obtained during a titration and find out the volume of equivalence. It's strongly recommended to insert a even
0485     // number of points, because of the best fit algorithm, sorted by volume (the X axis value).\n\nPlot\n The plot shows in red the curve that comes from
0486     // theoretical equations, in blue the experimental points, and in green the approximated curve for experimental points.");
0487 }
0488 
0489 /*
0490 void titrationCalculator::on_actionAbout_triggered()
0491 {
0492     QMessageBox::information(this, "IceeQt About", "I\nCompute\nEquilibria\nExactly\n\nIceeQt is a program for computing chemical equilibria in a easy way. The
0493 first version of Icee was written by Gabriele Balducci(University of Trieste, Italy) using matheval, gnuplot, and tk. This version, called IceeQt, was written
0494 by Luca Tringali using Qtopia. \n IceeQt is installable on every system supported by Qt: Windows, MacOS, GNU/Linux, FreeBSD, Solaris, Symbian, etc..\n This
0495 program is released under GPL3 licence.\n\nThe website is http://web.archive.org/web/20041207065103/http://www.dsch.units.it/~balducci/lca1/");
0496 }
0497 */
0498 void titrationCalculator::on_actionNew_triggered()
0499 {
0500     // set all the table cells as empty ("")
0501     for (int i = 0; i < uid.tableWidget->rowCount(); ++i) {
0502         auto titem = new QTableWidgetItem;
0503         titem->setText(QLatin1String(""));
0504         uid.tableWidget->setItem(i, 0, titem);
0505         auto titemo = new QTableWidgetItem;
0506         titemo->setText(QLatin1String(""));
0507         uid.tableWidget->setItem(i, 1, titemo);
0508     }
0509     uid.xaxis->setText(QLatin1String(""));
0510     uid.yaxis->setText(QLatin1String(""));
0511     for (int i = 0; i < uid.tableWidget_2->rowCount(); ++i) {
0512         auto titem = new QTableWidgetItem;
0513         titem->setText(QLatin1String(""));
0514         uid.tableWidget_2->setItem(i, 0, titem);
0515         auto titemo = new QTableWidgetItem;
0516         titemo->setText(QLatin1String(""));
0517         uid.tableWidget_2->setItem(i, 1, titemo);
0518     }
0519     uid.note->setText(QLatin1String(""));
0520 }
0521 
0522 void titrationCalculator::on_actionSave_triggered()
0523 {
0524     // save all the cells values
0525     //   if we have for example:
0526     //   table1:
0527     //   |a|f|
0528     //   |d|h|
0529     //   table2:
0530     //   |w|q|
0531     //   |h|l|
0532     //   then the file would be:
0533     //   table1|
0534     //   a|
0535     //   f|
0536     //   d|
0537     //   h|
0538     //   table2|
0539     //   w|
0540     //   q|
0541     //   h|
0542     //   l|
0543     //   note|
0544     //    ewewewww|
0545     //    as you can see we don't save also the empty cells, this is obvious.
0546 
0547     QString tempyval;
0548     tempyval = QStringLiteral("table1|");
0549     for (int i = 0; i < uid.tableWidget->rowCount(); ++i) {
0550         QTableWidgetItem *titem = uid.tableWidget->item(i, 0);
0551         QTableWidgetItem *titemo = uid.tableWidget->item(i, 1);
0552         if (!titem || titem->text().isEmpty()) {
0553             break;
0554         } else {
0555             QString yvaluerq = titemo->data(Qt::DisplayRole).toString();
0556             QString valuerq = titem->data(Qt::DisplayRole).toString();
0557             tempyval = tempyval + QChar('\n') + valuerq + QStringLiteral("|\n") + yvaluerq + QChar('|');
0558         }
0559     }
0560     tempyval = tempyval + QStringLiteral("\nxaxis|");
0561     tempyval = tempyval + QStringLiteral("\n") + uid.xaxis->text() + QChar('|');
0562     tempyval = tempyval + QStringLiteral("\nyaxis|");
0563     tempyval = tempyval + QStringLiteral("\n") + uid.yaxis->text() + QChar('|');
0564     tempyval = tempyval + QStringLiteral("\ntable2|");
0565     for (int i = 0; i < uid.tableWidget_2->rowCount(); ++i) {
0566         QTableWidgetItem *titem = uid.tableWidget_2->item(i, 0);
0567         QTableWidgetItem *titemo = uid.tableWidget_2->item(i, 1);
0568         if (!titem || titem->text().isEmpty()) {
0569             break;
0570         } else {
0571             QString yvaluerq = titemo->data(Qt::DisplayRole).toString();
0572             QString valuerq = titem->data(Qt::DisplayRole).toString();
0573             tempyval = tempyval + QChar('\n') + valuerq + QStringLiteral("|\n") + yvaluerq + QChar('|');
0574         }
0575     }
0576     tempyval = tempyval + QStringLiteral("\nnote|\n") + uid.note->toPlainText() + QChar('|');
0577 
0578     QString file = QFileDialog::getSaveFileName(this, i18n("Save work"), QLatin1String(""), i18n("Icee File (*.icee)"));
0579     if (!file.isEmpty()) {
0580         QByteArray ba = tempyval.toLatin1();
0581         char *strsave = ba.data();
0582         QByteArray bac = file.toLatin1();
0583         char *filec = bac.data();
0584 
0585         ofstream out(filec);
0586         cout << "|";
0587         cout << filec;
0588         cout << "|";
0589         if (!out) {
0590             QMessageBox::critical(this, i18n("Error"), i18n("Unable to create %1", file));
0591         }
0592         out << strsave;
0593         out.close();
0594         // if (out) QMessageBox::information(this, "Information", "File " + file + " successfully saved.");
0595     }
0596 }
0597 
0598 void titrationCalculator::on_actionOpen_triggered()
0599 {
0600     // loads all the cells text from a file previously saved
0601     QString file = QFileDialog::getOpenFileName(this, i18n("Open work"), QLatin1String(""), i18n("Icee File (*.icee)"));
0602     if (!file.isEmpty()) {
0603         QByteArray bac = file.toLatin1();
0604         char *filec = bac.data();
0605         ifstream texto(filec);
0606         if (!texto) {
0607             QMessageBox::critical(this, i18n("Error"), i18n("Unable to open %1", file));
0608         }
0609         if (texto) {
0610             on_actionNew_triggered();
0611             QString tempyval;
0612             char tmpchr;
0613             int i = 0;
0614             int tablea = 0;
0615             int tableb = 0;
0616             int xax = 0;
0617             int yax = 0;
0618             int notea = 0;
0619             do {
0620                 texto >> tmpchr;
0621                 if (tmpchr != '|') {
0622                     tempyval = tempyval + tmpchr;
0623                 } else {
0624                     if ((tablea == 1) && (tempyval != QStringLiteral("table1")) && (tempyval != QStringLiteral("table2"))
0625                         && (tempyval != QStringLiteral("xaxis")) && (tempyval != QStringLiteral("yaxis")) && (tempyval != QStringLiteral("note"))) {
0626                         if ((i % 2) != 0) {
0627                             QTableWidgetItem *titemo = uid.tableWidget->item((i - 1) / 2, 1);
0628                             if (titemo) {
0629                                 titemo->setText(tempyval);
0630                             }
0631                         } else {
0632                             QTableWidgetItem *titem = uid.tableWidget->item((i / 2), 0);
0633                             if (titem) {
0634                                 titem->setText(tempyval);
0635                             }
0636                         }
0637                         ++i;
0638                     }
0639 
0640                     if ((tableb == 1) && (tempyval != QStringLiteral("table1")) && (tempyval != QStringLiteral("table2"))
0641                         && (tempyval != QStringLiteral("xaxis")) && (tempyval != QStringLiteral("yaxis")) && (tempyval != QStringLiteral("note"))) {
0642                         if ((i % 2) != 0) {
0643                             QTableWidgetItem *titemo = uid.tableWidget_2->item((i - 1) / 2, 1);
0644                             if (titemo) {
0645                                 titemo->setText(tempyval);
0646                             }
0647                         } else {
0648                             QTableWidgetItem *titem = uid.tableWidget_2->item((i / 2), 0);
0649                             if (titem) {
0650                                 titem->setText(tempyval);
0651                             }
0652                             // cout << i;
0653                         }
0654                         ++i;
0655                     }
0656                     if ((xax == 1) && (tempyval != QStringLiteral("table1")) && (tempyval != QStringLiteral("table2")) && (tempyval != QStringLiteral("xaxis"))
0657                         && (tempyval != QStringLiteral("yaxis")) && (tempyval != QStringLiteral("note"))) {
0658                         uid.xaxis->setText(tempyval);
0659                     }
0660                     if ((yax == 1) && (tempyval != QStringLiteral("table1")) && (tempyval != QStringLiteral("table2")) && (tempyval != QStringLiteral("xaxis"))
0661                         && (tempyval != QStringLiteral("yaxis")) && (tempyval != QStringLiteral("note"))) {
0662                         uid.yaxis->setText(tempyval);
0663                     }
0664                     if ((notea == 1) && (tempyval != QStringLiteral("table1")) && (tempyval != QStringLiteral("table2"))
0665                         && (tempyval != QStringLiteral("xaxis")) && (tempyval != QStringLiteral("yaxis")) && (tempyval != QStringLiteral("note"))) {
0666                         uid.note->setText(tempyval);
0667                     }
0668 
0669                     if (tempyval == QStringLiteral("table1")) {
0670                         i = 0;
0671                         tablea = 1;
0672                         tableb = 0;
0673                         xax = 0;
0674                         yax = 0;
0675                         notea = 0;
0676                     }
0677                     if (tempyval == QStringLiteral("table2")) {
0678                         i = 0;
0679                         tablea = 0;
0680                         tableb = 1;
0681                         xax = 0;
0682                         yax = 0;
0683                         notea = 0;
0684                     }
0685                     if (tempyval == QStringLiteral("xaxis")) {
0686                         tablea = 0;
0687                         tableb = 0;
0688                         xax = 1;
0689                         yax = 0;
0690                         notea = 0;
0691                     }
0692                     if (tempyval == QStringLiteral("yaxis")) {
0693                         tablea = 0;
0694                         tableb = 0;
0695                         xax = 0;
0696                         yax = 1;
0697                         notea = 0;
0698                     }
0699                     if (tempyval == QStringLiteral("note")) {
0700                         tablea = 0;
0701                         tableb = 0;
0702                         xax = 0;
0703                         yax = 0;
0704                         notea = 1;
0705                     }
0706                     tempyval = QLatin1String("");
0707                 }
0708             } while (!texto.eof());
0709             texto.close();
0710         }
0711     }
0712 }
0713 
0714 void titrationCalculator::on_actionSave_image_triggered()
0715 {
0716     // This function saves the plot into a SVG file
0717     QString svgheader =
0718         R"(<?xml version="1.0" encoding="iso-8859-1" standalone="no"?> <!DOCTYPE svg PUBLIC "-//W3C//Dtd SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/Dtd/svg11.dtd"> <svg width=")"
0719         + QString::number((xmax * 10) + 5) + "\" height=\"" + QString::number((ymax * 10) + 5)
0720         + R"("  version="1.1" xmlns="http://www.w3.org/2000/svg"><polyline points="5,)" + QString::number(ymax * 10) + " " + QString::number((xmax * 10) - 5)
0721         + "," + QString::number(ymax * 10) + " " + QString::number((xmax * 10) - 5) + "," + QString::number((ymax * 10) - 5) + " " + QString::number(xmax * 10)
0722         + "," + QString::number(ymax * 10) + " " + QString::number((xmax * 10) - 5) + "," + QString::number((ymax * 10) + 5) + " "
0723         + QString::number((xmax * 10) - 5) + "," + QString::number(ymax * 10) + R"(" style="stroke:black;fill:none"/> <polyline points="5,)"
0724         + QString::number(ymax * 10) + R"( 5,5 10,5 5,0 0,5 5,5" style="stroke:black;fill:none"/> )";
0725     QString svgcomplete = svgheader + redplot + greenplot + blueplot + "</svg> ";
0726 
0727     QString file = QFileDialog::getSaveFileName(this, i18n("Save plot"), QLatin1String(""), i18n("Svg image (*.svg)"));
0728     if (!file.isEmpty()) {
0729         QByteArray svgt = svgcomplete.toLatin1();
0730         char *strsave = svgt.data();
0731         QByteArray ban = file.toLatin1();
0732         char *filec = ban.data();
0733 
0734         ofstream out(filec);
0735         cout << "|";
0736         cout << filec;
0737         cout << "|";
0738         if (!out) {
0739             QMessageBox::critical(this, i18n("Error"), i18n("Unable to create %1", file));
0740         }
0741         out << strsave;
0742         out.close();
0743     }
0744 }
0745 
0746 #include "moc_titrationCalculator.cpp"