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 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 #ifndef FUNCTION_H
15 #define FUNCTION_H
16 
17 #include "vector.h"
18 
19 #include <QByteArray>
20 #include <QColor>
21 #include <QFlags>
22 #include <QGradient>
23 #include <QVector>
24 
25 class Equation;
26 class Function;
27 class Plot;
28 
29 
30 /**
31  * Maximum number of plus-minus-s; each added one doubles the number of combinations
32  * which quickly grows. So put a bound on the number allowed.
33  */
34 extern int MAX_PM;
35 
36 
37 /**
38  * This stores a string which evaluates directly to a number (i.e. without any
39  * input variables such as x).
40  */
41 class Value
42 {
43 	public:
44 		/**
45 		 * Initializes Value with \p expression.
46 		 * This will have the value 0 if \p expression is empty or unparsable.
47 		 */
48 		Value( const QString & expression = QString() );
49 		/**
50 		 * Converts \p value to a string (see Parser::number) and initializes
51 		 * this with the \p value.
52 		 */
53 		explicit Value( double value );
54 
55 		/**
56 		 * @return The value of the current expression.
57 		 */
value()58 		double value() const { return m_value; }
59 		/**
60 		 * @return The current expression.
61 		 */
expression()62 		QString expression() const { return m_expression; }
63 		/**
64 		 * Sets the current expression. If the expression could be evaluated
65 		 * (i.e. no errors), then value is updated, the expression is saved and
66 		 * true is returned. Otherwise, just returns false.
67 		 */
68 		bool updateExpression( const QString & expression );
69 		/**
70 		 * Converts \p value to a string (see Parser::number) and uses it for
71 		 * the current expression.
72 		 */
73 		void updateExpression( double value );
74 		/**
75 		 * This checks if the expression strings (and hence values) are
76 		 * identical.
77 		 */
78 		bool operator == ( const Value & other ) const;
79 		/**
80 		 * Checks for inequality.
81 		 */
82 		bool operator != ( const Value & other ) const { return !((*this) == other); }
83 
84 	protected:
85 		QString m_expression;
86 		double m_value;
87 };
88 
89 
90 /**
91  * Stores details of the appearance of a plot of a function (e.g. its
92  * derivative or integral).
93  */
94 class PlotAppearance
95 {
96 	public:
97 		PlotAppearance();
98 
99 		// NOTE: When adding more members to this class, remember to update
100 		// the function PlotAppearance::operator!= and the functions in
101 		// KmPlotIO for saving / loading the plot appearance
102 
103 		double lineWidth;		///< line width in mm
104 		QColor color;			///< color that the plot will be drawn in
105 		Qt::PenStyle style;		///< pen style (e.g. dolif, dashes, dotted, etc)
106 		QGradient gradient;		///< the gradient if useGradient is true
107 		bool useGradient:1;		///< for plots with parameters, whether to use gradient instead of color
108 		bool showExtrema:1;		///< for cartesian functions, whether to show the extreme values of the function
109 		bool showTangentField:1;///< whether to draw the tangent field (for differential equations
110 		bool visible:1;			///< whether to display this plot
111 		bool showPlotName:1;	///< whether to show the name of the plot on the graph
112 
113 		bool operator != ( const PlotAppearance & other ) const;
114 
115 		/**
116 		 * Converts a pen style to a string (for non-displaying uses such as
117 		 * saving to file).
118 		 */
119 		static QString penStyleToString( Qt::PenStyle style );
120 		/**
121 		 * Converts a string (as returned by penStyleTostring) to a pen style.
122 		 */
123 		static Qt::PenStyle stringToPenStyle( const QString & style );
124 };
125 
126 
127 /**
128  * Used in differential equations; contains the initial conditions and the
129  * currently calculated value (used as a cache).
130  */
131 class DifferentialState
132 {
133 	public:
134 		DifferentialState();
135 		explicit DifferentialState( int order );
136 
137 		/**
138 		 * Resizes y, y0. Also calls resetToInitial.
139 		 */
140 		void setOrder( int order );
141 		/**
142 		 * Sets y=y0, x=x0.
143 		 */
144 		void resetToInitial();
145 
146 		Value x0; ///< the initial x-value
147 		QVector<Value> y0; ///< the value of ( f, f', f'', ...., f^(n) ) at x0
148 		double x; ///< the current x value
149 		Vector y; ///< the value of ( f, f', f'', ...., f^(n) ) at x
150 
151 		/**
152 		 * Whether the initial conditions and current state are the same.
153 		 */
154 		bool operator == ( const DifferentialState & other ) const;
155 };
156 
157 
158 class DifferentialStates
159 {
160 	public:
161 		DifferentialStates();
162 
163 		/**
164 		 * For Cartesian equations, can only have one state (for integrals).
165 		 */
166 		void setUniqueState( bool unique );
167 		/**
168 		 * \see order()
169 		 */
170 		void setOrder( int order );
171 		/**
172 		 * Creates a differential state. If this is for a Cartesian equation
173 		 * and there is already a differential state, then that will be
174 		 * returned instead, since a Cartesian equation can only have one
175 		 * differential state.
176 		 */
177 		DifferentialState * add();
178 		/**
179 		 * The order of the differential equations, e.g. "f''(x) = -f" is of
180 		 * order 2.
181 		 */
order()182 		int order() const { return m_order; }
183 		/**
184 		 * The number of differential states.
185 		 */
size()186 		int size() const { return m_data.size(); }
187 		/**
188 		 * Calls DifferentialState::resetToInitial for each state; i.e. resets
189 		 * the cached information about the state of the differential equation.
190 		 */
191 		void resetToInitial();
192 		/**
193 		 * The maximum step-size (and hence minimum precision) used in the RK4
194 		 * method (see XParser::differential). Of course, a smaller step size
195 		 * may be used in the visible section of a differential plot.
196 		 */
step()197 		Value step() const { return m_step; }
198 		/**
199 		 * \see maximumStep();
200 		 * \return whether could successfully set the step, i.e. that it is
201 		 * strictly positive.
202 		 */
203 		bool setStep( const Value & step );
204 
205 		bool operator == ( const DifferentialStates & other ) const { return (m_data == other.m_data) && (m_step == other.m_step); }
206 		bool operator != ( const DifferentialStates & other ) const { return !(*this == other); }
207 		DifferentialState & operator[] ( int i ) { return m_data[i]; }
208 		const DifferentialState & operator[] ( int i ) const { return m_data[i]; }
remove(int i)209 		void remove ( int i ) { m_data.remove(i); }
remove(int i,int count)210 		void remove ( int i, int count ) { m_data.remove( i, count ); }
removeAll()211 		void removeAll() { m_data.clear(); }
212 
213 	protected:
214 		QVector<DifferentialState> m_data;
215 		int m_order;
216 		bool m_uniqueState;
217 		Value m_step;
218 };
219 
220 
221 /**
222  * This is the non-visual mathematical expression.
223  * \note when adding new member variables, make sure to update operator !=
224  * and operator =.
225  */
226 class Equation
227 {
228 	public:
229 		enum Type
230 		{
231             Constant,
232 			Cartesian,
233 			ParametricX,
234 			ParametricY,
235 			Polar,
236 			Implicit,
237 			Differential
238 		};
239 
240 		Equation( Type type, Function * parent );
241 		~Equation();
242 
243 		/// The type of function
type()244 		Type type() const { return m_type; }
245 		/**
246 		 * \return whether this Equation has different user-entered values to
247 		 * the \p other equation.
248 		 */
249 		bool operator != ( const Equation & other );
250 		/**
251 		 * Assigns the value in \p other to this equation.
252 		 */
253 		Equation & operator = ( const Equation & other );
254 		/**
255 		 * Pointer to the allocated memory for the tokens.
256 		 */
257 		QByteArray mem;
258 		/**
259 		 * Array index to the token.
260 		 */
261 		char *mptr;
262 		/**
263 		 * @return a pointer to Function parent of this Equation.
264 		 */
parent()265 		Function * parent() const { return m_parent; }
266 		/**
267 		 * @return the name of the function, e.g. for the cartesian function
268 		 * f(x)=x^2, this would return "f".
269 		 */
270 		QString name( bool removePrimes = true ) const;
271 		/**
272 		 * \return a list of variables, e.g. {x} for "f(x)=y", and {x,y,k} for
273 		 * "f(x,y,k)=(x+k)(y+k)".
274 		 */
variables()275 		QStringList variables() const { return m_variables; }
276 		/**
277 		 * \return whether the function accepts a parameter in addition to the x
278 		 * (and possibly y) variables.
279 		 */
usesParameter()280 		bool usesParameter() const { return m_usesParameter; }
281 		/**
282 		 * \return the name of the parameter variable (or a blank string if a
283 		 * parameter is not used).
284 		 */
285 		QString parameterName() const;
286 		/**
287 		 * The full function expression, e.g. "f(x,k)=(x+k)(x-k)".
288 		 */
fstr()289 		QString fstr() const { return m_fstr; }
290 		/**
291 		 * @see fstr()
292 		 * @param string the equation
293 		 * @param error if non-null, then will be set to the parser error (or
294 		 * success).
295 		 * @param errorPosition the error position
296 		 * @param force Update the internal equation string even if it could not
297 		 * be parsed correctly. Used in opening old files, for example, in case
298 		 * something internal to kmplot has changed that results in the equation
299 		 * no longer being parsable.
300 		 * @return whether \p fstr could be parsed correctly. Note that if it
301 		 * was not parsed correctly, then this will return false and this class
302 		 * will not be updated.
303 		 */
304 		bool setFstr( const QString & string, int * error = 0, int * errorPosition = 0, bool force = false );
305 		/**
306 		 * \return true if the fstr looks like "f(x) = ..."
307 		 * \return false if the fstr looks like "y = ..." (note that this
308 		 * depends on the type of equation, so if this is a Cartesian equation
309 		 * and the fstr looks like "a = ..." (not y) then it'll be considered a
310 		 * function, even if it isn't a very useful one.
311 		 */
312 		bool looksLikeFunction() const;
313 		/**
314 		 * \return the order of the differential equations.
315 		 */
316 		int order() const;
317 		/**
318 		 * \return the number of plus-minus symbols in the equation.
319 		 */
320 		int pmCount() const;
321 
322 		/// For differential equations, all the states
323 		DifferentialStates differentialStates;
324 
325 		/**
326 		 * The current plus-minus signature (true for plus, false for minus).
327 		 */
pmSignature()328 		QVector<bool> pmSignature() const { return m_pmSignature; }
329 		/**
330 		 * \see pmSignature.
331 		 */
332 		void setPMSignature( QVector<bool> pmSignature );
333 
334 	protected:
335 		/**
336 		 * Updates m_variables.
337 		 */
338 		void updateVariables();
339 
340 		bool m_usesParameter;
341 		const Type m_type;
342 		QString m_fstr;
343 		Function * m_parent;
344 		QVector<bool> m_pmSignature;
345 		/**
346 		 * Cached list of variables. Updated when setFstr is called.
347 		 */
348 		QStringList m_variables;
349 };
350 
351 
352 /**
353  * Which parameters to use and how.
354  */
355  class ParameterSettings
356 {
357 	public:
358 		ParameterSettings();
359 
360 		bool operator == ( const ParameterSettings & other ) const;
361 		bool operator != ( const ParameterSettings & other ) const { return !((*this) == other); }
362 
363 		bool animating; ///< if true, then useSlider and useList are ignored, parameter value is assumed to be updated
364 		bool useSlider;
365 		int sliderID;
366 		bool useList;
367 		QList< Value > list;
368 };
369 
370 
371 /**
372  * Uniquely identifies a parameter (which could be from the list of Values
373  * stored in a Function or from a Slider.
374  */
375  class Parameter
376 {
377 	public:
378 		enum Type { Unknown, Animated, Slider, List };
379 		explicit Parameter( Type type = Unknown );
380 
type()381 		Type type() const { return m_type; }
382 		/**
383 		 * The slider ID specifies which slider to use (e.g. "2" specifies the
384 		 * third slider).
385 		 */
setSliderID(int id)386 		void setSliderID( int id ) { m_sliderID = id; }
387 		/**
388 		 * The list pos specifies which parameter to use in the list
389 		 * ParameterSettings::list.
390 		 */
setListPos(int pos)391 		void setListPos( int pos ) { m_listPos = pos; }
392 		/**
393 		 * \see setSliderID
394 		 */
sliderID()395 		int sliderID() const { return m_sliderID; }
396 		/**
397 		 * \see setListPos
398 		 */
listPos()399 		int listPos() const { return m_listPos; }
400 		/**
401 		 * \return Whether the parameter referred to is the same.
402 		 */
403 		bool operator == ( const Parameter & other ) const;
404 
405 	protected:
406 		Type m_type;
407 		int m_sliderID;
408 		int m_listPos;
409 };
410 
411 
412 /** Here are all attributes for a function. */
413 class Function
414 {
415 	public:
416 		enum PMode
417 		{
418 			Derivative0,
419 			Derivative1,
420 			Derivative2,
421 			Derivative3,
422 			Integral
423 		};
424 
425 		enum Type
426 		{
427 			Cartesian,
428 			Parametric,
429 			Polar,
430 			Implicit,
431 			Differential
432 		};
433 
434 		explicit Function( Type type );
435 		~Function();
436 
437 		/**
438 		 * \return the type of function.
439 		 */
type()440 		Type type() const { return m_type; }
441 
442 		enum PlotCombination
443 		{
444 			DifferentParameters		= 0x1,		///< For all the different parameters
445 			DifferentDerivatives	= 0x2,		///< Derivatives of the function
446 			DifferentPMSignatures	= 0x4,		///< Plus-minus combinations
447 			DifferentInitialStates	= 0x8,		///< For differential equations; different states
448 			AllCombinations			= 0x20-1
449 		};
450 		typedef QFlags<PlotCombination> PlotCombinations;
451 
452 		/**
453 		 * \return a list of plots for this function,
454 		 */
455 		QList< Plot > plots( PlotCombinations combinations = AllCombinations ) const;
456 		/**
457 		 * \return A string for displaying to the user that identifies this
458 		 * function. For identifying plots uniquely, see Plot::name()
459 		 */
460 		QString name() const;
461 		/**
462 		 * Converts the type to a string (which is used in save files).
463 		 */
464 		static QString typeToString( Type type );
465 		/**
466 		 * Converts the string to a type (used when loading files).
467 		 */
468 		static Type stringToType( const QString & type );
469 		/**
470 		 * Sets the current working parameter (which is used in calculations).
471 		 */
setParameter(double p)472 		void setParameter( double p ) { k = p; }
473 		/**
474 		 * The function parameter, as set by e.g. a slider.
475 		 */
476 		double k;
477 		/**
478 		 * Clears the list of functions that this function depends on.
479 		 */
clearFunctionDependencies()480 		void clearFunctionDependencies() { m_dependencies.clear(); }
481 		/**
482 		 * Adds \p function to the list of functions that this function depends
483 		 * on. For example, if this function is "f(x) = 1 + g(x)", then this
484 		 * function depends on the function g(x).
485 		 */
486 		void addFunctionDependency( Function * function );
487 		/**
488 		 * \return whether this function or any of the functions that this
489 		 * function depend on, etc, depend on \p function.
490 		 */
491 		bool dependsOn( Function * function ) const;
492 		/**
493 		 * Copies data members across, while avoiding id, mem, mptr type
494 		 * variables.
495 		 * @return whether any values have changed.
496 		 */
497 		bool copyFrom( const Function & function );
498 		/**
499 		 * \return the function ID, used to identify it from the parser.
500 		 */
id()501 		uint id() const { return m_id; }
502 		/**
503 		 * \see id()
504 		 */
setId(uint id)505 		void setId( uint id ) { m_id = id; }
506 		QVector<Equation*> eq;
507 		/**
508 		 * \return A reference to the appearance of the given plot type.
509 		 */
510 		PlotAppearance & plotAppearance( PMode plot );
511 		/**
512 		 * \return The appearance of the given plot type.
513 		 */
514 		PlotAppearance plotAppearance( PMode plot ) const;
515 		/**
516 		 * \returns true if all plots are hidden (i.e. plotAppearance().visible
517 		 * is false for all plot types).
518 		 * \returns false otherwise.
519 		 */
520 		bool allPlotsAreHidden() const;
521 		/**
522 		 * Custom plot range, lower boundary.
523 		 */
524 		Value dmin;
525 		/**
526 		 * Custom plot range, upper boundary.
527 		 */
528 		Value dmax;
529 
530 		ParameterSettings m_parameters;
531 
532 		bool usecustomxmin:1;
533 		bool usecustomxmax:1;
534 		// TODO double slider_min, slider_max; ///< extreme values of the slider
535 
536 		/**
537 		 * For use with implicit functions, when either x or y is held fixed.
538 		 */
539 		enum ImplicitMode
540 		{
541 			FixedX,
542 			FixedY,
543 			UnfixedXY
544 		};
545 		ImplicitMode m_implicitMode;
546 		/**
547 		 * The value of x when this is an implicit function and x is fixed.
548 		 */
549 		double x;
550 		/**
551 		 * The value of y when this is an implicit function and y is fixed.
552 		 */
553 		double y;
554 
555 		/**
556 		 * A list with all functions that this function depends on.
557 		 */
558 		QList<int> m_dependencies;
559 
560 	protected:
561 		uint m_id;
562 		const Type m_type;
563 
564 		PlotAppearance f0;		///< The actual function - the "zero'th derivative"
565 		PlotAppearance f1;		///< First derivative
566 		PlotAppearance f2;		///< Second derivative
567 		PlotAppearance f3;		///< Third derivative
568 		PlotAppearance integral;	///< integral
569 };
570 
571 
572 
573 
574 /**
575  * Uniquely identifies a single plot (i.e. a single curvy line in the View).
576  */
577 class Plot
578 {
579 	public:
580 		Plot();
581 
582 		bool operator == ( const Plot & other ) const;
583 
584 		void setFunctionID( int id );
585 		/**
586 		 * Changes the plotMode equivalent to differentiating.
587 		 */
588 		void differentiate();
589 		/**
590 		 * Changes the plotMode equivalent to integrating.
591 		 */
592 		void integrate();
functionID()593 		int functionID() const { return m_functionID; }
594 		/**
595 		 * \return a pointer to the function with ID as set by setFunctionID
596 		 */
function()597 		Function * function() const { return m_function; }
598 		/**
599 		 * \return the value of the parameter associated with this plot.
600 		 */
601 		double parameterValue() const;
602 		/**
603 		 * Generates a name appropriate for distinguishing the plot from others.
604 		 */
605 		QString name() const;
606 		/**
607 		 * The color that the plot should be drawn with.
608 		 */
609 		QColor color() const;
610 		/**
611 		 * Parameter in use.
612 		 */
613 		Parameter parameter;
614 		/**
615 		 * Which derivative.
616 		 */
617 		Function::PMode plotMode;
618 		/**
619 		 * Converts the plotMode to the derivative number, e.g.
620 		 * Function::Derivative1 -> 1, and Function::Integral -> -1
621 		 */
622 		int derivativeNumber() const;
623 		/**
624 		 * Assigned when Function::allPlots() is called. The plots for each
625 		 * plotMode are numbered 0 to *.
626 		 */
627 		int plotNumber;
628 		/**
629 		 * The total number of plots of the same plotMode as this.
630 		 */
631 		int plotNumberCount;
632 		/**
633 		 * Updates the current working parameter value in the function that
634 		 * this plot is for and the plus-minus signature for the function's
635 		 * equations.
636 		 */
637 		void updateFunction() const;
638 		/**
639 		 * For differential equations, which state to draw. It's probably
640 		 * easier to use the function differentialState(), however.
641 		 */
642 		int stateNumber;
643 		/**
644 		 * \return the differential state for the plot (or 0 if no state).
645 		 */
646 		DifferentialState * state() const;
647 		/**
648 		 * For equations containing a plus-minus symbols, this indicates
649 		 * whether to take the plus or the minus for each one. The list is for
650 		 * each equation of the function (so typically, the list will only be
651 		 * of size one, but parametric functions will have two).
652 		 */
653 		QList< QVector<bool> > pmSignature;
654 
655 	protected:
656 		void updateCached();
657 
658 		int m_functionID;			///< ID of function
659 		Function * m_function;		///< Cached pointer to function
660 };
661 
662 
663 #endif	// FUNCTION_H
664