Logo Search packages:      
Sourcecode: kdeedu-kde4 version File versions  Download package

function.cpp

/*
* KmPlot - a math. function plotter for the KDE-Desktop
*
* Copyright (C) 1998, 1999, 2000, 2002  Klaus-Dieter M�ler <kd.moeller@t-online.de>
*               2006 David Saxton <david@bluehaze.org>
*               
* This file is part of the KDE Project.
* KmPlot is part of the KDE-EDU Project.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/

#include "function.h"
#include "ksliderwindow.h"
#include "settings.h"
#include "view.h"
#include "xparser.h"

#include <kdebug.h>
#include <QImage>
#include <QLinearGradient>
#include <QPainter>

#include <assert.h>
#include <cmath>

int MAX_PM = 4;


//BEGIN class Value
00044 Value::Value( const QString & expression )
{
      m_value = 0.0;
      if ( expression.isEmpty() )
            m_expression = "0";
      else
            updateExpression( expression );
}


00054 Value::Value( double value )
{
      updateExpression( value );
}


00060 bool Value::updateExpression( const QString & expression )
{
      Parser::Error error;
      double newValue = XParser::self()->eval( expression, & error );
      if ( error != Parser::ParseSuccess )
            return false;
      
      m_value = newValue;
      m_expression = expression;
      return true;
}


00073 void Value::updateExpression( double value )
{
      m_value = value;
      m_expression = Parser::number( value );
}


00080 bool Value::operator == ( const Value & other ) const
{
      return m_expression == other.expression();
}
//END class Value



//BEGIN class PlotAppearance
PlotAppearance::PlotAppearance( )
{
      lineWidth = 0.3;
      color = Qt::black;
      useGradient = false;
      visible = false;
      style = Qt::SolidLine;
      showExtrema = false;
      showTangentField = false;
      showPlotName = false;
}


bool PlotAppearance::operator !=( const PlotAppearance & other ) const
{
      return
                  (lineWidth != other.lineWidth) ||
                  (color != other.color) ||
                  (useGradient != other.useGradient) ||
                  (gradient.stops() != other.gradient.stops()) ||
                  (visible != other.visible) ||
                  (style != other.style) ||
                  (showExtrema != other.showExtrema) ||
                  (showTangentField != other.showTangentField) ||
                  (showPlotName != other.showPlotName);
}


00117 QString PlotAppearance::penStyleToString( Qt::PenStyle style )
{
      switch ( style )
      {
            case Qt::NoPen:
                  return "NoPen";
                  
            case Qt::SolidLine:
                  return "SolidLine";
                  
            case Qt::DashLine:
                  return "DashLine";
                  
            case Qt::DotLine:
                  return "DotLine";
                  
            case Qt::DashDotLine:
                  return "DashDotLine";
            
            case Qt::DashDotDotLine:
                  return "DashDotDotLine";
                  
            case Qt::MPenStyle:
            case Qt::CustomDashLine:
                  kWarning() << "Unsupported pen style\n";
                  break;
      }
      
      kWarning() << "Unknown style " << style ;
      return "SolidLine";
}


00150 Qt::PenStyle PlotAppearance::stringToPenStyle( const QString & style )
{
      if ( style == "NoPen" )
            return Qt::NoPen;
                  
      if ( style == "SolidLine" )
            return Qt::SolidLine;
                  
      if ( style == "DashLine" )
            return Qt::DashLine;
                  
      if ( style == "DotLine" )
            return Qt::DotLine;
                  
      if ( style == "DashDotLine" )
            return Qt::DashDotLine;
            
      if ( style == "DashDotDotLine" )
            return Qt::DashDotDotLine;
      
      kWarning() << "Unknown style " << style ;
      return Qt::SolidLine;
}
//END class PlotAppearance



//BEGIN class DifferentialState
DifferentialState::DifferentialState()
{
      x = 0;
}


DifferentialState::DifferentialState( int order )
{
      x = 0;
      setOrder( order );
}


00191 void DifferentialState::setOrder( int order )
{
      bool orderWasZero = (y0.size() == 0);
      
      y.resize( order );
      y0.resize( order );
      
      if ( orderWasZero && order >= 1 )
            y0[0].updateExpression( "1" );
      
      resetToInitial();
}


bool DifferentialStates::setStep( const Value & step )
{
      if ( step.value() <= 0 )
            return false;
      
      m_step = step;
      return true;
}


00215 void DifferentialState::resetToInitial()
{
      x = x0.value();
      y = y0;
}


00222 bool DifferentialState::operator == ( const DifferentialState & other ) const
{
      return (x0 == other.x0) && (x == other.x) && (y0 == other.y0) && (y == other.y);
}
//END class DifferentialState



//BEGIN class DifferentialStates
DifferentialStates::DifferentialStates()
{
      m_uniqueState = false;
      m_order = 0;
      m_step.updateExpression( 0.05 );
}


void DifferentialStates::setOrder( int order )
{
      m_order = order;
      for ( int i = 0; i < m_data.size(); ++i )
            m_data[i].setOrder( order );
}


DifferentialState * DifferentialStates::add()
{
      if ( !m_uniqueState || m_data.isEmpty() )
            m_data << DifferentialState( order() );
      else
            kDebug() << "Unable to add another state!\n";
      
      return & m_data[ size() - 1 ];
}


void DifferentialStates::setUniqueState( bool unique )
{
      m_uniqueState = unique;
      if ( m_uniqueState && m_data.size() > 1 )
      {
            // Remove any states other than the first
            m_data.resize( 1 );
      }
}


void DifferentialStates::resetToInitial( )
{
      for ( int i = 0; i < m_data.size(); ++i )
            m_data[i].resetToInitial();
}
//END class DifferentialStates



//BEGIN class Equation
Equation::Equation( Type type, Function * parent )
      : m_type( type ),
        m_parent( parent )
{
      m_usesParameter = false;
      mptr = 0;
      
      if ( type == Differential || type == Cartesian )
      {
            differentialStates.setUniqueState( type == Cartesian );
            differentialStates.setOrder( order() );
            differentialStates.add();
      }
}


Equation::~ Equation()
{
}


00300 int Equation::order( ) const
{
      if ( type() == Cartesian )
      {
            // For drawing integrals
            return 1;
      }
      else
            return name(false).count( '\'' );
}


00312 int Equation::pmCount() const
{
      return m_fstr.count( PmSymbol );
}


00318 QString Equation::name( bool removePrimes ) const
{
      if ( m_fstr.isEmpty() )
            return QString();
      
      int open = m_fstr.indexOf( '(' );
      int equals = m_fstr.indexOf( '=' );
      
      if ( (equals == -1) && (open == -1) )
            return QString();
      
      int pos;
      if ( ((equals > open) && (open != -1)) || (equals == -1) )
            pos = open;
      else
            pos = equals;
      
      QString n = m_fstr.left( pos ).trimmed();
      
      if ( removePrimes )
            n.remove( '\'' );
      
      return n;
}


00344 bool Equation::looksLikeFunction( ) const
{
      int open = m_fstr.indexOf( '(' );
      int equals = m_fstr.indexOf( '=' );
      
      if ( (open != -1) && (open < equals) )
            return true;
      
      switch ( type() )
      {
            case Cartesian:
            case Differential:
            case ParametricY:
                  return (name() != "y");
                  
            case Polar:
                  return (name() != "r");
            
            case ParametricX:
                  return (name() != "x");
            
            case Implicit:
                  return false;
            
        case Constant:
            return false;
      }
      
      return true;
}


00376 void Equation::updateVariables()
{
    if ( type() == Constant )
        return;
    
      m_variables.clear();
      
      if ( looksLikeFunction() )
      {
            int p1 = m_fstr.indexOf( '(' );
            int p2 = m_fstr.indexOf( ')' );
      
            QStringList splitted;
            if ( (p1 != -1) && (p2 != -1) )
                  splitted = m_fstr.mid( p1+1, p2-p1-1 ).split( ',', QString::SkipEmptyParts );
            
            // Variables shouldn't contain spaces!
            foreach ( QString s, splitted )
            {
                  s = s.remove(' ');
                  if ( !s.isEmpty() )
                        m_variables << s;
            }
      }
      else switch ( type() )
      {
            case Cartesian:
            case Differential:
                  m_variables << "x" << "k";
                  break;
                  
            case Polar:
                  m_variables << QChar( 0x3b8 ) << "k"; // (theta)
                  break;
            
            case ParametricX:
            case ParametricY:
                  m_variables << "t" << "k";
                  break;
            
            case Implicit:
                  m_variables << "x" << "y" << "k";
                  break;
            
        case Constant:
            break;
      }
      
      // If we are a differential equation, then add on y, y', etc
      if ( type() == Differential && !name().isEmpty() )
      {
            QString n = name();
            
            int order = this->order();
            for ( int i = 0; i < order; ++i )
            {
                  m_variables << n;
                  n += '\'';
            }
      }
      
      
      //BEGIN Update whether we accept a parameter or not
      int expectedNumVariables = 0;
      
      switch ( m_type )
      {
            case Cartesian:
            case ParametricX:
            case ParametricY:
            case Polar:
                  expectedNumVariables = 1;
                  break;
                  
            case Implicit:
                  expectedNumVariables = 2;
                  break;
                  
            case Differential:
                  expectedNumVariables = order()+1;
                  break;
            
            case Constant:
                  expectedNumVariables = 0;
                  break;
      }
      
      m_usesParameter = (variables().size() > expectedNumVariables);
      //END Update whether we accept a parameter or not
}


00468 QString Equation::parameterName( ) const
{
      if ( !usesParameter() )
            return QString();
      
      int parAt = (type() == Implicit) ? 2 : 1;
      return variables()[parAt];
}


00478 bool Equation::setFstr( const QString & fstr, int * error, int * errorPosition, bool force )
{
#define HANDLE_ERROR \
      if ( !force ) \
      { \
            m_fstr = prevFstr; \
            updateVariables(); \
      } \
      else \
      { \
            kDebug() << "fstr "<<fstr<<" invalid, but forcing anyway: " << Parser::errorString( Parser::Error(*error) ) << " at position " << *errorPosition; \
            mem.clear(); \
      }
      
      int temp1, temp2;
      if ( !error )
            error = & temp1;
      if ( !errorPosition )
            errorPosition = & temp2;
      
      *error = Parser::ParseSuccess;
      *errorPosition = -1;
      
      QString prevFstr = m_fstr;
      m_fstr = fstr;
      updateVariables();
      
      if ( !fstr.contains('=') || QString(fstr).right( fstr.length() - fstr.indexOf('=') - 1).simplified().isEmpty() )
      {
            *error = Parser::SyntaxError;
            HANDLE_ERROR;
            return false;
      }
      
      // require order to be greater than 0 for differential equations
      if ( (type() == Differential) && (order() < 1) )
      {
            *error = Parser::ZeroOrder;
            HANDLE_ERROR;
            /// \todo indicate the position of the error
            return false;
      }
      
      int maxArg = order() + (( type() == Implicit ) ? 3 : 2);
      if ( variables().size() > maxArg )
      {
            *error = Parser::TooManyArguments;
            HANDLE_ERROR;
            /// \todo indicate the position of the invalid argument?
            return false;
      }
      
      XParser::self()->initEquation( this, (Parser::Error*)error, errorPosition );
      if ( *error != Parser::ParseSuccess )
      {
            HANDLE_ERROR;
            if ( !force )
                  XParser::self()->initEquation( this );
            return false;
      }
      
      differentialStates.setOrder( order() );
      return true;
}


00544 void Equation::setPMSignature( QVector< bool > pmSignature )
{
      differentialStates.resetToInitial();
      m_pmSignature = pmSignature;
}


00551 bool Equation::operator !=( const Equation & other )
{
      return (fstr() != other.fstr()) ||
                  (differentialStates != other.differentialStates);
}


00558 Equation & Equation::operator =( const Equation & other )
{
      setFstr( other.fstr() );
      differentialStates = other.differentialStates;
      
      return * this;
}
//END class Equation



//BEGIN class Function
Function::Function( Type type )
      : m_type( type )
{
      x = y = 0;
      m_implicitMode = UnfixedXY;
      
      usecustomxmin = false;
      usecustomxmax = false;
      
      dmin.updateExpression( QChar('0') );
      if ( Settings::anglemode() == Parser::Radians )
            dmax.updateExpression( QString(QChar('2')) + PiSymbol );
      else
            dmax.updateExpression( "360" );
      
      switch ( m_type )
      {
            case Cartesian:
                  eq << new Equation( Equation::Cartesian, this );
                  break;
                  
            case Polar:
                  eq << new Equation( Equation::Polar, this );
                  usecustomxmin = true;
                  usecustomxmax = true;
                  break;
                  
            case Parametric:
                  eq << new Equation( Equation::ParametricX, this );
                  eq << new Equation( Equation::ParametricY, this );
                  usecustomxmin = true;
                  usecustomxmax = true;
                  break;
                  
            case Implicit:
                  eq << new Equation( Equation::Implicit, this );
                  break;
                  
            case Differential:
                  eq << new Equation( Equation::Differential, this );
                  break;
      }
      
      m_id = 0;
      f0.visible = true;
      
      k = 0;
}


Function::~Function()
{
      foreach ( Equation * e, eq )
            delete e;
}


00627 bool Function::copyFrom( const Function & function )
{
      bool changed = false;
      int i = 0;
#define COPY_AND_CHECK(s) \
      { \
            if ( s != function.s ) \
            { \
                  s = function.s; \
                  changed = true; \
            } \
      } \
      i++;
      
      COPY_AND_CHECK( f0 );                     // 0
      if ( type() == Cartesian )
      {
            COPY_AND_CHECK( f1 );                     // 1
            COPY_AND_CHECK( f2 );                     // 2
            COPY_AND_CHECK( integral );               // 3
      }
      COPY_AND_CHECK( dmin );                   // 4,1
      COPY_AND_CHECK( dmax );                   // 5,2
      COPY_AND_CHECK( usecustomxmin );    // 6,3
      COPY_AND_CHECK( usecustomxmax );    // 7,4
      COPY_AND_CHECK( m_parameters );           // 8,5
      
      // handle equations separately
      for ( int i = 0; i < eq.size(); ++i )
      {
            if ( *eq[i] != *function.eq[i] )
            {
                  changed = true;
                  *eq[i] = *function.eq[i];
            }
      }
      
      return changed;
}


00668 QString Function::name() const
{
      QString n = eq[0]->fstr();
      for ( int i = 1; i < eq.size(); ++i )
            n += '\n' + eq[i]->fstr();
      
      return n;
}


00678 PlotAppearance & Function::plotAppearance( PMode plot )
{
      // NOTE: This function is identical to the const one, so changes to this should be applied to both
      
      switch ( plot )
      {
            case Function::Derivative0:
                  return f0;
            case Function::Derivative1:
                  return f1;
                  
            case Function::Derivative2:
                  return f2;
                  
            case Function::Integral:
                  return integral;
      }
      
      kError() << "Unknown plot " << plot << endl;
      return f0;
}
00699 PlotAppearance Function::plotAppearance( PMode plot ) const
{
      // NOTE: This function is identical to the none-const one, so changes to this should be applied to both
      
      switch ( plot )
      {
            case Function::Derivative0:
                  return f0;
            case Function::Derivative1:
                  return f1;
            case Function::Derivative2:
                  return f2;
            case Function::Integral:
                  return integral;
      }
      
      kError() << "Unknown plot " << plot << endl;
      return f0;
}


00720 bool Function::allPlotsAreHidden( ) const
{
      return !f0.visible && !f1.visible && !f2.visible && !integral.visible;
}


00726 QString Function::typeToString( Type type )
{
      switch ( type )
      {
            case Cartesian:
                  return "cartesian";
                  
            case Parametric:
                  return "parametric";
                  
            case Polar:
                  return "polar";
                  
            case Implicit:
                  return "implicit";
                  
            case Differential:
                  return "differential";
      }
      
      kWarning() << "Unknown type " << type ;
      return "unknown";
}


00751 Function::Type Function::stringToType( const QString & type )
{
      if ( type == "cartesian" )
            return Cartesian;
      
      if ( type == "parametric" )
            return Parametric;
      
      if ( type == "polar" )
            return Polar;
      
      if ( type == "implicit" )
            return Implicit;
      
      if ( type == "differential" )
            return Differential;
      
      kWarning() << "Unknown type " << type ;
      return Cartesian;
}


00773 QList< Plot > Function::plots( PlotCombinations combinations ) const
{
      QList< Plot > list;
      
      if ( allPlotsAreHidden() )
            return list;
      
      Plot plot;
      plot.setFunctionID( id() );
      plot.plotNumberCount = m_parameters.useList ? m_parameters.list.size() + (m_parameters.useSlider?1:0) : 1;
      
      bool singlePlot = (!m_parameters.useList && !m_parameters.useSlider) ||
                  m_parameters.animating ||
                  (~combinations & DifferentParameters) ||
                  (!m_parameters.useSlider && m_parameters.useList && m_parameters.list.isEmpty());
      
      if ( singlePlot )
      {
            if ( m_parameters.animating )
                  plot.parameter = Parameter( Parameter::Animated );
            
            list << plot;
      }
      else
      {
            int i = 0;
            
            if ( m_parameters.useSlider )
            {
                  Parameter param( Parameter::Slider );
                  param.setSliderID( m_parameters.sliderID );
                  plot.parameter = param;
                  plot.plotNumber = i++;
                  list << plot;
            }
            
            if ( m_parameters.useList )
            {
                  int pos = 0;
                  foreach ( const Value &v, m_parameters.list )
                  {
                        Parameter param( Parameter::List );
                        param.setListPos( pos++ );
                        plot.parameter = param;
                        plot.plotNumber = i++;
                        list << plot;
                  }
            }
      }
      
      
      // Copy each plot in the list for other variations
      if ( (type() == Cartesian) && (combinations & DifferentDerivatives) )
      {
            QList< Plot > duplicated;
            
            for ( PMode p = Derivative0; p <= Integral; p = PMode(p+1) )
            {
                  foreach ( Plot plot, list )
                  {
                        if ( !plotAppearance(p).visible )
                              continue;
                        plot.plotMode = p;
                        duplicated << plot;
                  }
            }
            
            list = duplicated;
      }
      
      if ( (type() == Differential) && (combinations & DifferentInitialStates) )
      {
            QList< Plot > duplicated;
            
            for ( int i = 0; i < eq[0]->differentialStates.size(); ++i )
            {
                  foreach ( Plot plot, list )
                  {
                        plot.stateNumber = i;
                        duplicated << plot;
                  }
            }
            
            list = duplicated;
      }
      
      if ( combinations & DifferentPMSignatures )
      {
            int size = 0;
            foreach ( Equation * equation, eq )
                  size += equation->pmCount();
      
            unsigned max = unsigned( pow( 2, size ) );
            QVector< QVector<bool> > signatures( max );
      
            for ( unsigned i = 0; i < max; ++i )
            {
                  QVector<bool> sig( size );
                  
                  for ( int j = 0; j < size; ++j )
                        sig[ j ] = i & (1<<j);
                  
                  signatures[i] = sig;
            }
      
            // Generate a plot for each signature in signatures
            QList< Plot > duplicated;
            foreach ( const QVector<bool> &signature, signatures )
            {
                  int at = 0;
                  QList< QVector<bool> > pmSignature;
            
                  foreach ( Equation * equation, eq )
                  {
                        int pmCount = equation->pmCount();
                        QVector<bool> sig( pmCount );
                        for ( int i = 0; i < pmCount; ++i )
                              sig[i] = signature[ i + at];
                        at += pmCount;
                  
                        pmSignature << sig;
                  }
            
                  foreach ( Plot plot, list )
                  {
                        plot.pmSignature = pmSignature;
                        duplicated << plot;
                  }
            }
            list = duplicated;
      }
      
      return list;
}


00909 void Function::addFunctionDependency( Function * function )
{
      if ( !function || m_dependencies.contains( function->id() ) )
            return;
      
      Q_ASSERT_X( !function->dependsOn( this ), "addFunctionDependency", "circular dependency" );
      
      m_dependencies << function->id();
}


00920 bool Function::dependsOn( Function * function ) const
{
      if ( !function )
            return false;
      
      if ( m_dependencies.contains( function->id() ) )
            return true;
      
      foreach ( int functionId, m_dependencies )
      {
            Function * f = XParser::self()->functionWithID( functionId );
            
            if ( f->dependsOn( function ) )
                  return true;
      }
      
      return false;
}
//END class Function



//BEGIN class ParameterSettings
ParameterSettings::ParameterSettings()
{
      animating = false;
      useSlider = false;
      sliderID = 0;
      useList = false;
}


bool ParameterSettings::operator == ( const ParameterSettings & other ) const
{
      return ( useSlider == other.useSlider ) &&
                  ( sliderID == other.sliderID ) &&
                  ( useList == other.useList ) &&
                  ( list == other.list );
}
//END class ParameterSettings



//BEGIN class Parameter
Parameter::Parameter( Type type )
      : m_type( type )
{
      m_sliderID = -1;
      m_listPos = -1;
}


00972 bool Parameter::operator == ( const Parameter & other ) const
{
      return ( type() == other.type() ) &&
                  ( listPos() == other.listPos() ) &&
                  ( sliderID() == other.sliderID() );
}
//END class Parameter



//BEGIN class Plot
Plot::Plot( )
{
      stateNumber = -1;
      plotNumberCount = 1;
      plotNumber = 0;
      m_function = 0;
      m_functionID = -1;
      plotMode = Function::Derivative0;
}


bool Plot::operator ==( const Plot & other ) const
{
      return ( m_functionID == other.functionID() ) &&
                  ( plotMode == other.plotMode ) &&
                  ( parameter == other.parameter ) &&
                  ( stateNumber == other.stateNumber );
}


void Plot::setFunctionID( int id )
{
      m_functionID = id;
      updateCached();
}


void Plot::updateCached()
{
      m_function = XParser::self()->functionWithID( m_functionID );
}


01016 QString Plot::name( ) const
{
      if ( !m_function )
            return QString();
      
      QString n = m_function->name();
      
      if ( m_function->eq[0]->usesParameter() )
            n += QString( "\n%1 = %2" ).arg( m_function->eq[0]->parameterName() ).arg( Parser::number( parameterValue() ) );
      
      return n;
}


01030 void Plot::updateFunction() const
{
      if ( !m_function )
            return;
      
      // Update the plus-minus signature
      assert( pmSignature.size() <= m_function->eq.size() );
      for ( int i = 0; i < pmSignature.size(); ++i )
            m_function->eq[i]->setPMSignature( pmSignature[i] );
      
      if ( parameter.type() != Parameter::Animated )
            m_function->setParameter( parameterValue() );
}


01045 double Plot::parameterValue() const
{
      switch ( parameter.type() )
      {
            case Parameter::Unknown:
                  return 0;
                  
            case Parameter::Slider:
            {
                  KSliderWindow * sw = View::self()->m_sliderWindow;
                  
                  if ( !sw )
                  {
                        // Slider window isn't open. Ask View to open it
                        View::self()->updateSliders();
                        
                        // It should now be open
                        sw = View::self()->m_sliderWindow;
                        assert( sw );
                  }
                  
                  return sw->value( parameter.sliderID() );
            }
                  
            case Parameter::List:
            {
                  if ( (parameter.listPos() >= 0) && (parameter.listPos() < m_function->m_parameters.list.size()) )
                        return m_function->m_parameters.list[ parameter.listPos() ].value();
            }
            
            case Parameter::Animated:
            {
                  kWarning() << "Shouldn't use this function for animated parameter!\n";
                  return 0;
            }
      }
      
      return 0;
}


01086 void Plot::differentiate()
{
      switch ( plotMode )
      {
            case Function::Integral:
                  plotMode = Function::Derivative0;
                  break;

            case Function::Derivative0:
                  plotMode = Function::Derivative1;
                  break;

            case Function::Derivative1:
                  plotMode = Function::Derivative2;
                  break;

            case Function::Derivative2:
                  kWarning() << "Can't handle this yet!\n";
                  break;
      }
}


01109 void Plot::integrate()
{
      switch ( plotMode )
      {
            case Function::Integral:
                  kWarning() << "Can't handle this yet!\n";
                  break;

            case Function::Derivative0:
                  plotMode = Function::Integral;
                  break;

            case Function::Derivative1:
                  plotMode = Function::Derivative0;
                  break;

            case Function::Derivative2:
                  plotMode = Function::Derivative1;
                  break;
      }
}


01132 QColor Plot::color( ) const
{
      Function * f = function();
      assert(f); // Shouldn't call color without a function
      PlotAppearance appearance = f->plotAppearance( plotMode );
      
      if ( (plotNumberCount <= 1) || !appearance.useGradient )
            return appearance.color;
      
      // Is a gradient
      
      int x = plotNumber;
      int l = plotNumberCount;
      
      QLinearGradient lg( 0, 0, l-1, 0 );
      lg.setStops( appearance.gradient.stops() );
      QImage im( l, 1, QImage::Format_RGB32 );
      QPainter p(&im);
      p.setPen( QPen( lg, 1 ) );
      p.drawLine( 0, 0, l, 0 );
      return im.pixel( x, 0 );
}


01156 int Plot::derivativeNumber( ) const
{
      switch ( plotMode )
      {
            case Function::Integral:
                  return -1;
            case Function::Derivative0:
                  return 0;
            case Function::Derivative1:
                  return 1;
            case Function::Derivative2:
                  return 2;
      }
      
      kWarning() << "Unknown derivative number.\n";
      return 0;
}


01175 DifferentialState * Plot::state( ) const
{
      if ( !function() || (stateNumber < 0) )
            return 0;
      
      if ( function()->eq[0]->differentialStates.size() <= stateNumber )
            return 0;
      
      return & function()->eq[0]->differentialStates[stateNumber];
}
//END class Plot


Generated by  Doxygen 1.6.0   Back to index