summaryrefslogtreecommitdiffstats
path: root/kmplot/kmplot/diagr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'kmplot/kmplot/diagr.cpp')
-rw-r--r--kmplot/kmplot/diagr.cpp653
1 files changed, 653 insertions, 0 deletions
diff --git a/kmplot/kmplot/diagr.cpp b/kmplot/kmplot/diagr.cpp
new file mode 100644
index 00000000..ba438c7b
--- /dev/null
+++ b/kmplot/kmplot/diagr.cpp
@@ -0,0 +1,653 @@
+/*
+* 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=qRgb(0, 0, 0);
+ axesColor=qRgb(0, 0, 0);
+ gridColor=qRgb(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(QPoint Ref, // Bezugspunkt links unten
+ int lx, int ly, // Achsenl�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(QPainter* pDC)
+{
+ QPen 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( QPainter* pDC ) // draw axes
+{ int a, b, tl;
+ double d, da, db;
+
+ if( Settings::showAxes() )
+ {
+ pDC->setPen( QPen( 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( QPen( 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( QPainter* pDC )
+{
+ int a, b;
+ double d, x, y;
+ QPen 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;
+ QRect 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(QPainter* pDC)
+{
+ int const dx=15;
+ int const dy=40;
+ QFont const font=QFont( Settings::axesFont(), Settings::axesFontSize() );
+ pDC->setFont(font);
+ int const x=Transx(0.);
+ int const y=Transy(0.);
+ double d;
+ int n;
+ QString s;
+
+ //pDC->drawText(x-dx, y+dy, 0, 0, Qt::AlignRight|Qt::AlignVCenter|Qt::DontClip, "0");
+ char draw_next=0;
+ QFontMetrics 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+=QChar(960)+QString("/2");
+ else if(n%2 == 0)
+ {
+ if(n==-2 || n==2)
+ s+="pi";//s+=QChar(960);
+ else
+ {
+ s=QString().sprintf("%+d", n/2);
+ s+="pi";//s+=QChar(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, Qt::AlignCenter|Qt::DontClip, s);
+ }
+ else if(fabs(ex-M_PI/3.)<1e-3)
+ {
+ if(n==-1 || n==1)
+ s+="pi/3";//s+=QChar(960)+QString("/3");
+ else if(n%3==0)
+ {
+ if(n==-3 || n==3)
+ s+="pi";//s+=QChar(960);
+ else
+ {
+ s=QString().sprintf("%+d", n/3);
+ s+="pi";//s+=QChar(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, Qt::AlignCenter|Qt::DontClip, s);
+ }
+ else if(fabs(ex-M_PI/4.)<1e-3)
+ {
+ if(n==-1 || n==1)
+ s+="pi/4";//s+=QChar(960)+QString("/4");
+ else if(n%4==0)
+ {
+ if(n==-4 || n==4)
+ s+="pi";//s+=QChar(960);
+ else
+ {
+ s=QString().sprintf("%+d", n/4);
+ s+="pi";//s+=QChar(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, Qt::AlignCenter|Qt::DontClip, s);
+ }
+ else if((n%5==0 || n==1 || n==-1 || draw_next))
+ {
+ s=QString().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, Qt::AlignCenter|Qt::DontClip, s);
+ }
+ }
+
+ if(ymax<0 && xmax<0)
+ pDC->drawText(Transx(xmax)-(4*dx), y+(dy-20), 0, 0, Qt::AlignCenter|Qt::DontClip, "x");
+ else
+ pDC->drawText(Transx(xmax)-dx, y+dy, 0, 0, Qt::AlignCenter|Qt::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+=QChar(960)+QString("/2");
+ else if(n%2==0)
+ {
+ if(n==-2 || n==2)
+ s+="pi";//s+=QChar(960);
+ else
+ {
+ s=QString().sprintf("%+d", n/2);
+ s+="pi";//s+=QChar(960);
+ }
+ }
+ else
+ continue;
+ if (xmin>=0)
+ pDC->drawText(x+dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignLeft|Qt::DontClip, s);
+ else
+ pDC->drawText(x-dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignRight|Qt::DontClip, s);
+ }
+ else if(fabs(ey-M_PI/3.)<1e-3)
+ {
+ if(n==-1 || n==1)
+ s+="pi/3";//s+=QChar(960)+QString("/3");
+ else if(n%3==0)
+ {
+ if(n==-3 || n==3)
+ s+="pi";//s+=QChar(960);
+ else
+ {
+ s=QString().sprintf("%+d", n/3);
+ s+="pi";//s+=QChar(960);
+ }
+ }
+ else
+ continue;
+ if (xmin>=0)
+ pDC->drawText(x+dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignLeft|Qt::DontClip, s);
+ else
+ pDC->drawText(x-dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignRight|Qt::DontClip, s);
+ }
+ else if(fabs(ey-M_PI/4.)<1e-3)
+ {
+ if(n==-1 || n==1)
+ s+="pi/4";//s+=QChar(960)+QString("/4");
+ else if(n%4==0)
+ {
+ if(n==-4 || n==4)
+ s+="pi";//s+=QChar(960);
+ else
+ {
+ s=QString().sprintf("%+d", n/4);
+ s+="pi";//s+=QChar(960);
+ }
+ }
+ else
+ continue;
+ if (xmin>=0)
+ pDC->drawText(x+dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignLeft|Qt::DontClip, s);
+ else
+ pDC->drawText(x-dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignRight|Qt::DontClip, s);
+ }
+ else if((n%5==0 || n==1 || n==-1))
+ {
+ s=QString().sprintf("%+0.3g", n*ey);
+ if (xmin>=0)
+ pDC->drawText(x+dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignLeft|Qt::DontClip, s);
+ else
+ pDC->drawText(x-dx, Transy(d), 0, 0, Qt::AlignVCenter|Qt::AlignRight|Qt::DontClip, s);
+ }
+ }
+
+ if(ymax<0 && xmax<0)
+ pDC->drawText(x-dx, Transy(ymax)+(2*dy), 0, 0, Qt::AlignVCenter|Qt::AlignRight|Qt::DontClip, "y");
+ else if (xmin>0)
+ pDC->drawText(x-(2*dx), Transy(ymax)+dy, 0, 0, Qt::AlignVCenter|Qt::AlignRight|Qt::DontClip, "y");
+ else
+ pDC->drawText(x-dx, Transy(ymax)+dy, 0, 0, Qt::AlignVCenter|Qt::AlignRight|Qt::DontClip, "y");
+}