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