Warning, file /education/kmplot/kmplot/xparser.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KmPlot - a math. function plotter for the KDE-Desktop 0003 0004 SPDX-FileCopyrightText: 1998, 1999, 2000, 2002 Klaus-Dieter Möller <kd.moeller@t-online.de> 0005 SPDX-FileCopyrightText: 2006, 2007 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 "xparser.h" 0015 0016 #include <kmplot/config-kmplot.h> 0017 0018 // local includes 0019 #include "maindlg.h" 0020 #include "parseradaptor.h" 0021 0022 // KDE includes 0023 #include <KLocalizedString> 0024 #include <KMessageBox> 0025 0026 #include <QList> 0027 0028 #include <assert.h> 0029 #include <cmath> 0030 #ifdef HAVE_IEEEFP_H 0031 #include <ieeefp.h> 0032 #endif 0033 0034 XParser *XParser::m_self = 0; 0035 0036 XParser *XParser::self() 0037 { 0038 if (!m_self) 0039 m_self = new XParser(); 0040 0041 return m_self; 0042 } 0043 0044 XParser::XParser() 0045 { 0046 differentialFinite = true; 0047 differentialDiverge = 0; 0048 0049 new ParserAdaptor(this); 0050 QDBusConnection::sessionBus().registerObject(QStringLiteral("/parser"), this); 0051 } 0052 0053 XParser::~XParser() 0054 { 0055 } 0056 0057 bool XParser::getext(Function *item, const QString &fstr) 0058 { 0059 bool errflg = false; 0060 int p1, p2, p3, pe; 0061 QString tstr; 0062 pe = fstr.length(); 0063 if (fstr.indexOf('N') != -1) 0064 item->plotAppearance(Function::Derivative0).visible = false; 0065 else { 0066 if (fstr.indexOf(QLatin1String("A1")) != -1) 0067 item->plotAppearance(Function::Derivative1).visible = true; 0068 if (fstr.indexOf(QLatin1String("A2")) != -1) 0069 item->plotAppearance(Function::Derivative2).visible = true; 0070 } 0071 switch (fstr[0].unicode()) { 0072 case 'x': 0073 case 'y': 0074 case 'r': 0075 item->plotAppearance(Function::Derivative1).visible = item->plotAppearance(Function::Derivative2).visible = false; 0076 } 0077 0078 p1 = fstr.indexOf(QLatin1String("D[")); 0079 if (p1 != -1) { 0080 p1 += 2; 0081 const QString str = fstr.mid(p1, pe - p1); 0082 p2 = str.indexOf(','); 0083 p3 = str.indexOf(']'); 0084 if (p2 > 0 && p2 < p3) { 0085 tstr = str.left(p2); 0086 errflg |= !item->dmin.updateExpression(tstr); 0087 tstr = str.mid(p2 + 1, p3 - p2 - 1); 0088 errflg |= !item->dmax.updateExpression(tstr); 0089 if (item->dmin.value() > item->dmax.value()) 0090 errflg = true; 0091 } else 0092 errflg = true; 0093 } 0094 p1 = fstr.indexOf(QLatin1String("P[")); 0095 if (p1 != -1) { 0096 int i = 0; 0097 p1 += 2; 0098 QString str = fstr.mid(p1, 1000); 0099 p3 = str.indexOf(']'); 0100 do { 0101 p2 = str.indexOf(','); 0102 if (p2 == -1 || p2 > p3) 0103 p2 = p3; 0104 tstr = str.left(p2++); 0105 str = str.mid(p2, 1000); 0106 Value value; 0107 if (!value.updateExpression(tstr)) { 0108 errflg = true; 0109 break; 0110 } 0111 item->m_parameters.list.append(value); 0112 p3 -= p2; 0113 } while (p3 > 0 && i < 10); 0114 } 0115 0116 if (errflg) { 0117 KMessageBox::error(0, i18n("Error in extension.")); 0118 return false; 0119 } else 0120 return true; 0121 } 0122 0123 double XParser::derivative(int n, Equation *eq, DifferentialState *state, double x, double h) 0124 { 0125 if (n < -1) { 0126 qCritical() << "Can't handle derivative < -1\n"; 0127 return 0.0; 0128 } 0129 0130 switch (n) { 0131 case -1: 0132 return differential(eq, &eq->differentialStates[0], x, h); 0133 0134 case 0: 0135 if (state) 0136 return differential(eq, state, x, h); 0137 else 0138 return fkt(eq, x); 0139 0140 case 1: 0141 if (state) 0142 return (differential(eq, state, x + (h / 2), h) - differential(eq, state, x - (h / 2), h)) / h; 0143 else 0144 return (fkt(eq, x + (h / 2)) - fkt(eq, x - (h / 2))) / h; 0145 0146 default: 0147 return (derivative(n - 1, eq, state, x + (h / 2), (h / 4)) - derivative(n - 1, eq, state, x - (h / 2), (h / 4))) / h; 0148 } 0149 } 0150 0151 double XParser::partialDerivative(int n1, int n2, Equation *eq, DifferentialState *state, double x, double y, double h1, double h2) 0152 { 0153 if (n1 < 0 || n2 < 0) { 0154 qCritical() << "Can't handle derivative < 0\n"; 0155 return 0.0; 0156 } 0157 0158 if (n1 > 0) 0159 return (partialDerivative(n1 - 1, n2, eq, state, x + (h1 / 2), y, (h1 / 4), h2) 0160 - partialDerivative(n1 - 1, n2, eq, state, x - (h1 / 2), y, (h1 / 4), h2)) 0161 / h1; 0162 0163 Function *f = eq->parent(); 0164 f->m_implicitMode = Function::FixedX; 0165 f->x = x; 0166 0167 return derivative(n2, eq, state, y, h2); 0168 } 0169 0170 QString XParser::findFunctionName(const QString &preferredName, int id, const QStringList &neededPatterns) 0171 { 0172 // The position of the character attempting to replace 0173 int pos = preferredName.length() - 1; 0174 0175 QString name = preferredName; 0176 0177 for (;; ++pos) { 0178 for (QChar lastChar = 'f'; lastChar < 'x'; ++lastChar.unicode()) { 0179 bool ok = true; 0180 name[pos] = lastChar; 0181 0182 for (Function *it : qAsConst(m_ufkt)) { 0183 if (int(it->id()) == id) 0184 continue; 0185 0186 for (Equation *eq : qAsConst(it->eq)) { 0187 for (const QString &pattern : neededPatterns) { 0188 if (eq->name() == pattern.arg(name)) 0189 ok = false; 0190 } 0191 } 0192 0193 if (!ok) 0194 break; 0195 } 0196 if (!ok) 0197 continue; 0198 0199 // Found a free name :) 0200 return name; 0201 } 0202 name[pos] = 'f'; 0203 name.append('f'); 0204 } 0205 } 0206 0207 void XParser::fixFunctionName(QString &str, Equation::Type const type, int const id) 0208 { 0209 int p1 = str.indexOf('('); 0210 int p2 = str.indexOf(')'); 0211 int p3 = str.indexOf('='); 0212 0213 if (p1 < 0) 0214 return; 0215 0216 for (int i = p2 + 1; i < p3; ++i) { 0217 if (!str.at(i).isSpace()) 0218 return; 0219 } 0220 0221 QString const fname = str.left(p1); 0222 for (Function *it : qAsConst(m_ufkt)) { 0223 if (int(it->id()) == id) 0224 continue; 0225 0226 for (Equation *eq : qAsConst(it->eq)) { 0227 if (eq->name() != fname) 0228 continue; 0229 0230 str = str.mid(p1, str.length() - 1); 0231 QString function_name; 0232 if (type == Equation::ParametricX) 0233 function_name = 'x'; 0234 else if (type == Equation::ParametricY) 0235 function_name = 'y'; 0236 else 0237 function_name = 'f'; 0238 function_name = findFunctionName(function_name, id); 0239 str.prepend(function_name); 0240 return; 0241 } 0242 } 0243 } 0244 0245 Vector XParser::rk4_f(int order, Equation *eq, double x, const Vector &y) 0246 { 0247 bool useParameter = eq->usesParameter(); 0248 0249 m_result.resize(order); 0250 m_arg.resize(order + 1 + (useParameter ? 1 : 0)); 0251 0252 m_arg[0] = x; 0253 0254 if (useParameter) 0255 m_arg[1] = eq->parent()->k; 0256 0257 memcpy(m_arg.data() + 1 + (useParameter ? 1 : 0), y.data(), order * sizeof(double)); 0258 memcpy(m_result.data(), y.data() + 1, (order - 1) * sizeof(double)); 0259 0260 m_result[order - 1] = XParser::fkt(eq, m_arg); 0261 0262 return m_result; 0263 } 0264 0265 double XParser::differential(Equation *eq, DifferentialState *state, double x_target, double max_dx) 0266 { 0267 differentialFinite = true; 0268 0269 if (eq->order() < 1) { 0270 qWarning() << "Zero order!\n"; 0271 return 0; 0272 } 0273 0274 max_dx = qAbs(max_dx); 0275 assert(max_dx > 0); // in case anyone tries to pass us a zero h 0276 0277 // the difference between h and dx is that h is only used as a hint for the 0278 // stepwidth; dx is made similar to h in size, yet tiles the gap between x 0279 // and the previous x perfectly 0280 0281 // see if the initial integral point in the function is closer to our 0282 // required x value than the last one (or the last point is invalid) 0283 if (qAbs(state->x0.value() - x_target) < qAbs(state->x - x_target)) 0284 state->resetToInitial(); 0285 0286 int order = eq->order(); 0287 0288 m_k1.resize(order); 0289 m_k2.resize(order); 0290 m_k3.resize(order); 0291 m_k4.resize(order); 0292 m_y_temp.resize(order); 0293 0294 double x = state->x; 0295 m_y = state->y; 0296 if (x_target == x) 0297 return m_y[0]; 0298 0299 int intervals = int(qAbs(x_target - x) / max_dx + 1); 0300 double dx = (x_target - x) / double(intervals); 0301 0302 for (int i = 0; i < intervals; ++i) { 0303 // Update differentialDiverge before y possible becomes infinite 0304 differentialDiverge = x; 0305 0306 x = state->x + i * dx; 0307 0308 m_k1 = rk4_f(order, eq, x, m_y); 0309 0310 m_y_temp.combine(m_y, dx / 2, m_k1); 0311 m_k2 = rk4_f(order, eq, x + dx / 2, m_y_temp); 0312 0313 m_y_temp.combine(m_y, dx / 2, m_k2); 0314 m_k3 = rk4_f(order, eq, x + dx / 2, m_y_temp); 0315 0316 m_y_temp.combine(m_y, dx, m_k3); 0317 m_k4 = rk4_f(order, eq, x + dx, m_y_temp); 0318 0319 m_y.addRK4(dx, m_k1, m_k2, m_k3, m_k4); 0320 0321 // The condition on the total accumulated error (O(dx^5)) should not be violated for rapidly increasing functions, e.g. e^x^2 0322 if (!std::isfinite(m_y[0]) || qAbs((state->y[0] - m_y[0]) * dx * dx) > 1) { 0323 differentialFinite = false; 0324 state->resetToInitial(); 0325 return 1e200 * ((m_y[0] > 0) - (m_y[0] < 0)); 0326 } 0327 } 0328 0329 state->x = x + dx; 0330 state->y = m_y; 0331 0332 return m_y[0]; 0333 } 0334 0335 QColor XParser::defaultColor(int function) 0336 { 0337 switch (function % 10) { 0338 case 0: 0339 return Settings::color0(); 0340 case 1: 0341 return Settings::color1(); 0342 case 2: 0343 return Settings::color2(); 0344 case 3: 0345 return Settings::color3(); 0346 case 4: 0347 return Settings::color4(); 0348 case 5: 0349 return Settings::color5(); 0350 case 6: 0351 return Settings::color6(); 0352 case 7: 0353 return Settings::color7(); 0354 case 8: 0355 return Settings::color8(); 0356 case 9: 0357 return Settings::color9(); 0358 } 0359 0360 assert(!"Should not happen - XParser::defaultColor"); 0361 return QColor(); 0362 } 0363 0364 QStringList XParser::listFunctionNames() 0365 { 0366 return userFunctions(); 0367 } 0368 0369 bool XParser::functionFVisible(uint id) 0370 { 0371 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance(Function::Derivative0).visible : false; 0372 } 0373 bool XParser::functionF1Visible(uint id) 0374 { 0375 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance(Function::Derivative1).visible : false; 0376 } 0377 bool XParser::functionF2Visible(uint id) 0378 { 0379 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance(Function::Derivative2).visible : false; 0380 } 0381 bool XParser::functionIntVisible(uint id) 0382 { 0383 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance(Function::Integral).visible : false; 0384 } 0385 0386 bool XParser::setFunctionFVisible(uint id, bool visible) 0387 { 0388 if (!m_ufkt.contains(id)) 0389 return false; 0390 m_ufkt[id]->plotAppearance(Function::Derivative0).visible = visible; 0391 MainDlg::self()->requestSaveCurrentState(); 0392 return true; 0393 } 0394 bool XParser::setFunctionF1Visible(uint id, bool visible) 0395 { 0396 if (!m_ufkt.contains(id)) 0397 return false; 0398 m_ufkt[id]->plotAppearance(Function::Derivative1).visible = visible; 0399 MainDlg::self()->requestSaveCurrentState(); 0400 return true; 0401 } 0402 bool XParser::setFunctionF2Visible(uint id, bool visible) 0403 { 0404 if (!m_ufkt.contains(id)) 0405 return false; 0406 m_ufkt[id]->plotAppearance(Function::Derivative2).visible = visible; 0407 MainDlg::self()->requestSaveCurrentState(); 0408 return true; 0409 } 0410 bool XParser::setFunctionIntVisible(uint id, bool visible) 0411 { 0412 if (!m_ufkt.contains(id)) 0413 return false; 0414 m_ufkt[id]->plotAppearance(Function::Integral).visible = visible; 0415 MainDlg::self()->requestSaveCurrentState(); 0416 return true; 0417 } 0418 0419 QString XParser::functionStr(uint id, uint eq) 0420 { 0421 if (!m_ufkt.contains(id) || (eq >= 2)) 0422 return QLatin1String(""); 0423 return m_ufkt[id]->eq[eq]->fstr(); 0424 } 0425 0426 QColor XParser::functionFColor(uint id) 0427 { 0428 if (!m_ufkt.contains(id)) 0429 return QColor(); 0430 return QColor(m_ufkt[id]->plotAppearance(Function::Derivative0).color); 0431 } 0432 QColor XParser::functionF1Color(uint id) 0433 { 0434 if (!m_ufkt.contains(id)) 0435 return QColor(); 0436 return QColor(m_ufkt[id]->plotAppearance(Function::Derivative1).color); 0437 } 0438 QColor XParser::functionF2Color(uint id) 0439 { 0440 if (!m_ufkt.contains(id)) 0441 return QColor(); 0442 return QColor(m_ufkt[id]->plotAppearance(Function::Derivative2).color); 0443 } 0444 QColor XParser::functionIntColor(uint id) 0445 { 0446 if (!m_ufkt.contains(id)) 0447 return QColor(); 0448 return QColor(m_ufkt[id]->plotAppearance(Function::Integral).color); 0449 } 0450 bool XParser::setFunctionFColor(uint id, const QColor &color) 0451 { 0452 if (!m_ufkt.contains(id)) 0453 return false; 0454 m_ufkt[id]->plotAppearance(Function::Derivative0).color = color; 0455 MainDlg::self()->requestSaveCurrentState(); 0456 return true; 0457 } 0458 bool XParser::setFunctionF1Color(uint id, const QColor &color) 0459 { 0460 if (!m_ufkt.contains(id)) 0461 return false; 0462 m_ufkt[id]->plotAppearance(Function::Derivative1).color = color; 0463 MainDlg::self()->requestSaveCurrentState(); 0464 return true; 0465 } 0466 bool XParser::setFunctionF2Color(uint id, const QColor &color) 0467 { 0468 if (!m_ufkt.contains(id)) 0469 return false; 0470 m_ufkt[id]->plotAppearance(Function::Derivative2).color = color; 0471 MainDlg::self()->requestSaveCurrentState(); 0472 return true; 0473 } 0474 bool XParser::setFunctionIntColor(uint id, const QColor &color) 0475 { 0476 if (!m_ufkt.contains(id)) 0477 return false; 0478 m_ufkt[id]->plotAppearance(Function::Integral).color = color; 0479 MainDlg::self()->requestSaveCurrentState(); 0480 return true; 0481 } 0482 0483 double XParser::functionFLineWidth(uint id) 0484 { 0485 if (!m_ufkt.contains(id)) 0486 return 0; 0487 return m_ufkt[id]->plotAppearance(Function::Derivative0).lineWidth; 0488 } 0489 double XParser::functionF1LineWidth(uint id) 0490 { 0491 if (!m_ufkt.contains(id)) 0492 return 0; 0493 return m_ufkt[id]->plotAppearance(Function::Derivative1).lineWidth; 0494 } 0495 double XParser::functionF2LineWidth(uint id) 0496 { 0497 if (!m_ufkt.contains(id)) 0498 return 0; 0499 return m_ufkt[id]->plotAppearance(Function::Derivative2).lineWidth; 0500 } 0501 double XParser::functionIntLineWidth(uint id) 0502 { 0503 if (!m_ufkt.contains(id)) 0504 return 0; 0505 return m_ufkt[id]->plotAppearance(Function::Integral).lineWidth; 0506 } 0507 bool XParser::setFunctionFLineWidth(uint id, double linewidth) 0508 { 0509 if (!m_ufkt.contains(id)) 0510 return false; 0511 m_ufkt[id]->plotAppearance(Function::Derivative0).lineWidth = linewidth; 0512 MainDlg::self()->requestSaveCurrentState(); 0513 return true; 0514 } 0515 bool XParser::setFunctionF1LineWidth(uint id, double linewidth) 0516 { 0517 if (!m_ufkt.contains(id)) 0518 return false; 0519 m_ufkt[id]->plotAppearance(Function::Derivative1).lineWidth = linewidth; 0520 MainDlg::self()->requestSaveCurrentState(); 0521 return true; 0522 } 0523 bool XParser::setFunctionF2LineWidth(uint id, double linewidth) 0524 { 0525 if (!m_ufkt.contains(id)) 0526 return false; 0527 m_ufkt[id]->plotAppearance(Function::Derivative2).lineWidth = linewidth; 0528 MainDlg::self()->requestSaveCurrentState(); 0529 return true; 0530 } 0531 bool XParser::setFunctionIntLineWidth(uint id, double linewidth) 0532 { 0533 if (!m_ufkt.contains(id)) 0534 return false; 0535 m_ufkt[id]->plotAppearance(Function::Integral).lineWidth = linewidth; 0536 MainDlg::self()->requestSaveCurrentState(); 0537 return true; 0538 } 0539 0540 QString XParser::functionMinValue(uint id) 0541 { 0542 if (!m_ufkt.contains(id)) 0543 return 0; 0544 return m_ufkt[id]->dmin.expression(); 0545 } 0546 0547 bool XParser::setFunctionMinValue(uint id, const QString &min) 0548 { 0549 if (!m_ufkt.contains(id)) 0550 return false; 0551 m_ufkt[id]->dmin.expression() = min; 0552 MainDlg::self()->requestSaveCurrentState(); 0553 return true; 0554 } 0555 0556 QString XParser::functionMaxValue(uint id) 0557 { 0558 if (!m_ufkt.contains(id)) 0559 return 0; 0560 return m_ufkt[id]->dmax.expression(); 0561 } 0562 0563 bool XParser::setFunctionMaxValue(uint id, const QString &max) 0564 { 0565 if (!m_ufkt.contains(id)) 0566 return false; 0567 m_ufkt[id]->dmax.expression() = max; 0568 MainDlg::self()->requestSaveCurrentState(); 0569 return true; 0570 } 0571 0572 bool XParser::setFunctionStartValue(uint id, const QString &x, const QString &y) 0573 { 0574 if (!m_ufkt.contains(id)) 0575 return false; 0576 DifferentialState *state = &m_ufkt[id]->eq[0]->differentialStates[0]; 0577 state->x0.updateExpression(x); 0578 state->y0[0].updateExpression(y); 0579 MainDlg::self()->requestSaveCurrentState(); 0580 return true; 0581 } 0582 0583 QString XParser::functionStartXValue(uint id) 0584 { 0585 if (!m_ufkt.contains(id)) 0586 return 0; 0587 DifferentialState *state = &m_ufkt[id]->eq[0]->differentialStates[0]; 0588 return state->x0.expression(); 0589 } 0590 0591 QString XParser::functionStartYValue(uint id) 0592 { 0593 if (!m_ufkt.contains(id)) 0594 return 0; 0595 DifferentialState *state = &m_ufkt[id]->eq[0]->differentialStates[0]; 0596 return state->y0[0].expression(); 0597 } 0598 0599 QStringList XParser::functionParameterList(uint id) 0600 { 0601 if (!m_ufkt.contains(id)) 0602 return QStringList(); 0603 Function *item = m_ufkt[id]; 0604 QStringList str_parameter; 0605 for (const Value &it : qAsConst(item->m_parameters.list)) 0606 str_parameter << it.expression(); 0607 return str_parameter; 0608 } 0609 bool XParser::functionAddParameter(uint id, const QString &new_parameter) 0610 { 0611 if (!m_ufkt.contains(id)) 0612 return false; 0613 Function *tmp_ufkt = m_ufkt[id]; 0614 0615 // check if the parameter already exists 0616 for (const Value &it : qAsConst(tmp_ufkt->m_parameters.list)) { 0617 if (it.expression() == new_parameter) 0618 return false; 0619 } 0620 0621 Value value; 0622 if (!value.updateExpression(new_parameter)) 0623 return false; 0624 tmp_ufkt->m_parameters.list.append(value); 0625 MainDlg::self()->requestSaveCurrentState(); 0626 return true; 0627 } 0628 bool XParser::functionRemoveParameter(uint id, const QString &remove_parameter) 0629 { 0630 if (!m_ufkt.contains(id)) 0631 return false; 0632 Function *tmp_ufkt = m_ufkt[id]; 0633 0634 bool found = false; 0635 QList<Value>::iterator it; 0636 for (it = tmp_ufkt->m_parameters.list.begin(); it != tmp_ufkt->m_parameters.list.end(); ++it) { 0637 if ((*it).expression() == remove_parameter) // check if the parameter already exists 0638 { 0639 found = true; 0640 break; 0641 } 0642 } 0643 if (!found) 0644 return false; 0645 tmp_ufkt->m_parameters.list.erase(it); 0646 MainDlg::self()->requestSaveCurrentState(); 0647 return true; 0648 } 0649 int XParser::addFunction(const QString &f_str0, const QString &_f_str1) 0650 { 0651 QString added_function(f_str0); 0652 QString f_str1(_f_str1); 0653 int const pos = added_function.indexOf(';'); 0654 if (pos != -1) 0655 added_function = added_function.left(pos); 0656 0657 fixFunctionName(added_function); 0658 if (!f_str1.isEmpty()) 0659 fixFunctionName(f_str1); 0660 0661 Function::Type type; 0662 0663 if (!f_str1.isEmpty()) 0664 type = Function::Parametric; 0665 else if (f_str0.count('=') > 1) 0666 type = Function::Implicit; 0667 else 0668 type = (added_function[0] == 'r') ? Function::Polar : Function::Cartesian; 0669 0670 int const id = Parser::addFunction(added_function, f_str1, type); 0671 if (id == -1) 0672 return -1; 0673 Function *tmp_ufkt = m_ufkt[id]; 0674 if (pos != -1 && !getext(tmp_ufkt, f_str0)) { 0675 Parser::removeFunction(tmp_ufkt); 0676 return -1; 0677 } 0678 MainDlg::self()->requestSaveCurrentState(); 0679 return id; 0680 } 0681 0682 bool XParser::addFunction(const QString &fstr_const0, 0683 const QString &fstr_const1, 0684 bool f_mode, 0685 bool f1_mode, 0686 bool f2_mode, 0687 bool integral_mode, 0688 double linewidth, 0689 double f1_linewidth, 0690 double f2_linewidth, 0691 double integral_linewidth, 0692 const QString &str_dmin, 0693 const QString &str_dmax, 0694 const QString &str_startx, 0695 const QString &str_starty, 0696 double integral_precision, 0697 const QColor &color, 0698 const QColor &f1_color, 0699 const QColor &f2_color, 0700 const QColor &integral_color, 0701 const QStringList &str_parameter, 0702 int use_slider) 0703 { 0704 QString fstr[2] = {fstr_const0, fstr_const1}; 0705 Function::Type type = Function::Cartesian; 0706 for (unsigned i = 0; i < 2; ++i) { 0707 if (fstr[i].isEmpty()) 0708 continue; 0709 0710 switch (fstr[i][0].unicode()) { 0711 case 'r': { 0712 fixFunctionName(fstr[i], Equation::Polar); 0713 type = Function::Polar; 0714 break; 0715 } 0716 case 'x': 0717 fixFunctionName(fstr[i], Equation::ParametricX); 0718 type = Function::Parametric; 0719 break; 0720 case 'y': 0721 fixFunctionName(fstr[i], Equation::ParametricY); 0722 type = Function::Parametric; 0723 break; 0724 default: 0725 fixFunctionName(fstr[i], Equation::Cartesian); 0726 type = Function::Cartesian; 0727 break; 0728 } 0729 } 0730 0731 int const id = Parser::addFunction(fstr[0], fstr[1], type); 0732 if (id == -1) 0733 return false; 0734 Function *added_function = m_ufkt[id]; 0735 0736 PlotAppearance appearance; 0737 0738 // f0 0739 appearance.visible = f_mode; 0740 appearance.color = color; 0741 appearance.lineWidth = linewidth; 0742 added_function->plotAppearance(Function::Derivative0) = appearance; 0743 0744 // f1 0745 appearance.visible = f1_mode; 0746 appearance.color = f1_color; 0747 appearance.lineWidth = f1_linewidth; 0748 added_function->plotAppearance(Function::Derivative1) = appearance; 0749 0750 // f2 0751 appearance.visible = f2_mode; 0752 appearance.color = f2_color; 0753 appearance.lineWidth = f2_linewidth; 0754 added_function->plotAppearance(Function::Derivative2) = appearance; 0755 0756 // integral 0757 appearance.visible = integral_mode; 0758 appearance.color = integral_color; 0759 appearance.lineWidth = integral_linewidth; 0760 added_function->plotAppearance(Function::Integral) = appearance; 0761 0762 added_function->dmin.updateExpression(str_dmin); 0763 added_function->usecustomxmin = !str_dmin.isEmpty(); 0764 0765 added_function->dmax.updateExpression(str_dmax); 0766 added_function->usecustomxmax = !str_dmax.isEmpty(); 0767 0768 DifferentialState *state = &added_function->eq[0]->differentialStates[0]; 0769 state->x0.updateExpression(str_startx); 0770 state->y0[0].updateExpression(str_starty); 0771 0772 added_function->eq[0]->differentialStates.setStep(Value(integral_precision)); 0773 0774 added_function->m_parameters.sliderID = use_slider; 0775 for (QStringList::ConstIterator it = str_parameter.begin(); it != str_parameter.end(); ++it) { 0776 added_function->m_parameters.list.append(*it); 0777 } 0778 MainDlg::self()->requestSaveCurrentState(); 0779 return true; 0780 } 0781 0782 bool XParser::setFunctionExpression(uint id, uint eq, const QString &f_str) 0783 { 0784 Function *tmp_ufkt = functionWithID(id); 0785 if (!tmp_ufkt) 0786 return false; 0787 QString const old_fstr = tmp_ufkt->eq[eq]->fstr(); 0788 QString const fstr_begin = tmp_ufkt->eq[eq]->fstr().left(tmp_ufkt->eq[eq]->fstr().indexOf('=') + 1); 0789 0790 return tmp_ufkt->eq[eq]->setFstr(fstr_begin + f_str); 0791 }