You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
436 lines
13 KiB
436 lines
13 KiB
/*
|
|
* KmPlot - a math. function plotter for the KDE-Desktop
|
|
*
|
|
* Copyright (C) 2004 Fredrik Edemar
|
|
* f_edemar@linux.se
|
|
*
|
|
* 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 <kinputdialog.h>
|
|
#include <klineedit.h>
|
|
#include <klocale.h>
|
|
#include <kmessagebox.h>
|
|
#include <kpushbutton.h>
|
|
#include <tqlabel.h>
|
|
#include <tqtooltip.h>
|
|
#include <tqwhatsthis.h>
|
|
|
|
|
|
#include "kminmax.h"
|
|
#include "xparser.h"
|
|
|
|
KMinMax::KMinMax(View *v, TQWidget *parent, const char *name)
|
|
: QMinMax(parent, name), m_view(v)
|
|
{
|
|
m_mode=-1;
|
|
connect( cmdClose, TQT_SIGNAL( clicked() ), this, TQT_SLOT( close() ));
|
|
connect( cmdFind, TQT_SIGNAL( clicked() ), this, TQT_SLOT( cmdFind_clicked() ));
|
|
connect( cmdParameter, TQT_SIGNAL( clicked() ), this, TQT_SLOT( cmdParameter_clicked() ));
|
|
connect( list, TQT_SIGNAL( highlighted(TQListBoxItem*) ), this, TQT_SLOT( list_highlighted(TQListBoxItem*) ));
|
|
connect( list, TQT_SIGNAL( doubleClicked( TQListBoxItem * ) ), this, TQT_SLOT( list_doubleClicked(TQListBoxItem *) ));
|
|
parameter="";
|
|
}
|
|
|
|
|
|
void KMinMax::init(char m)
|
|
{
|
|
if ( m_mode==m)
|
|
{
|
|
if ( m_mode == 2) //get y-value
|
|
max->setText("");
|
|
updateFunctions();
|
|
return;
|
|
}
|
|
|
|
m_mode = m;
|
|
if ( m_mode < 2) //find minimum point
|
|
{
|
|
max->setReadOnly(false);
|
|
TQString range;
|
|
range.setNum(View::xmin);
|
|
min->setText( range);
|
|
range.setNum(View::xmax);
|
|
max->setText(range);
|
|
lblMin->setText(i18n("Search between the x-value:"));
|
|
lblMax->setText(i18n("and:"));
|
|
cmdFind->setText(i18n("&Find"));
|
|
TQToolTip::add(min,i18n("Lower boundary of the plot range"));
|
|
TQWhatsThis::add(min,i18n("Enter the lower boundary of the plot range. Expressions like 2*pi are allowed, too."));
|
|
TQToolTip::add(max,i18n("Upper boundary of the plot range"));
|
|
TQWhatsThis::add(max,i18n("Enter the upper boundary of the plot range. Expressions like 2*pi are allowed, too."));
|
|
|
|
if ( m_mode == 1) //find maximum point
|
|
{
|
|
setCaption(i18n("Find Maximum Point"));
|
|
TQToolTip::add( cmdFind, i18n( "Search for the maximum point in the range you specified" ) );
|
|
TQWhatsThis::add(cmdFind,i18n("Search for the highest y-value in the x-range you specified and show the result in a message box."));
|
|
}
|
|
else
|
|
{
|
|
setCaption(i18n("Find Minimum Point"));
|
|
TQToolTip::add( cmdFind, i18n( "Search for the minimum point in the range you specified" ) );
|
|
TQWhatsThis::add(cmdFind,i18n("Search for the lowest y-value in the x-range you specified and show the result in a message box."));
|
|
}
|
|
}
|
|
else if ( m_mode == 2) //get y-value
|
|
{
|
|
setCaption(i18n("Get y-Value"));
|
|
lblMin->setText(i18n("X:"));
|
|
lblMax->setText(i18n("Y:"));
|
|
max->setReadOnly(true);
|
|
min->setText("");
|
|
max->setText("");
|
|
TQToolTip::add(min,i18n("Lower boundary of the plot range"));
|
|
TQWhatsThis::add(min,i18n("Enter the lower boundary of the plot range. Expressions like 2*pi are allowed, too."));
|
|
TQToolTip::add(max,i18n("No returned y-value yet"));
|
|
TQWhatsThis::add(max,i18n("Here you will see the y-value which you got from the x-value in the textbox above. To calculate the y-value, press the Calculate button."));
|
|
|
|
cmdFind->setText(i18n("&Calculate"));
|
|
TQToolTip::add( cmdFind, i18n( "Get the y-value from the x-value you typed" ) );
|
|
TQWhatsThis::add(cmdFind,i18n("Get the y-value from the x-value you typed and show it in the y-value box."));
|
|
|
|
}
|
|
else if ( m_mode == 3) //area under a graph
|
|
{
|
|
max->setReadOnly(false);
|
|
TQString range;
|
|
range.setNum(View::xmin);
|
|
min->setText( range);
|
|
range.setNum(View::xmax);
|
|
max->setText(range);
|
|
TQToolTip::add(min,i18n("Lower boundary of the plot range"));
|
|
TQWhatsThis::add(min,i18n("Enter the lower boundary of the plot range. Expressions like 2*pi are allowed, too."));
|
|
TQToolTip::add(max,i18n("Upper boundary of the plot range"));
|
|
TQWhatsThis::add(max,i18n("Enter the upper boundary of the plot range. Expressions like 2*pi are allowed, too."));
|
|
|
|
setCaption(i18n("Calculate Integral"));
|
|
lblMin->setText(i18n("Calculate the integral between the x-values:"));
|
|
lblMax->setText(i18n("and:"));
|
|
cmdFind->setText(i18n("&Calculate"));
|
|
TQToolTip::add( cmdFind, i18n( "Calculate the integral between the x-values" ) );
|
|
TQWhatsThis::add(cmdFind,i18n("Calculate the numeric integral between the x-values and draw the result as an area."));
|
|
|
|
}
|
|
|
|
min->setFocus();
|
|
updateFunctions();
|
|
}
|
|
|
|
void KMinMax::updateFunctions()
|
|
{
|
|
TQString const selected_item(list->currentText() );
|
|
list->clear();
|
|
|
|
for( TQValueVector<Ufkt>::iterator it = m_view->parser()->ufkt.begin(); it != m_view->parser()->ufkt.end(); ++it)
|
|
{
|
|
if( it->fname[0] != 'x' && it->fname[0] != 'y' && it->fname[0] != 'r' && !it->fname.isEmpty())
|
|
{
|
|
if ( it->f_mode )
|
|
list->insertItem(it->fstr);
|
|
|
|
if ( it->f1_mode ) //1st derivative
|
|
{
|
|
TQString function (it->fstr);
|
|
int i= function.find('(');
|
|
function.truncate(i);
|
|
function +="\'";
|
|
list->insertItem(function );
|
|
}
|
|
if ( it->f2_mode )//2nd derivative
|
|
{
|
|
TQString function (it->fstr);
|
|
int i= function.find('(');
|
|
function.truncate(i);
|
|
function +="\'\'";
|
|
list->insertItem(function );
|
|
}
|
|
if ( it->integral_mode )//integral
|
|
{
|
|
TQString function (it->fstr);
|
|
int i= function.find('(');
|
|
function.truncate(i);
|
|
function = function.upper();
|
|
list->insertItem(function );
|
|
}
|
|
}
|
|
}
|
|
list->sort();
|
|
if (list->count()==0) //empty list
|
|
cmdFind->setEnabled(false);
|
|
else
|
|
cmdFind->setEnabled(true);
|
|
selectItem();
|
|
TQListBoxItem *found_item = list->findItem(selected_item,TQt::ExactMatch);
|
|
if ( found_item && m_view->csmode < 0)
|
|
list->setSelected(found_item,true);
|
|
}
|
|
|
|
void KMinMax::selectItem()
|
|
{
|
|
cmdParameter->hide();
|
|
if ( m_view->csmode < 0)
|
|
return;
|
|
//kdDebug() << "cstype: " << (int)m_view->cstype << endl;
|
|
Ufkt *ufkt = &m_view->parser()->ufkt[m_view->parser()->ixValue(m_view->csmode)];
|
|
TQString function = ufkt->fstr;
|
|
if ( m_view->cstype == 2)
|
|
{
|
|
int i= function.find('(');
|
|
function.truncate(i);
|
|
function +="\'\'";
|
|
}
|
|
else if ( m_view->cstype == 1)
|
|
{
|
|
int i= function.find('(');
|
|
function.truncate(i);
|
|
function +="\'";
|
|
}
|
|
//kdDebug() << "function: " << function << endl;
|
|
TQListBoxItem *item = list->findItem(function,TQt::ExactMatch);
|
|
list->setSelected(item,true);
|
|
|
|
if ( !ufkt->parameters.isEmpty() )
|
|
parameter = ufkt->parameters[m_view->csparam].expression;
|
|
}
|
|
|
|
KMinMax::~KMinMax()
|
|
{
|
|
}
|
|
|
|
void KMinMax::cmdFind_clicked()
|
|
{
|
|
if ( list->currentItem() == -1)
|
|
{
|
|
KMessageBox::error(this, i18n("Please choose a function"));
|
|
return;
|
|
}
|
|
double dmin, dmax;
|
|
dmin = m_view->parser()->eval(min->text() );
|
|
if ( m_view->parser()->parserError()!=0 )
|
|
{
|
|
min->setFocus();
|
|
min->selectAll();
|
|
return;
|
|
}
|
|
if ( m_mode != 2)
|
|
{
|
|
dmax = m_view->parser()->eval(max->text() );
|
|
if ( m_view->parser()->parserError()!=0 )
|
|
{
|
|
max->setFocus();
|
|
max->selectAll();
|
|
return;
|
|
}
|
|
if ( dmin >= dmax)
|
|
{
|
|
KMessageBox::error(this,i18n("The minimum range value must be lower than the maximum range value"));
|
|
min->setFocus();
|
|
min->selectAll();
|
|
return;
|
|
}
|
|
|
|
if ( dmin<View::xmin || dmax>View::xmax )
|
|
{
|
|
KMessageBox::error(this,i18n("Please insert a minimum and maximum range between %1 and %2").arg(View::xmin).arg(View::xmax) );
|
|
min->setFocus();
|
|
min->selectAll();
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
TQString function( list->currentText() );
|
|
char p_mode = 0;
|
|
if ( function.contains('\'') == 1)
|
|
{
|
|
p_mode = 1;
|
|
int pos = function.find('\'');
|
|
function.remove(pos,1);
|
|
}
|
|
else if ( function.contains('\'') == 2)
|
|
{
|
|
p_mode = 2;
|
|
int pos = function.find('\'');
|
|
function.remove(pos,2);
|
|
}
|
|
else if ( function.at(0).category() == TQChar::Letter_Uppercase)
|
|
{
|
|
p_mode = 3;
|
|
function.at(0) = function.at(0).lower();
|
|
}
|
|
|
|
TQString fname, fstr;
|
|
Ufkt *ufkt = 0;
|
|
TQString sec_function = function.section('(',0,0);
|
|
|
|
for( TQValueVector<Ufkt>::iterator it = m_view->parser()->ufkt.begin(); it != m_view->parser()->ufkt.end(); ++it)
|
|
{
|
|
if ( it->fstr.section('(',0,0) == sec_function)
|
|
{
|
|
ufkt = it;
|
|
break;
|
|
}
|
|
}
|
|
if ( !ufkt)
|
|
{
|
|
KMessageBox::error(this,i18n("Function could not be found"));
|
|
return;
|
|
}
|
|
|
|
if ( ufkt->parameters.isEmpty() )
|
|
parameter = "0";
|
|
else if ( parameter.isEmpty())
|
|
{
|
|
KMessageBox::error(this,i18n("You must choose a parameter for that function"));
|
|
list_highlighted(list->selectedItem() );
|
|
return;
|
|
}
|
|
|
|
|
|
if ( m_mode == 0)
|
|
{
|
|
m_view->findMinMaxValue(ufkt,p_mode,true,dmin,dmax,parameter);
|
|
if ( !m_view->isCalculationStopped() )
|
|
KMessageBox::information(this,i18n("Minimum value:\nx: %1\ny: %2").arg(dmin).arg(dmax) );
|
|
}
|
|
else if ( m_mode == 1)
|
|
{
|
|
m_view->findMinMaxValue(ufkt,p_mode,false,dmin,dmax,parameter);
|
|
if ( !m_view->isCalculationStopped() )
|
|
KMessageBox::information(this,i18n("Maximum value:\nx: %1\ny: %2").arg(dmin).arg(dmax));
|
|
}
|
|
else if ( m_mode == 2)
|
|
{
|
|
m_view->getYValue(ufkt,p_mode,dmin,dmax,parameter);
|
|
if ( !m_view->isCalculationStopped() )
|
|
{
|
|
TQString tmp;
|
|
tmp.setNum(dmax);
|
|
max->setText(tmp);
|
|
}
|
|
TQToolTip::add(max,i18n("The returned y-value"));
|
|
TQWhatsThis::add(max,i18n("Here you see the result of the calculation: the returned y-value you got from the x-value in the textbox above"));
|
|
}
|
|
else if ( m_mode == 3)
|
|
{
|
|
double dmin_tmp = dmin;
|
|
m_view->areaUnderGraph(ufkt,p_mode,dmin,dmax,parameter, 0);
|
|
if ( !m_view->isCalculationStopped() )
|
|
{
|
|
m_view->setFocus();
|
|
m_view->update();
|
|
KMessageBox::information(this,i18n("The integral in the interval [%1, %2] is:\n%3").arg(dmin_tmp).arg(dmax).arg(dmin));
|
|
}
|
|
}
|
|
|
|
if ( m_view->isCalculationStopped() )
|
|
KMessageBox::error(this,i18n("The operation was cancelled by the user."));
|
|
}
|
|
void KMinMax::list_highlighted(TQListBoxItem* item)
|
|
{
|
|
if ( !item)
|
|
{
|
|
cmdParameter->hide();
|
|
return;
|
|
}
|
|
TQString function( list->currentText() );
|
|
char p_mode = 0;
|
|
if ( function.contains('\'') == 1)
|
|
{
|
|
p_mode = 1;
|
|
int pos = function.find('\'');
|
|
function.remove(pos,1);
|
|
}
|
|
else if ( function.contains('\'') == 2)
|
|
{
|
|
p_mode = 2;
|
|
int pos = function.find('\'');
|
|
function.remove(pos,2);
|
|
}
|
|
else if ( function.at(0).category() == TQChar::Letter_Uppercase)
|
|
{
|
|
p_mode = 3;
|
|
function.at(0) = function.at(0).lower();
|
|
}
|
|
TQString const sec_function = function.section('(',0,0);
|
|
for(TQValueVector<Ufkt>::iterator it = m_view->parser()->ufkt.begin(); it!=m_view->parser()->ufkt.end(); ++it)
|
|
{
|
|
if ( it->fstr.section('(',0,0) == sec_function)
|
|
{
|
|
if ( it->parameters.count() == 0)
|
|
cmdParameter->hide();
|
|
else
|
|
{
|
|
cmdParameter->show();
|
|
if (parameter.isEmpty() )
|
|
parameter = it->parameters.first().expression;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
void KMinMax::cmdParameter_clicked()
|
|
{
|
|
TQString function( list->currentText() );
|
|
char p_mode = 0;
|
|
if ( function.contains('\'') == 1)
|
|
{
|
|
p_mode = 1;
|
|
int pos = function.find('\'');
|
|
function.remove(pos,1);
|
|
}
|
|
else if ( function.contains('\'') == 2)
|
|
{
|
|
p_mode = 2;
|
|
int pos = function.find('\'');
|
|
function.remove(pos,2);
|
|
}
|
|
else if ( function.at(0).category() == TQChar::Letter_Uppercase)
|
|
{
|
|
p_mode = 3;
|
|
function.at(0) = function.at(0).lower();
|
|
}
|
|
|
|
TQString const sec_function = function.section('(',0,0);
|
|
for(TQValueVector<Ufkt>::iterator it = m_view->parser()->ufkt.begin() ; it!=m_view->parser()->ufkt.end(); ++it)
|
|
{
|
|
if ( it->fstr.section('(',0,0) == sec_function)
|
|
{
|
|
TQStringList str_parameters;
|
|
for ( TQValueList<ParameterValueItem>::Iterator k = it->parameters.begin(); k != it->parameters.end(); ++k )
|
|
str_parameters.append( (*k).expression);
|
|
bool ok;
|
|
TQStringList result = KInputDialog::getItemList( i18n("Choose Parameter"), i18n("Choose a parameter to use:"), str_parameters, TQStringList(parameter),false,&ok,this );
|
|
if ( ok)
|
|
parameter = result.first();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void KMinMax::list_doubleClicked(TQListBoxItem *)
|
|
{
|
|
if ( list->currentItem() == -1)
|
|
return;
|
|
else if( cmdParameter->isShown() )
|
|
cmdParameter_clicked();
|
|
}
|
|
#include "kminmax.moc"
|