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.
tdeedu/kmplot/kmplot/diagr.cpp

654 lines
13 KiB

/*
* KmPlot - a math. function plotter for the KDE-Desktop
*
* Copyright (C) 1998, 1999 Klaus-Dieter M<>ler
* 2000, 2002 kd.moeller@t-online.de
*
* 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.
*
*/
//local includes
#include "diagr.h"
#include "settings.h"
#ifdef __osf__
#include <nan.h>
#define isnan(x) IsNAN(x)
#define isinf(x) IsINF(X)
#endif
#ifdef USE_SOLARIS
#include <ieeefp.h>
int isinf(double x)
{
return !finite(x) && x==x;
}
#endif
#include <kdebug.h>
CDiagr::CDiagr()
{
frameColor=tqRgb(0, 0, 0);
axesColor=tqRgb(0, 0, 0);
gridColor=tqRgb(192, 192, 192);
borderThickness=2;
axesLineWidth = Settings::axesLineWidth();
gridLineWidth = Settings::gridLineWidth();
ticWidth = Settings::ticWidth();
ticLength = Settings::ticLength();
g_mode = Settings::gridStyle();
ex=ey=1.;
}
CDiagr::~CDiagr()
{}
void CDiagr::Create(TQPoint Ref, // Bezugspunkt links unten
int lx, int ly, // Achsenl<6E>gen
double xmin, double xmax, // x-Wertebereich
double ymin, double ymax) // y-Wertebereich
{ int x, y, h, w;
CDiagr::xmin=xmin; // globale Variablen setzen
CDiagr::xmax=xmax;
CDiagr::ymin=ymin;
CDiagr::ymax=ymax;
xmd=xmax+1e-6;
ymd=ymax+1e-6;
tsx=ceil(xmin/ex)*ex;
tsy=ceil(ymin/ey)*ey;
skx=lx/(xmax-xmin); // Skalierungsfaktoren berechnen
sky=ly/(ymax-ymin);
ox=Ref.x()-skx*xmin+0.5; // Ursprungskoordinaten berechnen
oy=Ref.y()+sky*ymax+0.5;
PlotArea.setRect(x=Ref.x(), y=Ref.y(), w=lx, h=ly);
if( Settings::showExtraFrame() )
{
x-=20;
y-=20;
w+=40;
h+=40;
if( Settings::showLabel() && ymin>=0. )
h+=60;
}
m_frame.setRect(x, y, w, h);
}
void CDiagr::Skal( double ex, double ey )
{
CDiagr::ex=ex;
CDiagr::ey=ey;
g_mode = Settings::gridStyle();
tsx=ceil(xmin/ex)*ex;
tsy=ceil(ymin/ey)*ey;
}
void CDiagr::Plot(TQPainter* pDC)
{
TQPen pen(frameColor, borderThickness);
if( g_mode != GRID_NONE )
drawGrid( pDC ); // draw the grid
drawAxes( pDC ); // draw the axes
if( Settings::showLabel() )
drawLabels(pDC); // Achsen beschriften
if( Settings::showFrame() || Settings::showExtraFrame() )// FRAME zeichnen
{
pDC->setPen(pen);
pDC->drawRect(m_frame);
}
}
int CDiagr::Transx( double x ) // reale x-Koordinate
{
int xi; // transformierte x-Koordinate
static double lastx; // vorherige x-Koordinate
if(isnan(x))
{
xclipflg=1;
if(lastx<1. && lastx>-1.)
xi=(int)(ox-skx*lastx);
else
xi=(lastx<0)? PlotArea.left(): PlotArea.right();
}
else if(isinf(x)==-1)
{
xclipflg=0;
xi=PlotArea.left();
}
else if(isinf(x)==1)
{
xclipflg=0;
xi=PlotArea.right();
}
else if(x<xmin)
{
xclipflg=1;
xi=PlotArea.left();
}
else if(x>xmax)
{
xclipflg=1;
xi=PlotArea.right();
}
else
{
xclipflg=0;
xi=(int)(ox+skx*x);
}
lastx=x;
return xi;
}
int CDiagr::Transy(double y) // reale y-Koordinate
{
int yi; // transformierte y-Koordinate
static double lasty; // vorherige y-Koordinate
if(isnan(y))
{
yclipflg=1;
if(lasty<1. && lasty>-1.)
yi=(int)(oy-sky*lasty);
else
yi=(lasty<0)? PlotArea.bottom(): PlotArea.top();
}
else if(isinf(y)==-1)
{
yclipflg=0;
yi=PlotArea.bottom();
}
else if(isinf(y)==1)
{
yclipflg=0;
yi=PlotArea.top();
}
else if(y<ymin)
{
yclipflg=1;
yi=PlotArea.bottom();
}
else if(y>ymax)
{
yclipflg=1;
yi=PlotArea.top();
}
else
{
yclipflg=0;
yi=(int)(oy-sky*y);
}
lasty=y;
return yi;
}
double CDiagr::Transx(int x) // Bildschirmkoordinate
{ return (x-ox)/skx; // reale x-Koordinate
}
double CDiagr::Transy(int y) // Bildschirmkoordinate
{ return (oy-y)/sky; // reale y-Koordinate
}
void CDiagr::drawAxes( TQPainter* pDC ) // draw axes
{ int a, b, tl;
double d, da, db;
if( Settings::showAxes() )
{
pDC->setPen( TQPen( axesColor, axesLineWidth ) );
b = Transy(0.);
a = PlotArea.right();
pDC->Lineh(PlotArea.left(), b, a); // x-Achse
if( Settings::showArrows()) // ARROWS
{ int const dx=40;
int const dy=15;
pDC->Line(a, b, a-dx, b+dy);
pDC->Line(a, b, a-dx, b-dy);
}
a = Transx(0.);
b = PlotArea.top();
pDC->Linev(a, PlotArea.bottom(), b); // y-Achse
if( Settings::showArrows() ) // ARROWS
{ int const dx=15;
int const dy=40;
pDC->Line(a, b, a-dx, b+dy);
pDC->Line(a, b, a+dx, b+dy);
}
}
pDC->setPen( TQPen( axesColor, ticWidth ) );
if( Settings::showAxes() )
{
da=oy-ticLength;
db=oy+ticLength;
tl= Settings::showFrame()? 0: ticLength;
d=tsx;
if(da<(double)PlotArea.top())
{
a=PlotArea.top()-tl;
b=PlotArea.top()+ticLength;
}
else if(db>(double)PlotArea.bottom())
{
b=PlotArea.bottom()+tl;
a=PlotArea.bottom()-ticLength;
}
else
{
a=(int)da;
b=(int)db;
}
while(d<xmd-ex/2.)
{
pDC->Linev(Transx(d), a, b);
d+=ex;
}
da=ox-ticLength;
db=ox+ticLength;
d=tsy;
if(da<(double)PlotArea.left())
{
a=PlotArea.left()-tl;
b=PlotArea.left()+ticLength;
}
else if(db>(double)PlotArea.right())
{
b=PlotArea.right()+tl;
a=PlotArea.right()-ticLength;
}
else
{
a=(int)da;
b=(int)db;
}
while(d<ymd-ey/2.)
{
pDC->Lineh(a, Transy(d), b);
d+=ey;
}
}
else if( Settings::showFrame() )
{
a=PlotArea.bottom()+ticLength;
b=PlotArea.top()-ticLength;
d=tsx;
while(d<xmd)
{
pDC->Linev(Transx(d), PlotArea.bottom(), a);
pDC->Linev(Transx(d), PlotArea.top(), b);
d+=ex;
}
a=PlotArea.left()+ticLength;
b=PlotArea.right()-ticLength;
d=tsy;
while(d<ymd)
{
pDC->Lineh(PlotArea.left(), Transy(d), a);
pDC->Lineh(PlotArea.right(), Transy(d), b);
d+=ey;
}
}
}
void CDiagr::drawGrid( TQPainter* pDC )
{
int a, b;
double d, x, y;
TQPen pen( gridColor, gridLineWidth );
pDC->setPen(pen);
if( g_mode==GRID_LINES )
{
d=tsx;
while(d<xmd)
{
pDC->Linev(Transx(d), PlotArea.bottom(), PlotArea.top());
d+=ex;
}
d=tsy;
while(d<ymd)
{
pDC->Lineh(PlotArea.left(), Transy(d), PlotArea.right());
d+=ey;
}
}
else if( g_mode==GRID_CROSSES )
{
int const dx = 5;
int const dy = 5;
for(x=tsx; x<xmd; x+=ex)
{
a=Transx(x);
for(y=tsy; y<ymd; y+=ey)
{
b=Transy(y);
pDC->Lineh(a-dx, b, a+dx);
pDC->Linev(a, b-dy, b+dy);
}
}
}
else if( g_mode==GRID_POLAR )
{
int y2;
double w;
TQRect const rc=PlotArea;
pDC->setClipRect(pDC->xForm(rc));
double const c=hypot(xmd*skx, ymd*sky);
int const xm=(int)(c+ox);
int const dr=(int)(skx*ex);
int const d2r=(int)(2.*skx*ex);
int x1=(int)ox-dr;
int y1=(int)oy-dr;
int x2=y2=d2r;
do
{
pDC->drawEllipse(x1, y1, x2, y2);
x1-=dr;
y1-=dr;
x2+=d2r;
y2+=d2r;
}
while(x2<=xm);
x1=(int)ox;
y1=(int)oy;
for(w=0.; w<2.*M_PI; w+=M_PI/12.)
{
x2=(int)(ox+c*cos(w));
y2=(int)(oy+c*sin(w));
pDC->Line(x1, y1, x2, y2);
}
pDC->setClipping(false);
}
}
void CDiagr::drawLabels(TQPainter* pDC)
{
int const dx=15;
int const dy=40;
TQFont const font=TQFont( Settings::axesFont(), Settings::axesFontSize() );
pDC->setFont(font);
int const x=Transx(0.);
int const y=Transy(0.);
double d;
int n;
TQString s;
//pDC->drawText(x-dx, y+dy, 0, 0, TQt::AlignRight|TQt::AlignVCenter|TQt::DontClip, "0");
char draw_next=0;
TQFontMetrics const test(font);
int swidth=0;
for(d=tsx, n=(int)ceil(xmin/ex); d<xmd; d+=ex, ++n)
{
if(n==0 || fabs(d-xmd)<=1.5*ex)
continue;
if(n<0)
s="-";
else
s="+";
if(fabs(ex-M_PI/2.)<1e-3)
{
if(n==-1 || n==1)
s+="pi/2";//s+=TQChar(960)+TQString("/2");
else if(n%2 == 0)
{
if(n==-2 || n==2)
s+="pi";//s+=TQChar(960);
else
{
s=TQString().sprintf("%+d", n/2);
s+="pi";//s+=TQChar(960);
}
}
else
continue;
swidth = test.width(s);
if ( Transx(d)-x<swidth && Transx(d)-x>-swidth && draw_next==0)
{
draw_next=1;
continue;
}
if (draw_next>0)
{
if (draw_next==1)
{
draw_next++;
continue;
}
else
draw_next=0;
}
pDC->drawText(Transx(d), y+dy, 0, 0, TQt::AlignCenter|TQt::DontClip, s);
}
else if(fabs(ex-M_PI/3.)<1e-3)
{
if(n==-1 || n==1)
s+="pi/3";//s+=TQChar(960)+TQString("/3");
else if(n%3==0)
{
if(n==-3 || n==3)
s+="pi";//s+=TQChar(960);
else
{
s=TQString().sprintf("%+d", n/3);
s+="pi";//s+=TQChar(960);
}
}
else
continue;
swidth = test.width(s);
if ( Transx(d)-x<swidth && Transx(d)-x>-swidth && draw_next==0)
{
draw_next=1;
continue;
}
if (draw_next>0)
{
if (draw_next==1)
{
draw_next++;
continue;
}
else
draw_next=0;
}
pDC->drawText(Transx(d), y+dy, 0, 0, TQt::AlignCenter|TQt::DontClip, s);
}
else if(fabs(ex-M_PI/4.)<1e-3)
{
if(n==-1 || n==1)
s+="pi/4";//s+=TQChar(960)+TQString("/4");
else if(n%4==0)
{
if(n==-4 || n==4)
s+="pi";//s+=TQChar(960);
else
{
s=TQString().sprintf("%+d", n/4);
s+="pi";//s+=TQChar(960);
}
}
else
continue;
swidth = test.width(s);
if ( Transx(d)-x<swidth && Transx(d)-x>-swidth && draw_next==0)
{
draw_next=1;
continue;
}
if (draw_next>0)
{
if (draw_next==1)
{
draw_next++;
continue;
}
else
draw_next=0;
}
pDC->drawText(Transx(d), y+dy, 0, 0, TQt::AlignCenter|TQt::DontClip, s);
}
else if((n%5==0 || n==1 || n==-1 || draw_next))
{
s=TQString().sprintf("%+0.3g", n*ex);
swidth = test.width(s);
if ( Transx(d)-x<swidth && Transx(d)-x>-swidth && draw_next==0)
{
draw_next=1;
continue;
}
if (draw_next>0)
{
if (draw_next==1)
{
draw_next++;
continue;
}
else
draw_next=0;
}
pDC->drawText(Transx(d), y+dy, 0, 0, TQt::AlignCenter|TQt::DontClip, s);
}
}
if(ymax<0 && xmax<0)
pDC->drawText(Transx(xmax)-(4*dx), y+(dy-20), 0, 0, TQt::AlignCenter|TQt::DontClip, "x");
else
pDC->drawText(Transx(xmax)-dx, y+dy, 0, 0, TQt::AlignCenter|TQt::DontClip, "x");
for(d=tsy, n=(int)ceil(ymin/ey); d<ymd; d+=ey, ++n)
{
if(n==0 || fabs(d-ymd)<=1.5*ey)
continue;
if(n<0)
s="-";
else
s="+";
if(fabs(ey-M_PI/2.)<1e-3)
{
if(n==-1 || n==1)
s+="pi/2";//s+=TQChar(960)+TQString("/2");
else if(n%2==0)
{
if(n==-2 || n==2)
s+="pi";//s+=TQChar(960);
else
{
s=TQString().sprintf("%+d", n/2);
s+="pi";//s+=TQChar(960);
}
}
else
continue;
if (xmin>=0)
pDC->drawText(x+dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignLeft|TQt::DontClip, s);
else
pDC->drawText(x-dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignRight|TQt::DontClip, s);
}
else if(fabs(ey-M_PI/3.)<1e-3)
{
if(n==-1 || n==1)
s+="pi/3";//s+=TQChar(960)+TQString("/3");
else if(n%3==0)
{
if(n==-3 || n==3)
s+="pi";//s+=TQChar(960);
else
{
s=TQString().sprintf("%+d", n/3);
s+="pi";//s+=TQChar(960);
}
}
else
continue;
if (xmin>=0)
pDC->drawText(x+dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignLeft|TQt::DontClip, s);
else
pDC->drawText(x-dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignRight|TQt::DontClip, s);
}
else if(fabs(ey-M_PI/4.)<1e-3)
{
if(n==-1 || n==1)
s+="pi/4";//s+=TQChar(960)+TQString("/4");
else if(n%4==0)
{
if(n==-4 || n==4)
s+="pi";//s+=TQChar(960);
else
{
s=TQString().sprintf("%+d", n/4);
s+="pi";//s+=TQChar(960);
}
}
else
continue;
if (xmin>=0)
pDC->drawText(x+dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignLeft|TQt::DontClip, s);
else
pDC->drawText(x-dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignRight|TQt::DontClip, s);
}
else if((n%5==0 || n==1 || n==-1))
{
s=TQString().sprintf("%+0.3g", n*ey);
if (xmin>=0)
pDC->drawText(x+dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignLeft|TQt::DontClip, s);
else
pDC->drawText(x-dx, Transy(d), 0, 0, TQt::AlignVCenter|TQt::AlignRight|TQt::DontClip, s);
}
}
if(ymax<0 && xmax<0)
pDC->drawText(x-dx, Transy(ymax)+(2*dy), 0, 0, TQt::AlignVCenter|TQt::AlignRight|TQt::DontClip, "y");
else if (xmin>0)
pDC->drawText(x-(2*dx), Transy(ymax)+dy, 0, 0, TQt::AlignVCenter|TQt::AlignRight|TQt::DontClip, "y");
else
pDC->drawText(x-dx, Transy(ymax)+dy, 0, 0, TQt::AlignVCenter|TQt::AlignRight|TQt::DontClip, "y");
}