/* * 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 #define isnan(x) IsNAN(x) #define isinf(x) IsINF(X) #endif #ifdef USE_SOLARIS #include int isinf(double x) { return !finite(x) && x==x; } #endif #include 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�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(xxmax) { 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(yymax) { 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(dLinev(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(dLineh(a, Transy(d), b); d+=ey; } } else if( Settings::showFrame() ) { a=PlotArea.bottom()+ticLength; b=PlotArea.top()-ticLength; d=tsx; while(dLinev(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(dLineh(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(dLinev(Transx(d), PlotArea.bottom(), PlotArea.top()); d+=ex; } d=tsy; while(dLineh(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; xLineh(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-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 && 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 && 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 && 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=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"); }