Qucs-GUI  0.0.19
/home/travis/build/Qucs/qucs/qucs/qucs/diagrams/marker.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           marker.cpp  -  description
00003                              -------------------
00004     begin                : Sat Apr 10 2004
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 
00024 #include "marker.h"
00025 #include "diagram.h"
00026 #include "graph.h"
00027 #include "main.h"
00028 
00029 #include <QString>
00030 #include <QPainter>
00031 #include <QDebug>
00032 
00033 #include <limits.h>
00034 #include <cmath>
00035 #include <stdlib.h>
00036 
00037 #include "misc.h"
00038 
00039 static double default_Z0=50;
00040 
00049 Marker::Marker(Graph *pg_, int branchNo, int cx_, int cy_) :
00050   Element(),
00051   pGraph(pg_),
00052   Precision(3),
00053   numMode(0),
00054   Z0(default_Z0) // BUG: see declaration.
00055 {
00056   Type = isMarker;
00057   isSelected = transparent = false;
00058 
00059   cx =  cx_;
00060   cy = -cy_;
00061   fCX = float(cx);
00062   fCY = float(cy);
00063   if(!pGraph){
00064     makeInvalid();
00065   }else{
00066     initText(branchNo);   // finally create marker
00067     createText();
00068   }
00069 
00070   x1 =  cx + 60;
00071   y1 = -cy - 60;
00072 
00073 }
00074 
00075 Marker::~Marker()
00076 {
00077 }
00078 
00079 // ---------------------------------------------------------------------
00086 void Marker::initText(int n)
00087 {
00088   if(pGraph->isEmpty()) {
00089       makeInvalid();
00090       return;
00091   }
00092 
00093   Axis const *pa;
00094   assert(diag());
00095   if(pGraph->yAxisNo == 0)  pa = &(diag()->yAxis);
00096   else  pa = &(diag()->zAxis);
00097   double Dummy = 0.0;   // needed for 2D graph in 3D diagram
00098   double *px, *py=&Dummy, *pz;
00099   Text = "";
00100 
00101   bool isCross = false;
00102   int nn, nnn, m, x, y, d, dmin = INT_MAX;
00103   DataX const *pD = pGraph->axis(0);
00104   px  = pD->Points;
00105   nnn = pD->count;
00106   DataX const *pDy = pGraph->axis(1);
00107   if(pDy) {   // only for 3D diagram
00108     nn = pGraph->countY * pD->count;
00109     py  = pDy->Points;
00110     if(n >= nn) {    // is on cross grid ?
00111       isCross = true;
00112       n -= nn;
00113       n /= nnn;
00114       px += (n % nnn);
00115       if(pGraph->axis(2))   // more than 2 indep variables ?
00116         n  = (n % nnn) + (n / nnn) * nnn * pDy->count;
00117       nnn = pDy->count;
00118     }
00119     else py += (n/pD->count) % pDy->count;
00120   }
00121 
00122   // find exact marker position
00123   m  = nnn - 1;
00124   pz = pGraph->cPointsY + 2*n;
00125   for(nn=0; nn<nnn; nn++) {
00126     diag()->calcCoordinate(px, pz, py, &fCX, &fCY, pa);
00127     ++px;
00128     pz += 2;
00129     if(isCross) {
00130       px--;
00131       py++;
00132       pz += 2*(pD->count-1);
00133     }
00134     x = int(fCX+0.5) - cx;
00135     y = int(fCY+0.5) - cy;
00136     d = x*x + y*y;
00137     if(d < dmin) {
00138       dmin = d;
00139       m = nn;
00140     }
00141   }
00142   if(isCross) m *= pD->count;
00143   n += m;
00144 
00145   // why check over and over again?! do in the right place and just assert otherwise.
00146   if(VarPos.size() != pGraph->numAxes()){
00147     qDebug() << "huh, wrong size" << VarPos.size() << pGraph->numAxes();
00148     VarPos.resize(pGraph->numAxes());
00149   }
00150 
00151   // gather text of all independent variables
00152   nn = n;
00153   for(unsigned i=0; (pD = pGraph->axis(i)); ++i) {
00154     px = pD->Points + (nn % pD->count);
00155     VarPos[i] = *px;
00156     Text += pD->Var + ": " + QString::number(*px,'g',Precision) + "\n";
00157     nn /= pD->count;
00158   }
00159 
00160   // createText();
00161 }
00162 
00163 // ---------------------------------------------------------------------
00169 void Marker::createText()
00170 {
00171   if(!(pGraph->cPointsY)) {
00172     makeInvalid();
00173     return;
00174   }
00175 
00176   unsigned nVarPos = VarPos.size();
00177 
00178   if(nVarPos > pGraph->numAxes()){
00179     qDebug() << "huh, VarPos too big?!";
00180   }
00181   if(nVarPos != pGraph->numAxes()){
00182     qDebug() << "padding" << VarPos.size() << pGraph->numAxes();
00183     VarPos.resize(pGraph->numAxes());
00184     while((unsigned int)nVarPos < pGraph->numAxes()){
00185       VarPos[nVarPos++] = 0.; // pad
00186     }
00187   }
00188 
00189   // independent variables
00190   Text = "";
00191   double *pp;
00192   nVarPos = pGraph->numAxes();
00193   DataX const *pD;
00194 
00195   auto p = pGraph->findSample(VarPos);
00196   VarDep[0] = p.first;
00197   VarDep[1] = p.second;
00198 
00199   double v=0.;   // needed for 2D graph in 3D diagram
00200   double *py=&v;
00201   pD = pGraph->axis(0);
00202   if(pGraph->axis(1)) {
00203     *py = VarPos[1];
00204   }else{
00205     qDebug() << *py << "is not" << VarPos[1]; // does it really matter?!
00206   }
00207 
00208   double pz[2];
00209   pz[0] = VarDep[0];
00210   pz[1] = VarDep[1];
00211 
00212   // now actually create text.
00213   for(unsigned ii=0; (pD=pGraph->axis(ii)); ++ii) {
00214     Text += pD->Var + ": " + QString::number(VarPos[ii],'g',Precision) + "\n";
00215   }
00216 
00217   Text += pGraph->Var + ": ";
00218   switch(numMode) {
00219     case nM_Rect: Text += misc::complexRect(*pz, *(pz+1), Precision);
00220       break;
00221     case nM_Deg: Text += misc::complexDeg(*pz, *(pz+1), Precision);
00222       break;
00223     case nM_Rad: Text += misc::complexRad(*pz, *(pz+1), Precision);
00224       break;
00225   }
00226 
00227   assert(diag());
00228   Text += diag()->extraMarkerText(this);
00229 
00230   Axis const *pa;
00231   if(pGraph->yAxisNo == 0)  pa = &(diag()->yAxis);
00232   else  pa = &(diag()->zAxis);
00233   pp = &(VarPos[0]);
00234 
00235   diag()->calcCoordinate(pp, pz, py, &fCX, &fCY, pa);
00236   diag()->finishMarkerCoordinates(fCX, fCY);
00237 
00238   cx = int(fCX+0.5);
00239   cy = int(fCY+0.5);
00240   getTextSize();
00241 }
00242 
00243 // ---------------------------------------------------------------------
00244 void Marker::makeInvalid()
00245 {
00246   fCX = fCY = -1e3; // invalid coordinates
00247   assert(diag());
00248   diag()->finishMarkerCoordinates(fCX, fCY); // leave to diagram
00249   cx = int(fCX+0.5);
00250   cy = int(fCY+0.5);
00251 
00252   Text = QObject::tr("invalid");
00253   getTextSize();
00254 }
00255 
00256 // ---------------------------------------------------------------------
00257 void Marker::getTextSize()
00258 {
00259   // get size of text using the screen-compatible metric
00260   QFontMetrics metrics(QucsSettings.font, 0);
00261   QSize r = metrics.size(0, Text);
00262   x2 = r.width()+5;
00263   y2 = r.height()+5;
00264 }
00265 
00266 // ---------------------------------------------------------------------
00267 bool Marker::moveLeftRight(bool left)
00268 {
00269   int n;
00270   double *px;
00271 
00272   DataX const *pD = pGraph->axis(0);
00273   px = pD->Points;
00274   if(!px) return false;
00275   for(n=0; n<pD->count; n++) {
00276     if(VarPos[0] <= *px) break;
00277     px++;
00278   }
00279   if(n == pD->count) px--;
00280 
00281   if(left) {
00282     if(px <= pD->Points) return false;
00283     px--;  // one position to the left
00284   }
00285   else {
00286     if(px >= (pD->Points + pD->count - 1)) return false;
00287     px++;  // one position to the right
00288   }
00289   VarPos[0] = *px;
00290   createText();
00291 
00292   return true;
00293 }
00294 
00295 // ---------------------------------------------------------------------
00296 bool Marker::moveUpDown(bool up)
00297 {
00298   int n, i=0;
00299   double *px;
00300 
00301   DataX const *pD = pGraph->axis(0);
00302   if(!pD) return false;
00303 
00304   if(up) {  // move upwards ? **********************
00305     do {
00306       pD = pGraph->axis(++i);
00307       if(!pD) return false;
00308       px = pD->Points;
00309       if(!px) return false;
00310       for(n=1; n<pD->count; n++) {  // go through all data points
00311         if(fabs(VarPos[i]-(*px)) < fabs(VarPos[i]-(*(px+1)))) break;
00312         px++;
00313       }
00314 
00315     } while(px >= (pD->Points + pD->count - 1));  // go to next dimension ?
00316 
00317     px++;  // one position up
00318     VarPos[i] = *px;
00319     while(i > 1) {
00320       pD = pGraph->axis(--i);
00321       VarPos[i] = *(pD->Points);
00322     }
00323   }
00324   else {  // move downwards **********************
00325     do {
00326       pD = pGraph->axis(++i);
00327       if(!pD) return false;
00328       px = pD->Points;
00329       if(!px) return false;
00330       for(n=0; n<pD->count; n++) {
00331         if(fabs(VarPos[i]-(*px)) < fabs(VarPos[i]-(*(px+1)))) break;
00332         px++;
00333       }
00334 
00335     } while(px <= pD->Points);  // go to next dimension ?
00336 
00337     px--;  // one position down
00338     VarPos[i] = *px;
00339     while(i > 1) {
00340       pD = pGraph->axis(--i);
00341       VarPos[i] = *(pD->Points + pD->count - 1);
00342     }
00343   }
00344   createText();
00345 
00346   return true;
00347 }
00348 
00349 // ---------------------------------------------------------------------
00350 void Marker::paint(ViewPainter *p, int x0, int y0)
00351 {
00352   // keep track of painter state
00353   p->Painter->save();
00354 
00355   // Workaround for bug in Qt: If WorldMatrix is turned off, \n in the
00356   // text creates a terrible mess.
00357   p->Painter->setWorldMatrixEnabled(true);
00358   QMatrix wm = p->Painter->worldMatrix();
00359   p->Painter->setWorldMatrix(QMatrix());
00360 
00361   int x2_, y2_;
00362   p->Painter->setPen(QPen(Qt::black,1));
00363   x2_ = p->drawText(Text, x0+x1+3, y0+y1+3, &y2_);
00364   x2_ += int(6.0*p->Scale);
00365   y2_ += int(6.0*p->Scale);
00366   if(!transparent) {
00367     p->eraseRect(x0+x1, y0+y1, x2_, y2_);
00368     p->drawText(Text, x0+x1+3, y0+y1+3);
00369   }
00370   p->Painter->setWorldMatrix(wm);
00371   p->Painter->setWorldMatrixEnabled(false);
00372 
00373   // restore painter state
00374   p->Painter->restore();
00375 
00376   p->Painter->setPen(QPen(Qt::darkMagenta,0));
00377   p->drawRectD(x0+x1, y0+y1, x2_, y2_);
00378 
00379   x2 = int(float(x2_) / p->Scale);
00380   y2 = int(float(y2_) / p->Scale);
00381 
00382   int x1_, y1_;
00383   p->map(x0+x1, y0+y1, x1_, y1_);
00384   // which corner of rectangle should be connected to line ?
00385   if(cx < x1+(x2>>1)) {
00386     if(-cy >= y1+(y2>>1))
00387       y1_ += y2_ - 1;
00388   }
00389   else {
00390     x1_ += x2_ - 1;
00391     if(-cy >= y1+(y2>>1))
00392       y1_ += y2_ - 1;
00393   }
00394   float fx2, fy2;
00395   fx2 = (float(x0)+fCX)*p->Scale + p->DX;
00396   fy2 = (float(y0)-fCY)*p->Scale + p->DY;
00397   p->Painter->drawLine(x1_, y1_, TO_INT(fx2), TO_INT(fy2));
00398 
00399   if(isSelected) {
00400     p->Painter->setPen(QPen(Qt::darkGray,3));
00401     p->drawRoundRect(x0+x1-3, y0+y1-3, x2+6, y2+6);
00402   }
00403 }
00404 
00405 // ---------------------------------------------------------------------
00406 void Marker::paintScheme(QPainter *p)
00407 {
00408   assert(diag());
00409   int x0 = diag()->cx;
00410   int y0 = diag()->cy;
00411   p->drawRect(x0+x1, y0+y1, x2, y2);
00412 
00413   // which corner of rectangle should be connected to line ?
00414   if(cx < x1+(x2>>1)) {
00415     if(-cy < y1+(y2>>1))
00416       p->drawLine(x0+cx, y0-cy, x0+x1, y0+y1);
00417     else
00418       p->drawLine(x0+cx, y0-cy, x0+x1, y0+y1+y2-1);
00419   }
00420   else {
00421     if(-cy < y1+(y2>>1))
00422       p->drawLine(x0+cx, y0-cy, x0+x1+x2-1, y0+y1);
00423     else
00424       p->drawLine(x0+cx, y0-cy, x0+x1+x2-1, y0+y1+y2-1);
00425   }
00426 }
00427 
00428 // ------------------------------------------------------------
00429 void Marker::setCenter(int x, int y, bool relative)
00430 {
00431   if(relative) {
00432     x1 += x;  y1 += y;
00433   }
00434   else {
00435     x1 = x;  y1 = y;
00436   }
00437 }
00438 
00439 // -------------------------------------------------------
00440 void Marker::Bounding(int& _x1, int& _y1, int& _x2, int& _y2)
00441 {
00442   if(diag()) {
00443     _x1 = diag()->cx + x1;
00444     _y1 = diag()->cy + y1;
00445     _x2 = diag()->cx + x1+x2;
00446     _y2 = diag()->cy + y1+y2;
00447   }
00448   else {
00449     _x1 = x1;
00450     _y1 = y1+y2;
00451     _x2 = x1+x2;
00452     _y2 = y1;
00453   }
00454 }
00455 
00456 // ---------------------------------------------------------------------
00457 QString Marker::save()
00458 {
00459   QString s  = "<Mkr ";
00460 
00461   for(auto i : VarPos){
00462     s += QString::number(i)+"/";
00463   }
00464   s.replace(s.length()-1,1,' ');
00465   //s.at(s.length()-1) = (const QChar&)' ';
00466 
00467   s += QString::number(x1) +" "+ QString::number(y1) +" "
00468       +QString::number(Precision) +" "+ QString::number(numMode);
00469   if(transparent)  s += " 1>";
00470   else  s += " 0>";
00471 
00472   return s;
00473 }
00474 
00475 // ---------------------------------------------------------------------
00476 // All graphs must have been loaded before this function !
00477 bool Marker::load(const QString& _s)
00478 {
00479   bool ok;
00480   QString s = _s;
00481 
00482   if(s.at(0) != '<') return false;
00483   if(s.at(s.length()-1) != '>') return false;
00484   s = s.mid(1, s.length()-2);   // cut off start and end character
00485 
00486   if(s.section(' ',0,0) != "Mkr") return false;
00487 
00488   int i=0, j;
00489   QString n = s.section(' ',1,1);    // VarPos
00490 
00491   unsigned nVarPos = 0;
00492   j = (n.count('/') + 3);
00493   VarPos.resize(j);
00494 
00495   do {
00496     j = n.indexOf('/', i);
00497     VarPos[nVarPos++] = n.mid(i,j-i).toDouble(&ok);
00498     if(!ok) return false;
00499     i = j+1;
00500   } while(j >= 0);
00501 
00502   n  = s.section(' ',2,2);    // x1
00503   x1 = n.toInt(&ok);
00504   if(!ok) return false;
00505 
00506   n  = s.section(' ',3,3);    // y1
00507   y1 = n.toInt(&ok);
00508   if(!ok) return false;
00509 
00510   n  = s.section(' ',4,4);      // Precision
00511   Precision = n.toInt(&ok);
00512   if(!ok) return false;
00513 
00514   n  = s.section(' ',5,5);      // numMode
00515   numMode = n.toInt(&ok);
00516   if(!ok) return false;
00517 
00518   n  = s.section(' ',6,6);      // transparent
00519   if(n.isEmpty()) return true;  // is optional
00520   if(n == "0")  transparent = false;
00521   else  transparent = true;
00522 
00523   return true;
00524 }
00525 
00526 // ------------------------------------------------------------------------
00527 // Checks if the coordinates x/y point to the marker text. x/y are relative
00528 // to diagram cx/cy.
00529 bool Marker::getSelected(int x_, int y_)
00530 {
00531   if(x_ >= x1) if(x_ <= x1+x2) if(y_ >= y1) if(y_ <= y1+y2)
00532     return true;
00533 
00534   return false;
00535 }
00536 
00537 // ------------------------------------------------------------------------
00538 /*
00539  * the diagram this belongs to
00540  */
00541 const Diagram* Marker::diag() const
00542 {
00543   if(!pGraph) return NULL;
00544   return pGraph->parentDiagram();
00545 }
00546 
00547 // ------------------------------------------------------------------------
00548 Marker* Marker::sameNewOne(Graph *pGraph_)
00549 {
00550   Marker *pm = new Marker(pGraph_, 0, cx ,cy);
00551 
00552   pm->x1 = x1;  pm->y1 = y1;
00553   pm->x2 = x2;  pm->y2 = y2;
00554 
00555   pm->VarPos = VarPos;
00556 
00557   pm->Text        = Text;
00558   pm->transparent = transparent;
00559   pm->Precision   = Precision;
00560   pm->numMode     = numMode;
00561 
00562   return pm;
00563 }
00564 
00565 // vim:ts=8:sw=2:noet
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines