Qucs-GUI  0.0.18
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
diagram.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  diagram.cpp
3  -------------
4  begin : Thu Oct 2 2003
5  copyright : (C) 2003, 2004, 2005 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 
18 #if HAVE_CONFIG_H
19 # include <config.h>
20 #endif
21 #include <QtGui>
22 #include <stdlib.h>
23 #include <math.h>
24 #include <float.h>
25 #if HAVE_IEEEFP_H
26 # include <ieeefp.h>
27 #endif
28 #include <locale.h>
29 
30 #include <QTextStream>
31 #include <QMessageBox>
32 #include <QRegExp>
33 #include <QDateTime>
34 
35 #include "diagram.h"
36 #include "qucs.h"
37 #include "main.h"
38 #include "mnemo.h"
39 #include "schematic.h"
40 
41 #include "rect3ddiagram.h"
42 
43 using namespace std;
44 
45 Diagram::Diagram(int _cx, int _cy)
46 {
47  cx = _cx; cy = _cy;
48 
49  // x1, x2, y1, y2 are the selectable boundings of the diagram, but these
50  // are the real boundings. They are set in "createAxisLabels()".
51  Bounding_x1 = Bounding_x2 = Bounding_y1 = Bounding_y2 = 0;
52 
53  xAxis.numGraphs = yAxis.numGraphs = zAxis.numGraphs = 0;
54  xAxis.min = xAxis.low =
55  yAxis.min = yAxis.low = zAxis.min = zAxis.low = 0.0;
56  xAxis.max = xAxis.up =
57  yAxis.max = yAxis.up = zAxis.max = zAxis.up = 1.0;
58  xAxis.GridOn = yAxis.GridOn = true;
59  zAxis.GridOn = false;
60  xAxis.log = yAxis.log = zAxis.log = false;
61 
62  xAxis.limit_min = yAxis.limit_min = zAxis.limit_min = 0.0;
63  xAxis.limit_max = yAxis.limit_max = zAxis.limit_max = 1.0;
64  xAxis.step = yAxis.step = zAxis.step = 1.0;
65  xAxis.autoScale = yAxis.autoScale = zAxis.autoScale = true;
66 
67  rotX = 315; // for 3D diagram
68  rotY = 0;
69  rotZ = 225;
70  hideLines = true; // hide invisible lines
71 
72  Type = isDiagram;
73  isSelected = false;
74  GridPen = QPen(Qt::lightGray,0);
75  Graphs.setAutoDelete(true);
76  Arcs.setAutoDelete(true);
77  Lines.setAutoDelete(true);
78  Texts.setAutoDelete(true);
79 }
80 
82 {
83 }
84 
85 // ------------------------------------------------------------
86 // Paint function for most diagrams (cartesian, smith, polar, ...)
88 {
89  // paint all lines
90  for(Line *pl = Lines.first(); pl != 0; pl = Lines.next()) {
91  p->Painter->setPen(pl->style);
92  p->drawLine(cx+pl->x1, cy-pl->y1, cx+pl->x2, cy-pl->y2);
93  }
94 
95  // paint all arcs (1 pixel larger to compensate for strange circle method)
96  for(struct Arc *pa = Arcs.first(); pa != 0; pa = Arcs.next()) {
97  p->Painter->setPen(pa->style);
98  p->drawArc(cx+pa->x, cy-pa->y, pa->w, pa->h, pa->angle, pa->arclen);
99  }
100 
101  Graph *pg;
102  // draw all graphs
103  for(pg = Graphs.first(); pg != 0; pg = Graphs.next())
104  pg->paint(p, cx, cy);
105 
106  // keep track of painter state
107  p->Painter->save();
108 
109  // write whole text (axis label inclusively)
110  QMatrix wm = p->Painter->worldMatrix();
111  for(Text *pt = Texts.first(); pt != 0; pt = Texts.next()) {
112  p->Painter->setWorldMatrix(
113  QMatrix(pt->mCos, -pt->mSin, pt->mSin, pt->mCos,
114  p->DX + float(cx+pt->x) * p->Scale,
115  p->DY + float(cy-pt->y) * p->Scale));
116 
117  p->Painter->setPen(pt->Color);
118  p->Painter->drawText(0, 0, pt->s);
119  }
120  p->Painter->setWorldMatrix(wm);
121  p->Painter->setWorldXForm(false);
122 
123  // restore painter state
124  p->Painter->restore();
125 
126  // draw markers last, so they are at the top of painting layers
127  for(pg = Graphs.first(); pg != 0; pg = Graphs.next())
128  for(Marker *pm = pg->Markers.first(); pm != 0; pm = pg->Markers.next())
129  pm->paint(p, cx, cy);
130 
131 
132  if(isSelected) {
133  int x_, y_;
134  float fx_, fy_;
135  p->map(cx, cy-y2, x_, y_);
136  fx_ = float(x2)*p->Scale + 10;
137  fy_ = float(y2)*p->Scale + 10;
138 
139  p->Painter->setPen(QPen(Qt::darkGray,3));
140  p->Painter->drawRect(x_-5, y_-5, TO_INT(fx_), TO_INT(fy_));
141  p->Painter->setPen(QPen(Qt::darkRed,2));
142  p->drawResizeRect(cx, cy-y2); // markers for changing the size
143  p->drawResizeRect(cx, cy);
144  p->drawResizeRect(cx+x2, cy-y2);
145  p->drawResizeRect(cx+x2, cy);
146  }
147 }
148 
149 // ------------------------------------------------------------
151 {
152  p->PostPaintEvent(_Rect, cx, cy-y2, x2, y2);
153 }
154 
155 // ------------------------------------------------------------
156 // Put axis labels into the text list.
158 {
159  Graph *pg;
160  int x, y, w, wmax = 0;
161  QString Str;
162  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
163  int LineSpacing = metrics.lineSpacing();
164 
165 
166  x = (x2>>1);
167  y = -y1;
168  if(xAxis.Label.isEmpty()) {
169  // write all x labels ----------------------------------------
170  for(pg = Graphs.first(); pg != 0; pg = Graphs.next()) {
171  DataX *pD = pg->cPointsX.getFirst();
172  if(!pD) continue;
173  y -= LineSpacing;
174  if(Name[0] != 'C') { // locus curve ?
175  w = metrics.width(pD->Var) >> 1;
176  if(w > wmax) wmax = w;
177  Texts.append(new Text(x-w, y, pD->Var, pg->Color, 12.0));
178  }
179  else {
180  w = metrics.width("real("+pg->Var+")") >> 1;
181  if(w > wmax) wmax = w;
182  Texts.append(new Text(x-w, y, "real("+pg->Var+")",
183  pg->Color, 12.0));
184  }
185  }
186  }
187  else {
188  y -= LineSpacing;
189  encode_String(xAxis.Label, Str);
190  w = metrics.width(Str) >> 1;
191  if(w > wmax) wmax = w;
192  Texts.append(new Text(x-w, y, Str, Qt::black, 12.0));
193  }
194  Bounding_y2 = 0;
195  Bounding_y1 = y - LineSpacing;
196  Bounding_x2 = wmax - (x2 >> 1);
197  if(Bounding_x2 < 0) Bounding_x2 = 0;
198  Bounding_x1 = Bounding_x2;
199 
200 
201  wmax = 0;
202  x = -x1;
203  y = y2>>1;
204  if(yAxis.Label.isEmpty()) {
205  // draw left y-label for all graphs ------------------------------
206  for(pg = Graphs.first(); pg != 0; pg = Graphs.next()) {
207  if(pg->yAxisNo != 0) continue;
208  if(pg->cPointsY) {
209  if(Name[0] != 'C') { // location curve ?
210  w = metrics.width(pg->Var) >> 1;
211  if(w > wmax) wmax = w;
212  Texts.append(new Text(x, y-w, pg->Var, pg->Color, 12.0, 0.0, 1.0));
213  }
214  else {
215  w = metrics.width("imag("+pg->Var+")") >> 1;
216  if(w > wmax) wmax = w;
217  Texts.append(new Text(x, y-w, "imag("+pg->Var+")",
218  pg->Color, 12.0, 0.0, 1.0));
219  }
220  }
221  else { // if no data => <invalid>
222  w = metrics.width(pg->Var+INVALID_STR) >> 1;
223  if(w > wmax) wmax = w;
224  Texts.append(new Text(x, y-w, pg->Var+INVALID_STR,
225  pg->Color, 12.0, 0.0, 1.0));
226  }
227  x -= LineSpacing;
228  }
229  }
230  else {
231  encode_String(yAxis.Label, Str);
232  w = metrics.width(Str) >> 1;
233  if(w > wmax) wmax = w;
234  Texts.append(new Text(x, y-w, Str, Qt::black, 12.0, 0.0, 1.0));
235  x -= LineSpacing;
236  }
237  if(Bounding_x1 < -x) Bounding_x1 = -x;
238 
239 
240  x = x3;
241  y = y2>>1;
242  if(zAxis.Label.isEmpty()) {
243  // draw right y-label for all graphs ------------------------------
244  for(pg = Graphs.first(); pg != 0; pg = Graphs.next()) {
245  if(pg->yAxisNo != 1) continue;
246  if(pg->cPointsY) {
247  if(Name[0] != 'C') { // location curve ?
248  w = metrics.width(pg->Var) >> 1;
249  if(w > wmax) wmax = w;
250  Texts.append(new Text(x, y+w, pg->Var,
251  pg->Color, 12.0, 0.0, -1.0));
252  }
253  else {
254  w = metrics.width("imag("+pg->Var+")") >> 1;
255  if(w > wmax) wmax = w;
256  Texts.append(new Text(x, y+w, "imag("+pg->Var+")",
257  pg->Color, 12.0, 0.0, -1.0));
258  }
259  }
260  else { // if no data => <invalid>
261  w = metrics.width(pg->Var+INVALID_STR) >> 1;
262  if(w > wmax) wmax = w;
263  Texts.append(new Text(x, y+w, pg->Var+INVALID_STR,
264  pg->Color, 12.0, 0.0, -1.0));
265  }
266  x += LineSpacing;
267  }
268  }
269  else {
270  encode_String(zAxis.Label, Str);
271  w = metrics.width(Str) >> 1;
272  if(w > wmax) wmax = w;
273  Texts.append(new Text(x, y+w, Str, Qt::black, 12.0, 0.0, -1.0));
274  }
275  x -= x2;
276  if(Bounding_x2 < x) Bounding_x2 = x;
277 
278  wmax -= y2 >> 1;
279  if(wmax > 0) {
280  Bounding_y2 = wmax;
281  wmax *= -1;
282  if(wmax < Bounding_y1) Bounding_y1 = wmax;
283  }
284 }
285 
286 // ------------------------------------------------------------
287 int Diagram::regionCode(float x, float y)
288 {
289  int code=0; // code for clipping
290  if(x < 0.0)
291  code |= 1;
292  else if(x > float(x2)) // compare as float to avoid integer overflow
293  code |= 2;
294 
295  if(y < 0.0)
296  code |= 4;
297  else if(y > float(y2)) // compare as float to avoid integer overflow
298  code |= 8;
299 
300  return code;
301 }
302 
303 // ------------------------------------------------------------
304 // Is virtual. This one is for round diagrams only.
305 bool Diagram::insideDiagram(float x, float y)
306 {
307  float R = float(x2)/2.0 + 1.0; // +1 seems better (graph sometimes little outside)
308  x -= R;
309  y -= R;
310  return ((x*x + y*y) <= R*R);
311 }
312 
313 // ------------------------------------------------------------
314 // Cohen-Sutherland clipping algorithm
315 void Diagram::rectClip(float* &p)
316 {
317  int code, z=0;
318  float x=0, y=0, dx, dy;
319  float x_1 = *(p-4), y_1 = *(p-3);
320  float x_2 = *(p-2), y_2 = *(p-1);
321 
322  int code1 = regionCode(x_1, y_1);
323  int code2 = regionCode(x_2, y_2);
324  if((code1 | code2) == 0) return; // line completly inside ?
325 
326  if(code1 != 0) if(*(p-5) >= 0) { // is there already a line end flag ?
327  p++;
328  *(p-5) = STROKEEND;
329  }
330  if(code1 & code2) // line not visible at all ?
331  goto endWithHidden;
332 
333  if(code2 != 0) {
334  *p = STROKEEND;
335  *(p+1) = x_2;
336  *(p+2) = y_2;
337  z += 3;
338  }
339 
340 
341  for(;;) {
342  if((code1 | code2) == 0) break; // line completly inside ?
343 
344  if(code1) code = code1;
345  else code = code2;
346 
347  dx = x_2 - x_1; // dx and dy never equals zero !
348  dy = y_2 - y_1;
349  if(code & 1) {
350  y = y_1 - dy * x_1 / dx;
351  x = 0.0;
352  }
353  else if(code & 2) {
354  y = y_1 + dy * (x2-x_1) / dx;
355  x = float(x2);
356  }
357  else if(code & 4) {
358  x = x_1 - dx * y_1 / dy;
359  y = 0.0;
360  }
361  else if(code & 8) {
362  x = x_1 + dx * (y2-y_1) / dy;
363  y = float(y2);
364  }
365 
366  if(code == code1) {
367  x_1 = x;
368  y_1 = y;
369  code1 = regionCode(x, y);
370  }
371  else {
372  x_2 = x;
373  y_2 = y;
374  code2 = regionCode(x, y);
375  }
376  if(code1 & code2)
377  goto endWithHidden; // line not visible at all ?
378  }
379 
380  *(p-4) = x_1;
381  *(p-3) = y_1;
382  *(p-2) = x_2;
383  *(p-1) = y_2;
384  p += z;
385  return;
386 
387 endWithHidden:
388  *(p-4) = x_2;
389  *(p-3) = y_2;
390  p -= 2;
391 }
392 
393 // ------------------------------------------------------------
394 // Clipping for round diagrams (smith, polar, ...)
395 void Diagram::clip(float* &p)
396 {
397  float R = float(x2) / 2.0;
398  float x_1 = *(p-4) - R, y_1 = *(p-3) - R;
399  float x_2 = *(p-2) - R, y_2 = *(p-1) - R;
400 
401  float dt1 = R*R; // square of radius
402  float dt2 = dt1 - x_2*x_2 - y_2*y_2;
403  dt1 -= x_1*x_1 + y_1*y_1;
404 
405  if(dt1 >= 0.0) if(dt2 >= 0.0) return; // line completly inside ?
406 
407  if(dt1 < 0.0) if(*(p-5) >= 0.0) { // is there already a line end flag ?
408  p++;
409  *(p-5) = STROKEEND;
410  }
411 
412  float x = x_1-x_2;
413  float y = y_1-y_2;
414  float C = x_1*x + y_1*y;
415  float D = x*x + y*y;
416  float F = C*C + dt1*D;
417 
418  x_1 += R;
419  y_1 += R;
420  x_2 += R;
421  y_2 += R;
422  if(F <= 0.0) { // line not visible at all ?
423  *(p-4) = x_2;
424  *(p-3) = y_2;
425  p -= 2;
426  return;
427  }
428 
429  int code = 0;
430  R = sqrt(F);
431  dt1 = C - R;
432  if((dt1 > 0.0) && (dt1 < D)) { // intersection outside start/end point ?
433  *(p-4) = x_1 - x*dt1 / D;
434  *(p-3) = y_1 - y*dt1 / D;
435  code |= 1;
436  }
437  else {
438  *(p-4) = x_1;
439  *(p-3) = y_1;
440  }
441 
442  dt2 = C + R;
443  if((dt2 > 0.0) && (dt2 < D)) { // intersection outside start/end point ?
444  *(p-2) = x_1 - x*dt2 / D;
445  *(p-1) = y_1 - y*dt2 / D;
446  *p = STROKEEND;
447  p += 3;
448  code |= 2;
449  }
450  *(p-2) = x_2;
451  *(p-1) = y_2;
452 
453  if(code == 0) { // intersections both lie outside ?
454  *(p-4) = x_2;
455  *(p-3) = y_2;
456  p -= 2;
457  }
458 
459 }
460 
461 
462 // ------------------------------------------------------------
463 // g->Points must already be empty!!!
465 {
466  double *px;
467  double *pz = g->cPointsY;
468  if(!pz) return;
469  if(g->cPointsX.count() < 1) return;
470 
471  int i, z, tmp, Counter=2;
472  float dx, dy, xtmp, ytmp;
473  int Size = ((2*(g->cPointsX.getFirst()->count) + 1) * g->countY) + 10;
474 
475  if(xAxis.autoScale) if(yAxis.autoScale) if(zAxis.autoScale)
476  Counter = -50000;
477 
478  double Dummy = 0.0; // not used
479  double *py = &Dummy;
480 
481  float *p = (float*)malloc( Size*sizeof(float) ); // create memory for points
482  float *p_end;
483  g->ScrPoints = p_end = p;
484  p_end += Size - 9; // limit of buffer
485  *(p++) = STROKEEND;
486 
487  Axis *pa;
488  if(g->yAxisNo == 0) pa = &yAxis;
489  else pa = &zAxis;
490 
491  double Stroke=10.0, Space=10.0; // length of strokes and spaces in pixel
492  switch(g->Style) {
493  case GRAPHSTYLE_SOLID: // ***** solid line ****************************
494  for(i=g->countY; i>0; i--) { // every branch of curves
495  px = g->cPointsX.getFirst()->Points;
496  calcCoordinate(px, pz, py, p, p+1, pa);
497  p += 2;
498  for(z=g->cPointsX.getFirst()->count-1; z>0; z--) { // every point
499  FIT_MEMORY_SIZE; // need to enlarge memory block ?
500  calcCoordinate(px, pz, py, p, p+1, pa);
501  p += 2;
502  if(Counter >= 2) // clipping only if an axis is manual
503  clip(p);
504  }
505  if(*(p-3) == STROKEEND)
506  p -= 3; // no single point after "no stroke"
507  else if(*(p-3) == BRANCHEND) {
508  if((*(p-2) < 0) || (*(p-1) < 0))
509  p -= 2; // erase last hidden point
510  }
511  *(p++) = BRANCHEND;
512  }
513 
514 
515  *p = GRAPHEND;
516 /*z = p-g->Points+1;
517 p = g->Points;
518 qDebug("\n****** p=%p", p);
519 for(int zz=0; zz<z; zz+=2)
520  qDebug("c: %d/%d", *(p+zz), *(p+zz+1));*/
521  return;
522 
523  case GRAPHSTYLE_DASH:
524  Stroke = 10.0; Space = 6.0;
525  break;
526  case GRAPHSTYLE_DOT:
527  Stroke = 2.0; Space = 4.0;
528  break;
529  case GRAPHSTYLE_LONGDASH:
530  Stroke = 24.0; Space = 8.0;
531  break;
532 
533  default: // symbol (e.g. star) at each point **********************
534  for(i=g->countY; i>0; i--) { // every branch of curves
535  px = g->cPointsX.getFirst()->Points;
536  for(z=g->cPointsX.getFirst()->count; z>0; z--) { // every point
537  calcCoordinate(px, pz, py, p, p+1, pa);
538  if(insideDiagram(*p, *(p+1))) // within diagram ?
539  p += 2;
540  }
541  *(p++) = BRANCHEND;
542  }
543  *p = GRAPHEND;
544 /*qDebug("\n******");
545 for(int zz=0; zz<60; zz+=2)
546  qDebug("c: %d/%d", *(g->Points+zz), *(g->Points+zz+1));*/
547  return;
548  }
549 
550  double alpha, dist;
551  int Flag; // current state: 1=stroke, 0=space
552  for(i=g->countY; i>0; i--) { // every branch of curves
553  Flag = 1;
554  dist = -Stroke;
555  px = g->cPointsX.getFirst()->Points;
556  calcCoordinate(px, pz, py, &xtmp, &ytmp, pa);
557  *(p++) = xtmp;
558  *(p++) = ytmp;
559  Counter = 1;
560  for(z=g->cPointsX.getFirst()->count-1; z>0; z--) {
561  dx = xtmp;
562  dy = ytmp;
563  calcCoordinate(px, pz, py, &xtmp, &ytmp, pa);
564  dx = xtmp - dx;
565  dy = ytmp - dy;
566  dist += sqrt(double(dx*dx + dy*dy)); // distance between points
567  if(Flag == 1) if(dist <= 0.0) {
568  FIT_MEMORY_SIZE; // need to enlarge memory block ?
569 
570  *(p++) = xtmp; // if stroke then save points
571  *(p++) = ytmp;
572  if((++Counter) >= 2) clip(p);
573  continue;
574  }
575  alpha = atan2(double(dy), double(dx)); // slope for interpolation
576  while(dist > 0) { // stroke or space finished ?
577  FIT_MEMORY_SIZE; // need to enlarge memory block ?
578 
579  *(p++) = xtmp - float(dist*cos(alpha)); // linearly interpolate
580  *(p++) = ytmp - float(dist*sin(alpha));
581  if((++Counter) >= 2) clip(p);
582 
583  if(Flag == 0) {
584  dist -= Stroke;
585  if(dist <= 0) {
586  *(p++) = xtmp; // don't forget point after ...
587  *(p++) = ytmp; // ... interpolated point
588  if((++Counter) >= 2) clip(p);
589  }
590  }
591  else {
592  dist -= Space;
593  if(*(p-3) < 0) p -= 2;
594  else *(p++) = STROKEEND;
595  if(Counter < 0) Counter = -50000; // if auto-scale
596  else Counter = 0;
597  }
598  Flag ^= 1; // toggle between stroke and space
599  }
600 
601  } // of x loop
602 
603  if(*(p-3) == STROKEEND)
604  p -= 3; // no single point after "no stroke"
605  else if(*(p-3) == BRANCHEND) {
606  if((*(p-2) < 0) || (*(p-1) < 0))
607  p -= 2; // erase last hidden point
608  }
609  *(p++) = BRANCHEND;
610  } // of y loop
611 
612 
613  *p = GRAPHEND;
614 /*z = p-g->Points+1;
615 p = g->Points;
616 qDebug("\n****** p=%p", p);
617 for(int zz=0; zz<z; zz+=2)
618  qDebug("c: %d/%d", *(p+zz), *(p+zz+1));*/
619 }
620 
621 // -------------------------------------------------------
622 void Diagram::Bounding(int& _x1, int& _y1, int& _x2, int& _y2)
623 {
624  _x1 = cx - Bounding_x1;
625  _y1 = cy - y2 - Bounding_y2;
626  _x2 = cx + x2 + Bounding_x2;
627  _y2 = cy - Bounding_y1;
628 }
629 
630 // -------------------------------------------------------
631 bool Diagram::getSelected(int x_, int y_)
632 {
633  if(x_ >= cx-x1) if(x_ <= cx+x3) if(y_ >= cy-y2) if(y_ <= cy+y1)
634  return true;
635 
636  return false;
637 }
638 
639 // ------------------------------------------------------------
640 // Checks if the resize area was clicked. If so return "true" and sets
641 // x1/y1 and x2/y2 to the border coordinates to draw a rectangle.
642 bool Diagram::resizeTouched(float fX, float fY, float len)
643 {
644  float fCX = float(cx), fCY = float(cy);
645  float fX2 = float(cx+x2), fY2 = float(cy-y2);
646  if(fX < fCX-len) return false;
647  if(fX > fX2+len) return false;
648  if(fY < fY2-len) return false;
649  if(fY > fCY+len) return false;
650 
651  State = 0;
652  if(fX < fCX+len) State = 1;
653  else if(fX <= fX2-len) return false;
654  if(fY > fCY-len) State |= 2;
655  else if(fY >= fY2+len) return false;
656 
657  return true;
658 }
659 
660 // --------------------------------------------------------------------------
662 {
663  int z;
664  double x, y, *p;
665  DataX *pD = pg->cPointsX.first();
666  if(pD == 0) return;
667 
668  if(Name[0] != 'C') { // not for location curves
669  p = pD->Points;
670  for(z=pD->count; z>0; z--) { // check x coordinates (1. dimension)
671  x = *(p++);
672  if(isfinite(x)) {
673  if(x > xAxis.max) xAxis.max = x;
674  if(x < xAxis.min) xAxis.min = x;
675  }
676  }
677  }
678 
679  if(Name == "Rect3D") {
680  DataX *pDy = pg->cPointsX.next();
681  if(pDy) {
682  p = pDy->Points;
683  for(z=pDy->count; z>0; z--) { // check y coordinates (2. dimension)
684  y = *(p++);
685  if(isfinite(y)) {
686  if(y > yAxis.max) yAxis.max = y;
687  if(y < yAxis.min) yAxis.min = y;
688  }
689  }
690  }
691  }
692 
693  Axis *pa;
694  if(pg->yAxisNo == 0) pa = &yAxis;
695  else pa = &zAxis;
696  (pa->numGraphs)++; // count graphs
697  p = pg->cPointsY;
698  if(p == 0) return; // if no data => invalid
699  for(z=pg->countY*pD->count; z>0; z--) { // check every y coordinate
700  x = *(p++);
701  y = *(p++);
702 
703  if(Name[0] != 'C') {
704  if(fabs(y) >= 1e-250) x = sqrt(x*x+y*y);
705  if(isfinite(x)) {
706  if(x > pa->max) pa->max = x;
707  if(x < pa->min) pa->min = x;
708  }
709  }
710  else { // location curve needs different treatment
711  if(isfinite(x)) {
712  if(x > xAxis.max) xAxis.max = x;
713  if(x < xAxis.min) xAxis.min = x;
714  }
715  if(isfinite(y)) {
716  if(y > pa->max) pa->max = y;
717  if(y < pa->min) pa->min = y;
718  }
719  }
720  }
721 }
722 
723 // --------------------------------------------------------------------------
724 void Diagram::loadGraphData(const QString& defaultDataSet)
725 {
726  int yNum = yAxis.numGraphs;
727  int zNum = zAxis.numGraphs;
728  yAxis.numGraphs = zAxis.numGraphs = 0;
729 
730  double xmin = xAxis.min, ymin = yAxis.min, zmin = zAxis.min;
731  double xmax = xAxis.max, ymax = yAxis.max, zmax = zAxis.max;
732  yAxis.min = zAxis.min = xAxis.min = DBL_MAX;
733  yAxis.max = zAxis.max = xAxis.max = -DBL_MAX;
734 
735  int No=0;
736  for(Graph *pg = Graphs.first(); pg != 0; pg = Graphs.next()) {
737  if(loadVarData(defaultDataSet, pg) != 1) // load data, determine max/min values
738  No++;
739  else
740  getAxisLimits(pg);
741  pg->lastLoaded = QDateTime::currentDateTime();
742  }
743 
744  if(No <= 0) { // All dataset files unchanged ?
745  yAxis.numGraphs = yNum; // rebuild scrollbar position
746  zAxis.numGraphs = zNum;
747 
748  xAxis.min = xmin; yAxis.min = ymin; zAxis.min = zmin;
749  xAxis.max = xmax; yAxis.max = ymax; zAxis.max = zmax;
750  return; // -> no update neccessary
751  }
752 
753  if(xAxis.min > xAxis.max)
754  xAxis.min = xAxis.max = 0.0;
755  if(yAxis.min > yAxis.max)
756  yAxis.min = yAxis.max = 0.0;
757  if(zAxis.min > zAxis.max)
758  zAxis.min = zAxis.max = 0.0;
759 
760 /* if((Name == "Polar") || (Name == "Smith")) { // one axis only
761  if(yAxis.min > zAxis.min) yAxis.min = zAxis.min;
762  if(yAxis.max < zAxis.max) yAxis.max = zAxis.max;
763  }*/
764  updateGraphData();
765 }
766 
767 // ------------------------------------------------------------------------
768 // Calculate diagram again without reading dataset from file.
770 {
771  yAxis.min = zAxis.min = xAxis.min = DBL_MAX;
772  yAxis.max = zAxis.max = xAxis.max = -DBL_MAX;
773  yAxis.numGraphs = zAxis.numGraphs = 0;
774 
775  // get maximum and minimum values
776  for(Graph *pg = Graphs.first(); pg != 0; pg = Graphs.next())
777  getAxisLimits(pg);
778 
779  if(xAxis.min > xAxis.max) {
780  xAxis.min = 0.0;
781  xAxis.max = 1.0;
782  }
783  if(yAxis.min > yAxis.max) {
784  yAxis.min = 0.0;
785  yAxis.max = 1.0;
786  }
787  if(zAxis.min > zAxis.max) {
788  zAxis.min = 0.0;
789  zAxis.max = 1.0;
790  }
791  if((Name == "Polar") || (Name == "Smith")) { // one axis only
792  if(yAxis.min > zAxis.min) yAxis.min = zAxis.min;
793  if(yAxis.max < zAxis.max) yAxis.max = zAxis.max;
794  }
795 
796  updateGraphData();
797 }
798 
799 // ------------------------------------------------------------------------
801 {
802  int valid = calcDiagram(); // do not calculate graph data if invalid
803 
804  Graph *pg;
805  for(pg = Graphs.first(); pg != 0; pg = Graphs.next()) {
806  if(pg->ScrPoints != 0) {
807  free(pg->ScrPoints);
808  pg->ScrPoints = 0;
809  }
810  if((valid & (pg->yAxisNo+1)) != 0)
811  calcData(pg); // calculate screen coordinates
812  else if(pg->cPointsY) {
813  delete[] pg->cPointsY;
814  pg->cPointsY = 0;
815  }
816  }
817 
818  createAxisLabels(); // virtual function
819 
820  // Setting markers must be done last, because in 3D diagram "Mem"
821  // is released in "createAxisLabels()".
822  for(pg = Graphs.first(); pg != 0; pg = Graphs.next())
823  for(Marker *pm = pg->Markers.first(); pm != 0; pm = pg->Markers.next())
824  pm->createText();
825 }
826 
827 // --------------------------------------------------------------------------
828 int Diagram::loadVarData(const QString& fileName, Graph *g)
829 {
830  QFile file;
831  QString Variable;
832  QFileInfo Info(fileName);
833 
834  int pos = g->Var.find(':');
835 // if(g->Var.right(3) == "].X") // e.g. stdl[8:0].X
836 // if(pos > g->Var.find('['))
837 // pos = -1;
838 
839  /* WORK-AROUND: A bug in SCIM (libscim) which Qt is linked to causes
840  to change the locale to the default. */
841  setlocale (LC_NUMERIC, "C");
842 
843  if(pos <= 0) {
844  file.setName(fileName);
845  Variable = g->Var;
846  }
847  else {
848  file.setName(Info.dirPath()+QDir::separator() + g->Var.left(pos)+".dat");
849  Variable = g->Var.mid(pos+1);
850  }
851 
852  Info.setFile(file);
853  if(g->lastLoaded.isValid())
854  if(g->lastLoaded > Info.lastModified())
855  return 1; // dataset unchanged -> no update neccessary
856 
857  g->countY = 0;
858  g->cPointsX.clear();
859  if(g->cPointsY) { delete[] g->cPointsY; g->cPointsY = 0; }
860  if(Variable.isEmpty()) return 0;
861 
862  if(Variable.right(2) == ".X")
863  if(Name.at(0) != 'T')
864  return 0; // digital variables only for tabulars and ziming diagram
865 
866 
867  if(!file.open(QIODevice::ReadOnly)) return 0;
868 
869  // *****************************************************************
870  // To strongly speed up the file read operation the whole file is
871  // read into the memory in one piece.
872  QByteArray FileContent;
873  FileContent = file.readAll();
874  file.close();
875  char *FileString = FileContent.data();
876  if(!FileString) return 0;
877  char *pPos = FileString+FileContent.size()-1;
878  if(*pPos > ' ') if(*pPos != '>') return 0;
879  *pPos = 0;
880 
881 
882  // *****************************************************************
883  // look for variable name in data file ****************************
884  bool isIndep = false;
885  Variable = "dep "+Variable+" ";
886  // "pFile" is used through-out the whole function and must NOT used
887  // for other purposes!
888  char *pFile = strstr(FileString, Variable.latin1());
889  while(pFile) {
890  if(*(pFile-1) == '<') // is dependent variable ?
891  break;
892  else if(strncmp(pFile-3, "<in", 3) == 0) { // is independent variable ?
893  isIndep = true;
894  break;
895  }
896  pFile = strstr(pFile+4, Variable.latin1());
897  }
898 
899  if(!pFile) return 0; // data not found
900 
901  QString Line, tmp;
902  pFile += Variable.length();
903  pPos = strchr(pFile, '>');
904  if(!pPos) return 0; // file corrupt
905  *pPos = 0;
906  Line = QString(pFile);
907  *pPos = '>';
908  pFile = pPos+1;
909  if(!isIndep) {
910  pos = 0;
911  tmp = Line.section(' ', pos, pos);
912  while(!tmp.isEmpty()) {
913  g->cPointsX.append(new DataX(tmp)); // name of independet variable
914  pos++;
915  tmp = Line.section(' ', pos, pos);
916  }
917  }
918 
919  Axis *pa;
920  // *****************************************************************
921  // get independent variable ****************************************
922  bool ok=true;
923  double *p;
924  int counting = 0;
925  if(isIndep) { // create independent variable by myself ?
926  counting = Line.toInt(&ok); // get number of values
927  g->cPointsX.append(new DataX("number", 0, counting));
928  if(!ok) return 0;
929 
930  p = new double[counting]; // memory of new independent variable
931  g->countY = 1;
932  g->cPointsX.current()->Points = p;
933  for(int z=1; z<=counting; z++) *(p++) = double(z);
934  if(xAxis.min > 1.0) xAxis.min = 1.0;
935  if(xAxis.max < double(counting)) xAxis.max = double(counting);
936  }
937  else { // ...................................
938  // get independent variables from data file
939  g->countY = 1;
940  DataX *bLast = 0;
941  if(Name == "Rect3D") bLast = g->cPointsX.at(1); // y axis for Rect3D
942 
943  double min_tmp = xAxis.min, max_tmp = xAxis.max;
944  for(DataX *pD = g->cPointsX.last(); pD!=0; pD = g->cPointsX.prev()) {
945  pa = &xAxis;
946  if(pD == g->cPointsX.getFirst()) {
947  xAxis.min = min_tmp; // only count first independent variable
948  xAxis.max = max_tmp;
949  }
950  else if(pD == bLast) pa = &yAxis; // y axis for Rect3D
951  counting = loadIndepVarData(pD->Var, FileString, pa, g);
952  if(counting <= 0) return 0;
953 
954  g->countY *= counting;
955  }
956  g->countY /= counting;
957  }
958 
959 
960  // *****************************************************************
961  // get dependent variables *****************************************
962  counting *= g->countY;
963  p = new double[2*counting]; // memory for dependent variables
964  g->cPointsY = p;
965  if(g->yAxisNo == 0) pa = &yAxis; // for which axis
966  else pa = &zAxis;
967  (pa->numGraphs)++; // count graphs
968 
969  char *pEnd;
970  double x, y;
971  pPos = pFile;
972 
973 if(Variable.right(3) != ".X ")
974 
975  for(int z=counting; z>0; z--) {
976  pEnd = 0;
977  while((*pPos) && (*pPos <= ' ')) pPos++; // find start of next number
978  x = strtod(pPos, &pEnd); // real part
979  pPos = pEnd + 1;
980  if(*pEnd < ' ') // is there an imaginary part ?
981  y = 0.0;
982  else {
983  if(((*pEnd != '+') && (*pEnd != '-')) || (*pPos != 'j')) {
984  delete[] g->cPointsY; g->cPointsY = 0;
985  return 0;
986  }
987  *pPos = *pEnd; // overwrite 'j' with sign
988  pEnd = 0;
989  y = strtod(pPos, &pEnd); // imaginary part
990  *pPos = 'j'; // write back old character
991  pPos = pEnd;
992  }
993  *(p++) = x;
994  *(p++) = y;
995  if(Name[0] != 'C') {
996  if(fabs(y) >= 1e-250) x = sqrt(x*x+y*y);
997  if(isfinite(x)) {
998  if(x > pa->max) pa->max = x;
999  if(x < pa->min) pa->min = x;
1000  }
1001  }
1002  else { // location curve needs different treatment
1003  if(isfinite(x)) {
1004  if(x > xAxis.max) xAxis.max = x;
1005  if(x < xAxis.min) xAxis.min = x;
1006  }
1007  if(isfinite(y)) {
1008  if(y > pa->max) pa->max = y;
1009  if(y < pa->min) pa->min = y;
1010  }
1011  }
1012  }
1013 
1014 
1015 else { // of "if not digital"
1016 
1017  char *pc = (char*)p;
1018  pEnd = pc + 2*(counting-1)*sizeof(double);
1019  // for digital variables (e.g. 100ZX0):
1020  for(int z=counting; z>0; z--) {
1021 
1022  while((*pPos) && (*pPos <= ' ')) pPos++; // find start of next bit vector
1023  if(*pPos == 0) {
1024  delete[] g->cPointsY; g->cPointsY = 0;
1025  return 0;
1026  }
1027 
1028  while(*pPos > ' ') { // copy bit vector
1029  *(pc++) = *(pPos++);
1030  if(pEnd <= pc) {
1031  counting = pc - (char*)g->cPointsY;
1032  pc = (char*)realloc(g->cPointsY, counting+1024);
1033  pEnd = pc;
1034  g->cPointsY = (double*)pEnd;
1035  pc += counting;
1036  pEnd += counting+1020;
1037  }
1038  }
1039  *(pc++) = 0; // terminate each vector with NULL
1040  }
1041 
1042 } // of "if not digital"
1043 
1044  return 2;
1045 }
1046 
1047 // --------------------------------------------------------------------------
1048 // Reads the data of an independent variable. Returns the number of points.
1049 int Diagram::loadIndepVarData(const QString& Variable,
1050  char *FileString, Axis *pa, Graph *pg)
1051 {
1052  bool isIndep = false;
1053  QString Line, tmp;
1054 
1055  /* WORK-AROUND: A bug in SCIM (libscim) which Qt is linked to causes
1056  to change the locale to the default. */
1057  setlocale (LC_NUMERIC, "C");
1058 
1059  Line = "dep "+Variable+" ";
1060  // "pFile" is used through-out the whole function and must NOT used
1061  // for other purposes!
1062  char *pFile = strstr(FileString, Line.latin1());
1063  while(pFile) {
1064  if(*(pFile-1) == '<') // is dependent variable ?
1065  break;
1066  else if(strncmp(pFile-3, "<in", 3) == 0) { // is independent variable ?
1067  isIndep = true;
1068  break;
1069  }
1070  pFile = strstr(pFile+4, Line.latin1());
1071  }
1072 
1073  if(!pFile) return -1; // data not found
1074 
1075  pFile += Line.length();
1076  char *pPos = strchr(pFile, '>');
1077  if(!pPos) return -1; // file corrupt
1078  *pPos = 0;
1079  Line = QString(pFile);
1080  *pPos = '>';
1081  pFile = pPos+1;
1082  char *pEnd;
1083  if(!isIndep) { // dependent variable can also be used...
1084  if(Line.find(' ') >= 0) return -1; // ...if only one dependency
1085  Line = "<indep "+Line+" ";
1086  pPos = strstr(FileString, Line.latin1());
1087  if(!pPos) return -1;
1088  pPos += Line.length();
1089  pEnd = strchr(pPos, '>');
1090  if(!pEnd) return -1; // file corrupt
1091  *pEnd = 0;
1092  Line = QString(pPos);
1093  *pEnd = '>';
1094  }
1095 
1096 
1097  bool ok;
1098  int n = Line.toInt(&ok); // number of values
1099  if(!ok) return -1;
1100 
1101  double *p = new double[n]; // memory for new independent variable
1102  DataX *pD = pg->cPointsX.current();
1103  pD->Points = p;
1104  pD->count = n;
1105 
1106 
1107  double x;
1108  pPos = pFile;
1109  // find first position containing no whitespace
1110  while((*pPos) && (*pPos <= ' ')) pPos++;
1111 
1112  for(int z=0; z<n; z++) {
1113  pEnd = 0;
1114  x = strtod(pPos, &pEnd); // real part
1115  if(pPos == pEnd) {
1116  delete[] pD->Points; pD->Points = 0;
1117  return -1;
1118  }
1119 
1120  *(p++) = x;
1121  if(Name[0] != 'C') // not for location curves
1122  if(isfinite(x)) {
1123  if(x > pa->max) pa->max = x;
1124  if(x < pa->min) pa->min = x;
1125  }
1126 
1127  pPos = pEnd;
1128  while((*pPos) && (*pPos <= ' ')) pPos++; // find start of next number
1129  }
1130 
1131  return n; // return number of independent data
1132 }
1133 
1134 // ------------------------------------------------------------
1135 // Checks if the two graphs have the same independent variables.
1137 {
1138  if(g1 == g2) return true;
1139 
1140  DataX *g1Data = g1->cPointsX.first();
1141  DataX *g2Data = g2->cPointsX.first();
1142  while(g1Data && g2Data) {
1143  if(g1Data->Var != g2Data->Var) return false;
1144  g1Data = g1->cPointsX.next();
1145  g2Data = g2->cPointsX.next();
1146  }
1147 
1148  if(g1Data) return false; // Is there more data ?
1149  if(g2Data) return false; // Is there more data ?
1150  return true;
1151 }
1152 
1153 // ------------------------------------------------------------
1154 int Diagram::checkColumnWidth(const QString& Str,
1155  const QFontMetrics& metrics, int colWidth, int x, int y)
1156 {
1157  //qDebug("%i", metrics.charWidth(Str,0));
1158  int w = metrics.boundingRect(Str).width(); // width of text
1159  if(w > colWidth) {
1160  colWidth = w;
1161  if((x+colWidth) >= x2) { // enough space for text ?
1162  // mark lack of space with a small arrow
1163  Lines.append(new Line(x2-6, y-4, x2+7, y-4, QPen(Qt::red,2)));
1164  Lines.append(new Line(x2, y-7, x2+6, y-4, QPen(Qt::red,2)));
1165  Lines.append(new Line(x2, y-1, x2+6, y-4, QPen(Qt::red,2)));
1166  return -1;
1167  }
1168  }
1169  return colWidth;
1170 }
1171 
1172 // ------------------------------------------------------------
1173 void Diagram::setCenter(int x, int y, bool relative)
1174 {
1175  if(relative) {
1176  cx += x; cy += y;
1177  }
1178  else {
1179  cx = x; cy = y;
1180  }
1181 }
1182 
1183 // -------------------------------------------------------
1184 void Diagram::getCenter(int& x, int& y)
1185 {
1186  x = cx + (x2 >> 1);
1187  y = cy - (y2 >> 1);
1188 }
1189 
1190 // ------------------------------------------------------------
1192 {
1193  return new Diagram();
1194 }
1195 
1196 // ------------------------------------------------------------
1197 QString Diagram::save()
1198 {
1199  QString s = "<"+Name+" "+QString::number(cx)+" "+QString::number(cy)+" ";
1200  s += QString::number(x2)+" "+QString::number(y2)+" ";
1201  char c = '0';
1202  if(xAxis.GridOn) c |= 1;
1203  if(hideLines) c |= 2;
1204  s += c;
1205  s += " " + GridPen.color().name() + " " + QString::number(GridPen.style());
1206 
1207  if(xAxis.log) s+= " 1"; else s += " 0";
1208  c = '0';
1209  if(yAxis.log) c |= 1;
1210  if(zAxis.log) c |= 2;
1211  s += c;
1212 
1213  if(xAxis.autoScale) s+= " 1 ";
1214  else s+= " 0 ";
1215  s += QString::number(xAxis.limit_min) + " ";
1216  s += QString::number(xAxis.step) + " ";
1217  s += QString::number(xAxis.limit_max);
1218  if(yAxis.autoScale) s+= " 1 ";
1219  else s+= " 0 ";
1220  s += QString::number(yAxis.limit_min) + " ";
1221  s += QString::number(yAxis.step) + " ";
1222  s += QString::number(yAxis.limit_max);
1223  if(zAxis.autoScale) s+= " 1 ";
1224  else s+= " 0 ";
1225  s += QString::number(zAxis.limit_min) + " ";
1226  s += QString::number(zAxis.step) + " ";
1227  s += QString::number(zAxis.limit_max) + " ";
1228 
1229  s += QString::number(rotX)+" "+QString::number(rotY)+" "+
1230  QString::number(rotZ);
1231 
1232  // labels can contain spaces -> must be last items in the line
1233  s += " \""+xAxis.Label+"\" \""+yAxis.Label+"\" \""+zAxis.Label+"\">\n";
1234 
1235  for(Graph *pg=Graphs.first(); pg != 0; pg=Graphs.next())
1236  s += pg->save()+"\n";
1237 
1238  s += " </"+Name+">";
1239  return s;
1240 }
1241 
1242 // ------------------------------------------------------------
1243 bool Diagram::load(const QString& Line, QTextStream *stream)
1244 {
1245  bool ok;
1246  QString s = Line;
1247 
1248  if(s.at(0) != '<') return false;
1249  if(s.at(s.length()-1) != '>') return false;
1250  s = s.mid(1, s.length()-2); // cut off start and end character
1251 
1252  QString n;
1253  n = s.section(' ',1,1); // cx
1254  cx = n.toInt(&ok);
1255  if(!ok) return false;
1256 
1257  n = s.section(' ',2,2); // cy
1258  cy = n.toInt(&ok);
1259  if(!ok) return false;
1260 
1261  n = s.section(' ',3,3); // x2
1262  x2 = n.toInt(&ok);
1263  if(!ok) return false;
1264 
1265  n = s.section(' ',4,4); // y2
1266  y2 = n.toInt(&ok);
1267  if(!ok) return false;
1268 
1269  char c;
1270  n = s.section(' ',5,5); // GridOn
1271  c = n.at(0).latin1() - '0';
1272  xAxis.GridOn = yAxis.GridOn = (c & 1) != 0;
1273  hideLines = (c & 2) != 0;
1274 
1275  n = s.section(' ',6,6); // color for GridPen
1276  QColor co;
1277  co.setNamedColor(n);
1278  GridPen.setColor(co);
1279  if(!GridPen.color().isValid()) return false;
1280 
1281  n = s.section(' ',7,7); // line style
1282  GridPen.setStyle((Qt::PenStyle)n.toInt(&ok));
1283  if(!ok) return false;
1284 
1285  n = s.section(' ',8,8); // xlog, ylog
1286  xAxis.log = n.at(0) != '0';
1287  c = n.at(1).latin1();
1288  yAxis.log = ((c - '0') & 1) == 1;
1289  zAxis.log = ((c - '0') & 2) == 2;
1290 
1291  n = s.section(' ',9,9); // xAxis.autoScale
1292  if(n.at(0) != '"') { // backward compatible
1293  if(n == "1") xAxis.autoScale = true;
1294  else xAxis.autoScale = false;
1295 
1296  n = s.section(' ',10,10); // xAxis.limit_min
1297  xAxis.limit_min = n.toDouble(&ok);
1298  if(!ok) return false;
1299 
1300  n = s.section(' ',11,11); // xAxis.step
1301  xAxis.step = n.toDouble(&ok);
1302  if(!ok) return false;
1303 
1304  n = s.section(' ',12,12); // xAxis.limit_max
1305  xAxis.limit_max = n.toDouble(&ok);
1306  if(!ok) return false;
1307 
1308  n = s.section(' ',13,13); // yAxis.autoScale
1309  if(n == "1") yAxis.autoScale = true;
1310  else yAxis.autoScale = false;
1311 
1312  n = s.section(' ',14,14); // yAxis.limit_min
1313  yAxis.limit_min = n.toDouble(&ok);
1314  if(!ok) return false;
1315 
1316  n = s.section(' ',15,15); // yAxis.step
1317  yAxis.step = n.toDouble(&ok);
1318  if(!ok) return false;
1319 
1320  n = s.section(' ',16,16); // yAxis.limit_max
1321  yAxis.limit_max = n.toDouble(&ok);
1322  if(!ok) return false;
1323 
1324  n = s.section(' ',17,17); // zAxis.autoScale
1325  if(n == "1") zAxis.autoScale = true;
1326  else zAxis.autoScale = false;
1327 
1328  n = s.section(' ',18,18); // zAxis.limit_min
1329  zAxis.limit_min = n.toDouble(&ok);
1330  if(!ok) return false;
1331 
1332  n = s.section(' ',19,19); // zAxis.step
1333  zAxis.step = n.toDouble(&ok);
1334  if(!ok) return false;
1335 
1336  n = s.section(' ',20,20); // zAxis.limit_max
1337  zAxis.limit_max = n.toDouble(&ok);
1338  if(!ok) return false;
1339 
1340  n = s.section(' ',21,21); // rotX
1341  if(n.at(0) != '"') { // backward compatible
1342  rotX = n.toInt(&ok);
1343  if(!ok) return false;
1344 
1345  n = s.section(' ',22,22); // rotY
1346  rotY = n.toInt(&ok);
1347  if(!ok) return false;
1348 
1349  n = s.section(' ',23,23); // rotZ
1350  rotZ = n.toInt(&ok);
1351  if(!ok) return false;
1352  }
1353  }
1354 
1355  xAxis.Label = s.section('"',1,1); // xLabel
1356  yAxis.Label = s.section('"',3,3); // yLabel left
1357  zAxis.Label = s.section('"',5,5); // yLabel right
1358 
1359  Graph *pg;
1360  // .......................................................
1361  // load graphs of the diagram
1362  while(!stream->atEnd()) {
1363  s = stream->readLine();
1364  s = s.stripWhiteSpace();
1365  if(s.isEmpty()) continue;
1366 
1367  if(s == ("</"+Name+">")) return true; // found end tag ?
1368  if(s.section(' ', 0,0) == "<Mkr") {
1369 
1370  // .......................................................
1371  // load markers of the diagram
1372  pg = Graphs.current();
1373  if(!pg) return false;
1374  Marker *pm = new Marker(this, pg);
1375  if(!pm->load(s)) {
1376  delete pm;
1377  return false;
1378  }
1379  pg->Markers.append(pm);
1380  continue;
1381  }
1382 
1383  pg = new Graph();
1384  if(!pg->load(s)) {
1385  delete pg;
1386  return false;
1387  }
1388  Graphs.append(pg);
1389  }
1390 
1391  return false; // end tag missing
1392 }
1393 
1394 // --------------------------------------------------------------
1395 void Diagram::calcSmithAxisScale(Axis *Axis, int& GridX, int& GridY)
1396 {
1397  xAxis.low = xAxis.min;
1398  xAxis.up = xAxis.max;
1399 
1400  Axis->low = 0.0;
1401  if(fabs(Axis->min) > Axis->max)
1402  Axis->max = fabs(Axis->min); // also fit negative values
1403  if(Axis->autoScale) {
1404  if(Axis->max > 1.01) Axis->up = 1.05*Axis->max;
1405  else Axis->up = 1.0;
1406  GridX = GridY = 4;
1407  }
1408  else {
1409  Axis->up = Axis->limit_max = fabs(Axis->limit_max);
1410  GridX = GridY = int(Axis->step);
1411  }
1412 }
1413 
1414 // ------------------------------------------------------------
1416 {
1417  int GridX; // number of arcs with re(z)=const
1418  int GridY; // number of arcs with im(z)=const
1419  calcSmithAxisScale(Axis, GridX, GridY);
1420 
1421 
1422  if(!xAxis.GridOn) return;
1423 
1424  bool Zplane = ((Mode & 1) == 1); // impedance or admittance chart ?
1425  bool Above = ((Mode & 2) == 2); // paint upper half ?
1426  bool Below = ((Mode & 4) == 4); // paint lower half ?
1427 
1428  int dx2 = x2>>1;
1429 
1430  double im, n_cos, n_sin, real, real1, real2, root;
1431  double rMAXq = Axis->up*Axis->up;
1432  int theta, beta, phi, len, m, x, y;
1433 
1434  int R1 = int(x2/Axis->up + 0.5);
1435  // ....................................................
1436  // draw arcs with im(z)=const
1437  for(m=1; m<GridY; m++) {
1438  n_sin = M_PI*double(m)/double(GridY);
1439  n_cos = cos(n_sin);
1440  n_sin = sin(n_sin);
1441  im = (1.0-n_cos)/n_sin * pow(Axis->up,0.7); // up^0.7 is beauty correction
1442  y = int(im/Axis->up*x2 + 0.5); // diameter
1443 
1444  if(Axis->up <= 1.0) { // Smith chart with |r|=1
1445  beta = int(16.0*180.0*atan2(n_sin-im,n_cos-1.0)/M_PI - 0.5);
1446  if(beta<0) beta += 16*360;
1447  theta = 16*270-beta;
1448  }
1449  else { // Smith chart with |r|>1
1450  im = 1.0/im;
1451  real = (rMAXq+1.0)/(rMAXq-1.0);
1452  root = real*real - im*im - 1.0;
1453  if(root < 0.0) { // circle lies completely within the Smith chart ?
1454  beta = 0; // yes, ...
1455  theta = 16*360; // ... draw whole circle
1456  }
1457  else {
1458  // calculate both intersections with most outer circle
1459  real1 = sqrt(root)-real;
1460  real2 = -sqrt(root)-real;
1461 
1462  root = (real1+1.0)*(real1+1.0) + im*im;
1463  n_cos = (real1*real1 + im*im - 1.0) / root;
1464  n_sin = 2.0*im / root;
1465  beta = int(16.0*180.0*atan2(n_sin-1.0/im,n_cos-1.0)/M_PI);
1466  if(beta<0) beta += 16*360;
1467 
1468  root = (real2+1.0)*(real2+1.0) + im*im;
1469  n_cos = (real2*real2 + im*im - 1.0) / root;
1470  n_sin = 2.0*im / root;
1471  theta = int(16.0*180.0*atan2(n_sin-1/im,n_cos-1)/M_PI);
1472  if(theta<0) theta += 16*360;
1473  theta = theta - beta; // arc length
1474  if(theta < 0) theta = 16*360+theta;
1475  }
1476  }
1477 
1478  if(Zplane)
1479  x = (x2 + R1 - y) >> 1;
1480  else {
1481  x = (x2 - R1 - y) >> 1;
1482  beta = 16*180 - beta - theta; // mirror
1483  if(beta < 0) beta += 16*360; // angle has to be > 0
1484  }
1485 
1486  if(Above)
1487  Arcs.append(new struct Arc(x, dx2+y, y, y, beta, theta, GridPen));
1488  if(Below)
1489  Arcs.append(new struct Arc(x, dx2, y, y, 16*360-beta-theta, theta, GridPen));
1490  }
1491 
1492  // ....................................................
1493  // draw arcs with Re(z)=const
1494  theta = 0; // arc length
1495  beta = 16*180; // start angle
1496  if(Above) { beta = 0; theta = 16*180; }
1497  if(Below) theta += 16*180;
1498 
1499  for(m=1; m<GridX; m++) {
1500  im = m*(Axis->up+1.0)/GridX - Axis->up;
1501  y = int((1.0-im)/Axis->up*double(dx2) + 0.5); // diameter
1502 
1503  if(Zplane)
1504  x = ((x2+R1)>>1) - y;
1505  else
1506  x = (x2-R1)>>1;
1507  if(fabs(fabs(im)-1.0) > 0.2) // if too near to |r|=1, it looks ugly
1508  Arcs.append(new struct Arc(x, (x2+y)>>1, y, y, beta, theta, GridPen));
1509 
1510  if(Axis->up > 1.0) { // draw arcs on the rigth-handed side ?
1511  im = 1.0-im;
1512  im = (rMAXq-1.0)/(im*(im/2.0+1.0)) - 1.0;
1513  if(Zplane) x += y;
1514  else x -= y;
1515  if(im >= 1.0)
1516  Arcs.append(new struct Arc(x, (x2+y)>>1, y, y, beta, theta, GridPen));
1517  else {
1518  phi = int(16.0*180.0/M_PI*acos(im));
1519  len = 16*180-phi;
1520  if(Above && Below) len += len;
1521  else if(Below) phi = 16*180;
1522  if(!Zplane) phi += 16*180;
1523  Arcs.append(new struct Arc(x, (x2+y)>>1, y, y, phi, len, GridPen));
1524  }
1525  }
1526  }
1527 
1528 
1529  // ....................................................
1530  if(Axis->up > 1.0) { // draw circle with |r|=1 ?
1531  x = (x2-R1) >> 1;
1532  y = (x2+R1) >> 1;
1533  Arcs.append(new struct Arc(x, y, R1, R1, beta, theta, QPen(Qt::black,0)));
1534 
1535  // vertical line Re(r)=1 (visible only if |r|>1)
1536  if(Zplane) x = y;
1537  y = int(sqrt(rMAXq-1)/Axis->up*dx2 + 0.5);
1538  if(Above) m = y;
1539  else m = 0;
1540  if(!Below) y = 0;
1541  Lines.append(new Line(x, dx2+m, x, dx2-y, GridPen));
1542 
1543  if(Below) y = 4;
1544  else y = y2-4-QucsSettings.font.pointSize();
1545  Texts.append(new Text(0, y, StringNum(Axis->up)));
1546  }
1547 
1548 }
1549 
1550 
1551 // --------------------------------------------------------------
1552 void Diagram::calcPolarAxisScale(Axis *Axis, double& numGrids,
1553  double& GridStep, double& zD)
1554 {
1555  if(Axis->autoScale) { // auto-scale or user defined limits ?
1556  double Expo, Base;
1557  numGrids = floor(double(x2)/80.0); // minimal grid is 40 pixel
1558  Expo = floor(log10(Axis->max/numGrids));
1559  Base = Axis->max/numGrids/pow(10.0,Expo);// get first significant digit
1560  if(Base < 3.5) { // use only 1, 2 and 5, which ever is best fitted
1561  if(Base < 1.5) Base = 1.0;
1562  else Base = 2.0;
1563  }
1564  else {
1565  if(Base < 7.5) Base = 5.0;
1566  else { Base = 1.0; Expo++; }
1567  }
1568  GridStep = Base * pow(10.0,Expo); // grid distance in real values
1569  numGrids -= floor(numGrids - Axis->max/GridStep); // correct num errors
1570  Axis->up = GridStep*numGrids;
1571 
1572  zD = double(x2) / numGrids; // grid distance in pixel
1573  }
1574  else { // no auto-scale
1575  Axis->up = Axis->limit_max = fabs(Axis->limit_max);
1576  GridStep = Axis->step;
1577  zD = double(x2) / Axis->limit_max * Axis->step; // grid distance in pixel
1578 
1579  if(fabs(zD) < 2.0) { // if grid too small, then no grid
1580  zD = double(x2);
1581  GridStep = Axis->step = Axis->up;
1582  numGrids = 1.0;
1583  }
1584  else numGrids = Axis->limit_max / Axis->step;
1585  }
1586 }
1587 
1588 // ------------------------------------------------------------
1590 {
1591  xAxis.low = xAxis.min;
1592  xAxis.up = xAxis.max;
1593  Axis->low = 0.0;
1594  if(fabs(Axis->min) > Axis->max)
1595  Axis->max = fabs(Axis->min); // also fit negative values
1596 
1597 
1598  bool Above = ((Mode & 1) == 1); // paint upper half ?
1599  bool Below = ((Mode & 2) == 2); // paint lower half ?
1600 
1601  int i, z, tmp;
1602  if(Above) i = y2; else i = y2>>1;
1603  if(Below) z = 0; else z = y2>>1;
1604  // y line
1605  Lines.append(new Line(x2>>1, i, x2>>1, z, GridPen));
1606 
1607  int len = 0; // arc length
1608  int beta = 16*180; // start angle
1609  if(Above) { beta = 0; len = 16*180; }
1610  if(Below) len += 16*180;
1611 
1612  int phi, tPos;
1613  int tHeight = QucsSettings.font.pointSize() + 5;
1614  if(!Below) tPos = (y2>>1) + 3;
1615  else tPos = (y2>>1) - tHeight + 3;
1616 
1617  double Expo, Base, numGrids, GridStep, zD;
1618  if(xAxis.GridOn) {
1619  calcPolarAxisScale(Axis, numGrids, GridStep, zD);
1620 
1621  double zDstep = zD;
1622  double GridNum = 0.0;
1623  for(i=int(numGrids); i>1; i--) { // create all grid circles
1624  z = int(zD);
1625  GridNum += GridStep;
1626  Texts.append(new Text(((x2+z)>>1)-10, tPos, StringNiceNum(GridNum)));
1627 
1628  phi = int(16.0*180.0/M_PI*atan(double(2*tHeight)/zD));
1629  if(!Below) tmp = beta + phi;
1630  else tmp = beta;
1631  Arcs.append(new struct Arc((x2-z)>>1, (y2+z)>>1, z, z, tmp, len-phi,
1632  GridPen));
1633  zD += zDstep;
1634  }
1635  }
1636  else { // of "if(GridOn)"
1637  Expo = floor(log10(Axis->max));
1638  Base = ceil(Axis->max/pow(10.0,Expo) - 0.01);
1639  Axis->up = Base * pow(10.0,Expo); // separate Base * 10^Expo
1640  }
1641 
1642  // create outer circle
1643  Texts.append(new Text(x2-8, tPos, StringNiceNum(Axis->up)));
1644  phi = int(16.0*180.0/M_PI*atan(double(2*tHeight)/double(x2)));
1645  if(!Below) tmp = phi;
1646  else tmp = 0;
1647  Arcs.append(new struct Arc(0, y2, x2, y2, tmp, 16*360-phi, QPen(Qt::black,0)));
1648 
1649  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
1650  QSize r = metrics.size(0, Texts.current()->s); // width of text
1651  len = x2+r.width()-4; // more space at the right
1652  if(len > x3) x3 = len;
1653 }
1654 
1655 // --------------------------------------------------------------
1656 // Calculations for Cartesian diagrams (RectDiagram and Rect3DDiagram).
1657 // parameters: Axis - pointer to the axis to scale
1658 // Dist - length of axis in pixel on the screen
1659 // return value: "true" if axis runs from largest to smallest value
1660 //
1661 // GridNum - number where the first numbered grid is placed
1662 // GridStep - distance from one grid to the next
1663 // zD - screen coordinate where the first grid is placed
1664 // zDstep - distance on screen from one grid to the next
1665 bool Diagram::calcAxisScale(Axis *Axis, double& GridNum, double& zD,
1666  double& zDstep, double& GridStep, double Dist)
1667 {
1668  bool back=false;
1669  double numGrids, Base, Expo, corr;
1670 if(Axis->autoScale) {
1671 
1672  if(fabs(Axis->max-Axis->min) < 1e-200) {
1673  if((Axis->max == 0.0) && (Axis->min == 0.0)) {
1674  Axis->up = 1.0;
1675  Axis->low = -1.0;
1676  }
1677  else { // if max = min, double difference
1678  Axis->up = Axis->max + fabs(Axis->max);
1679  Axis->low = Axis->min - fabs(Axis->min);
1680  }
1681  }
1682  else if(Axis != &xAxis) {
1683  // keep a small bounding between graph and diagram limit
1684  Axis->up = Axis->max + 0.1*(Axis->max-Axis->min);
1685  Axis->low = Axis->min - 0.1*(Axis->max-Axis->min);
1686  }
1687  else {
1688  Axis->up = Axis->max; // normal case for x axis
1689  Axis->low = Axis->min;
1690  }
1691 
1692 
1693  numGrids = floor(Dist/60.0); // minimal grid is 60 pixel
1694  if(numGrids < 1.0) Base = Axis->up-Axis->low;
1695  else Base = (Axis->up-Axis->low)/numGrids;
1696  Expo = floor(log10(Base));
1697  Base = Base/pow(10.0,Expo); // separate first significant digit
1698  if(Base < 3.5) { // use only 1, 2 and 5, which ever is best fitted
1699  if(Base < 1.5) Base = 1.0;
1700  else Base = 2.0;
1701  }
1702  else {
1703  if(Base < 7.5) Base = 5.0;
1704  else { Base = 1.0; Expo++; }
1705  }
1706  GridStep = Base * pow(10.0,Expo); // grid distance in real coordinates
1707  corr = floor((Axis->up-Axis->low)/GridStep - numGrids);
1708  if(corr < 0.0) corr++;
1709  numGrids += corr; // correct rounding faults
1710 
1711 
1712  // upper y boundery ...........................
1713  zD = fabs(fmod(Axis->up, GridStep));// expand grid to upper diagram edge ?
1714  GridNum = zD/GridStep;
1715  if((1.0-GridNum) < 1e-10) GridNum = 0.0; // fix rounding errors
1716  if(Axis->up <= 0.0) {
1717  if(GridNum < 0.3) { Axis->up += zD; zD = 0.0; }
1718  }
1719  else if(GridNum > 0.7) Axis->up += GridStep-zD;
1720  else if(GridNum < 0.1)
1721  if(GridNum*Dist >= 1.0)// more than 1 pixel above ?
1722  Axis->up += 0.3*GridStep; // beauty correction
1723 
1724 
1725  // lower y boundery ...........................
1726  zD = fabs(fmod(Axis->low, GridStep));// expand grid to lower diagram edge ?
1727  GridNum = zD/GridStep;
1728  if((1.0-GridNum) < 1e-10) zD = GridNum = 0.0; // fix rounding errors
1729  if(Axis->low <= 0.0) {
1730  if(GridNum > 0.7) { Axis->low -= GridStep-zD; zD = 0.0; }
1731  else if(GridNum < 0.1)
1732  if(GridNum*Dist >= 1.0) { // more than 1 pixel above ?
1733  Axis->low -= 0.3*GridStep; // beauty correction
1734  zD += 0.3*GridStep;
1735  }
1736  }
1737  else {
1738  if(GridNum > 0.3) {
1739  zD = GridStep-zD;
1740  if(GridNum > 0.9) {
1741  if((1.0-GridNum)*Dist >= 1.0) { // more than 1 pixel above ?
1742  Axis->low -= 0.3*GridStep; // beauty correction
1743  zD += 0.3*GridStep;
1744  }
1745  }
1746  }
1747  else { Axis->low -= zD; zD = 0.0; }
1748  }
1749 
1750  GridNum = Axis->low + zD;
1751  zD /= (Axis->up-Axis->low)/Dist;
1752 }
1753 else { // user defined limits
1754  zD = 0.0;
1755  Axis->low = GridNum = Axis->limit_min;
1756  Axis->up = Axis->limit_max;
1757  if(Axis->limit_max < Axis->limit_min)
1758  back = true;
1759  GridStep = Axis->step;
1760 }
1761 
1762  zDstep = GridStep/(Axis->up-Axis->low)*Dist; // grid in pixel
1763 
1764  if(fabs(zDstep) < 2.0) { // if grid too small, then no grid
1765  zDstep = Dist;
1766  GridStep = Axis->step = Axis->up-Axis->low;
1767  }
1768 
1769  return back;
1770 }
1771 
1772 // --------------------------------------------------------------
1773 // Calculations for logarithmical Cartesian diagrams (RectDiagram and
1774 // Rect3DDiagram).
1775 // parameters: Axis - pointer to the axis to scale
1776 // Dist - length of axis in pixel on the screen
1777 // return value: "true" if axis runs from largest to smallest value
1778 //
1779 // z - screen coordinate where the first grid is placed
1780 // zD - number where the first grid is placed
1781 // zDstep - number increment from one grid to the next
1782 // coor - scale factor for calculate screen coordinate
1783 bool Diagram::calcAxisLogScale(Axis *Axis, int& z, double& zD,
1784  double& zDstep, double& corr, int len)
1785 {
1786  if(fabs(Axis->max-Axis->min) < 1e-200) { // if max = min, double difference
1787  Axis->max *= 10.0;
1788  Axis->min /= 10.0;
1789  }
1790  Axis->low = Axis->min; Axis->up = Axis->max;
1791 
1792  if(!Axis->autoScale) {
1793  Axis->low = Axis->limit_min;
1794  Axis->up = Axis->limit_max;
1795  }
1796 
1797 
1798  bool mirror=false, mirror2=false;
1799  double tmp;
1800  if(Axis->up < 0.0) { // for negative values
1801  tmp = Axis->low;
1802  Axis->low = -Axis->up;
1803  Axis->up = -tmp;
1804  mirror = true;
1805  }
1806 
1807  double Base, Expo;
1808  if(Axis->autoScale) {
1809  if(mirror) { // set back values ?
1810  tmp = Axis->min;
1811  Axis->min = -Axis->max;
1812  Axis->max = -tmp;
1813  }
1814 
1815  Expo = floor(log10(Axis->max));
1816  Base = Axis->max/pow(10.0,Expo);
1817  if(Base > 3.0001) Axis->up = pow(10.0,Expo+1.0);
1818  else if(Base < 1.0001) Axis->up = pow(10.0,Expo);
1819  else Axis->up = 3.0 * pow(10.0,Expo);
1820 
1821  Expo = floor(log10(Axis->min));
1822  Base = Axis->min/pow(10.0,Expo);
1823  if(Base < 2.999) Axis->low = pow(10.0,Expo);
1824  else if(Base > 9.999) Axis->low = pow(10.0,Expo+1.0);
1825  else Axis->low = 3.0 * pow(10.0,Expo);
1826 
1827  corr = double(len) / log10(Axis->up / Axis->low);
1828 
1829  z = 0;
1830  zD = Axis->low;
1831  zDstep = pow(10.0,Expo);
1832 
1833  if(mirror) { // set back values ?
1834  tmp = Axis->min;
1835  Axis->min = -Axis->max;
1836  Axis->max = -tmp;
1837  }
1838  }
1839  else { // user defined limits
1840  if(Axis->up < Axis->low) {
1841  tmp = Axis->low;
1842  Axis->low = Axis->up;
1843  Axis->up = tmp;
1844  mirror2 = true;
1845  }
1846 
1847  Expo = floor(log10(Axis->low));
1848  Base = ceil(Axis->low/pow(10.0,Expo));
1849  zD = Base * pow(10.0, Expo);
1850  zDstep = pow(10.0,Expo);
1851  if(zD > 9.5*zDstep) zDstep *= 10.0;
1852 
1853  corr = double(len) / log10(Axis->up / Axis->low);
1854  z = int(corr*log10(zD / Axis->low) + 0.5); // int(..) implies floor(..)
1855 
1856  if(mirror2) { // set back values ?
1857  tmp = Axis->low;
1858  Axis->low = Axis->up;
1859  Axis->up = tmp;
1860  }
1861  }
1862 
1863  if(mirror) { // set back values ?
1864  tmp = Axis->low;
1865  Axis->low = -Axis->up;
1866  Axis->up = -tmp;
1867  }
1868 
1869  if(mirror == mirror2) return false;
1870  else return true;
1871 }
1872 
1873 // --------------------------------------------------------------
1875 {
1876  int z, w;
1877  double GridStep, corr, zD, zDstep, GridNum;
1878 
1879  QString tmp;
1880  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
1881  int maxWidth = 0;
1882 
1883  bool back = false;
1884 if(Axis->log) {
1885  if(Axis->autoScale) {
1886  if(Axis->max*Axis->min <= 0.0) return false; // invalid
1887  }
1888  else if(Axis->limit_min*Axis->limit_max <= 0.0) return false; // invalid
1889 
1890  back = calcAxisLogScale(Axis, z, zD, zDstep, corr, y2);
1891 
1892  if(back) z = y2;
1893  while((z <= y2) && (z >= 0)) { // create all grid lines
1894  if(Axis->GridOn) if(z < y2) if(z > 0)
1895  Lines.prepend(new Line(0, z, x2, z, GridPen)); // y grid
1896 
1897  if((zD < 1.5*zDstep) || (z == 0)) {
1898  tmp = StringNiceNum(zD);
1899  if(Axis->up < 0.0) tmp = '-'+tmp;
1900 
1901  w = metrics.width(tmp); // width of text
1902  if(maxWidth < w) maxWidth = w;
1903  if(x0 > 0)
1904  Texts.append(new Text(x0+7, z-6, tmp)); // text aligned left
1905  else
1906  Texts.append(new Text(-w-7, z-6, tmp)); // text aligned right
1907 
1908  // y marks
1909  Lines.append(new Line(x0-5, z, x0+5, z, QPen(Qt::black,0)));
1910  }
1911 
1912  zD += zDstep;
1913  if(zD > 9.5*zDstep) zDstep *= 10.0;
1914  if(back) {
1915  z = int(corr*log10(zD / fabs(Axis->up)) + 0.5); // int() implies floor()
1916  z = y2 - z;
1917  }
1918  else
1919  z = int(corr*log10(zD / fabs(Axis->low)) + 0.5);// int() implies floor()
1920  }
1921 }
1922 else { // not logarithmical
1923  back = calcAxisScale(Axis, GridNum, zD, zDstep, GridStep, double(y2));
1924 
1925  double Expo;
1926  if(Axis->up == 0.0) Expo = log10(fabs(Axis->up-Axis->low));
1927  else Expo = log10(fabs(Axis->up));
1928 
1929  zD += 0.5; // perform rounding
1930  z = int(zD); // "int(...)" implies "floor(...)"
1931  while((z <= y2) && (z >= 0)) { // create all grid lines
1932  if(fabs(GridNum) < 0.01*pow(10.0, Expo)) GridNum = 0.0;// make 0 really 0
1933  tmp = StringNiceNum(GridNum);
1934 
1935  w = metrics.width(tmp); // width of text
1936  if(maxWidth < w) maxWidth = w;
1937  if(x0 > 0)
1938  Texts.append(new Text(x0+8, z-6, tmp)); // text aligned left
1939  else
1940  Texts.append(new Text(-w-7, z-6, tmp)); // text aligned right
1941  GridNum += GridStep;
1942 
1943  if(Axis->GridOn) if(z < y2) if(z > 0)
1944  Lines.prepend(new Line(0, z, x2, z, GridPen)); // y grid
1945  Lines.append(new Line(x0-5, z, x0+5, z, QPen(Qt::black,0))); // y marks
1946  zD += zDstep;
1947  z = int(zD);
1948  }
1949 } // of "if(ylog) ... else ..."
1950  if(x0 == 0) x1 = maxWidth+14;
1951  else x3 = x2+maxWidth+14;
1952  return true;
1953 }
Diagram(int _cx=0, int _cy=0)
Definition: diagram.cpp:45
virtual bool insideDiagram(float, float)
Definition: diagram.cpp:305
Q3PtrList< Marker > Markers
Definition: graph.h:79
void getCenter(int &, int &)
Definition: diagram.cpp:1184
void drawResizeRect(int, int)
QPainter * Painter
Definition: viewpainter.h:58
void recalcGraphData()
Definition: diagram.cpp:769
#define GRAPHSTYLE_DASH
Definition: graph.h:36
int regionCode(float, float)
Definition: diagram.cpp:287
bool load(const QString &, QTextStream *)
Definition: diagram.cpp:1243
int countY
Definition: graph.h:74
Definition: element.h:55
virtual void createAxisLabels()
Definition: diagram.cpp:157
void PostPaintEvent(PE pe, int x1=0, int y1=0, int x2=0, int y2=0, int a=0, int b=0, bool PaintOnViewport=false)
Definition: schematic.cpp:533
int count
Definition: graph.h:53
QFont font
Definition: main.h:46
Definition: graph.h:57
#define GRAPHSTYLE_LONGDASH
Definition: graph.h:38
float Scale
Definition: viewpainter.h:59
#define isDiagram
Definition: element.h:131
void map(int, int, int &, int &)
Definition: viewpainter.cpp:63
tQucsSettings QucsSettings
Definition: main.cpp:52
float * ScrPoints
Definition: graph.h:73
#define BRANCHEND
Definition: graph.h:32
Definition: marker.h:31
bool sameDependencies(Graph *, Graph *)
Definition: diagram.cpp:1136
QString Var
Definition: graph.h:50
void drawLine(int, int, int, int)
Definition: viewpainter.cpp:85
QString StringNum(double num, char form, int Precision)
Definition: main.cpp:263
Definition: graph.h:47
double limit_min
Definition: diagram.h:56
#define STROKEEND
Definition: graph.h:31
bool load(const QString &)
Definition: graph.cpp:105
bool GridOn
Definition: diagram.h:53
void setCenter(int, int, bool relative=false)
Definition: diagram.cpp:1173
QString Var
Definition: graph.h:75
Definitions and declarations for the main application.
QucsApp * QucsMain
Definition: main.cpp:54
QString StringNiceNum(double num)
Definition: main.cpp:293
void getAxisLimits(Graph *)
Definition: diagram.cpp:661
virtual void clip(float *&)
Definition: diagram.cpp:395
void rectClip(float *&)
Definition: diagram.cpp:315
void encode_String(const QString &Input, QString &Output)
Definition: mnemo.cpp:58
QDateTime lastLoaded
Definition: graph.h:69
bool getSelected(int, int)
Definition: diagram.cpp:631
void createSmithChart(Axis *, int Mode=7)
Definition: diagram.cpp:1415
void createPolarDiagram(Axis *, int Mode=3)
Definition: diagram.cpp:1589
int numGraphs
Definition: diagram.h:52
int loadVarData(const QString &, Graph *)
Definition: diagram.cpp:828
void Bounding(int &, int &, int &, int &)
Definition: diagram.cpp:622
Definition: diagram.h:47
bool log
Definition: diagram.h:50
Definition: element.h:82
void drawArc(int, int, int, int, int, int)
int checkColumnWidth(const QString &, const QFontMetrics &, int, int, int)
Definition: diagram.cpp:1154
Definition: element.h:48
bool calcAxisLogScale(Axis *, int &, double &, double &, double &, int)
Definition: diagram.cpp:1783
QString save()
Definition: diagram.cpp:1197
double max
Definition: diagram.h:48
virtual void paint(ViewPainter *)
Definition: diagram.cpp:87
#define TO_INT(f)
Definition: viewpainter.h:23
double limit_max
Definition: diagram.h:56
#define GRAPHSTYLE_SOLID
Definition: graph.h:35
int Style
Definition: graph.h:78
QTabWidget * DocumentTab
Definition: qucs.h:164
QColor Color
Definition: graph.h:76
#define FIT_MEMORY_SIZE
Definition: diagram.h:37
virtual void calcData(Graph *)
Definition: diagram.cpp:464
bool calcAxisScale(Axis *, double &, double &, double &, double &, double)
Definition: diagram.cpp:1665
void paint(ViewPainter *, int, int)
Definition: graph.cpp:53
virtual ~Diagram()
Definition: diagram.cpp:81
void updateGraphData()
Definition: diagram.cpp:800
virtual Diagram * newOne()
Definition: diagram.cpp:1191
double step
Definition: diagram.h:56
void loadGraphData(const QString &)
Definition: diagram.cpp:724
void calcSmithAxisScale(Axis *, int &, int &)
Definition: diagram.cpp:1395
#define M_PI
Definition: diagramdialog.h:25
double * Points
Definition: graph.h:52
Q3PtrList< DataX > cPointsX
Definition: graph.h:71
double up
Definition: diagram.h:49
int loadIndepVarData(const QString &, char *, Axis *, Graph *)
Definition: diagram.cpp:1049
void calcPolarAxisScale(Axis *, double &, double &, double &)
Definition: diagram.cpp:1552
#define INVALID_STR
Definition: diagram.h:33
#define GRAPHEND
Definition: graph.h:33
double * cPointsY
Definition: graph.h:72
bool autoScale
Definition: diagram.h:55
bool calcYAxis(Axis *, int)
Definition: diagram.cpp:1874
#define GRAPHSTYLE_DOT
Definition: graph.h:37
double low
Definition: diagram.h:49
double min
Definition: diagram.h:48
void paintScheme(Schematic *)
Definition: diagram.cpp:150
bool resizeTouched(float, float, float)
Definition: diagram.cpp:642
int yAxisNo
Definition: graph.h:70
bool load(const QString &Line)
Definition: marker.cpp:514