Commit 3f05ae50 authored by Fredrik Edemar's avatar Fredrik Edemar

* Support for more than 10 functions.

* Support for more than 10 parameter values for a function.
* Make calls to other functions work again, it was a problem with the auto-adding of *-characters:  f(g(x)) != f(g*(x)) :-)

CCMAIL:kdmoeller@foni.net
CCMAIL:bmlmessmer@web.de

svn path=/trunk/kdeedu/kmplot/; revision=344256
parent 0103fa92
Last modified: 2004-06-16
Last modified: 2004-09-06
TODO
=========================
......@@ -7,7 +7,7 @@ TODO
* DCOP
* KParts
* In tool menu:
* find "nollställen" ( eng: where the function's value is 0)
* find "nollställen" ( en: where the function's value is 0)
* get slope for a x-point
* Fix the unpolished lines
* #52887, need to calculate with complex numbers.
......@@ -65,4 +65,6 @@ DONE
* Basic popup menu for single parametric points.
* Configure Dialog for global Settings / save as default Checkboxes (Started)
* Replace QFile with KIO in KmplotIO.
* Ability to export the parameter values.
\ No newline at end of file
* Ability to export the parameter values.
* Support for more than 10 functions.
* Support for more than 10 parameter values for a function.
\ No newline at end of file
......@@ -60,22 +60,23 @@ void FktDlg::slotDelete()
PushButtonDel->setEnabled(false);
return;
}
int ix, num;
int num;
if ( ( num = lb_fktliste->currentItem() ) == -1 ) return ;
if( lb_fktliste->text( num )[0] == 'x' )
{
// Delete pair of parametric function
int i, j;
getParamIx( lb_fktliste->text( num ), i, j );
m_parser->delfkt( i );
m_parser->delfkt( j );
int const i = getParamIx( lb_fktliste->text( num ) );
if ( i == -1)
return;
m_parser->delfkt( i+1 );
m_parser->delfkt( i );
}
else
{
// only one function to be deleted
ix = getIx( lb_fktliste->text( num ) );
m_parser->delfkt( ix );
m_parser->delfkt( getIx( lb_fktliste->text( num ) ) );
}
lb_fktliste->removeItem( num );
changed = true;
......@@ -89,11 +90,11 @@ void FktDlg::slotEdit()
PushButtonEdit->setEnabled(false);
return;
}
int num = lb_fktliste->currentItem();
int index = getIx( lb_fktliste->text( num ).section( ";", 0, 0) );
int const num = lb_fktliste->currentItem();
int index = getIx( lb_fktliste->currentText().section( ";", 0, 0) );
// find out the function type
char prefix = m_parser->fktext[ index ].extstr.at(0).latin1();
char const prefix = m_parser->fktext[ index ].extstr.at(0).latin1();
if ( prefix == 'r')
slotEditPolar( index, num );
......@@ -103,28 +104,29 @@ void FktDlg::slotEdit()
slotEditFunction( index, num );
}
int FktDlg::getIx( const QString f_str )
int FktDlg::getIx( const QString &f_str )
{
QString fname;
QString fstr;
for ( int ix = 0; ix < m_parser->ufanz; ++ix )
int ix=0;
for( QValueVector<XParser::FktExt>::iterator it = m_parser->fktext.begin(); it != m_parser->fktext.end(); ++it)
{
if ( m_parser->getfkt( ix, fname, fstr ) == -1 )
continue;
if ( m_parser->fktext[ ix ].extstr == f_str )
if ( it->extstr == f_str )
return ix;
++ix;
}
return -1;
}
void FktDlg::getParamIx( const QString f_str, int &index1, int &index2 )
int FktDlg::getParamIx( const QString &f_str)
{
QString fname = f_str.section( "(", 0, 0 );
index1 = m_parser->getfix( fname );
if( fname[0] == 'x' ) fname[0] = 'y';
else fname[0] = 'x';
index2 = m_parser->getfix( fname );
QString const fname = f_str.section( "(", 0, 0 );
int ix=0;
for( QValueVector<Parser::Ufkt>::iterator it = m_parser->ufkt.begin(); it != m_parser->ufkt.end(); ++it)
{
if ( it->fname == fname )
return ix;
++ix;
}
return -1;
}
void FktDlg::updateView()
......@@ -199,25 +201,19 @@ void FktDlg::slotNewPolar()
void FktDlg::getPlots()
{
int index;
QString fname, fstr;
lb_fktliste->clear();
// adding all yet added functions
for ( index = 0; index < m_parser->ufanz; ++index )
for( QValueVector<XParser::FktExt>::iterator it = m_parser->fktext.begin(); it != m_parser->fktext.end(); ++it)
{
if ( m_parser->getfkt( index, fname, fstr ) == -1 ) continue;
if( fname[0] == 'y' ) continue;
if( fname[0] == 'x' )
if( it->extstr[0] == 'y' ) continue;
if( it->extstr[0] == 'x' )
{
QString y_name( fname );
y_name[0] = 'y';
int y_index = m_parser->getfix( y_name );
if( y_index == -1 ) continue;
lb_fktliste->insertItem( m_parser->fktext[ index ].extstr + ";" + m_parser->fktext[ y_index ].extstr );
QString y = it->extstr;
++it;
lb_fktliste->insertItem( y + ";" + it->extstr );
}
else lb_fktliste->insertItem( m_parser->fktext[ index ].extstr );
else lb_fktliste->insertItem( it->extstr );
}
}
......
......@@ -93,9 +93,9 @@ protected slots:
private:
/// Looks up the index of \a f_str in the parser instance.
int getIx( const QString f_str );
int getIx( const QString &f_str );
/// Looks up the indices of the parametric pair of function.
void getParamIx( const QString f_str, int &i, int &j );
int getParamIx( const QString &f_str );
/// Update the view of the main window.
void updateView();
/// Called when the dialog is showed
......
......@@ -239,7 +239,6 @@ bool MainDlg::checkModified()
}
// Slots
void MainDlg::slotOpenNew()
{
if( !checkModified() ) return;
......@@ -531,13 +530,12 @@ void MainDlg::slotQuickEdit(const QString& tmp_f_str )
//creates a valid name for the function if the user has forgotten that
QString f_str( tmp_f_str );
view->parser()->fixFunctionName(f_str);
if ( f_str.at(0)== 'x' || f_str.at(0)== 'y')
{
KMessageBox::error( this, i18n("Parametric functions must be definied in the \"New Parametric Plot\"-dialog which you can find in the menubar"));
return;
}
int index = view->parser()->addfkt( f_str );
if (index==-1)
{
......@@ -554,17 +552,18 @@ void MainDlg::slotQuickEdit(const QString& tmp_f_str )
view->parser()->delfkt( index );
return;
}
view->parser()->fktext[index].color = view->parser()->fktext[index].color0;
view->parser()->fktext[index].f1_color = view->parser()->fktext[index].color0;
view->parser()->fktext[index].f2_color = view->parser()->fktext[index].color0;
view->parser()->fktext[index].integral_color = view->parser()->fktext[index].color0;
view->parser()->fktext[index].f1_linewidth = view->parser()->fktext[index].linewidth;
view->parser()->fktext[index].f2_linewidth = view->parser()->fktext[index].linewidth;
view->parser()->fktext[index].integral_linewidth = view->parser()->fktext[index].linewidth;
view->parser()->fktext[index].f_mode = 1;
view->parser()->fktext[index].integral_precision=Settings::relativeStepWidth();
view->parser()->fktext[index].extstr = f_str;
view->parser()->getext( index );
XParser::FktExt fktext;
view->parser()->prepareAddingFktExtFunction(fktext);
fktext.extstr = f_str;
view->parser()->fktext.append(fktext );
if ( view->parser()->getext( index ) == -1)
{
m_quickEdit->setFocus();
m_quickEdit->selectAll();
view->parser()->delfkt( index );
}
m_quickEdit->clear();
m_modified = true;
view->drawPlot();
......
......@@ -87,8 +87,7 @@ void KmPlotProgress::increase()
View::View(bool & mo, KPopupMenu *p, QWidget* parent, const char* name ) : QWidget( parent, name , WStaticContents ), buffer( width(), height() ), m_popupmenu(p), m_modified(mo)
{
m_parser = new XParser( UFANZ, MEMSIZE, STACKSIZE );
m_parser = new XParser(MEMSIZE, STACKSIZE );
init();
csflg=0;
csmode=-1;
......@@ -128,7 +127,7 @@ XParser* View::parser()
}
void View::draw(QPaintDevice *dev, int form)
{ int ix, lx, ly;
{ int lx, ly;
float sf;
QRect rc;
QPainter DC; // our painter
......@@ -169,7 +168,6 @@ void View::draw(QPaintDevice *dev, int form)
//DC.end();
//((QPixmap *)dev)->fill(QColor("#FF00FF"));
//DC.begin(dev);
}
else if(form==2) // svg
{ ref=QPoint(0, 0);
......@@ -221,11 +219,10 @@ void View::draw(QPaintDevice *dev, int form)
isDrawing=true;
setCursor(Qt::WaitCursor );
stop_calculating = false;
for(ix=0; ix<m_parser->ufanz && !stop_calculating; ++ix)
{
if(m_parser->chkfix(ix)==-1) continue;
for(uint ix=0; ix<m_parser->fktext.count() && !stop_calculating; ++ix)
plotfkt(ix, &DC);
}
isDrawing=false;
restoreCursor();
csflg=0;
......@@ -233,24 +230,25 @@ void View::draw(QPaintDevice *dev, int form)
}
void View::plotfkt(int ix, QPainter *pDC)
void View::plotfkt(int const ix, QPainter *pDC)
{
char fktmode, p_mode;
char p_mode;
int iy, k, ke, mflg;
double x, y, dmin, dmax;
QString fname, fstr;
QPoint p1, p2;
QPen pen;
pen.setCapStyle(Qt::RoundCap);
if(ix==-1 || ix>=m_parser->ufanz) return ; // ungltiger Index
fktmode=m_parser->fktext[ix].extstr[0].latin1();
QValueVector<Parser::Ufkt>::iterator ufkt = &m_parser->ufkt[ix];
QValueVector<XParser::FktExt>::iterator fktext = &m_parser->fktext[ix];
char const fktmode=fktext->extstr[0].latin1();
if(fktmode=='y') return ;
dmin=m_parser->fktext[ix].dmin;
dmax=m_parser->fktext[ix].dmax;
dmin=fktext->dmin;
dmax=fktext->dmax;
if(dmin==dmax) //no special plot range is specified. Use the screen border instead.
{
if(fktmode=='r')
......@@ -264,7 +262,6 @@ void View::plotfkt(int ix, QPainter *pDC)
dmax=xmax;
}
}
double dx;
if(fktmode=='r')
dx=stepWidth*0.05/(dmax-dmin);
......@@ -272,53 +269,55 @@ void View::plotfkt(int ix, QPainter *pDC)
dx=stepWidth*(dmax-dmin)/area.width();
if(fktmode=='x')
{
m_parser->getfkt(ix, fname, fstr);
fname[0]='y';
iy=m_parser->getfix(fname);
if(iy==-1)
return;
}
iy = ix+1;
p_mode=0;
pen.setWidth((int)(m_parser->fktext[ix].linewidth*s) );
pen.setColor(m_parser->fktext[ix].color);
pen.setWidth((int)(fktext->linewidth*s) );
pen.setColor(fktext->color);
pDC->setPen(pen);
while(1)
{
{
k=0;
ke=m_parser->fktext[ix].k_anz;
ke=fktext->k_liste.count();
do
{
{
//kdDebug() << "drawing " << ix << endl;
if ( p_mode == 3 && stop_calculating)
break;
if( m_parser->fktext[ ix ].use_slider == -1 )
m_parser->setparameter(ix, m_parser->fktext[ix].k_liste[k]);
if( fktext->use_slider == -1 )
{
if ( !fktext->k_liste.isEmpty() )
ufkt->setParameter( fktext->k_liste[k] );
}
else
m_parser->setparameter(ix, sliders[ m_parser->fktext[ix].use_slider ]->slider->value() );
ufkt->setParameter( sliders[ fktext->use_slider ]->slider->value() );
mflg=2;
if ( p_mode == 3)
{
if ( m_parser->fktext[ix].integral_use_precision )
dx = m_parser->fktext[ix].integral_precision*(dmax-dmin)/(area.width()*10);
if ( fktext->integral_use_precision )
dx = fktext->integral_precision*(dmax-dmin)/(area.width()*10);
else
dx=dx/10;
progressbar->progress->reset();
progressbar->progress->setTotalSteps ( (int)double((dmax-dmin)/dx)/2 );
progressbar->show();
x = m_parser->fktext[ix].startx; //the initial x-point
x = fktext->startx; //the initial x-point
}
else
x=dmin;
bool forward_direction;
if (dmin<0 && dmax<0)
forward_direction = false;
else
forward_direction = true;
if ( p_mode != 0 || m_parser->fktext[ix].f_mode) // if not the function is hidden
if ( p_mode != 0 || fktext->f_mode) // if not the function is hidden
while ((x>=dmin && x<=dmax) || (p_mode == 3 && x>=dmin && !forward_direction) || (p_mode == 3 && x<=dmax && forward_direction))
{
if ( p_mode == 3 && stop_calculating)
......@@ -330,7 +329,7 @@ void View::plotfkt(int ix, QPainter *pDC)
switch(p_mode)
{
case 0:
y=m_parser->fkt(ix, x);
y=ufkt->fkt(x);
break;
case 1:
......@@ -341,7 +340,7 @@ void View::plotfkt(int ix, QPainter *pDC)
break;
case 3:
{
y=m_parser->fkt(ix, x);
y=ufkt->fkt(x);
m_parser->euler_method(x, y,ix);
if ( int(x*100)%2==0)
{
......@@ -396,7 +395,7 @@ void View::plotfkt(int ix, QPainter *pDC)
if (x>dmax && p_mode== 3)
{
forward_direction = false;
x = m_parser->fktext[ix].startx;
x = fktext->startx;
mflg=2;
}
}
......@@ -409,30 +408,31 @@ void View::plotfkt(int ix, QPainter *pDC)
}
while(++k<ke);
if(m_parser->fktext[ix].f1_mode==1 && p_mode< 1) //draw the 1st derivative
if(fktext->f1_mode==1 && p_mode< 1) //draw the 1st derivative
{
p_mode=1;
pen.setWidth((int)(m_parser->fktext[ix].f1_linewidth*s) );
pen.setColor(m_parser->fktext[ix].f1_color);
pen.setWidth((int)(fktext->f1_linewidth*s) );
pen.setColor(fktext->f1_color);
pDC->setPen(pen);
}
else if(m_parser->fktext[ix].f2_mode==1 && p_mode< 2) //draw the 2nd derivative
else if(fktext->f2_mode==1 && p_mode< 2) //draw the 2nd derivative
{
p_mode=2;
pen.setWidth((int)(m_parser->fktext[ix].f2_linewidth*s) );
pen.setColor(m_parser->fktext[ix].f2_color);
pen.setWidth((int)(fktext->f2_linewidth*s) );
pen.setColor(fktext->f2_color);
pDC->setPen(pen);
}
else if( m_parser->fktext[ix].integral_mode==1 && p_mode< 3) //draw the integral
else if( fktext->integral_mode==1 && p_mode< 3) //draw the integral
{
p_mode=3;
pen.setWidth((int)(m_parser->fktext[ix].integral_linewidth*s) );
pen.setColor(m_parser->fktext[ix].integral_color);
pen.setWidth((int)(fktext->integral_linewidth*s) );
pen.setColor(fktext->integral_color);
pDC->setPen(pen);
}
else break; //otherwise stop
}
if ( progressbar->isVisible())
{
progressbar->hide(); // hide the progressbar-widget if it was shown
......@@ -443,7 +443,7 @@ void View::plotfkt(int ix, QPainter *pDC)
}
void View::drawHeaderTable(QPainter *pDC)
{ int ix, ypos;
{
QString alx, aly, atx, aty, dfx, dfy;
if( m_printHeaderTable )
......@@ -492,9 +492,9 @@ void View::drawHeaderTable(QPainter *pDC)
pDC->drawText(0, 300, i18n("Functions:"));
pDC->Lineh(0, 320, 700);
for(ix=0, ypos=380; ix<m_parser->ufanz; ++ix)
int ypos = 380;
for(uint ix=0; ix<m_parser->fktext.count() && !stop_calculating; ++ix)
{
if(m_parser->chkfix(ix)==-1) continue;
pDC->drawText(100, ypos, m_parser->fktext[ix].extstr);
ypos+=60;
}
......@@ -636,12 +636,16 @@ void View::mouseMoveEvent(QMouseEvent *e)
DC.setWorldMatrix(wm);
ptl=DC.xFormDev(e->pos());
if((csmode=m_parser->chkfix(csmode)) >= 0)
if( csmode >= 0 && csmode <= (int)m_parser->fktext.count() )
{
if( m_parser->fktext[ csmode ].use_slider == -1 )
m_parser->setparameter(csmode, m_parser->fktext[csmode].k_liste[csparam]);
if( m_parser->fktext[ csmode ].use_slider == -1 )
{
if( !m_parser->fktext[csmode].k_liste.isEmpty() )
m_parser->setParameter(csmode, m_parser->fktext[csmode].k_liste[csparam]);
}
else
m_parser->setparameter(csmode, sliders[ m_parser->fktext[csmode].use_slider ]->slider->value() );
m_parser->setParameter(csmode, sliders[ m_parser->fktext[csmode].use_slider ]->slider->value() );
if ( cstype == 0)
ptl.setY(dgr.Transy(csypos=m_parser->fkt(csmode, csxpos=dgr.Transx(ptl.x()))));
else if ( cstype == 1)
......@@ -837,29 +841,31 @@ void View::mousePressEvent(QMouseEvent *e)
return;
}
int ix;
uint ix;
double const g=tlgy*double(xmax-xmin)/(2*double(ymax-ymin));
if(e->button()==RightButton) //clicking with the right mouse button
{
char function_type;
for(ix=0; ix<m_parser->ufanz; ++ix)
for(ix=0; ix</*m_parser->ufanz*/m_parser->fktext.count(); ++ix)
{
function_type = m_parser->fktext[ix].extstr[0].latin1();
if ( function_type==0 || function_type=='y' || function_type=='r')
continue;
int k=0;
int const ke=m_parser->fktext[ix].k_anz;
int const ke=m_parser->fktext[ix].k_liste.count();
do
{
if( m_parser->fktext[ ix ].use_slider == -1 )
m_parser->setparameter(ix, m_parser->fktext[ix].k_liste[k]);
{
if ( !m_parser->fktext[ix].k_liste.isEmpty())
m_parser->setParameter(ix, m_parser->fktext[ix].k_liste[k]);
}
else
m_parser->setparameter(ix, sliders[ m_parser->fktext[ix].use_slider ]->slider->value() );
m_parser->setParameter(ix, sliders[ m_parser->fktext[ix].use_slider ]->slider->value() );
if ( function_type=='x' && fabs(csxpos-m_parser->fkt(ix, csxpos))< g && m_parser->fktext[ix].extstr.contains('t')==1) //parametric plot
{
int y_index = ix+1;
if ( y_index == UFANZ)
y_index=0;
uint y_index = ix+1;
if ( fabs(csypos-m_parser->fkt(y_index, csxpos)<g) && m_parser->fktext[y_index].extstr.contains('t')==1)
{
......@@ -953,7 +959,7 @@ void View::mousePressEvent(QMouseEvent *e)
return ;
}
for(ix=0; ix<m_parser->ufanz; ++ix)
for(ix=0; ix</*m_parser->ufanz*/m_parser->fktext.count(); ++ix)
{
switch(m_parser->fktext[ix].extstr[0].latin1())
{
......@@ -961,15 +967,16 @@ void View::mousePressEvent(QMouseEvent *e)
}
int k=0;
int const ke=m_parser->fktext[ix].k_anz;
int const ke=m_parser->fktext[ix].k_liste.count();
do
{
if( m_parser->fktext[ ix ].use_slider == -1 )
m_parser->setparameter(ix, m_parser->fktext[ix].k_liste[k]);
{
if ( !m_parser->fktext[ix].k_liste.isEmpty() )
m_parser->setParameter(ix, m_parser->fktext[ix].k_liste[k]);
}
else
m_parser->setparameter(ix, sliders[ m_parser->fktext[ix].use_slider ]->slider->value() );
m_parser->setParameter(ix, sliders[ m_parser->fktext[ix].use_slider ]->slider->value() );
if(fabs(csypos-m_parser->fkt(ix, csxpos))< g && m_parser->fktext[ix].f_mode)
{
csmode=ix;
......@@ -1149,16 +1156,6 @@ void View::getSettings()
{
m_parser->setAngleMode( Settings::anglemode() );
m_parser->linewidth0 = Settings::gridLineWidth();
m_parser->fktext[ 0 ].color0 = Settings::color0().rgb();
m_parser->fktext[ 1 ].color0 = Settings::color1().rgb();
m_parser->fktext[ 2 ].color0 = Settings::color2().rgb();
m_parser->fktext[ 3 ].color0 = Settings::color3().rgb();
m_parser->fktext[ 4 ].color0 = Settings::color4().rgb();
m_parser->fktext[ 5 ].color0 = Settings::color5().rgb();
m_parser->fktext[ 6 ].color0 = Settings::color6().rgb();
m_parser->fktext[ 7 ].color0 = Settings::color7().rgb();
m_parser->fktext[ 8 ].color0 = Settings::color8().rgb();
m_parser->fktext[ 9 ].color0 = Settings::color9().rgb();
backgroundcolor = Settings::backgroundcolor();
invertColor(backgroundcolor,inverted_backgroundcolor);
......@@ -1168,9 +1165,15 @@ void View::getSettings()
void View::init()
{
getSettings();
for ( int ix = 0; ix < m_parser->ufanz; ++ix )
m_parser->delfkt( ix );
if ( m_parser->fktext.isEmpty() )
return;
QValueVector<Parser::Ufkt>::iterator it = m_parser->ufkt.begin();
it->fname="";
while ( m_parser->ufkt.count() > 1)
m_parser->Parser::delfkt( &m_parser->ufkt.last() );
m_parser->fktext.clear();
}
......@@ -1185,16 +1188,16 @@ void View::findMinMaxValue(int ix, char p_mode, bool minimum, double &dmin, doub
double result_x = 0;
double result_y = 0;
bool start = true;
if(ix==-1 || ix>=m_parser->ufanz) return ; // ungltiger Index
if(ix==-1 || ix>=(int)m_parser->fktext.count() ) return ; // ungltiger Index
// TODO: parameter sliders
int i=0;
if ( m_parser->fktext[ix].k_anz != 0)
if ( !m_parser->fktext[ix].k_liste.isEmpty())
for ( QStringList::Iterator it = m_parser->fktext[ix].str_parameter.begin(); it != m_parser->fktext[ix].str_parameter.end(); ++it )
{
if ( *it == str_parameter)
{
m_parser->setparameter(ix, m_parser->fktext[ix].k_liste[i]);
m_parser->setParameter(ix, m_parser->fktext[ix].k_liste[i]);
break;
}
i++;
......@@ -1314,12 +1317,12 @@ void View::getYValue(int ix, char p_mode, double x, double &y, QString &str_par
{