1 /*
2 KmPlot - a math. function plotter for the KDE-Desktop
3
4 SPDX-FileCopyrightText: 1998, 1999, 2000, 2002 Klaus-Dieter Möller <kd.moeller@t-online.de>
5 SPDX-FileCopyrightText: 2006, 2007 David Saxton <david@bluehaze.org>
6
7 This file is part of the KDE Project.
8 KmPlot is part of the KDE-EDU Project.
9
10 SPDX-License-Identifier: GPL-2.0-or-later
11
12 */
13
14 #include "xparser.h"
15
16 #include <kmplot/config-kmplot.h>
17
18 // local includes
19 #include "parseradaptor.h"
20 #include "maindlg.h"
21
22 // KDE includes
23 #include <KLocalizedString>
24 #include <KMessageBox>
25
26 #include <QList>
27
28 #include <assert.h>
29 #include <cmath>
30 #ifdef HAVE_IEEEFP_H
31 #include <ieeefp.h>
32 #endif
33
34
35 XParser * XParser::m_self = 0;
36
self()37 XParser * XParser::self()
38 {
39 if ( !m_self )
40 m_self = new XParser();
41
42 return m_self;
43 }
44
45
XParser()46 XParser::XParser()
47 {
48 differentialFinite = true;
49 differentialDiverge = 0;
50
51 new ParserAdaptor(this);
52 QDBusConnection::sessionBus().registerObject(QStringLiteral("/parser"), this);
53 }
54
~XParser()55 XParser::~XParser()
56 {
57 }
58
getext(Function * item,const QString & fstr)59 bool XParser::getext( Function *item, const QString &fstr )
60 {
61 bool errflg = false;
62 int p1, p2, p3, pe;
63 QString tstr;
64 pe = fstr.length();
65 if ( fstr.indexOf( 'N' ) != -1 )
66 item->plotAppearance( Function::Derivative0 ).visible = false;
67 else
68 {
69 if ( fstr.indexOf( QLatin1String("A1") ) != -1 )
70 item->plotAppearance( Function::Derivative1 ).visible = true;
71 if ( fstr.indexOf( QLatin1String("A2") ) != -1 )
72 item->plotAppearance( Function::Derivative2 ).visible = true;
73 }
74 switch ( fstr[0].unicode() )
75 {
76 case 'x':
77 case 'y':
78 case 'r':
79 item->plotAppearance( Function::Derivative1 ).visible = item->plotAppearance( Function::Derivative2 ).visible = false;
80 }
81
82 p1 = fstr.indexOf( QLatin1String("D[") );
83 if ( p1 != -1 )
84 {
85 p1 += 2;
86 const QString str = fstr.mid( p1, pe - p1);
87 p2 = str.indexOf(',');
88 p3 = str.indexOf(']');
89 if ( p2 > 0 && p2 < p3 )
90 {
91 tstr = str.left( p2 );
92 errflg |= !item->dmin.updateExpression( tstr );
93 tstr = str.mid( p2 + 1, p3 - p2 - 1 );
94 errflg |= !item->dmax.updateExpression( tstr );
95 if ( item->dmin.value() > item->dmax.value() )
96 errflg = true;
97 }
98 else
99 errflg = true;
100 }
101 p1 = fstr.indexOf( QLatin1String("P[") );
102 if ( p1 != -1 )
103 {
104 int i = 0;
105 p1 += 2;
106 QString str = fstr.mid( p1, 1000);
107 p3 = str.indexOf( ']' );
108 do
109 {
110 p2 = str.indexOf( ',' );
111 if ( p2 == -1 || p2 > p3 )
112 p2 = p3;
113 tstr = str.left( p2++ );
114 str = str.mid( p2, 1000 );
115 Value value;
116 if ( !value.updateExpression( tstr ) )
117 {
118 errflg = true;
119 break;
120 }
121 item->m_parameters.list.append( value );
122 p3 -= p2;
123 }
124 while ( p3 > 0 && i < 10 );
125 }
126
127 if ( errflg )
128 {
129 KMessageBox::error( 0, i18n( "Error in extension." ) );
130 return false;
131 }
132 else
133 return true;
134 }
135
136
derivative(int n,Equation * eq,DifferentialState * state,double x,double h)137 double XParser::derivative( int n, Equation * eq, DifferentialState * state, double x, double h )
138 {
139 if ( n < -1 )
140 {
141 qCritical() << "Can't handle derivative < -1\n";
142 return 0.0;
143 }
144
145 switch ( n )
146 {
147 case -1:
148 return differential( eq, & eq->differentialStates[0], x, h );
149
150 case 0:
151 if ( state )
152 return differential( eq, state, x, h );
153 else
154 return fkt( eq, x );
155
156 case 1:
157 if ( state )
158 return ( differential(eq, state, x + (h/2), h ) - differential( eq, state, x - (h/2), h ) ) / h;
159 else
160 return ( fkt(eq, x + (h/2) ) - fkt( eq, x - (h/2) ) ) / h;
161
162 default:
163 return ( derivative( n-1, eq, state, x+(h/2), (h/4) ) - derivative( n-1, eq, state, x-(h/2), (h/4) ) ) / h;
164 }
165 }
166
167
partialDerivative(int n1,int n2,Equation * eq,DifferentialState * state,double x,double y,double h1,double h2)168 double XParser::partialDerivative( int n1, int n2, Equation * eq, DifferentialState * state, double x, double y, double h1, double h2 )
169 {
170 if ( n1 < 0 || n2 < 0 )
171 {
172 qCritical() << "Can't handle derivative < 0\n";
173 return 0.0;
174 }
175
176 if ( n1 > 0 )
177 return ( partialDerivative( n1-1, n2, eq, state, x+(h1/2), y, (h1/4), h2 ) - partialDerivative( n1-1, n2, eq, state, x-(h1/2), y, (h1/4), h2 ) ) / h1;
178
179 Function * f = eq->parent();
180 f->m_implicitMode = Function::FixedX;
181 f->x = x;
182
183 return derivative( n2, eq, state, y, h2 );
184 }
185
186
findFunctionName(const QString & preferredName,int id,const QStringList & neededPatterns)187 QString XParser::findFunctionName( const QString & preferredName, int id, const QStringList& neededPatterns )
188 {
189 // The position of the character attempting to replace
190 int pos = preferredName.length()-1;
191
192 QString name = preferredName;
193
194 for ( ; ; ++pos)
195 {
196 for ( QChar lastChar = 'f'; lastChar<'x'; ++lastChar.unicode() )
197 {
198 bool ok = true;
199 name[pos] = lastChar;
200
201 for ( Function * it : qAsConst(m_ufkt) )
202 {
203 if ( int(it->id()) == id )
204 continue;
205
206 for ( Equation * eq : qAsConst(it->eq) )
207 {
208 for ( const QString& pattern : neededPatterns) {
209 if ( eq->name() == pattern.arg(name) )
210 ok = false;
211 }
212 }
213
214 if (!ok)
215 break;
216 }
217 if ( !ok )
218 continue;
219
220 // Found a free name :)
221 return name;
222 }
223 name[pos]='f';
224 name.append('f');
225 }
226 }
227
228
fixFunctionName(QString & str,Equation::Type const type,int const id)229 void XParser::fixFunctionName( QString &str, Equation::Type const type, int const id)
230 {
231 int p1 = str.indexOf('(');
232 int p2 = str.indexOf(')');
233 int p3 = str.indexOf('=');
234
235 if ( p1 < 0 )
236 return;
237
238 for ( int i = p2+1; i < p3; ++i )
239 {
240 if ( !str.at(i).isSpace() )
241 return;
242 }
243
244 QString const fname = str.left(p1);
245 for ( Function * it : qAsConst(m_ufkt) )
246 {
247 if ( int(it->id()) == id )
248 continue;
249
250 for ( Equation * eq : qAsConst(it->eq) )
251 {
252 if ( eq->name() != fname )
253 continue;
254
255 str = str.mid(p1,str.length()-1);
256 QString function_name;
257 if ( type == Equation::ParametricX )
258 function_name = 'x';
259 else if ( type == Equation::ParametricY )
260 function_name = 'y';
261 else
262 function_name = 'f';
263 function_name = findFunctionName( function_name, id );
264 str.prepend( function_name );
265 return;
266 }
267 }
268 }
269
270
rk4_f(int order,Equation * eq,double x,const Vector & y)271 Vector XParser::rk4_f( int order, Equation * eq, double x, const Vector & y )
272 {
273 bool useParameter = eq->usesParameter();
274
275 m_result.resize( order );
276 m_arg.resize( order+1 + (useParameter ? 1 : 0) );
277
278 m_arg[0] = x;
279
280 if ( useParameter )
281 m_arg[1] = eq->parent()->k;
282
283 memcpy( m_arg.data() + 1 + (useParameter ? 1 : 0), y.data(), order*sizeof(double) );
284 memcpy( m_result.data(), y.data() + 1, (order-1)*sizeof(double) );
285
286 m_result[order-1] = XParser::fkt( eq, m_arg );
287
288 return m_result;
289 }
290
291
differential(Equation * eq,DifferentialState * state,double x_target,double max_dx)292 double XParser::differential( Equation * eq, DifferentialState * state, double x_target, double max_dx )
293 {
294 differentialFinite = true;
295
296 if ( eq->order() < 1 )
297 {
298 qWarning() << "Zero order!\n";
299 return 0;
300 }
301
302 max_dx = qAbs(max_dx);
303 assert( max_dx > 0 ); // in case anyone tries to pass us a zero h
304
305 // the difference between h and dx is that h is only used as a hint for the
306 // stepwidth; dx is made similar to h in size, yet tiles the gap between x
307 // and the previous x perfectly
308
309 // see if the initial integral point in the function is closer to our
310 // required x value than the last one (or the last point is invalid)
311 if ( qAbs( state->x0.value() - x_target ) < qAbs( state->x - x_target ) )
312 state->resetToInitial();
313
314 int order = eq->order();
315
316 m_k1.resize( order );
317 m_k2.resize( order );
318 m_k3.resize( order );
319 m_k4.resize( order );
320 m_y_temp.resize( order );
321
322 double x = state->x;
323 m_y = state->y;
324 if ( x_target == x )
325 return m_y[0];
326
327 int intervals = int( qAbs(x_target-x)/max_dx + 1 );
328 double dx = (x_target-x) / double(intervals);
329
330 for ( int i = 0; i < intervals; ++i )
331 {
332 // Update differentialDiverge before y possible becomes infinite
333 differentialDiverge = x;
334
335 x = state->x + i*dx;
336
337
338 m_k1 = rk4_f( order, eq, x, m_y );
339
340 m_y_temp.combine( m_y, dx/2, m_k1 );
341 m_k2 = rk4_f( order, eq, x + dx/2, m_y_temp);
342
343 m_y_temp.combine( m_y, dx/2, m_k2 );
344 m_k3 = rk4_f( order, eq, x + dx/2, m_y_temp );
345
346 m_y_temp.combine( m_y, dx, m_k3 );
347 m_k4 = rk4_f( order, eq, x + dx, m_y_temp );
348
349 m_y.addRK4( dx, m_k1, m_k2, m_k3, m_k4 );
350
351 // The condition on the total accumulated error (O(dx^5)) should not be violated for rapidly increasing functions, e.g. e^x^2
352 if ( !std::isfinite(m_y[0]) || qAbs((state->y[0]-m_y[0])*dx*dx) > 1)
353 {
354 differentialFinite = false;
355 state->resetToInitial();
356 return 1e200*((m_y[0] > 0) - (m_y[0] < 0));
357 }
358 }
359
360 state->x = x + dx;
361 state->y = m_y;
362
363 return m_y[0];
364 }
365
366
defaultColor(int function)367 QColor XParser::defaultColor(int function)
368 {
369 switch ( function % 10 )
370 {
371 case 0:
372 return Settings::color0();
373 case 1:
374 return Settings::color1();
375 case 2:
376 return Settings::color2();
377 case 3:
378 return Settings::color3();
379 case 4:
380 return Settings::color4();
381 case 5:
382 return Settings::color5();
383 case 6:
384 return Settings::color6();
385 case 7:
386 return Settings::color7();
387 case 8:
388 return Settings::color8();
389 case 9:
390 return Settings::color9();
391 }
392
393 assert( !"Should not happen - XParser::defaultColor" );
394 return QColor();
395 }
396
listFunctionNames()397 QStringList XParser::listFunctionNames()
398 {
399 return userFunctions();
400 }
401
functionFVisible(uint id)402 bool XParser::functionFVisible(uint id)
403 {
404 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Derivative0 ).visible : false;
405 }
functionF1Visible(uint id)406 bool XParser::functionF1Visible(uint id)
407 {
408 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Derivative1 ).visible : false;
409 }
functionF2Visible(uint id)410 bool XParser::functionF2Visible(uint id)
411 {
412 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Derivative2 ).visible : false;
413 }
functionIntVisible(uint id)414 bool XParser::functionIntVisible(uint id)
415 {
416 return m_ufkt.contains(id) ? m_ufkt[id]->plotAppearance( Function::Integral ).visible : false;
417 }
418
setFunctionFVisible(uint id,bool visible)419 bool XParser::setFunctionFVisible(uint id, bool visible)
420 {
421 if ( !m_ufkt.contains( id ) )
422 return false;
423 m_ufkt[id]->plotAppearance( Function::Derivative0 ).visible = visible;
424 MainDlg::self()->requestSaveCurrentState();
425 return true;
426 }
setFunctionF1Visible(uint id,bool visible)427 bool XParser::setFunctionF1Visible(uint id, bool visible)
428 {
429 if ( !m_ufkt.contains( id ) )
430 return false;
431 m_ufkt[id]->plotAppearance( Function::Derivative1 ).visible = visible;
432 MainDlg::self()->requestSaveCurrentState();
433 return true;
434 }
setFunctionF2Visible(uint id,bool visible)435 bool XParser::setFunctionF2Visible(uint id, bool visible)
436 {
437 if ( !m_ufkt.contains( id ) )
438 return false;
439 m_ufkt[id]->plotAppearance( Function::Derivative2 ).visible = visible;
440 MainDlg::self()->requestSaveCurrentState();
441 return true;
442 }
setFunctionIntVisible(uint id,bool visible)443 bool XParser::setFunctionIntVisible(uint id, bool visible)
444 {
445 if ( !m_ufkt.contains( id ) )
446 return false;
447 m_ufkt[id]->plotAppearance( Function::Integral ).visible = visible;
448 MainDlg::self()->requestSaveCurrentState();
449 return true;
450 }
451
functionStr(uint id,uint eq)452 QString XParser::functionStr(uint id, uint eq)
453 {
454 if ( !m_ufkt.contains( id ) || (eq>=2) )
455 return QLatin1String("");
456 return m_ufkt[id]->eq[eq]->fstr();
457 }
458
functionFColor(uint id)459 QColor XParser::functionFColor(uint id)
460 {
461 if ( !m_ufkt.contains( id ) )
462 return QColor();
463 return QColor(m_ufkt[id]->plotAppearance( Function::Derivative0 ).color);
464 }
functionF1Color(uint id)465 QColor XParser::functionF1Color(uint id)
466 {
467 if ( !m_ufkt.contains( id ) )
468 return QColor();
469 return QColor(m_ufkt[id]->plotAppearance( Function::Derivative1 ).color);
470 }
functionF2Color(uint id)471 QColor XParser::functionF2Color(uint id)
472 {
473 if ( !m_ufkt.contains( id ) )
474 return QColor();
475 return QColor(m_ufkt[id]->plotAppearance( Function::Derivative2 ).color);
476 }
functionIntColor(uint id)477 QColor XParser::functionIntColor(uint id)
478 {
479 if ( !m_ufkt.contains( id ) )
480 return QColor();
481 return QColor(m_ufkt[id]->plotAppearance( Function::Integral ).color);
482 }
setFunctionFColor(uint id,const QColor & color)483 bool XParser::setFunctionFColor(uint id, const QColor &color)
484 {
485 if ( !m_ufkt.contains( id ) )
486 return false;
487 m_ufkt[id]->plotAppearance( Function::Derivative0 ).color = color;
488 MainDlg::self()->requestSaveCurrentState();
489 return true;
490 }
setFunctionF1Color(uint id,const QColor & color)491 bool XParser::setFunctionF1Color(uint id, const QColor &color)
492 {
493 if ( !m_ufkt.contains( id ) )
494 return false;
495 m_ufkt[id]->plotAppearance( Function::Derivative1 ).color = color;
496 MainDlg::self()->requestSaveCurrentState();
497 return true;
498 }
setFunctionF2Color(uint id,const QColor & color)499 bool XParser::setFunctionF2Color(uint id, const QColor &color)
500 {
501 if ( !m_ufkt.contains( id ) )
502 return false;
503 m_ufkt[id]->plotAppearance( Function::Derivative2 ).color = color;
504 MainDlg::self()->requestSaveCurrentState();
505 return true;
506 }
setFunctionIntColor(uint id,const QColor & color)507 bool XParser::setFunctionIntColor(uint id, const QColor &color)
508 {
509 if ( !m_ufkt.contains( id ) )
510 return false;
511 m_ufkt[id]->plotAppearance( Function::Integral ).color = color;
512 MainDlg::self()->requestSaveCurrentState();
513 return true;
514 }
515
functionFLineWidth(uint id)516 double XParser::functionFLineWidth(uint id)
517 {
518 if ( !m_ufkt.contains( id ) )
519 return 0;
520 return m_ufkt[id]->plotAppearance( Function::Derivative0 ).lineWidth;
521 }
functionF1LineWidth(uint id)522 double XParser::functionF1LineWidth(uint id)
523 {
524 if ( !m_ufkt.contains( id ) )
525 return 0;
526 return m_ufkt[id]->plotAppearance( Function::Derivative1 ).lineWidth;
527 }
functionF2LineWidth(uint id)528 double XParser::functionF2LineWidth(uint id)
529 {
530 if ( !m_ufkt.contains( id ) )
531 return 0;
532 return m_ufkt[id]->plotAppearance( Function::Derivative2 ).lineWidth;
533 }
functionIntLineWidth(uint id)534 double XParser::functionIntLineWidth(uint id)
535 {
536 if ( !m_ufkt.contains( id ) )
537 return 0;
538 return m_ufkt[id]->plotAppearance( Function::Integral ).lineWidth;
539 }
setFunctionFLineWidth(uint id,double linewidth)540 bool XParser::setFunctionFLineWidth(uint id, double linewidth)
541 {
542 if ( !m_ufkt.contains( id ) )
543 return false;
544 m_ufkt[id]->plotAppearance( Function::Derivative0 ).lineWidth = linewidth;
545 MainDlg::self()->requestSaveCurrentState();
546 return true;
547 }
setFunctionF1LineWidth(uint id,double linewidth)548 bool XParser::setFunctionF1LineWidth(uint id, double linewidth)
549 {
550 if ( !m_ufkt.contains( id ) )
551 return false;
552 m_ufkt[id]->plotAppearance( Function::Derivative1 ).lineWidth = linewidth;
553 MainDlg::self()->requestSaveCurrentState();
554 return true;
555 }
setFunctionF2LineWidth(uint id,double linewidth)556 bool XParser::setFunctionF2LineWidth(uint id, double linewidth)
557 {
558 if ( !m_ufkt.contains( id ) )
559 return false;
560 m_ufkt[id]->plotAppearance( Function::Derivative2 ).lineWidth = linewidth;
561 MainDlg::self()->requestSaveCurrentState();
562 return true;
563 }
setFunctionIntLineWidth(uint id,double linewidth)564 bool XParser::setFunctionIntLineWidth(uint id, double linewidth)
565 {
566 if ( !m_ufkt.contains( id ) )
567 return false;
568 m_ufkt[id]->plotAppearance( Function::Integral ).lineWidth = linewidth;
569 MainDlg::self()->requestSaveCurrentState();
570 return true;
571 }
572
functionMinValue(uint id)573 QString XParser::functionMinValue(uint id)
574 {
575 if ( !m_ufkt.contains( id ) )
576 return 0;
577 return m_ufkt[id]->dmin.expression();
578 }
579
setFunctionMinValue(uint id,const QString & min)580 bool XParser::setFunctionMinValue(uint id, const QString &min)
581 {
582 if ( !m_ufkt.contains( id ) )
583 return false;
584 m_ufkt[id]->dmin.expression() = min;
585 MainDlg::self()->requestSaveCurrentState();
586 return true;
587 }
588
functionMaxValue(uint id)589 QString XParser::functionMaxValue(uint id)
590 {
591 if ( !m_ufkt.contains( id ) )
592 return 0;
593 return m_ufkt[id]->dmax.expression();
594 }
595
setFunctionMaxValue(uint id,const QString & max)596 bool XParser::setFunctionMaxValue(uint id, const QString &max)
597 {
598 if ( !m_ufkt.contains( id ) )
599 return false;
600 m_ufkt[id]->dmax.expression() = max;
601 MainDlg::self()->requestSaveCurrentState();
602 return true;
603 }
604
setFunctionStartValue(uint id,const QString & x,const QString & y)605 bool XParser::setFunctionStartValue(uint id, const QString &x, const QString &y)
606 {
607 if ( !m_ufkt.contains( id ) )
608 return false;
609 DifferentialState * state = & m_ufkt[id]->eq[0]->differentialStates[0];
610 state->x0.updateExpression( x );
611 state->y0[0].updateExpression( y );
612 MainDlg::self()->requestSaveCurrentState();
613 return true;
614 }
615
functionStartXValue(uint id)616 QString XParser::functionStartXValue(uint id)
617 {
618 if ( !m_ufkt.contains( id ) )
619 return 0;
620 DifferentialState * state = & m_ufkt[id]->eq[0]->differentialStates[0];
621 return state->x0.expression();
622 }
623
624
functionStartYValue(uint id)625 QString XParser::functionStartYValue(uint id)
626 {
627 if ( !m_ufkt.contains( id ) )
628 return 0;
629 DifferentialState * state = & m_ufkt[id]->eq[0]->differentialStates[0];
630 return state->y0[0].expression();
631 }
632
functionParameterList(uint id)633 QStringList XParser::functionParameterList(uint id)
634 {
635 if ( !m_ufkt.contains( id ) )
636 return QStringList();
637 Function *item = m_ufkt[id];
638 QStringList str_parameter;
639 for ( const Value &it : qAsConst(item->m_parameters.list) )
640 str_parameter << it.expression();
641 return str_parameter;
642 }
functionAddParameter(uint id,const QString & new_parameter)643 bool XParser::functionAddParameter(uint id, const QString &new_parameter)
644 {
645 if ( !m_ufkt.contains( id ) )
646 return false;
647 Function *tmp_ufkt = m_ufkt[id];
648
649 //check if the parameter already exists
650 for ( const Value &it : qAsConst(tmp_ufkt->m_parameters.list) )
651 {
652 if ( it.expression() == new_parameter )
653 return false;
654 }
655
656 Value value;
657 if ( !value.updateExpression( new_parameter ) )
658 return false;
659 tmp_ufkt->m_parameters.list.append( value );
660 MainDlg::self()->requestSaveCurrentState();
661 return true;
662 }
functionRemoveParameter(uint id,const QString & remove_parameter)663 bool XParser::functionRemoveParameter(uint id, const QString &remove_parameter)
664 {
665 if ( !m_ufkt.contains( id ) )
666 return false;
667 Function *tmp_ufkt = m_ufkt[id];
668
669 bool found = false;
670 QList<Value>::iterator it;
671 for ( it = tmp_ufkt->m_parameters.list.begin(); it != tmp_ufkt->m_parameters.list.end(); ++it)
672 {
673 if ( (*it).expression() == remove_parameter) //check if the parameter already exists
674 {
675 found = true;
676 break;
677 }
678 }
679 if (!found)
680 return false;
681 tmp_ufkt->m_parameters.list.erase(it);
682 MainDlg::self()->requestSaveCurrentState();
683 return true;
684 }
addFunction(const QString & f_str0,const QString & _f_str1)685 int XParser::addFunction(const QString &f_str0, const QString &_f_str1)
686 {
687 QString added_function(f_str0);
688 QString f_str1(_f_str1);
689 int const pos = added_function.indexOf(';');
690 if (pos!=-1)
691 added_function = added_function.left(pos);
692
693 fixFunctionName(added_function);
694 if ( !f_str1.isEmpty() )
695 fixFunctionName( f_str1 );
696
697 Function::Type type;
698
699 if ( !f_str1.isEmpty() )
700 type = Function::Parametric;
701 else if ( f_str0.count( '=' ) > 1 )
702 type = Function::Implicit;
703 else
704 type = (added_function[0] == 'r') ? Function::Polar : Function::Cartesian;
705
706 int const id = Parser::addFunction( added_function, f_str1, type );
707 if (id==-1)
708 return -1;
709 Function *tmp_ufkt = m_ufkt[id];
710 if ( pos!=-1 && !getext( tmp_ufkt, f_str0 ) )
711 {
712 Parser::removeFunction( tmp_ufkt );
713 return -1;
714 }
715 MainDlg::self()->requestSaveCurrentState();
716 return id;
717 }
718
addFunction(const QString & fstr_const0,const QString & fstr_const1,bool f_mode,bool f1_mode,bool f2_mode,bool integral_mode,double linewidth,double f1_linewidth,double f2_linewidth,double integral_linewidth,const QString & str_dmin,const QString & str_dmax,const QString & str_startx,const QString & str_starty,double integral_precision,const QColor & color,const QColor & f1_color,const QColor & f2_color,const QColor & integral_color,const QStringList & str_parameter,int use_slider)719 bool XParser::addFunction(const QString &fstr_const0, const QString &fstr_const1, bool f_mode, bool f1_mode, bool f2_mode, bool integral_mode, double linewidth, double f1_linewidth, double f2_linewidth, double integral_linewidth, const QString &str_dmin, const QString &str_dmax, const QString &str_startx, const QString &str_starty, double integral_precision, const QColor &color, const QColor &f1_color, const QColor &f2_color, const QColor &integral_color, const QStringList & str_parameter, int use_slider)
720 {
721 QString fstr[2] = { fstr_const0, fstr_const1 };
722 Function::Type type = Function::Cartesian;
723 for ( unsigned i = 0; i < 2; ++i )
724 {
725 if ( fstr[i].isEmpty() )
726 continue;
727
728 switch ( fstr[i][0].unicode() )
729 {
730 case 'r':
731 {
732 fixFunctionName(fstr[i], Equation::Polar);
733 type = Function::Polar;
734 break;
735 }
736 case 'x':
737 fixFunctionName(fstr[i], Equation::ParametricX);
738 type = Function::Parametric;
739 break;
740 case 'y':
741 fixFunctionName(fstr[i], Equation::ParametricY);
742 type = Function::Parametric;
743 break;
744 default:
745 fixFunctionName(fstr[i], Equation::Cartesian );
746 type = Function::Cartesian;
747 break;
748 }
749 }
750
751 int const id = Parser::addFunction( fstr[0], fstr[1], type );
752 if ( id==-1 )
753 return false;
754 Function *added_function = m_ufkt[id];
755
756 PlotAppearance appearance;
757
758 // f0
759 appearance.visible = f_mode;
760 appearance.color = color;
761 appearance.lineWidth = linewidth;
762 added_function->plotAppearance( Function::Derivative0 ) = appearance;
763
764 // f1
765 appearance.visible = f1_mode;
766 appearance.color = f1_color;
767 appearance.lineWidth = f1_linewidth;
768 added_function->plotAppearance( Function::Derivative1 ) = appearance;
769
770 // f2
771 appearance.visible = f2_mode;
772 appearance.color = f2_color;
773 appearance.lineWidth = f2_linewidth;
774 added_function->plotAppearance( Function::Derivative2 ) = appearance;
775
776 // integral
777 appearance.visible = integral_mode;
778 appearance.color = integral_color;
779 appearance.lineWidth = integral_linewidth;
780 added_function->plotAppearance( Function::Integral ) = appearance;
781
782 added_function->dmin.updateExpression( str_dmin );
783 added_function->usecustomxmin = !str_dmin.isEmpty();
784
785 added_function->dmax.updateExpression( str_dmax );
786 added_function->usecustomxmax = !str_dmax.isEmpty();
787
788 DifferentialState * state = & added_function->eq[0]->differentialStates[0];
789 state->x0.updateExpression( str_startx );
790 state->y0[0].updateExpression( str_starty );
791
792 added_function->eq[0]->differentialStates.setStep( Value( integral_precision ) );
793
794 added_function->m_parameters.sliderID = use_slider;
795 for( QStringList::ConstIterator it = str_parameter.begin(); it != str_parameter.end(); ++it )
796 {
797 added_function->m_parameters.list.append( *it );
798 }
799 MainDlg::self()->requestSaveCurrentState();
800 return true;
801 }
802
setFunctionExpression(uint id,uint eq,const QString & f_str)803 bool XParser::setFunctionExpression(uint id, uint eq, const QString &f_str)
804 {
805 Function * tmp_ufkt = functionWithID( id );
806 if ( !tmp_ufkt )
807 return false;
808 QString const old_fstr = tmp_ufkt->eq[eq]->fstr();
809 QString const fstr_begin = tmp_ufkt->eq[eq]->fstr().left(tmp_ufkt->eq[eq]->fstr().indexOf('=')+1);
810
811 return tmp_ufkt->eq[eq]->setFstr( fstr_begin+f_str );
812 }
813
814