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