Qucs-GUI  0.0.18
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
marker.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  marker.cpp - description
3  -------------------
4  begin : Sat Apr 10 2004
5  copyright : (C) 2003 by Michael Margraf
6  email : michael.margraf@alumni.tu-berlin.de
7  ***************************************************************************/
8 
9 /***************************************************************************
10  * *
11  * This program is free software; you can redistribute it and/or modify *
12  * it under the terms of the GNU General Public License as published by *
13  * the Free Software Foundation; either version 2 of the License, or *
14  * (at your option) any later version. *
15  * *
16  ***************************************************************************/
17 #include <QtGui>
18 #include "marker.h"
19 #include "diagram.h"
20 #include "graph.h"
21 #include "main.h"
22 #include "../dialogs/matchdialog.h" //For r2z function
23 
24 #include <QString>
25 #include <QWidget>
26 #include <QPainter>
27 
28 #include <limits.h>
29 #include <math.h>
30 #include <stdlib.h>
31 
32 
33 #include "qucs.h"
34 #include "schematic.h"
35 
36 
37 
38 Marker::Marker(Diagram *Diag_, Graph *pg_, int _nn, int cx_, int cy_)
39 {
40  Type = isMarker;
41  isSelected = transparent = false;
42 
43  Diag = Diag_;
44  pGraph = pg_;
45  Precision = 3; // before createText()
46  VarPos = 0;
47  numMode = nVarPos = 0;
48  cx = cx_;
49  cy = -cy_;
50  fCX = float(cx);
51  fCY = float(cy);
52  Z0 = 50; //Used for Smith chart marker, to calculate impedance
53  if(!pGraph) makeInvalid();
54  else initText(_nn); // finally create marker
55 
56  x1 = cx + 60;
57  y1 = -cy - 60;
58 
59 }
60 
62 {
63  if(VarPos) free(VarPos);
64 }
65 
66 // ---------------------------------------------------------------------
67 void Marker::initText(int n)
68 {
69  if(pGraph->cPointsX.isEmpty()) {
70  makeInvalid();
71  return;
72  }
73 
74  Axis *pa;
75  if(pGraph->yAxisNo == 0) pa = &(Diag->yAxis);
76  else pa = &(Diag->zAxis);
77  double Dummy = 0.0; // needed for 2D graph in 3D diagram
78  double *px, *py=&Dummy, *pz;
79  Text = "";
80 
81  bool isCross = false;
82  int nn, nnn, m, x, y, d, dmin = INT_MAX;
83  DataX *pD = pGraph->cPointsX.first();
84  px = pD->Points;
85  nnn = pD->count;
86  DataX *pDy = pGraph->cPointsX.next();
87  if(pDy) { // only for 3D diagram
88  nn = pGraph->countY * pD->count;
89  py = pDy->Points;
90  if(n >= nn) { // is on cross grid ?
91  isCross = true;
92  n -= nn;
93  n /= nnn;
94  px += (n % nnn);
95  if(pGraph->cPointsX.next()) // more than 2 indep variables ?
96  n = (n % nnn) + (n / nnn) * nnn * pDy->count;
97  nnn = pDy->count;
98  }
99  else py += (n/pD->count) % pDy->count;
100  }
101 
102  // find exact marker position
103  m = nnn - 1;
104  pz = pGraph->cPointsY + 2*n;
105  for(nn=0; nn<nnn; nn++) {
106  Diag->calcCoordinate(px, pz, py, &fCX, &fCY, pa);
107  if(isCross) {
108  px--;
109  py++;
110  pz += 2*(pD->count-1);
111  }
112  x = int(fCX+0.5) - cx;
113  y = int(fCY+0.5) - cy;
114  d = x*x + y*y;
115  if(d < dmin) {
116  dmin = d;
117  m = nn;
118  }
119  }
120  if(isCross) m *= pD->count;
121  n += m;
122 
123  nVarPos = 0;
124  nn = (pGraph->cPointsX.count() + 2) * sizeof(double);
125  if(VarPos)
126  VarPos = (double*)realloc(VarPos, nn);
127  else
128  VarPos = (double*)malloc(nn);
129 
130  // gather text of all independent variables
131  nn = n;
132  for(pD = pGraph->cPointsX.first(); pD!=0; pD = pGraph->cPointsX.next()) {
133  px = pD->Points + (nn % pD->count);
134  VarPos[nVarPos++] = *px;
135  Text += pD->Var + ": " + QString::number(*px,'g',Precision) + "\n";
136  nn /= pD->count;
137  }
138 
139  // gather text of dependent variable
140  pz = pGraph->cPointsY + 2*n;
141  Text += pGraph->Var + ": ";
142  switch(numMode) {
143  case 0: Text += complexRect(*pz, *(pz+1), Precision);
144  break;
145  case 1: Text += complexDeg(*pz, *(pz+1), Precision);
146  break;
147  case 2: Text += complexRad(*pz, *(pz+1), Precision);
148  break;
149  }
150  VarPos[nVarPos] = *pz;
151  VarPos[nVarPos+1] = *(pz+1);
152  if(Diag->Name=="Smith") //impedance is useful as well here
153  {
154  double Zr, Zi;
155  Zr = *pz;
156  Zi = *(pz+1);
157 
158  MatchDialog::r2z(Zr, Zi, Z0);
159  QString Var = pGraph->Var;
160  if(Var.startsWith("S"))
161  Text += "\n"+ Var.replace('S', 'Z')+": " +complexRect(Zr, Zi, Precision);
162  else
163  Text += "\nZ("+ Var+"): " +complexRect(Zr, Zi, Precision);
164  }
165  px = VarPos;
166  if(py != &Dummy) // 2D in 3D diagram ?
167  py = VarPos + 1;
168  Diag->calcCoordinate(px, pz, py, &fCX, &fCY, pa);
169 
170  if(!Diag->insideDiagram(fCX, fCY)) {
171  // if marker out of valid bounds, point to origin
172  if((Diag->Name.left(4) != "Rect") && (Diag->Name != "Curve")) {
173  fCX = float(Diag->x2 >> 1);
174  fCY = float(Diag->y2 >> 1);
175  }
176  else
177  fCX = fCY = 0.0;
178  }
179 
180  cx = int(fCX+0.5);
181  cy = int(fCY+0.5);
183 }
184 
185 // ---------------------------------------------------------------------
187 {
188  if(!(pGraph->cPointsY)) {
189  makeInvalid();
190  return;
191  }
192 
193  VarPos = (double*)realloc(VarPos,
194  (pGraph->cPointsX.count() + 2) * sizeof(double));
195 
196  while((unsigned int)nVarPos < pGraph->cPointsX.count())
197  VarPos[nVarPos++] = 0.0; // fill up VarPos
198 
199 
200  // independent variables
201  Text = "";
202  double *pp, v;
203  int n = 0, m = 1, i;
204  DataX *pD;
205  nVarPos = 0;
206  for(pD = pGraph->cPointsX.first(); pD!=0; pD = pGraph->cPointsX.next()) {
207  pp = pD->Points;
208  v = VarPos[nVarPos];
209  for(i=pD->count; i>1; i--) { // find appropiate marker position
210  if(fabs(v-(*pp)) < fabs(v-(*(pp+1)))) break;
211  pp++;
212  n += m;
213  }
214 
215  m *= pD->count;
216  VarPos[nVarPos++] = *pp;
217  Text += pD->Var + ": " + QString::number(*pp,'g',Precision) + "\n";
218  }
219 
220 
221  v = 0.0; // needed for 2D graph in 3D diagram
222  double *py=&v, *pz = pGraph->cPointsY + 2*n;
223  pD = pGraph->cPointsX.first();
224  if(pGraph->cPointsX.next()) {
225  py = pGraph->cPointsX.current()->Points; // only for 3D diagram
226  py += (n / pD->count) % pGraph->cPointsX.current()->count;
227  }
228 
229  Text += pGraph->Var + ": ";
230  switch(numMode) {
231  case 0: Text += complexRect(*pz, *(pz+1), Precision);
232  break;
233  case 1: Text += complexDeg(*pz, *(pz+1), Precision);
234  break;
235  case 2: Text += complexRad(*pz, *(pz+1), Precision);
236  break;
237  }
238  if(Diag->Name=="Smith") //impedance is useful as well here
239  {
240  double Zr, Zi;
241  Zr = *pz;
242  Zi = *(pz+1);
243 
244  MatchDialog::r2z(Zr, Zi, Z0);
245  QString Var = pGraph->Var;
246  if(Var.startsWith("S"))
247  Text += "\n"+ Var.replace('S', 'Z')+": " +complexRect(Zr, Zi, Precision);
248  else
249  Text += "\nZ("+ Var+"): " +complexRect(Zr, Zi, Precision);
250  }
251  VarPos[nVarPos] = *pz;
252  VarPos[nVarPos+1] = *(pz+1);
253 
254  Axis *pa;
255  if(pGraph->yAxisNo == 0) pa = &(Diag->yAxis);
256  else pa = &(Diag->zAxis);
257  pp = &(VarPos[0]);
258 
259  Diag->calcCoordinate(pp, pz, py, &fCX, &fCY, pa);
260 
261  if(!Diag->insideDiagram(fCX, fCY)) {
262  // if marker out of valid bounds, point to origin
263  if((Diag->Name.left(4) != "Rect") && (Diag->Name != "Curve")) {
264  fCX = float(Diag->x2 >> 1);
265  fCY = float(Diag->y2 >> 1);
266  }
267  else
268  fCX = fCY = 0.0;
269  }
270 
271  cx = int(fCX+0.5);
272  cy = int(fCY+0.5);
274 }
275 
276 // ---------------------------------------------------------------------
278 {
279  cx = 0;
280  cy = 0;
281  if(Diag) if(Diag->Name.left(4) != "Rect") if(Diag->Name != "Curve") {
282  cx = Diag->x2 >> 1;
283  cy = Diag->y2 >> 1;
284  }
285  Text = QObject::tr("invalid");
286 
287  fCX = float(cx);
288  fCY = float(cy);
290 }
291 
292 // ---------------------------------------------------------------------
293 void Marker::getTextSize(const QFont& Font)
294 {
295  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
296  QSize r = metrics.size(0, Text);
297  x2 = r.width()+5;
298  y2 = r.height()+5;
299 }
300 
301 // ---------------------------------------------------------------------
302 bool Marker::moveLeftRight(bool left)
303 {
304  int n;
305  double *px;
306 
307  DataX *pD = pGraph->cPointsX.getFirst();
308  px = pD->Points;
309  if(!px) return false;
310  for(n=0; n<pD->count; n++) {
311  if(VarPos[0] <= *px) break;
312  px++;
313  }
314  if(n == pD->count) px--;
315 
316  if(left) {
317  if(px <= pD->Points) return false;
318  px--; // one position to the left
319  }
320  else {
321  if(px >= (pD->Points + pD->count - 1)) return false;
322  px++; // one position to the right
323  }
324  VarPos[0] = *px;
325  createText();
326 
327  return true;
328 }
329 
330 // ---------------------------------------------------------------------
331 bool Marker::moveUpDown(bool up)
332 {
333  int n, i=0;
334  double *px;
335 
336  DataX *pD = pGraph->cPointsX.first();
337  if(!pD) return false;
338 
339  if(up) { // move upwards ? **********************
340  do {
341  i++;
342  pD = pGraph->cPointsX.next();
343  if(!pD) return false;
344  px = pD->Points;
345  if(!px) return false;
346  for(n=1; n<pD->count; n++) { // go through all data points
347  if(fabs(VarPos[i]-(*px)) < fabs(VarPos[i]-(*(px+1)))) break;
348  px++;
349  }
350 
351  } while(px >= (pD->Points + pD->count - 1)); // go to next dimension ?
352 
353  px++; // one position up
354  VarPos[i] = *px;
355  while(i > 1) {
356  pD = pGraph->cPointsX.prev();
357  i--;
358  VarPos[i] = *(pD->Points);
359  }
360  }
361  else { // move downwards **********************
362  do {
363  i++;
364  pD = pGraph->cPointsX.next();
365  if(!pD) return false;
366  px = pD->Points;
367  if(!px) return false;
368  for(n=0; n<pD->count; n++) {
369  if(fabs(VarPos[i]-(*px)) < fabs(VarPos[i]-(*(px+1)))) break;
370  px++;
371  }
372 
373  } while(px <= pD->Points); // go to next dimension ?
374 
375  px--; // one position down
376  VarPos[i] = *px;
377  while(i > 1) {
378  pD = pGraph->cPointsX.prev();
379  i--;
380  VarPos[i] = *(pD->Points + pD->count - 1);
381  }
382  }
383  createText();
384 
385  return true;
386 }
387 
388 // ---------------------------------------------------------------------
389 void Marker::paint(ViewPainter *p, int x0, int y0)
390 {
391  // keep track of painter state
392  p->Painter->save();
393 
394  // Workaround for bug in Qt: If WorldMatrix is turned off, \n in the
395  // text creates a terrible mess.
396  p->Painter->setWorldXForm(true);
397  QMatrix wm = p->Painter->worldMatrix();
398  p->Painter->setWorldMatrix(QMatrix());
399 
400  int x2_, y2_;
401  p->Painter->setPen(QPen(Qt::black,1));
402  x2_ = p->drawText(Text, x0+x1+3, y0+y1+3, &y2_);
403  x2_ += int(6.0*p->Scale);
404  y2_ += int(6.0*p->Scale);
405  if(!transparent) {
406  p->eraseRect(x0+x1, y0+y1, x2_, y2_);
407  p->drawText(Text, x0+x1+3, y0+y1+3);
408  }
409  p->Painter->setWorldMatrix(wm);
410  p->Painter->setWorldXForm(false);
411 
412  // restore painter state
413  p->Painter->restore();
414 
415  p->Painter->setPen(QPen(Qt::darkMagenta,0));
416  p->drawRectD(x0+x1, y0+y1, x2_, y2_);
417 
418  x2 = int(float(x2_) / p->Scale);
419  y2 = int(float(y2_) / p->Scale);
420 
421  int x1_, y1_;
422  p->map(x0+x1, y0+y1, x1_, y1_);
423  // which corner of rectangle should be connected to line ?
424  if(cx < x1+(x2>>1)) {
425  if(-cy >= y1+(y2>>1))
426  y1_ += y2_ - 1;
427  }
428  else {
429  x1_ += x2_ - 1;
430  if(-cy >= y1+(y2>>1))
431  y1_ += y2_ - 1;
432  }
433  float fx2, fy2;
434  fx2 = (float(x0)+fCX)*p->Scale + p->DX;
435  fy2 = (float(y0)-fCY)*p->Scale + p->DY;
436  p->Painter->drawLine(x1_, y1_, TO_INT(fx2), TO_INT(fy2));
437 
438  if(isSelected) {
439  p->Painter->setPen(QPen(Qt::darkGray,3));
440  p->drawRoundRect(x0+x1-3, y0+y1-3, x2+6, y2+6);
441  }
442 }
443 
444 // ---------------------------------------------------------------------
445 void Marker::paintScheme(QPainter *p)
446 {
447  int x0 = Diag->cx;
448  int y0 = Diag->cy;
449  p->drawRect(x0+x1, y0+y1, x2, y2);
450 
451  // which corner of rectangle should be connected to line ?
452  if(cx < x1+(x2>>1)) {
453  if(-cy < y1+(y2>>1))
454  p->drawLine(x0+cx, y0-cy, x0+x1, y0+y1);
455  else
456  p->drawLine(x0+cx, y0-cy, x0+x1, y0+y1+y2-1);
457  }
458  else {
459  if(-cy < y1+(y2>>1))
460  p->drawLine(x0+cx, y0-cy, x0+x1+x2-1, y0+y1);
461  else
462  p->drawLine(x0+cx, y0-cy, x0+x1+x2-1, y0+y1+y2-1);
463  }
464 }
465 
466 // ------------------------------------------------------------
467 void Marker::setCenter(int x, int y, bool relative)
468 {
469  if(relative) {
470  x1 += x; y1 += y;
471  }
472  else {
473  x1 = x; y1 = y;
474  }
475 }
476 
477 // -------------------------------------------------------
478 void Marker::Bounding(int& _x1, int& _y1, int& _x2, int& _y2)
479 {
480  if(Diag) {
481  _x1 = Diag->cx + x1;
482  _y1 = Diag->cy + y1;
483  _x2 = Diag->cx + x1+x2;
484  _y2 = Diag->cy + y1+y2;
485  }
486  else {
487  _x1 = x1;
488  _y1 = y1+y2;
489  _x2 = x1+x2;
490  _y2 = y1;
491  }
492 }
493 
494 // ---------------------------------------------------------------------
495 QString Marker::save()
496 {
497  QString s = "<Mkr ";
498 
499  for(int i=0; i<nVarPos; i++)
500  s += QString::number(VarPos[i])+"/";
501  s.replace(s.length()-1,1,' ');
502  //s.at(s.length()-1) = (const QChar&)' ';
503 
504  s += QString::number(x1) +" "+ QString::number(y1) +" "
505  +QString::number(Precision) +" "+ QString::number(numMode);
506  if(transparent) s += " 1>";
507  else s += " 0>";
508 
509  return s;
510 }
511 
512 // ---------------------------------------------------------------------
513 // All graphs must have been loaded before this function !
514 bool Marker::load(const QString& _s)
515 {
516  bool ok;
517  QString s = _s;
518 
519  if(s.at(0) != '<') return false;
520  if(s.at(s.length()-1) != '>') return false;
521  s = s.mid(1, s.length()-2); // cut off start and end character
522 
523  if(s.section(' ',0,0) != "Mkr") return false;
524 
525  int i=0, j;
526  QString n = s.section(' ',1,1); // VarPos
527 
528  nVarPos = 0;
529  j = (n.count('/') + 3) * sizeof(double);
530  if(VarPos)
531  VarPos = (double*)realloc(VarPos, j);
532  else
533  VarPos = (double*)malloc(j);
534 
535  do {
536  j = n.find('/', i);
537  VarPos[nVarPos++] = n.mid(i,j-i).toDouble(&ok);
538  if(!ok) return false;
539  i = j+1;
540  } while(j >= 0);
541 
542  n = s.section(' ',2,2); // x1
543  x1 = n.toInt(&ok);
544  if(!ok) return false;
545 
546  n = s.section(' ',3,3); // y1
547  y1 = n.toInt(&ok);
548  if(!ok) return false;
549 
550  n = s.section(' ',4,4); // Precision
551  Precision = n.toInt(&ok);
552  if(!ok) return false;
553 
554  n = s.section(' ',5,5); // numMode
555  numMode = n.toInt(&ok);
556  if(!ok) return false;
557 
558  n = s.section(' ',6,6); // transparent
559  if(n.isEmpty()) return true; // is optional
560  if(n == "0") transparent = false;
561  else transparent = true;
562 
563  return true;
564 }
565 
566 // ------------------------------------------------------------------------
567 // Checks if the coordinates x/y point to the marker text. x/y are relative
568 // to diagram cx/cy.
569 bool Marker::getSelected(int x_, int y_)
570 {
571  if(x_ >= x1) if(x_ <= x1+x2) if(y_ >= y1) if(y_ <= y1+y2)
572  return true;
573 
574  return false;
575 }
576 
577 // ------------------------------------------------------------------------
579 {
580  Marker *pm = new Marker(Diag, pGraph_, 0, cx ,cy);
581 
582  pm->x1 = x1; pm->y1 = y1;
583  pm->x2 = x2; pm->y2 = y2;
584 
585  int z = (nVarPos+2) * sizeof(double);
586  if(pm->VarPos)
587  pm->VarPos = (double*)realloc(pm->VarPos, z);
588  else
589  pm->VarPos = (double*)malloc(z);
590 
591  pm->nVarPos = nVarPos;
592  for(z=0; z<nVarPos; z++)
593  pm->VarPos[z] = VarPos[z];
594 
595  pm->Text = Text;
596  pm->transparent = transparent;
597  pm->Precision = Precision;
598  pm->numMode = numMode;
599 
600  return pm;
601 }
virtual bool insideDiagram(float, float)
Definition: diagram.cpp:305
QPainter * Painter
Definition: viewpainter.h:58
int Type
Definition: element.h:152
double * VarPos
Definition: marker.h:55
QString save()
Definition: marker.cpp:495
bool moveUpDown(bool)
Definition: marker.cpp:331
int countY
Definition: graph.h:74
float fCX
Definition: marker.h:56
void setCenter(int, int, bool)
Definition: marker.cpp:467
int y1
Definition: element.h:153
int count
Definition: graph.h:53
void makeInvalid()
Definition: marker.cpp:277
QFont font
Definition: main.h:46
Definition: graph.h:57
float Scale
Definition: viewpainter.h:59
QString Name
Definition: diagram.h:92
void map(int, int, int &, int &)
Definition: viewpainter.cpp:63
tQucsSettings QucsSettings
Definition: main.cpp:52
void paint(ViewPainter *, int, int)
Definition: marker.cpp:389
QString Text
Definition: marker.h:58
int y2
Definition: element.h:153
Definition: marker.h:31
QString complexDeg(double real, double imag, int Precision)
Definition: main.cpp:240
void Bounding(int &_x1, int &_y1, int &_x2, int &_y2)
Definition: marker.cpp:478
int x1
Definition: element.h:153
QString Var
Definition: graph.h:50
void getTextSize(const QFont &)
Definition: marker.cpp:293
Definition: graph.h:47
QString Var
Definition: graph.h:75
Definitions and declarations for the main application.
void initText(int)
Definition: marker.cpp:67
QucsApp * QucsMain
Definition: main.cpp:54
Marker * sameNewOne(Graph *)
Definition: marker.cpp:578
int cx
Definition: element.h:153
QString complexRad(double real, double imag, int Precision)
Definition: main.cpp:251
~Marker()
Definition: marker.cpp:61
virtual void calcCoordinate(double *&, double *&, double *&, float *, float *, Axis *)
Definition: diagram.h:68
bool isSelected
Definition: element.h:151
int drawText(const QString &, int, int, int *Height=0)
void paintScheme(QPainter *)
Definition: marker.cpp:445
Axis zAxis
Definition: diagram.h:101
QString complexRect(double real, double imag, int Precision)
Definition: main.cpp:224
void drawRoundRect(int, int, int, int)
Definition: diagram.h:47
double Z0
Definition: marker.h:63
Definition: element.h:82
int nVarPos
Definition: marker.h:54
#define TO_INT(f)
Definition: viewpainter.h:23
bool moveLeftRight(bool)
Definition: marker.cpp:302
static void r2z(double &, double &, double)
QTabWidget * DocumentTab
Definition: qucs.h:164
Marker(Diagram *Diag_, Graph *pg_=0, int _nn=0, int cx_=0, int cy_=0)
Definition: marker.cpp:38
int cy
Definition: element.h:153
Axis yAxis
Definition: diagram.h:101
int numMode
Definition: marker.h:62
int Precision
Definition: marker.h:61
void createText()
Definition: marker.cpp:186
bool transparent
Definition: marker.h:59
void drawRectD(int, int, int, int)
double * Points
Definition: graph.h:52
Q3PtrList< DataX > cPointsX
Definition: graph.h:71
void eraseRect(int, int, int, int)
int x2
Definition: element.h:153
double * cPointsY
Definition: graph.h:72
float fCY
Definition: marker.h:56
bool getSelected(int, int)
Definition: marker.cpp:569
Diagram * Diag
Definition: marker.h:51
#define isMarker
Definition: element.h:117
Graph * pGraph
Definition: marker.h:52
int yAxisNo
Definition: graph.h:70
bool load(const QString &Line)
Definition: marker.cpp:514