File indexing completed on 2024-04-14 03:40:43

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 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 #ifndef FUNCTION_H
0015 #define FUNCTION_H
0016 
0017 #include "vector.h"
0018 
0019 #include <QByteArray>
0020 #include <QColor>
0021 #include <QFlags>
0022 #include <QGradient>
0023 #include <QVector>
0024 
0025 class Equation;
0026 class Function;
0027 class Plot;
0028 
0029 /**
0030  * Maximum number of plus-minus-s; each added one doubles the number of combinations
0031  * which quickly grows. So put a bound on the number allowed.
0032  */
0033 extern int MAX_PM;
0034 
0035 /**
0036  * This stores a string which evaluates directly to a number (i.e. without any
0037  * input variables such as x).
0038  */
0039 class Value
0040 {
0041 public:
0042     /**
0043      * Initializes Value with \p expression.
0044      * This will have the value 0 if \p expression is empty or unparsable.
0045      */
0046     Value(const QString &expression = QString());
0047     /**
0048      * Converts \p value to a string (see Parser::number) and initializes
0049      * this with the \p value.
0050      */
0051     explicit Value(double value);
0052 
0053     /**
0054      * @return The value of the current expression.
0055      */
0056     double value() const
0057     {
0058         return m_value;
0059     }
0060     /**
0061      * @return The current expression.
0062      */
0063     QString expression() const
0064     {
0065         return m_expression;
0066     }
0067     /**
0068      * Sets the current expression. If the expression could be evaluated
0069      * (i.e. no errors), then value is updated, the expression is saved and
0070      * true is returned. Otherwise, just returns false.
0071      */
0072     bool updateExpression(const QString &expression);
0073     /**
0074      * Converts \p value to a string (see Parser::number) and uses it for
0075      * the current expression.
0076      */
0077     void updateExpression(double value);
0078     /**
0079      * This checks if the expression strings (and hence values) are
0080      * identical.
0081      */
0082     bool operator==(const Value &other) const;
0083     /**
0084      * Checks for inequality.
0085      */
0086     bool operator!=(const Value &other) const
0087     {
0088         return !((*this) == other);
0089     }
0090 
0091 protected:
0092     QString m_expression;
0093     double m_value;
0094 };
0095 
0096 /**
0097  * Stores details of the appearance of a plot of a function (e.g. its
0098  * derivative or integral).
0099  */
0100 class PlotAppearance
0101 {
0102 public:
0103     PlotAppearance();
0104 
0105     // NOTE: When adding more members to this class, remember to update
0106     // the function PlotAppearance::operator!= and the functions in
0107     // KmPlotIO for saving / loading the plot appearance
0108 
0109     double lineWidth; ///< line width in mm
0110     QColor color; ///< color that the plot will be drawn in
0111     Qt::PenStyle style; ///< pen style (e.g. dolif, dashes, dotted, etc)
0112     QGradient gradient; ///< the gradient if useGradient is true
0113     bool useGradient : 1; ///< for plots with parameters, whether to use gradient instead of color
0114     bool showExtrema : 1; ///< for cartesian functions, whether to show the extreme values of the function
0115     bool showTangentField : 1; ///< whether to draw the tangent field (for differential equations
0116     bool visible : 1; ///< whether to display this plot
0117     bool showPlotName : 1; ///< whether to show the name of the plot on the graph
0118 
0119     bool operator!=(const PlotAppearance &other) const;
0120 
0121     /**
0122      * Converts a pen style to a string (for non-displaying uses such as
0123      * saving to file).
0124      */
0125     static QString penStyleToString(Qt::PenStyle style);
0126     /**
0127      * Converts a string (as returned by penStyleTostring) to a pen style.
0128      */
0129     static Qt::PenStyle stringToPenStyle(const QString &style);
0130 };
0131 
0132 /**
0133  * Used in differential equations; contains the initial conditions and the
0134  * currently calculated value (used as a cache).
0135  */
0136 class DifferentialState
0137 {
0138 public:
0139     DifferentialState();
0140     explicit DifferentialState(int order);
0141 
0142     /**
0143      * Resizes y, y0. Also calls resetToInitial.
0144      */
0145     void setOrder(int order);
0146     /**
0147      * Sets y=y0, x=x0.
0148      */
0149     void resetToInitial();
0150 
0151     Value x0; ///< the initial x-value
0152     QVector<Value> y0; ///< the value of ( f, f', f'', ...., f^(n) ) at x0
0153     double x; ///< the current x value
0154     Vector y; ///< the value of ( f, f', f'', ...., f^(n) ) at x
0155 
0156     /**
0157      * Whether the initial conditions and current state are the same.
0158      */
0159     bool operator==(const DifferentialState &other) const;
0160 };
0161 
0162 class DifferentialStates
0163 {
0164 public:
0165     DifferentialStates();
0166 
0167     /**
0168      * For Cartesian equations, can only have one state (for integrals).
0169      */
0170     void setUniqueState(bool unique);
0171     /**
0172      * \see order()
0173      */
0174     void setOrder(int order);
0175     /**
0176      * Creates a differential state. If this is for a Cartesian equation
0177      * and there is already a differential state, then that will be
0178      * returned instead, since a Cartesian equation can only have one
0179      * differential state.
0180      */
0181     DifferentialState *add();
0182     /**
0183      * The order of the differential equations, e.g. "f''(x) = -f" is of
0184      * order 2.
0185      */
0186     int order() const
0187     {
0188         return m_order;
0189     }
0190     /**
0191      * The number of differential states.
0192      */
0193     int size() const
0194     {
0195         return m_data.size();
0196     }
0197     /**
0198      * Calls DifferentialState::resetToInitial for each state; i.e. resets
0199      * the cached information about the state of the differential equation.
0200      */
0201     void resetToInitial();
0202     /**
0203      * The maximum step-size (and hence minimum precision) used in the RK4
0204      * method (see XParser::differential). Of course, a smaller step size
0205      * may be used in the visible section of a differential plot.
0206      */
0207     Value step() const
0208     {
0209         return m_step;
0210     }
0211     /**
0212      * \see maximumStep();
0213      * \return whether could successfully set the step, i.e. that it is
0214      * strictly positive.
0215      */
0216     bool setStep(const Value &step);
0217 
0218     bool operator==(const DifferentialStates &other) const
0219     {
0220         return (m_data == other.m_data) && (m_step == other.m_step);
0221     }
0222     bool operator!=(const DifferentialStates &other) const
0223     {
0224         return !(*this == other);
0225     }
0226     DifferentialState &operator[](int i)
0227     {
0228         return m_data[i];
0229     }
0230     const DifferentialState &operator[](int i) const
0231     {
0232         return m_data[i];
0233     }
0234     void remove(int i)
0235     {
0236         m_data.remove(i);
0237     }
0238     void remove(int i, int count)
0239     {
0240         m_data.remove(i, count);
0241     }
0242     void removeAll()
0243     {
0244         m_data.clear();
0245     }
0246 
0247 protected:
0248     QVector<DifferentialState> m_data;
0249     int m_order;
0250     bool m_uniqueState;
0251     Value m_step;
0252 };
0253 
0254 /**
0255  * This is the non-visual mathematical expression.
0256  * \note when adding new member variables, make sure to update operator !=
0257  * and operator =.
0258  */
0259 class Equation
0260 {
0261 public:
0262     enum Type {
0263         Constant,
0264         Cartesian,
0265         ParametricX,
0266         ParametricY,
0267         Polar,
0268         Implicit,
0269         Differential,
0270     };
0271 
0272     Equation(Type type, Function *parent);
0273     ~Equation();
0274 
0275     /// The type of function
0276     Type type() const
0277     {
0278         return m_type;
0279     }
0280     /**
0281      * \return whether this Equation has different user-entered values to
0282      * the \p other equation.
0283      */
0284     bool operator!=(const Equation &other);
0285     /**
0286      * Assigns the value in \p other to this equation.
0287      */
0288     Equation &operator=(const Equation &other);
0289     /**
0290      * Pointer to the allocated memory for the tokens.
0291      */
0292     QByteArray mem;
0293     /**
0294      * Array index to the token.
0295      */
0296     char *mptr;
0297     /**
0298      * @return a pointer to Function parent of this Equation.
0299      */
0300     Function *parent() const
0301     {
0302         return m_parent;
0303     }
0304     /**
0305      * @return the name of the function, e.g. for the cartesian function
0306      * f(x)=x^2, this would return "f".
0307      */
0308     QString name(bool removePrimes = true) const;
0309     /**
0310      * \return a list of variables, e.g. {x} for "f(x)=y", and {x,y,k} for
0311      * "f(x,y,k)=(x+k)(y+k)".
0312      */
0313     QStringList variables() const
0314     {
0315         return m_variables;
0316     }
0317     /**
0318      * \return whether the function accepts a parameter in addition to the x
0319      * (and possibly y) variables.
0320      */
0321     bool usesParameter() const
0322     {
0323         return m_usesParameter;
0324     }
0325     /**
0326      * \return the name of the parameter variable (or a blank string if a
0327      * parameter is not used).
0328      */
0329     QString parameterName() const;
0330     /**
0331      * The full function expression, e.g. "f(x,k)=(x+k)(x-k)".
0332      */
0333     QString fstr() const
0334     {
0335         return m_fstr;
0336     }
0337     /**
0338      * @see fstr()
0339      * @param string the equation
0340      * @param error if non-null, then will be set to the parser error (or
0341      * success).
0342      * @param errorPosition the error position
0343      * @param force Update the internal equation string even if it could not
0344      * be parsed correctly. Used in opening old files, for example, in case
0345      * something internal to kmplot has changed that results in the equation
0346      * no longer being parsable.
0347      * @return whether \p fstr could be parsed correctly. Note that if it
0348      * was not parsed correctly, then this will return false and this class
0349      * will not be updated.
0350      */
0351     bool setFstr(const QString &string, int *error = nullptr, int *errorPosition = nullptr, bool force = false);
0352     /**
0353      * \return true if the fstr looks like "f(x) = ..."
0354      * \return false if the fstr looks like "y = ..." (note that this
0355      * depends on the type of equation, so if this is a Cartesian equation
0356      * and the fstr looks like "a = ..." (not y) then it'll be considered a
0357      * function, even if it isn't a very useful one.
0358      */
0359     bool looksLikeFunction() const;
0360     /**
0361      * \return the order of the differential equations.
0362      */
0363     int order() const;
0364     /**
0365      * \return the number of plus-minus symbols in the equation.
0366      */
0367     int pmCount() const;
0368 
0369     /// For differential equations, all the states
0370     DifferentialStates differentialStates;
0371 
0372     /**
0373      * The current plus-minus signature (true for plus, false for minus).
0374      */
0375     QVector<bool> pmSignature() const
0376     {
0377         return m_pmSignature;
0378     }
0379     /**
0380      * \see pmSignature.
0381      */
0382     void setPMSignature(QVector<bool> pmSignature);
0383 
0384 protected:
0385     /**
0386      * Updates m_variables.
0387      */
0388     void updateVariables();
0389 
0390     bool m_usesParameter;
0391     const Type m_type;
0392     QString m_fstr;
0393     Function *m_parent;
0394     QVector<bool> m_pmSignature;
0395     /**
0396      * Cached list of variables. Updated when setFstr is called.
0397      */
0398     QStringList m_variables;
0399 };
0400 
0401 /**
0402  * Which parameters to use and how.
0403  */
0404 class ParameterSettings
0405 {
0406 public:
0407     ParameterSettings();
0408 
0409     bool operator==(const ParameterSettings &other) const;
0410     bool operator!=(const ParameterSettings &other) const
0411     {
0412         return !((*this) == other);
0413     }
0414 
0415     bool animating; ///< if true, then useSlider and useList are ignored, parameter value is assumed to be updated
0416     bool useSlider;
0417     int sliderID;
0418     bool useList;
0419     QList<Value> list;
0420 };
0421 
0422 /**
0423  * Uniquely identifies a parameter (which could be from the list of Values
0424  * stored in a Function or from a Slider.
0425  */
0426 class Parameter
0427 {
0428 public:
0429     enum Type {
0430         Unknown,
0431         Animated,
0432         Slider,
0433         List,
0434     };
0435     explicit Parameter(Type type = Unknown);
0436 
0437     Type type() const
0438     {
0439         return m_type;
0440     }
0441     /**
0442      * The slider ID specifies which slider to use (e.g. "2" specifies the
0443      * third slider).
0444      */
0445     void setSliderID(int id)
0446     {
0447         m_sliderID = id;
0448     }
0449     /**
0450      * The list pos specifies which parameter to use in the list
0451      * ParameterSettings::list.
0452      */
0453     void setListPos(int pos)
0454     {
0455         m_listPos = pos;
0456     }
0457     /**
0458      * \see setSliderID
0459      */
0460     int sliderID() const
0461     {
0462         return m_sliderID;
0463     }
0464     /**
0465      * \see setListPos
0466      */
0467     int listPos() const
0468     {
0469         return m_listPos;
0470     }
0471     /**
0472      * \return Whether the parameter referred to is the same.
0473      */
0474     bool operator==(const Parameter &other) const;
0475 
0476 protected:
0477     Type m_type;
0478     int m_sliderID;
0479     int m_listPos;
0480 };
0481 
0482 /** Here are all attributes for a function. */
0483 class Function
0484 {
0485 public:
0486     enum PMode {
0487         Derivative0,
0488         Derivative1,
0489         Derivative2,
0490         Derivative3,
0491         Integral,
0492     };
0493 
0494     enum Type {
0495         Cartesian,
0496         Parametric,
0497         Polar,
0498         Implicit,
0499         Differential,
0500     };
0501 
0502     explicit Function(Type type);
0503     ~Function();
0504 
0505     /**
0506      * \return the type of function.
0507      */
0508     Type type() const
0509     {
0510         return m_type;
0511     }
0512 
0513     enum PlotCombination {
0514         DifferentParameters = 0x1, ///< For all the different parameters
0515         DifferentDerivatives = 0x2, ///< Derivatives of the function
0516         DifferentPMSignatures = 0x4, ///< Plus-minus combinations
0517         DifferentInitialStates = 0x8, ///< For differential equations; different states
0518         AllCombinations = 0x20 - 1
0519     };
0520     typedef QFlags<PlotCombination> PlotCombinations;
0521 
0522     /**
0523      * \return a list of plots for this function,
0524      */
0525     QList<Plot> plots(PlotCombinations combinations = AllCombinations) const;
0526     /**
0527      * \return A string for displaying to the user that identifies this
0528      * function. For identifying plots uniquely, see Plot::name()
0529      */
0530     QString name() const;
0531     /**
0532      * Converts the type to a string (which is used in save files).
0533      */
0534     static QString typeToString(Type type);
0535     /**
0536      * Converts the string to a type (used when loading files).
0537      */
0538     static Type stringToType(const QString &type);
0539     /**
0540      * Sets the current working parameter (which is used in calculations).
0541      */
0542     void setParameter(double p)
0543     {
0544         k = p;
0545     }
0546     /**
0547      * The function parameter, as set by e.g. a slider.
0548      */
0549     double k;
0550     /**
0551      * Clears the list of functions that this function depends on.
0552      */
0553     void clearFunctionDependencies()
0554     {
0555         m_dependencies.clear();
0556     }
0557     /**
0558      * Adds \p function to the list of functions that this function depends
0559      * on. For example, if this function is "f(x) = 1 + g(x)", then this
0560      * function depends on the function g(x).
0561      */
0562     void addFunctionDependency(Function *function);
0563     /**
0564      * \return whether this function or any of the functions that this
0565      * function depend on, etc, depend on \p function.
0566      */
0567     bool dependsOn(Function *function) const;
0568     /**
0569      * Copies data members across, while avoiding id, mem, mptr type
0570      * variables.
0571      * @return whether any values have changed.
0572      */
0573     bool copyFrom(const Function &function);
0574     /**
0575      * \return the function ID, used to identify it from the parser.
0576      */
0577     uint id() const
0578     {
0579         return m_id;
0580     }
0581     /**
0582      * \see id()
0583      */
0584     void setId(uint id)
0585     {
0586         m_id = id;
0587     }
0588     QVector<Equation *> eq;
0589     /**
0590      * \return A reference to the appearance of the given plot type.
0591      */
0592     PlotAppearance &plotAppearance(PMode plot);
0593     /**
0594      * \return The appearance of the given plot type.
0595      */
0596     PlotAppearance plotAppearance(PMode plot) const;
0597     /**
0598      * \returns true if all plots are hidden (i.e. plotAppearance().visible
0599      * is false for all plot types).
0600      * \returns false otherwise.
0601      */
0602     bool allPlotsAreHidden() const;
0603     /**
0604      * Custom plot range, lower boundary.
0605      */
0606     Value dmin;
0607     /**
0608      * Custom plot range, upper boundary.
0609      */
0610     Value dmax;
0611 
0612     ParameterSettings m_parameters;
0613 
0614     bool usecustomxmin : 1;
0615     bool usecustomxmax : 1;
0616     // TODO double slider_min, slider_max; ///< extreme values of the slider
0617 
0618     /**
0619      * For use with implicit functions, when either x or y is held fixed.
0620      */
0621     enum ImplicitMode {
0622         FixedX,
0623         FixedY,
0624         UnfixedXY,
0625 
0626     };
0627     ImplicitMode m_implicitMode;
0628     /**
0629      * The value of x when this is an implicit function and x is fixed.
0630      */
0631     double x;
0632     /**
0633      * The value of y when this is an implicit function and y is fixed.
0634      */
0635     double y;
0636 
0637     /**
0638      * A list with all functions that this function depends on.
0639      */
0640     QList<int> m_dependencies;
0641 
0642 protected:
0643     uint m_id;
0644     const Type m_type;
0645 
0646     PlotAppearance f0; ///< The actual function - the "zero'th derivative"
0647     PlotAppearance f1; ///< First derivative
0648     PlotAppearance f2; ///< Second derivative
0649     PlotAppearance f3; ///< Third derivative
0650     PlotAppearance integral; ///< integral
0651 };
0652 
0653 /**
0654  * Uniquely identifies a single plot (i.e. a single curvy line in the View).
0655  */
0656 class Plot
0657 {
0658 public:
0659     Plot();
0660 
0661     bool operator==(const Plot &other) const;
0662 
0663     void setFunctionID(int id);
0664     /**
0665      * Changes the plotMode equivalent to differentiating.
0666      */
0667     void differentiate();
0668     /**
0669      * Changes the plotMode equivalent to integrating.
0670      */
0671     void integrate();
0672     int functionID() const
0673     {
0674         return m_functionID;
0675     }
0676     /**
0677      * \return a pointer to the function with ID as set by setFunctionID
0678      */
0679     Function *function() const
0680     {
0681         return m_function;
0682     }
0683     /**
0684      * \return the value of the parameter associated with this plot.
0685      */
0686     double parameterValue() const;
0687     /**
0688      * Generates a name appropriate for distinguishing the plot from others.
0689      */
0690     QString name() const;
0691     /**
0692      * The color that the plot should be drawn with.
0693      */
0694     QColor color() const;
0695     /**
0696      * Parameter in use.
0697      */
0698     Parameter parameter;
0699     /**
0700      * Which derivative.
0701      */
0702     Function::PMode plotMode;
0703     /**
0704      * Converts the plotMode to the derivative number, e.g.
0705      * Function::Derivative1 -> 1, and Function::Integral -> -1
0706      */
0707     int derivativeNumber() const;
0708     /**
0709      * Assigned when Function::allPlots() is called. The plots for each
0710      * plotMode are numbered 0 to *.
0711      */
0712     int plotNumber;
0713     /**
0714      * The total number of plots of the same plotMode as this.
0715      */
0716     int plotNumberCount;
0717     /**
0718      * Updates the current working parameter value in the function that
0719      * this plot is for and the plus-minus signature for the function's
0720      * equations.
0721      */
0722     void updateFunction() const;
0723     /**
0724      * For differential equations, which state to draw. It's probably
0725      * easier to use the function differentialState(), however.
0726      */
0727     int stateNumber;
0728     /**
0729      * \return the differential state for the plot (or 0 if no state).
0730      */
0731     DifferentialState *state() const;
0732     /**
0733      * For equations containing a plus-minus symbols, this indicates
0734      * whether to take the plus or the minus for each one. The list is for
0735      * each equation of the function (so typically, the list will only be
0736      * of size one, but parametric functions will have two).
0737      */
0738     QList<QVector<bool>> pmSignature;
0739 
0740 protected:
0741     void updateCached();
0742 
0743     int m_functionID; ///< ID of function
0744     Function *m_function; ///< Cached pointer to function
0745 };
0746 
0747 #endif // FUNCTION_H