MNE-CPP  beta 1.0
formulaeditor.cpp
Go to the documentation of this file.
1 //=============================================================================================================
36 //*************************************************************************************************************
37 //=============================================================================================================
38 // INCLUDES
39 //=============================================================================================================
40 
41 #include "formulaeditor.h"
42 #include "ui_formulaeditor.h"
43 #include "mainwindow.h"
44 
45 #include <math.h>
46 #include <float.h>
47 #include <iostream>
48 
49 //*************************************************************************************************************
50 //=============================================================================================================
51 // QT INCLUDES
52 //=============================================================================================================
53 
54 #include <QtGui>
55 #include <QtCore>
56 #include <QMessageBox>
57 
58 //*************************************************************************************************************
59 //=============================================================================================================
60 // USED NAMESPACES
61 //=============================================================================================================
62 
63 
64 
65 //*************************************************************************************************************
66 //=============================================================================================================
67 // FORWARD DECLARATIONS
68 //=============================================================================================================
69 
70 QString oldStringX = "";
71 QString oldStringA = "";
72 QString oldStringB = "";
73 QString oldStringC = "";
74 QString oldStringD = "";
75 QString oldStringE = "";
76 QString oldStringF = "";
77 QString oldStringG = "";
78 QString oldStringH = "";
79 QString Formulaeditor::g_strF = "";
80 QString errorText = "";
81 QList<qreal> atomList;
82 qint32 atomLength;
83 
84 qreal startValue;
85 qreal endValue;
86 qreal stepWidth;
87 
88 //*************************************************************************************************************
89 //=============================================================================================================
90 // MAIN
91 //=============================================================================================================
92 Formulaeditor::Formulaeditor(QWidget *parent) : QWidget(parent), ui(new Ui::Formulaeditor)
93 {
94  ui->setupUi(this);
95 
96  QSettings settings;
97  move(settings.value("pos_formula_editor", QPoint(200, 200)).toPoint());
98  resize(settings.value("size_formula_editor", QSize(555, 418)).toSize());
99 
100  callAtomPaintWindow = new AtomPaintWindow();
101  ui->l_PaintAtom->addWidget(callAtomPaintWindow);
102 
103  atomList.clear();
104 
105  m_strStandardFunction.append("");
106  m_strStandardFunction.append("PI");
107  m_strStandardFunction.append("ABS");
108  m_strStandardFunction.append("SQRT");
109  m_strStandardFunction.append("SINH");
110  m_strStandardFunction.append("COSH");
111  m_strStandardFunction.append("TANH");
112  m_strStandardFunction.append("ARCTAN");
113  m_strStandardFunction.append("LN");
114  m_strStandardFunction.append("LOG");
115  m_strStandardFunction.append("EXP");
116  m_strStandardFunction.append("SIN"); //must be addended behind SINH!!!
117  m_strStandardFunction.append("COS");
118  m_strStandardFunction.append("TAN");
119  m_strStandardFunction.append("COT");
120  m_strStandardFunction.append("ARCSIN");
121  m_strStandardFunction.append("ARCCOS");
122  m_strStandardFunction.append("INT");
123  m_strStandardFunction.append("RAD");
124  m_strStandardFunction.append("DEG");
125  m_strStandardFunction.append("SIGN");
126  m_strStandardFunction.append("ARSINH");
127  m_strStandardFunction.append("ARCOSH");
128  m_strStandardFunction.append("ARTANH");
129  m_strStandardFunction.append("KGV");
130  m_strStandardFunction.append("GGT");
131 
132  callAtomPaintWindow->update();
133  //update();
134 }
135 
136 //*************************************************************************************************************************************
137 
138 Formulaeditor::~Formulaeditor()
139 {
140  delete ui;
141 }
142 
143 //*************************************************************************************************************************************
144 
145 void Formulaeditor::closeEvent(QCloseEvent * event)
146 {
147  Q_UNUSED(event);
148  QSettings settings;
149  if(!this->isMaximized())
150  {
151  settings.setValue("pos_formula_editor", pos());
152  settings.setValue("size_formula_editor", size());
153  }
154 }
155 
156 //*************************************************************************************************************************************
157 
158 void AtomPaintWindow::paintEvent(QPaintEvent *event)
159 {
160  Q_UNUSED(event);
161  paint_signal(atomList, this->size());
162 }
163 
164 //*************************************************************************************************************************************
165 
166 void AtomPaintWindow::paint_signal(QList<qreal> valueList, QSize windowSize)
167 {
168  QPainter painter(this);
169  painter.setRenderHint(QPainter::Antialiasing, true);
170  painter.fillRect(0,0,windowSize.width(),windowSize.height(),QBrush(Qt::white));
171 
172 
173  if(valueList.length() > 0)
174  {
175  qint32 borderMarginHeigth = 15; // reduce paintspace in GraphWindow of borderMargin pixels
176  qint32 borderMarginWidth = 5; // reduce paintspace in GraphWindow of borderMargin pixels
177  qint32 i = 0;
178  qreal maxNeg = 0; // smalest signalvalue
179  qreal maxPos = 0; // highest signalvalue
180  qreal absMin = 0; // minimum of abs(maxNeg and maxPos)
181  qint32 drawFactor = 0; // shift factor for decimal places (linear)
182  qint32 startDrawFactor = 1; // shift factor for decimal places (exponential-base 10)
183  qint32 decimalPlace = 0; // decimal places for axis title
184  QPolygonF polygon; // points for drwing the signal
185  QList<qreal> internListValue; // intern representation of y-axis values of the signal (for painting only)
186 
187  internListValue.clear();
188  while(i < valueList.length())
189  {
190  internListValue.append(valueList.at(i)); //TODO stupid
191  i++;
192  }
193 
194  // paint window white
195  painter.fillRect(0,0,windowSize.width(),windowSize.height(),QBrush(Qt::white));
196 
197  // find min and max of signal
198  i = 0;
199  while(i < valueList.length())
200  {
201  if(valueList.at(i) > maxPos)
202  maxPos = valueList.at(i);
203 
204  if(valueList.at(i) < maxNeg )
205  maxNeg = valueList.at(i);
206  i++;
207  }
208 
209  if(maxPos > fabs(maxNeg)) absMin = maxNeg; // find absolute minimum of (maxPos, maxNeg)
210  else absMin = maxPos;
211 
212  if(absMin != 0) // absMin must not be zero
213  {
214  while(true) // shift factor for decimal places?
215  {
216  if(fabs(absMin) < 1) // if absMin > 1 , no shift of decimal places nescesary
217  {
218  absMin = absMin * 10;
219  drawFactor++; // shiftfactor counter
220  }
221  if(fabs(absMin) >= 1) break;
222  }
223  }
224 
225  // shift of decimal places with drawFactor for all signalpoints and save to intern list
226  while(drawFactor > 0)
227  {
228  i = 0;
229  while(i < valueList.length())
230  {
231  qreal replaceValue = internListValue.at(i) * 10;
232  internListValue.replace(i, replaceValue);
233  i++;
234  }
235  startDrawFactor = startDrawFactor * 10;
236  decimalPlace++;
237  maxPos = maxPos * 10;
238  maxNeg = maxNeg * 10;
239  drawFactor--;
240  }
241 
242  qreal maxmax;
243  // absolute signalheight
244  if(maxNeg <= 0) maxmax = maxPos - maxNeg;
245  else maxmax = maxPos + maxNeg;
246 
247 
248  // scale axis title
249  qreal scaleYText = (qreal)maxmax / (qreal)10;
250  qint32 negScale = floor((maxNeg * 10 / maxmax)+0.5);
251 
252  //find lenght of text of y-axis for shift of y-axis to the right (so the text will stay readable and is not painted into the y-axis
253  qint32 k = 0;
254  qint32 negScale2 = negScale;
255  qint32 maxStrLenght = 0;
256  while(k < 16)
257  {
258  QString string2;
259 
260  qreal scaledYText = negScale2 * scaleYText / (qreal)startDrawFactor; // scale value y-axis
261  string2 = QString::number(scaledYText, 'f', decimalPlace + 1); // scale in string with correct decimal places (precision depends on signal codomain)
262 
263  if(string2.length()> maxStrLenght) maxStrLenght = string2.length();
264 
265  k++;
266  negScale2++;
267  }
268  maxStrLenght = 6 + maxStrLenght * 6;
269 
270  //todo adjust distance for last text
271  //while(((windowSize.width() - maxStrLenght - borderMarginWidth)*100) % 15) borderMarginWidth++;
272 
273  qreal inStartValue = startValue;
274  qreal inEndValue = endValue;
275 
276  // scale signal
277  qreal scaleX = ((qreal)(windowSize.width() - maxStrLenght - 6 * borderMarginWidth))/ ((qreal)valueList.length() - 1);
278  qreal scaleY = (qreal)(windowSize.height() - borderMarginHeigth) / (qreal)maxmax;
279 
280  //scale axis
281  qreal scaleXAchse = (qreal)(windowSize.width() - maxStrLenght - 6 * borderMarginWidth) / (qreal)15;
282  qreal scaleYAchse = (qreal)(windowSize.height() - borderMarginHeigth) / (qreal)10;
283 
284  // position of title of x-axis
285  qint32 xAxisTextPos = 8;
286  if(maxNeg == 0) xAxisTextPos = -10; // if signal only positiv: titles above axis
287 
288  i = 1;
289 
290  qreal internStepWidth = (endValue - startValue) / 15;
291  qint32 decimalPlaceX = 0;
292  if(internStepWidth > 0.000999999999999)
293  decimalPlaceX = 3;
294  if(internStepWidth > 0.009999999)
295  decimalPlaceX = 2;
296  if(internStepWidth > 0.0999999999)
297  decimalPlaceX = 1;
298  if(internStepWidth > 0.999999)
299  decimalPlace = 0;
300  while(i <= 11)
301  {
302  QString string;
303 
304  qreal scaledYText = negScale * scaleYText / (qreal)startDrawFactor; // scale value y-axis
305 
306  string = QString::number(scaledYText, 'f', decimalPlace + 1); // scale in string with correct decimal places (precision depends on signal codomain)
307 
308  if(negScale == 0) // x-axis reached (y-value = 0)
309  {
310  // append scaled signalpoints
311  qint32 h = 0;
312  while(h < valueList.length())
313  {
314  polygon.append(QPointF(h * scaleX + maxStrLenght + 10, -((internListValue.at(h) * scaleY + ((i - 1) * scaleYAchse)-(windowSize.height()) + borderMarginHeigth / 2))));
315  h++;
316  }
317 
318  // paint x-axis
319  qreal j = 0;
320  inStartValue = startValue;
321  while(inStartValue <= inEndValue)
322  {
323  QString str;
324  painter.drawText(j * scaleXAchse + maxStrLenght + 3, -(((i - 1) * scaleYAchse)-(windowSize.height())) + xAxisTextPos, str.append(QString::number(inStartValue, 'f', decimalPlaceX))); // scale value x-axis
325  painter.drawLine(j * scaleXAchse + maxStrLenght + 10, -(((i - 1) * scaleYAchse)-(windowSize.height() - borderMarginHeigth / 2 - 2)), j * scaleXAchse + maxStrLenght + 10 , -(((i - 1) * scaleYAchse)-(windowSize.height() - borderMarginHeigth / 2 + 2))); // marks of x-axis
326  j++;
327  inStartValue += internStepWidth;
328  }
329  painter.drawLine(maxStrLenght, -(((i - 1) * scaleYAchse)-(windowSize.height()) + borderMarginHeigth / 2), windowSize.width()-5, -(((i - 1) * scaleYAchse)-(windowSize.height()) + borderMarginHeigth / 2));
330  }
331 
332  painter.drawText(3, -((i - 1) * scaleYAchse - windowSize.height()) - borderMarginHeigth/2 + 4, string); // paint scale value y-axis
333  painter.drawLine(maxStrLenght - 2, -(((i - 1) * scaleYAchse)-(windowSize.height()) + borderMarginHeigth / 2), maxStrLenght + 2, -(((i - 1) * scaleYAchse)-(windowSize.height()) + borderMarginHeigth / 2)); // marks of y-axis
334  i++;
335  negScale++;
336  }
337 
338  painter.drawLine(maxStrLenght, 2, maxStrLenght, windowSize.height() - 2); // paint y-axis
339 
340  painter.drawPolyline(polygon); // paint signal
341  }
342  painter.end();
343 }
344 
345 //*************************************************************************************************************************************
346 
347 void Formulaeditor::on_tb_Formula_textChanged(const QString &arg1)
348 {
349  ui->btt_Save->setEnabled(false);
350  QList<QChar> foundChar;
351  foundChar.clear();
352  for(qint32 i = 0; i < arg1.length(); i++)
353  {
354  bool beforeFound = false;
355  bool nextfound = false;
356  QChar upperChar = arg1.at(i).toUpper();
357  if((upperChar >= 'A' && upperChar <= 'H') || upperChar == 'X')
358  {
359  if(i != 0)
360  {
361  QChar beforeUpperChar = arg1.at(i - 1).toUpper();
362  if(beforeUpperChar < 'A' || (beforeUpperChar > 'Z' && beforeUpperChar < 126)) beforeFound = true;
363  }
364  else beforeFound = true;
365 
366  if(i < arg1.length() - 1)
367  {
368  QChar nextUpperChar = arg1.at(i+1).toUpper();
369  if(nextUpperChar < 'A' || (nextUpperChar > 'Z' && nextUpperChar < 126)) nextfound = true;
370  }
371  else nextfound = true;
372 
373 
374  if(beforeFound && nextfound)
375  {
376  if(upperChar == 'A') foundChar.append(upperChar);
377  else if(upperChar == 'B') foundChar.append(upperChar);
378  else if(upperChar == 'C') foundChar.append(upperChar);
379  else if(upperChar == 'D') foundChar.append(upperChar);
380  else if(upperChar == 'E') foundChar.append(upperChar);
381  else if(upperChar == 'F') foundChar.append(upperChar);
382  else if(upperChar == 'G') foundChar.append(upperChar);
383  else if(upperChar == 'H') foundChar.append(upperChar);
384  else if(upperChar == 'X') foundChar.append(upperChar);
385  }
386  }
387  }
388 
389  ui->lb_A->setEnabled(false);
390  ui->tb_A->setEnabled(false);
391  ui->lb_B->setEnabled(false);
392  ui->tb_B->setEnabled(false);
393  ui->lb_C->setEnabled(false);
394  ui->tb_C->setEnabled(false);
395  ui->lb_D->setEnabled(false);
396  ui->tb_D->setEnabled(false);
397  ui->lb_E->setEnabled(false);
398  ui->tb_E->setEnabled(false);
399  ui->lb_F->setEnabled(false);
400  ui->tb_F->setEnabled(false);
401  ui->lb_G->setEnabled(false);
402  ui->tb_G->setEnabled(false);
403  ui->lb_H->setEnabled(false);
404  ui->tb_H->setEnabled(false);
405  ui->lb_StartValue->setEnabled(false);
406  ui->lb_StepWidth->setEnabled(false);
407  ui->lb_EndValue->setEnabled(false);
408  ui->dsb_StartValue->setEnabled(false);
409  ui->dsb_StepWidth->setEnabled(false);
410  ui->dsb_EndValue->setEnabled(false);
411 
412  for(qint32 j = 0; j < foundChar.length(); j++)
413  {
414  if(foundChar.at(j) =='A')
415  {
416  ui->lb_A->setEnabled(true);
417  ui->tb_A->setEnabled(true);
418  }
419  else if(foundChar.at(j) =='B')
420  {
421  ui->lb_B->setEnabled(true);
422  ui->tb_B->setEnabled(true);
423  }
424  else if(foundChar.at(j) =='C')
425  {
426  ui->lb_C->setEnabled(true);
427  ui->tb_C->setEnabled(true);
428  }
429  else if(foundChar.at(j) =='D')
430  {
431  ui->lb_D->setEnabled(true);
432  ui->tb_D->setEnabled(true);
433  }
434  else if(foundChar.at(j) =='E')
435  {
436  ui->lb_E->setEnabled(true);
437  ui->tb_E->setEnabled(true);
438  }
439  else if(foundChar.at(j) =='F')
440  {
441  ui->lb_F->setEnabled(true);
442  ui->tb_F->setEnabled(true);
443  }
444  else if(foundChar.at(j) =='G')
445  {
446  ui->lb_G->setEnabled(true);
447  ui->tb_G->setEnabled(true);
448  }
449  else if(foundChar.at(j) =='H')
450  {
451  ui->lb_H->setEnabled(true);
452  ui->tb_H->setEnabled(true);
453  }
454  else if(foundChar.at(j) =='X')
455  {
456  ui->lb_StartValue->setEnabled(true);
457  ui->lb_StepWidth->setEnabled(true);
458  ui->lb_EndValue->setEnabled(true);
459  ui->dsb_StartValue->setEnabled(true);
460  ui->dsb_StepWidth->setEnabled(true);
461  ui->dsb_EndValue->setEnabled(true);
462  }
463  }
464 }
465 
466 //*************************************************************************************************************************************
467 
468 void Formulaeditor::on_tb_A_textChanged(const QString &arg1)
469 {
470  bool ok = false;
471  arg1.toFloat(&ok);
472  if(ok) oldStringA = arg1;
473  else if(arg1 != "") ui->tb_A->setText(oldStringA);
474 }
475 
476 void Formulaeditor::on_tb_B_textChanged(const QString &arg1)
477 {
478  bool ok = false;
479  arg1.toFloat(&ok);
480  if(ok) oldStringB = arg1;
481  else if(arg1 != "") ui->tb_B->setText(oldStringB);
482 }
483 
484 void Formulaeditor::on_tb_C_textChanged(const QString &arg1)
485 {
486  bool ok = false;
487  arg1.toFloat(&ok);
488  if(ok) oldStringC = arg1;
489  else if(arg1 != "") ui->tb_C->setText(oldStringC);
490 }
491 
492 void Formulaeditor::on_tb_D_textChanged(const QString &arg1)
493 {
494  bool ok = false;
495  arg1.toFloat(&ok);
496  if(ok) oldStringD = arg1;
497  else if(arg1 != "") ui->tb_D->setText(oldStringD);
498 }
499 
500 void Formulaeditor::on_tb_E_textChanged(const QString &arg1)
501 {
502  bool ok = false;
503  arg1.toFloat(&ok);
504  if(ok) oldStringE = arg1;
505  else if(arg1 != "") ui->tb_E->setText(oldStringE);
506 }
507 
508 void Formulaeditor::on_tb_F_textChanged(const QString &arg1)
509 {
510  bool ok = false;
511  arg1.toFloat(&ok);
512  if(ok) oldStringF = arg1;
513  else if(arg1 != "") ui->tb_F->setText(oldStringF);
514 }
515 
516 void Formulaeditor::on_tb_G_textChanged(const QString &arg1)
517 {
518  bool ok = false;
519  arg1.toFloat(&ok);
520  if(ok) oldStringG = arg1;
521  else if(arg1 != "") ui->tb_G->setText(oldStringG);
522 }
523 
524 void Formulaeditor::on_tb_H_textChanged(const QString &arg1)
525 {
526  bool ok = false;
527  arg1.toFloat(&ok);
528  if(ok) oldStringH = arg1;
529  else if(arg1 != "") ui->tb_H->setText(oldStringH);
530 }
531 
532 void Formulaeditor::on_dsb_StartValue_editingFinished()
533 {
534  ui->dsb_EndValue->setMinimum(ui->dsb_StartValue->value() + ui->dsb_StepWidth->value());
535 }
536 
537 void Formulaeditor::on_dsb_StepWidth_editingFinished()
538 {
539  ui->dsb_EndValue->setMinimum(ui->dsb_StartValue->value() + ui->dsb_StepWidth->value());
540 }
541 
542 //*************************************************************************************************************************************
543 
544 void Formulaeditor::on_btt_Test_clicked()
545 {
546  Formulaeditor FormulaParser;
547 
548  FormulaParser.set_funct_const(0, ui->tb_A->text().toFloat());
549  FormulaParser.set_funct_const(1, ui->tb_B->text().toFloat());
550  FormulaParser.set_funct_const(2, ui->tb_C->text().toFloat());
551  FormulaParser.set_funct_const(3, ui->tb_D->text().toFloat());
552  FormulaParser.set_funct_const(4, ui->tb_E->text().toFloat());
553  FormulaParser.set_funct_const(5, ui->tb_F->text().toFloat());
554  FormulaParser.set_funct_const(6, ui->tb_G->text().toFloat());
555  FormulaParser.set_funct_const(7, ui->tb_H->text().toFloat());
556 
557  double retValue = FormulaParser.calculation(ui->tb_Formula->text(), ui->dsb_StartValue->value()); // TODO Float or only Int at X
558 
559  if(errorText.isEmpty())
560  {
561  if(ui->lb_StartValue->isEnabled())
562  ui->btt_Save->setEnabled(true);
563  if(retValue < 0.0000000000001 && retValue > -0.0000000000001)
564  retValue = 0;
565  ui->lb_Result->setText(QString("result start value = %1").arg(retValue));
566  }
567  else
568  {
569  ui->lb_Result->setText(errorText);
570  errorText = "";
571  return;
572  }
573  QList<qreal> resultsList;
574  resultsList.clear();
575  startValue = ui->dsb_StartValue->value();
576  qreal internStartValue = startValue;
577  endValue = ui->dsb_EndValue->value();
578  stepWidth = ui->dsb_StepWidth->value();
579  if(stepWidth == 0)
580  {
581  QMessageBox::warning(this, tr("error"), tr("Increment can not be null."));
582  return;
583  }
584 
585  if(ui->dsb_StartValue->isEnabled() && ui->dsb_EndValue->isEnabled() && ui->dsb_StepWidth->isEnabled())
586  {
587  while(internStartValue <= endValue)
588  {
589  resultsList.append(FormulaParser.calculation(ui->tb_Formula->text(), internStartValue ));
590  internStartValue += stepWidth;
591  }
592  }
593  else
594  {
595  qreal result = FormulaParser.calculation(ui->tb_Formula->text(), internStartValue );
596  ui->lb_Result->setText(QString("result = %1").arg(result));
597  }
598 
599  atomList = resultsList;
600  atomLength = resultsList.length();
601  errorText = "";
602  callAtomPaintWindow->update();
603  update();
604 }
605 
606 //*************************************************************************************************************************************
607 
608 // access when "sforumla save" clicked
609 void Formulaeditor::on_btt_Save_clicked()
610 {
611  QFile saveFile(QDir::homePath() + "/" + "Matching-Pursuit-Toolbox/user.fml");
612  if(!saveFile.exists())
613  {
614  if (saveFile.open(QIODevice::ReadWrite | QIODevice::Text))
615  saveFile.close();
616  }
617 
618  if (saveFile.open(QIODevice::WriteOnly| QIODevice::Append))
619  {
620  QTextStream stream( &saveFile);
621  stream << ui->tb_Formula->text() << "\n";
622  }
623  saveFile.close();
624 
625  ui->tb_Formula->clear();
626  ui->tb_A->setText("0");
627  ui->tb_B->setText("0");
628  ui->tb_C->setText("0");
629  ui->tb_D->setText("0");
630  ui->tb_E->setText("0");
631  ui->tb_F->setText("0");
632  ui->tb_G->setText("0");
633  ui->tb_H->setText("0");
634  ui->lb_Result->setText("result start value = ---");
635  atomList.clear();
636  update();
637 
638  emit formula_saved();
639 }
640 
641 //*************************************************************************************************************************************
642 // formula methods Copyright: 2004, Ralf Wirtz adapted to qt for formula editor by Daniel Knobl **********************************
643 // this Code is licensed under The Code Project Open License (CPOL) 1.02 **************************************************************
644 //*************************************************************************************************************************************
645 
646 qreal Formulaeditor::sign_factor(qint32& nPosition, QString& strCharacter)
647 {
648  if (strCharacter == "-")
649  {
650  char_n(nPosition, strCharacter);
651  return (-1.0) * factor(nPosition, strCharacter);
652  }
653  else return factor(nPosition, strCharacter);
654 }
655 
656 //*************************************************************************************************************************************
657 
658 void Formulaeditor::strip_formula(QString &strFormula)
659 {
660  qint32 level = 0;
661 
662  if (strFormula.length() < 1) return;
663 
664  // replace comma by points all round brackets
665  strFormula.replace("PI", "3.14159265358979323846");
666  strFormula.replace("pi", "3.14159265358979323846");
667  strFormula.replace("Pi", "3.14159265358979323846");
668  strFormula.replace("pI", "3.14159265358979323846");
669  strFormula.replace(" ", "");
670  strFormula.replace(",", ".");
671  strFormula.replace("[", "(");
672  strFormula.replace("]", ")");
673  strFormula.replace("{", "(");
674  strFormula.replace("}", ")");
675 
676  strFormula.replace("*(1)","");
677  strFormula.replace("(1)*","");
678 
679  strFormula.replace("*(x)","*x");
680  strFormula.replace("((x)*","(x*");
681  strFormula.replace("+(x)*","+x*");
682  strFormula.replace("-(x)*","-x*");
683  strFormula.replace("*(x)*","*x*");
684  strFormula.replace("(sin(x))","sin(x)");
685  strFormula.replace("(cos(x))","cos(x)");
686  strFormula.replace("(cot(x))","cot(x)");
687  strFormula.replace("(tan(x))","tan(x)");
688  strFormula.replace("(exp(x))","exp(x)");
689  strFormula.replace("(log(x))","log(x)");
690  strFormula.replace("(ln(x))","ln(x)");
691 
692  // delete enclosing marks
693  for (qint32 i = 0; i < strFormula.length(); i++)
694  {
695  if(QString::compare(strFormula.at(i), "(") == 0)
696  {
697  level++;
698  continue;
699  }
700  if(QString::compare(strFormula.at(i), ")") == 0)
701  {
702  level--;
703  continue;
704  }
705 
706  if (level == 0 && i < strFormula.length() - 1)
707  {
708  level = -1; // marker
709  break;
710  }
711  }
712 
713  if (level != -1)
714  {
715  while (strFormula.at(0) == '(' && strFormula.at(strFormula.length() - 1) == ')')
716  {
717  strFormula = strFormula.mid(1, strFormula.length() - 2);
718  }
719  }
720 
721  // delete whitespaces and positive signs
722  while (strFormula.at(0) == '+'
723  || strFormula.at(0) == ' ')
724  {
725  strFormula = strFormula.mid(1);
726  }
727  strFormula.trimmed();
728 
729  //remove unused brackets
730  qint32 Pos[1000];
731  qint32 j = 0;
732  level = 0;
733  qint32 l = strFormula.length();
734 
735  for (qint32 i = 0; i < l; i++)
736  {
737  if (strFormula.at(i) == '(')
738  {
739  qint32 min = 0;
740  if(i+1 < l-1)
741  min = i+1;
742  else
743  min = l - 1;
744  if (i == 0 || (i > 0 && (strFormula.at(i-1) == '(' || strFormula.at(min) == '(')))
745  {
746  level++;
747  Pos[++j] = i;
748  }
749  }
750  else if (strFormula.at(i) == ')')
751  {
752  level--;
753  if (level > 0 && strFormula.at(i+1) == ')')
754  {
755  //right bracket
756  QString left = strFormula.left(i);
757  QString mid = strFormula.mid(i+1);
758  strFormula = left + "|" + mid;
759 
760  //left bracket
761  left = strFormula.left(Pos[level] + 1);
762  mid = strFormula.mid(Pos[level+1] + 1);
763  strFormula = left + "|" + mid;
764 
765  j = 0;
766  }
767  }
768  }
769  strFormula.replace("|", "");
770 }
771 
772 //*************************************************************************************************************************************
773 
774 double Formulaeditor::calculation(QString strFormula, qreal xValue, bool strip)
775 {
776  qint32 nPosition;
777  QString strCharacter;
778  qreal result;
779 
780  if (strFormula.length() < 1) return 0.0;
781 
782  m_strErrortext = "";
783 
784  if (strip) strip_formula(strFormula);
785 
786  m_strFunction = strFormula;
787  m_dFktValue = xValue;
788  if (m_dFktValue == 0)
789  m_dFktValue = FLT_MIN;
790  nPosition = 0;
791  char_n(nPosition, strCharacter);
792 
793  result = expression(nPosition, strCharacter);
794 
795  return result;
796 }
797 
798 //*************************************************************************************************************************************
799 
800 double Formulaeditor::expression(int& nPosition, QString& strCharacter)
801 {
802  QString strOperator;
803  double erg = simple_expression(nPosition, strCharacter);
804  while (strCharacter == "+" || strCharacter == "-")
805  {
806  strOperator = strCharacter;
807  char_n(nPosition, strCharacter);
808  if (strOperator == "+")
809  erg += simple_expression(nPosition, strCharacter);
810  else if (strOperator == "-")
811  erg -= simple_expression(nPosition, strCharacter);
812  }
813 
814  return erg;
815 }
816 
817 //*************************************************************************************************************************************
818 
819 double Formulaeditor::simple_expression(int& nPosition, QString& strCharacter)
820 {
821  double s,dum;
822  QString strOperator;
823  s = term(nPosition, strCharacter);
824  while (strCharacter == "*" || strCharacter == "/")
825  {
826  strOperator = strCharacter;
827  char_n(nPosition, strCharacter);
828  if (strOperator == "*")
829  s = s * term(nPosition, strCharacter);
830  else if (strOperator == "/")
831  {
832  dum = term(nPosition, strCharacter);
833  if (dum != 0) s = s / dum;
834  else errorText = QString("Divide by 0 is not possible.");
835  }
836  }
837  return s;
838 }
839 
840 //*************************************************************************************************************************************
841 
842 double Formulaeditor::term(int& nPosition, QString& strCharacter)
843 {
844  qreal t,vz;
845  t = sign_factor(nPosition, strCharacter);
846  while (strCharacter == "^")
847  {
848  char_n(nPosition, strCharacter);
849  vz = sign_factor(nPosition, strCharacter);
850 
851  if ((t <= 0 && fabs(vz) <= 1) || (t <= 0 && vz != qint32(vz))) errorText = QString("Extraction of square root of negative numbers is not possible using dense matrix algebra.");
852  else t = pow(t,vz);
853  }
854  return t;
855 }
856 
857 //*************************************************************************************************************************************
858 
859 double Formulaeditor::char_n(int& nPosition, QString& strCharacter)
860 {
861  do
862  {
863  nPosition ++;
864  if (nPosition <= m_strFunction.length())
865  strCharacter = m_strFunction.mid(nPosition - 1, 1);
866  else
867  strCharacter = str_char("?");
868  }
869  while (strCharacter == " ");
870 
871  return nPosition;
872 }
873 
874 //*************************************************************************************************************************************
875 
876 void Formulaeditor::set_formula(QString Formula)
877 {
878  m_strFormula = Formula;
879 }
880 
881 //*************************************************************************************************************************************
882 
884 {
885  return m_strFormula;
886 }
887 
888 //*************************************************************************************************************************************
889 
890 double Formulaeditor::factor(qint32& nPosition, QString& strCharacter)
891 {
892  qreal f = 0.0;
893  qint32 wI = 0, wL = 0, wBeginn = 0, wError = 0;
894 
895  if (strCharacter == str_char(0)) return 0.0;
896  // read digit and save as float in f
897  if (((strCharacter >= "0") && (strCharacter <= "9")) || (strCharacter == "."))
898  {
899  wBeginn = nPosition;
900 
901  do
902  {
903  char_n(nPosition, strCharacter);
904  }
905  while ((((strCharacter >= "0") && (strCharacter <= "9")) || (strCharacter == ".")));
906 
907  if (strCharacter == ".")
908  {
909  do
910  {
911  char_n(nPosition, strCharacter);
912  }
913  while (!(((qint8)strCharacter.at(0).digitValue() >= 0) && ((qint8)strCharacter.at(0).digitValue() <= 9)) || (strCharacter.at(0) == '.'));
914  }
915 
916  QString g_strF = m_strFunction.mid(wBeginn - 1, nPosition - wBeginn);
917  f = g_strF.toFloat();
918  }
919  else
920  {
921  QString strCharacterUpper = strCharacter.toUpper();
922  if (strCharacter == "(")
923  {
924  char_n(nPosition, strCharacter);
925  f = expression(nPosition, strCharacter);
926  if (strCharacter == ")")
927  char_n(nPosition, strCharacter);
928  }
929  else if (strCharacterUpper == "X")
930  {
931  char_n(nPosition, strCharacter);
932  f = m_dFktValue;
933  }
934  else
935  {
936  bool gefunden = false;
937  qint32 AnzStdFunctions = m_strStandardFunction.length() - 1;
938  for (wI = 1; wI <= AnzStdFunctions; wI++)
939  {
940  wL = m_strStandardFunction.at(wI).length();
941  QString strFunktionUpper = m_strFunction.mid(nPosition - 1, wL);
942  strFunktionUpper = strFunktionUpper.toUpper();
943  QString strDummy(m_strStandardFunction.at(wI));
944  strDummy = strDummy.toUpper();
945  if (strFunktionUpper == strDummy)
946  {
947  gefunden = true;
948  nPosition = nPosition + wL - 1;
949  char_n(nPosition, strCharacter);
950  // ! recursion !!!!!!!!!!!!!!!!!!!!!!
951  f = factor(nPosition, strCharacter);
953  if (strFunktionUpper == "ABS")
954  f = fabs(f);
955  else if (strFunktionUpper == "SQRT")
956  if (f >= 0)
957  f = sqrt(f);
958  else
959  wError = -1;
960  else if (strFunktionUpper == "SINH")
961  f = sinh(f);
962  else if (strFunktionUpper == "COSH")
963  f = cosh(f);
964  else if (strFunktionUpper == "TANH")
965  f = tanh(f);
966  else if (strFunktionUpper == "ARCTAN")
967  f = atan(f);
968  else if (strFunktionUpper == "LN")
969  {
970  if (f >= 0)
971  f = log(f);
972  else
973  wError = -1;
974  }
975  else if (strFunktionUpper == "LOG")
976  {
977  if (f >= 0)
978  f = log10(f);
979  else
980  wError = -1;
981  }
982  else if (strFunktionUpper == "EXP")
983  {
984  //if (f <= 41)
985  f = exp(f);
986  //else
987  //wError = -1;
988  }
989  else if (strFunktionUpper == "SIN")
990  f = sin(f);
991  else if (strFunktionUpper == "COS")
992  f = cos(f);
993  else if (strFunktionUpper == "COT")
994  f = cot(f);
995  else if (strFunktionUpper == "TAN")
996  {
997  if (cos(f) != 0)
998  f = tan(f);
999  else
1000  wError = -1;
1001  }
1002  else if (strFunktionUpper == "ARCSIN")
1003  {
1004  if (fabs(f) < 1)
1005  f = asin(f);
1006  else
1007  wError = -1;
1008  }
1009  else if (strFunktionUpper == "ARCCOS")
1010  {
1011  if (fabs(f) <= 1)
1012  f = acos(f);
1013  else
1014  wError = -1;
1015  }
1016  else if (strFunktionUpper == "SIGN")
1017  f = signl(f);
1018  else if (strFunktionUpper == "RAD")
1019  f = RAD(f);
1020  else if (strFunktionUpper == "DEG")
1021  f = DEG(f);
1022  else if (strFunktionUpper == "ARSINH")
1023  f = ArSinh(f);
1024  else if (strFunktionUpper == "ARCOSH")
1025  {
1026  if (fabs(f) >= 1)
1027  f = ArCosh(f);
1028  else
1029  wError = -1;
1030  }
1031  else if (strFunktionUpper == "ARTANH")
1032  {
1033  if (fabs(f) <= 1)
1034  f = ArTanh(f);
1035  else
1036  wError = -1;
1037  }
1038  break;
1039  }
1040  }
1041  if (!gefunden)
1042  {
1043  char_n(nPosition, strCharacter);
1044  if (strCharacterUpper == "A")
1045  f = m_dFunctionConstant[0];
1046  else if (strCharacterUpper == "B")
1047  f = m_dFunctionConstant[1];
1048  else if (strCharacterUpper == "C")
1049  f = m_dFunctionConstant[2];
1050  else if (strCharacterUpper == "D")
1051  f = m_dFunctionConstant[3];
1052  else if (strCharacterUpper == "E")
1053  f = m_dFunctionConstant[4];
1054  else if (strCharacterUpper == "F")
1055  f = m_dFunctionConstant[5];
1056  else if (strCharacterUpper == "G")
1057  f = m_dFunctionConstant[6];
1058  else if (strCharacterUpper == "H")
1059  f = m_dFunctionConstant[7];
1060  }
1061  }
1062  }
1063 
1064  if (wError == -1) errorText = QString("General Parser Error blocked!");
1065 
1066  return f;
1067 }
1068 
1069 //*************************************************************************************************************************************
1070 
1071 void Formulaeditor::set_funct_const(int index, double val)
1072 {
1073  //between 0 and 9
1074  if (index >= 0 && index < 9) m_dFunctionConstant[index] = val;
1075  else errorText = QString("Error in SetFunctConst()");
1076 }
1077 
1078 QString Formulaeditor::str_char(QString DecimalZahl)
1079 {
1080  if(DecimalZahl == "?") return QString("?");
1081  else return DecimalZahl;
1082 }
1083 
1084 double Formulaeditor::SINQ(double Winkel_grad)
1085 {
1086  double Winkel_rad = PI * Winkel_grad / 180.0;
1087  return sin(Winkel_rad);
1088 }
1089 
1090 double Formulaeditor::COSQ(double Winkel_grad)
1091 {
1092  // const float PI = 3.141592654f;
1093  double Winkel_rad = PI * Winkel_grad / 180.0;
1094  return cos(Winkel_rad);
1095 }
1096 
1097 double Formulaeditor::cot(double x)
1098 {
1099  return cos(x)/sin(x);
1100 }
1101 
1102 double Formulaeditor::DEG(double x /* rad */)
1103 {
1104  // returns angle in grad
1105  return x * 180.0 / PI;
1106 }
1107 
1108 double Formulaeditor::RAD(double x /* grad */)
1109 {
1110  // returns angle in rad
1111  return x * PI / 180.0;
1112 }
1113 
1114 QString Formulaeditor::get_next_token(QString &strSrc, const QString strDelim)
1115 {
1116  QString token;
1117  int idx = strSrc.indexOf(strDelim);
1118  if(idx != -1)
1119  {
1120  token = strSrc.left(idx);
1121  strSrc = strSrc.right(strSrc.length() - (idx + 1) );
1122  }
1123  else
1124  {
1125  token = strSrc;
1126  strSrc = "";
1127  }
1128  return token;
1129 }
1130 
1131 long double Formulaeditor::signl(long double x)
1132 {
1133  if (x > 0.0L) return 1.0L;
1134  if (x < 0.0L) return -1.0L;
1135  return 0.0L;
1136 }
1137 
1138 double Formulaeditor::ArSinh(double x)
1139 {
1140  if (x < 0)
1141  return -log(-x + sqrt(sqr(-x) + 1));
1142  return log(x + sqrt(sqr(x) + 1));
1143 }
1144 
1145 double Formulaeditor::ArCosh(double x)
1146 {
1147  return log(x + sqrt(sqr(x) - 1));
1148 }
1149 
1150 double Formulaeditor::ArTanh(double x)
1151 {
1152  return 0.5*logl((1 + x)/ (1 - x));
1153 }
1154 
1155 double Formulaeditor::ArCoth(double x)
1156 {
1157  return 0.5*log((x + 1)/ (x - 1));
1158 }
1159 
1160 double Formulaeditor::sqr(double x)
1161 {
1162  return x*x;
1163 }
1164 
1165 //*************************************************************************************************************************************
1166 // end formula methods Copyright: 2004, Ralf Wirtz adapted to qt for formula editor by Daniel Knobl ******************************
1167 //*************************************************************************************************************************************
1168 
void set_formula(QString Formula)
void set_funct_const(int index, double val)
Definition: aboutwindow.h:52
double calculation(QString strFormula, qreal xValue, bool strip=true)
QString get_formula()
FormulaEditor class declaration which allows the definition of individual atomformulas for the usage ...
void strip_formula(QString &strFormula)