Qucs-GUI
0.0.19
|
00001 /*************************************************************************** 00002 misc.cpp 00003 ---------- 00004 begin : Wed Nov 11 2004 00005 copyright : (C) 2014 by YodaLee 00006 email : lc85301@gmail.com 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 ***************************************************************************/ 00022 #ifdef HAVE_CONFIG_H 00023 # include <config.h> 00024 #endif 00025 00026 #include <cmath> 00027 #include "misc.h" 00028 #include "main.h" 00029 00030 #include <cstdio> 00031 #include <QString> 00032 #include <QStringList> 00033 #include <QRegExp> 00034 #include <QFileInfo> 00035 #include <QDir> 00036 00037 // ######################################################################### 00038 QString misc::complexRect(double real, double imag, int Precision) 00039 { 00040 QString Text; 00041 if(fabs(imag) < 1e-250) Text = QString::number(real,'g',Precision); 00042 else { 00043 Text = QString::number(imag,'g',Precision); 00044 if(Text.at(0) == '-') { 00045 Text.replace(0,1,'j'); 00046 Text = '-'+Text; 00047 } 00048 else Text = "+j"+Text; 00049 Text = QString::number(real,'g',Precision) + Text; 00050 } 00051 return Text; 00052 } 00053 00054 QString misc::complexDeg(double real, double imag, int Precision) 00055 { 00056 QString Text; 00057 if(fabs(imag) < 1e-250) Text = QString::number(real,'g',Precision); 00058 else { 00059 Text = QString::number(sqrt(real*real+imag*imag),'g',Precision) + " / "; 00060 Text += QString::number(180.0/pi*atan2(imag,real),'g',Precision) + QString::fromUtf8("°"); 00061 } 00062 return Text; 00063 } 00064 00065 QString misc::complexRad (double real, double imag, int Precision) 00066 { 00067 QString Text; 00068 if(fabs(imag) < 1e-250) Text = QString::number(real,'g',Precision); 00069 else { 00070 Text = QString::number(sqrt(real*real+imag*imag),'g',Precision); 00071 Text += " / " + QString::number(atan2(imag,real),'g',Precision) + "rad"; 00072 } 00073 return Text; 00074 } 00075 00076 // ######################################################################### 00077 QString misc::StringNum(double num, char form, int Precision) 00078 { 00079 int a = 0; 00080 char *p, Buffer[512], Format[6] = "%.00g"; 00081 00082 if(Precision < 0) { 00083 Format[1] = form; 00084 Format[2] = 0; 00085 } 00086 else { 00087 Format[4] = form; 00088 Format[2] += Precision / 10; 00089 Format[3] += Precision % 10; 00090 } 00091 sprintf(Buffer, Format, num); 00092 p = strchr(Buffer, 'e'); 00093 if(p) { 00094 p++; 00095 if(*(p++) == '+') { a = 1; } // remove '+' of exponent 00096 if(*p == '0') { a++; p++; } // remove leading zeros of exponent 00097 if(a > 0) 00098 do { 00099 *(p-a) = *p; 00100 } while(*(p++) != 0); // override characters not needed 00101 } 00102 00103 return QString(Buffer); 00104 } 00105 00106 // ######################################################################### 00107 QString misc::StringNiceNum(double num) 00108 { 00109 char Format[6] = "%.8e"; 00110 if(fabs(num) < 1e-250) return QString("0"); // avoid many problems 00111 if(fabs(log10(fabs(num))) < 3.0) Format[3] = 'g'; 00112 00113 int a = 0; 00114 char *p, *pe, Buffer[512]; 00115 00116 sprintf(Buffer, Format, num); 00117 p = pe = strchr(Buffer, 'e'); 00118 if(p) { 00119 if(*(++p) == '+') { a = 1; } // remove '+' of exponent 00120 if(*(++p) == '0') { a++; p++; } // remove leading zeros of exponent 00121 if(a > 0) 00122 do { 00123 *(p-a) = *p; 00124 } while(*(p++) != 0); // override characters not needed 00125 00126 // In 'g' format, trailing zeros are already cut off !!! 00127 p = strchr(Buffer, '.'); 00128 if(p) { 00129 if(!pe) pe = Buffer + strlen(Buffer); 00130 p = pe-1; 00131 while(*p == '0') // looking for unneccessary zero characters 00132 if((--p) <= Buffer) break; 00133 if(*p != '.') p++; // no digit after decimal point ? 00134 while( (*(p++) = *(pe++)) != 0 ) ; // overwrite zero characters 00135 } 00136 } 00137 00138 return QString(Buffer); 00139 } 00140 00141 // ######################################################################### 00142 void misc::str2num(const QString& s_, double& Number, QString& Unit, double& Factor) 00143 { 00144 QString str = s_.stripWhiteSpace(); 00145 00146 /* int i=0; 00147 bool neg = false; 00148 if(str[0] == '-') { // check sign 00149 neg = true; 00150 i++; 00151 } 00152 else if(str[0] == '+') i++; 00153 00154 double num = 0.0; 00155 for(;;) { 00156 if(str[i] >= '0') if(str[i] <= '9') { 00157 num = 10.0*num + double(str[i]-'0'); 00158 } 00159 }*/ 00160 00161 QRegExp Expr( QRegExp("[^0-9\\x2E\\x2D\\x2B]") ); 00162 int i = str.find( Expr ); 00163 if(i >= 0) 00164 if((str.at(i).latin1() | 0x20) == 'e') { 00165 int j = str.find( Expr , ++i); 00166 if(j == i) j--; 00167 i = j; 00168 } 00169 00170 Number = str.left(i).toDouble(); 00171 Unit = str.mid(i).stripWhiteSpace(); 00172 if(Unit.length()>0) 00173 { 00174 switch(Unit.at(0).latin1()) { 00175 case 'T': Factor = 1e12; break; 00176 case 'G': Factor = 1e9; break; 00177 case 'M': Factor = 1e6; break; 00178 case 'k': Factor = 1e3; break; 00179 case 'c': Factor = 1e-2; break; 00180 case 'm': Factor = 1e-3; break; 00181 case 'u': Factor = 1e-6; break; 00182 case 'n': Factor = 1e-9; break; 00183 case 'p': Factor = 1e-12; break; 00184 case 'f': Factor = 1e-15; break; 00185 // case 'd': 00186 default: Factor = 1.0; 00187 } 00188 } 00189 else 00190 { 00191 Factor = 1.0; 00192 } 00193 00194 return; 00195 } 00196 00197 // ######################################################################### 00198 QString misc::num2str(double Num) 00199 { 00200 char c = 0; 00201 double cal = fabs(Num); 00202 if(cal > 1e-20) { 00203 cal = log10(cal) / 3.0; 00204 if(cal < -0.2) cal -= 0.98; 00205 int Expo = int(cal); 00206 00207 if(Expo >= -5) if(Expo <= 4) 00208 switch(Expo) { 00209 case -5: c = 'f'; break; 00210 case -4: c = 'p'; break; 00211 case -3: c = 'n'; break; 00212 case -2: c = 'u'; break; 00213 case -1: c = 'm'; break; 00214 case 1: c = 'k'; break; 00215 case 2: c = 'M'; break; 00216 case 3: c = 'G'; break; 00217 case 4: c = 'T'; break; 00218 } 00219 00220 if(c) Num /= pow(10.0, double(3*Expo)); 00221 } 00222 00223 QString Str = QString::number(Num); 00224 if(c) Str += c; 00225 00226 return Str; 00227 } 00228 00229 // ######################################################################### 00230 void misc::convert2Unicode(QString& Text) 00231 { 00232 bool ok; 00233 int i = 0; 00234 QString n; 00235 unsigned short ch; 00236 while((i=Text.find("\\x", i)) >= 0) { 00237 n = Text.mid(i, 6); 00238 ch = n.mid(2).toUShort(&ok, 16); 00239 if(ok) Text.replace(n, QChar(ch)); 00240 i++; 00241 } 00242 Text.replace("\\n", "\n"); 00243 Text.replace("\\\\", "\\"); 00244 } 00245 00246 // ######################################################################### 00247 void misc::convert2ASCII(QString& Text) 00248 { 00249 Text.replace('\\', "\\\\"); 00250 Text.replace('\n', "\\n"); 00251 00252 int i = 0; 00253 QChar ch; 00254 char Str[8]; 00255 while(Text.size()<i) { // convert special characters 00256 if(ch > QChar(0x7F)) { 00257 sprintf(Str, "\\x%04X", ch.unicode()); 00258 Text.replace(ch, Str); 00259 } 00260 } 00261 } 00262 00263 // ######################################################################### 00264 // Converts a path to an absolute path and resolves paths relative to the 00265 // Qucs home directory 00266 QString misc::properAbsFileName(const QString& Name) 00267 { 00268 QString s = Name; 00269 QFileInfo Info(s); 00270 00271 if(Info.isRelative()) 00272 { 00273 // if it's a relative file, look for it relative to the 00274 // working directory (the qucs home directory) 00275 s = QucsSettings.QucsWorkDir.filePath(s); 00276 } 00277 // return the clean path 00278 return QDir::cleanPath(s); 00279 } 00280 00281 // ######################################################################### 00282 QString misc::properFileName(const QString& Name) 00283 { 00284 QFileInfo Info(Name); 00285 return Info.fileName(); 00286 } 00287 00288 // ######################################################################### 00289 // Takes a file name (with path) and replaces all special characters. 00290 QString misc::properName(const QString& Name) 00291 { 00292 QString s = Name; 00293 QFileInfo Info(s); 00294 if(Info.extension() == "sch") 00295 s = s.left(s.length()-4); 00296 if(s.at(0) <= '9') if(s.at(0) >= '0') 00297 s = 'n' + s; 00298 s.replace(QRegExp("\\W"), "_"); // none [a-zA-Z0-9] into "_" 00299 s.replace("__", "_"); // '__' not allowed in VHDL 00300 if(s.at(0) == '_') 00301 s = 'n' + s; 00302 return s; 00303 } 00304 00305 // ######################################################################### 00306 // Creates and returns delay time for VHDL entities. 00307 bool misc::VHDL_Delay(QString& td, const QString& Name) 00308 { 00309 if(strtod(td.latin1(), 0) != 0.0) { // delay time property 00310 if(!misc::VHDL_Time(td, Name)) 00311 return false; // time has not VHDL format 00312 td = " after " + td; 00313 return true; 00314 } 00315 else if(isalpha(td.latin1()[0])) { 00316 td = " after " + td; 00317 return true; 00318 } 00319 else { 00320 td = ""; 00321 return true; 00322 } 00323 } 00324 00325 // ######################################################################### 00326 // Checks and corrects a time (number & unit) according VHDL standard. 00327 bool misc::VHDL_Time(QString& t, const QString& Name) 00328 { 00329 char *p; 00330 double Time = strtod(t.latin1(), &p); 00331 while(*p == ' ') p++; 00332 for(;;) { 00333 if(Time >= 0.0) { 00334 if(strcmp(p, "fs") == 0) break; 00335 if(strcmp(p, "ps") == 0) break; 00336 if(strcmp(p, "ns") == 0) break; 00337 if(strcmp(p, "us") == 0) break; 00338 if(strcmp(p, "ms") == 0) break; 00339 if(strcmp(p, "sec") == 0) break; 00340 if(strcmp(p, "min") == 0) break; 00341 if(strcmp(p, "hr") == 0) break; 00342 } 00343 t = QString::fromUtf8("§") + QObject::tr("Error: Wrong time format in \"%1\". Use positive number with units").arg(Name) 00344 + " fs, ps, ns, us, ms, sec, min, hr.\n"; 00345 return false; 00346 } 00347 00348 t = QString::number(Time) + " " + QString(p); // the space is mandatory ! 00349 return true; 00350 } 00351 00352 // ######################################################################### 00353 // Returns parameters for Verilog modules. 00354 QString misc::Verilog_Param(const QString Value) 00355 { 00356 if(strtod(Value.latin1(), 0) != 0.0) { 00357 QString td = Value; 00358 if(!misc::Verilog_Time(td, "parameter")) 00359 return Value; 00360 else 00361 return td; 00362 } 00363 else 00364 return Value; 00365 } 00366 00367 // ######################################################################### 00368 // Creates and returns delay time for Verilog modules. 00369 bool misc::Verilog_Delay(QString& td, const QString& Name) 00370 { 00371 if(strtod(td.latin1(), 0) != 0.0) { // delay time property 00372 if(!misc::Verilog_Time(td, Name)) 00373 return false; // time has not Verilog format 00374 td = " #" + td; 00375 return true; 00376 } 00377 else if(isalpha(td.latin1()[0])) { 00378 td = " #" + td; 00379 return true; 00380 } 00381 else { 00382 td = ""; 00383 return true; 00384 } 00385 } 00386 00387 // ######################################################################### 00388 // Checks and corrects a time (number & unit) according Verilog standard. 00389 bool misc::Verilog_Time(QString& t, const QString& Name) 00390 { 00391 char *p; 00392 double Time = strtod(t.latin1(), &p); 00393 double factor = 1.0; 00394 while(*p == ' ') p++; 00395 for(;;) { 00396 if(Time >= 0.0) { 00397 if(strcmp(p, "fs") == 0) { factor = 1e-3; break; } 00398 if(strcmp(p, "ps") == 0) { factor = 1; break; } 00399 if(strcmp(p, "ns") == 0) { factor = 1e3; break; } 00400 if(strcmp(p, "us") == 0) { factor = 1e6; break; } 00401 if(strcmp(p, "ms") == 0) { factor = 1e9; break; } 00402 if(strcmp(p, "sec") == 0) { factor = 1e12; break; } 00403 if(strcmp(p, "min") == 0) { factor = 1e12*60; break; } 00404 if(strcmp(p, "hr") == 0) { factor = 1e12*60*60; break; } 00405 } 00406 t = QString::fromUtf8("§") + QObject::tr("Error: Wrong time format in \"%1\". Use positive number with units").arg(Name) 00407 + " fs, ps, ns, us, ms, sec, min, hr.\n"; 00408 return false; 00409 } 00410 00411 t = QString::number(Time*factor); 00412 return true; 00413 } 00414 00415 // ######################################################################### 00416 bool misc::checkVersion(QString& Line) 00417 { 00418 QStringList sl = QStringList::split('.',PACKAGE_VERSION); 00419 QStringList ll = QStringList::split('.',Line); 00420 if (ll.count() != 3 || sl.count() != 3) 00421 return false; 00422 int sv = (int)sl.at(1).toLongLong()*10000+sl.at(2).toLongLong()*100; 00423 int lv = (int)ll.at(1).toLongLong()*10000+ll.at(2).toLongLong()*100; 00424 if(lv > sv) // wrong version number ? (only backward compatible) 00425 return false; 00426 return true; 00427 }