Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/diagrams/curvediagram.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                               curvediagram.cpp
00003                              ------------------
00004     begin                : Sat Apr 9 2005
00005     copyright            : (C) 2005 by Michael Margraf
00006     email                : michael.margraf@alumni.tu-berlin.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This program is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU General Public License as published by  *
00013  *   the Free Software Foundation; either version 2 of the License, or     *
00014  *   (at your option) any later version.                                   *
00015  *                                                                         *
00016  ***************************************************************************/
00017 
00023 #if HAVE_CONFIG_H
00024 # include <config.h>
00025 #endif
00026 #include <cmath>
00027 #include <float.h>
00028 #if HAVE_IEEEFP_H
00029 # include <ieeefp.h>
00030 #endif
00031 
00032 #include <QMessageBox>
00033 
00034 #include "curvediagram.h"
00035 #include "main.h"
00036 #include "misc.h"
00037 
00038 CurveDiagram::CurveDiagram(int _cx, int _cy) : Diagram(_cx, _cy)
00039 {
00040   x1 = 10;      // position of label text
00041   y1 = y3 = 33;
00042   x2 = y2 = 200;    // initial size of diagram
00043   x3 = 207;    // with some distance for right axes text
00044 
00045   Name = "Curve"; // BUG.
00046   calcDiagram();
00047 }
00048 
00049 CurveDiagram::~CurveDiagram()
00050 {
00051 }
00052 
00053 // ------------------------------------------------------------
00054 void CurveDiagram::calcCoordinate(const double*, const double* yD, const double*,
00055           float *px, float *py, Axis const *pa) const
00056 {
00057   double yr = yD[0];
00058   double yi = yD[1];
00059   if(xAxis.log)
00060     *px = float(log10(yr / xAxis.low)/log10(xAxis.up / xAxis.low)
00061     *double(x2));
00062   else  *px = float((yr-xAxis.low)/(xAxis.up-xAxis.low)*double(x2));
00063 
00064   if(pa->log)
00065     *py = float(log10(yi / pa->low)/log10(pa->up / pa->low)
00066     *double(y2));
00067   else  *py = float((yi-pa->low)/(pa->up-pa->low)*double(y2));
00068 
00069   if(std::isfinite(*px))
00070     if(std::isfinite(*py))
00071       return;
00072 
00073   *px = *py = 0.0;
00074 }
00075 
00076 // --------------------------------------------------------------
00077 void CurveDiagram::finishMarkerCoordinates(float& fCX, float& fCY) const
00078 {
00079   if(!insideDiagram(fCX, fCY)) {
00080     fCX = fCY = 0.0;
00081   }
00082 }
00083 
00084 // ------------------------------------------------------------
00085 void CurveDiagram::calcLimits()
00086 {
00087   int i;
00088   double a, b, c;
00089 
00090   if(xAxis.autoScale) {// check before, to preserve limit exchange (max < min)
00091     if(xAxis.log) {
00092       calcAxisLogScale(&xAxis, i, a, b, c, x2);
00093       xAxis.step = 1.0;
00094     }
00095     else  calcAxisScale(&xAxis, a, b, c, xAxis.step, double(x2));
00096     xAxis.limit_min = xAxis.low;
00097     xAxis.limit_max = xAxis.up;
00098   }
00099 
00100   if(yAxis.autoScale) {// check before, to preserve limit exchange (max < min)
00101     if(yAxis.log) {
00102       calcAxisLogScale(&yAxis, i, a, b, c, y2);
00103       yAxis.step = 1.0;
00104     }
00105     else  calcAxisScale(&yAxis, a, b, c, yAxis.step, double(y2));
00106     yAxis.limit_min = yAxis.low;
00107     yAxis.limit_max = yAxis.up;
00108   }
00109 
00110   if(zAxis.autoScale) {// check before, to preserve limit exchange (max < min)
00111     if(zAxis.log) {
00112       calcAxisLogScale(&zAxis, i, a, b, c, y2);
00113       zAxis.step = 1.0;
00114     }
00115     else  calcAxisScale(&zAxis, a, b, c, zAxis.step, double(y2));
00116     zAxis.limit_min = zAxis.low;
00117     zAxis.limit_max = zAxis.up;
00118   }
00119 }
00120 
00121 // --------------------------------------------------------------
00122 int CurveDiagram::calcDiagram()
00123 {
00124   Lines.clear();
00125   Texts.clear();
00126   Arcs.clear();
00127 
00128   double GridStep, corr, zD, zDstep, GridNum;
00129   // get size of text using the screen-compatible metric
00130   QFontMetrics metrics(QucsSettings.font, 0);
00131   y1 = QucsSettings.font.pointSize() + 6;
00132 
00133   x1 = 10;      // position of label text
00134   x3 = x2 + 7;
00135   QString tmp;
00136   bool back = false;
00137   int  z, w, valid = 0;
00138 
00139   // =====  give "step" the right sign (if user made it wrong)  ==============
00140   xAxis.step = fabs(xAxis.step);
00141   if(xAxis.limit_min > xAxis.limit_max)
00142     xAxis.step *= -1.0;
00143 
00144   yAxis.step = fabs(yAxis.step);
00145   if(yAxis.limit_min > yAxis.limit_max)
00146     yAxis.step *= -1.0;
00147 
00148   zAxis.step = fabs(zAxis.step);
00149   if(zAxis.limit_min > zAxis.limit_max)
00150     zAxis.step *= -1.0;
00151 
00152 
00153   // ====  x grid  =======================================================
00154 if(xAxis.log) {
00155   if(xAxis.autoScale) {
00156     if(xAxis.max*xAxis.min <= 0.0)  goto Frame;  // invalid
00157   }
00158   else  if(xAxis.limit_min*xAxis.limit_max <= 0.0)  goto Frame;  // invalid
00159 
00160   back = calcAxisLogScale(&xAxis, z, zD, zDstep, corr, x2);
00161 
00162   if(back) z = x2;
00163   while((z <= x2) && (z >= 0)) {    // create all grid lines
00164     if(xAxis.GridOn)  if(z < x2)  if(z > 0)
00165       Lines.prepend(new Line(z, y2, z, 0, GridPen));  // x grid
00166 
00167     if((zD < 1.5*zDstep) || (z == 0) || (z == x2)) {
00168       tmp = misc::StringNiceNum(zD);
00169       if(xAxis.up < 0.0)  tmp = '-'+tmp;
00170       w = metrics.width(tmp);  // width of text
00171       // center text horizontally under the x tick mark
00172       Texts.append(new Text(z-(w>>1), -y1, tmp));
00173       Lines.append(new Line(z, 5, z, -5, QPen(Qt::black,0)));  // x tick marks
00174     }
00175 
00176     zD += zDstep;
00177     if(zD > 9.5*zDstep)  zDstep *= 10.0;
00178     if(back) {
00179       z = int(corr*log10(zD / fabs(xAxis.up)) + 0.5); // int() implies floor()
00180       z = x2 - z;
00181     }
00182     else
00183       z = int(corr*log10(zD / fabs(xAxis.low)) + 0.5);// int() implies floor()
00184   }
00185 }
00186 else {  // not logarithmical
00187   calcAxisScale(&xAxis, GridNum, zD, zDstep, GridStep, double(x2));
00188 
00189   double Expo;
00190   if(xAxis.up == 0.0)  Expo = log10(fabs(xAxis.up-xAxis.low));
00191   else  Expo = log10(fabs(xAxis.up));
00192 
00193   zD += 0.5;     // perform rounding
00194   z = int(zD);   //  "int(...)" implies "floor(...)"
00195   while((z <= x2) && (z >= 0)) {    // create all grid lines
00196     if(fabs(GridNum) < 0.01*pow(10.0, Expo)) GridNum = 0.0;// make 0 really 0
00197     tmp = misc::StringNiceNum(GridNum);
00198     w = metrics.width(tmp);  // width of text
00199     // center text horizontally under the x tick mark
00200     Texts.append(new Text(z-(w>>1), -y1, tmp)); // Text(x, y, str, ...)
00201     GridNum += GridStep;
00202 
00203     if(xAxis.GridOn)  if(z < x2)  if(z > 0)
00204       Lines.prepend(new Line(z, y2, z, 0, GridPen)); // x grid
00205     Lines.append(new Line(z, 5, z, -5, QPen(Qt::black,0)));   // x tick marks
00206     zD += zDstep;
00207     z = int(zD);
00208   }
00209   
00210   if(xAxis.up >= 0.0) if(xAxis.low <= 0.0) {  // paint origin cross ?
00211     z = int(double(x2) * fabs(xAxis.low / (xAxis.up-xAxis.low)) + 0.5);
00212     Lines.append(new Line(z, 0, z, y2, QPen(Qt::black,0)));
00213   }
00214 } // of "if(xlog) ... else ..."
00215 
00216 
00217   // ====  y grid  =======================================================
00218   if(zAxis.numGraphs > 0) if(calcYAxis(&zAxis, x2)) valid |= 2;
00219   if(yAxis.numGraphs > 0) if(calcYAxis(&yAxis, 0)) {
00220     valid |= 1;
00221     if(yAxis.up >= 0.0) if(yAxis.low <= 0.0) {  // paint origin cross ?
00222       z = int(double(y2) * fabs(yAxis.low / (yAxis.up-yAxis.low)) + 0.5);
00223       Lines.append(new Line(0, z, x2, z, QPen(Qt::black,0)));
00224     }
00225   }
00226 
00227 
00228 Frame:
00229   // outer frame
00230   Lines.append(new Line(0,  y2, x2, y2, QPen(Qt::black,0)));
00231   Lines.append(new Line(x2, y2, x2,  0, QPen(Qt::black,0)));
00232   Lines.append(new Line(0,   0, x2,  0, QPen(Qt::black,0)));
00233   Lines.append(new Line(0,  y2,  0,  0, QPen(Qt::black,0)));
00234   return valid;
00235 }
00236 
00237 // ------------------------------------------------------------
00238 bool CurveDiagram::insideDiagram(float x, float y) const
00239 {
00240   return (regionCode(x, y) == 0);
00241 }
00242 
00243 // ------------------------------------------------------------
00244 void CurveDiagram::clip(Graph::iterator &p) const
00245 {
00246   rectClip(p);
00247 }
00248 
00249 // ------------------------------------------------------------
00250 Diagram* CurveDiagram::newOne()
00251 {
00252   return new CurveDiagram();
00253 }
00254 
00255 // ------------------------------------------------------------
00256 Element* CurveDiagram::info(QString& Name, char* &BitmapFile, bool getNewOne)
00257 {
00258   Name = QObject::tr("Locus Curve");
00259   BitmapFile = (char *) "curve";
00260 
00261   if(getNewOne)  return new CurveDiagram();
00262   return 0;
00263 }
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines