Qucs-GUI  0.0.18
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
rect3ddiagram.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  rect3ddiagram.cpp
3  -------------------
4  begin : Sat Mar 5 2005
5  copyright : (C) 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 #include <limits.h>
26 #if HAVE_IEEEFP_H
27 # include <ieeefp.h>
28 #endif
29 
30 #include "rect3ddiagram.h"
31 #include "main.h"
32 #include "qucs.h"
33 #include "schematic.h"
34 
35 Rect3DDiagram::Rect3DDiagram(int _cx, int _cy) : Diagram(_cx, _cy)
36 {
37  x1 = 10; // position of label text
38  y1 = y3 = 7;
39  x2 = 200; // initial size of diagram
40  y2 = 200;
41  x3 = 207; // with some distance for right axes text
42 
43  Mem = pMem = 0; // auxiliary buffer for hidden lines
44 
45  Name = "Rect3D";
46  // symbolic diagram painting
47  Lines.append(new Line(0, 0, cx, 0, QPen(Qt::black,0)));
48  Lines.append(new Line(0, 0, 0, cy, QPen(Qt::black,0)));
49  Lines.append(new Line(0, 0, cx/2, cy/2, QPen(Qt::black,0)));
50 }
51 
53 {
54 }
55 
56 // ------------------------------------------------------------
57 // Calculates the coefficients for 3D -> 2D transformation
59 {
60  double rX = double(rotX) * M_PI/180.0;
61  double rY = double(rotY) * M_PI/180.0;
62  double rZ = double(rotZ) * M_PI/180.0;
63 
64  cxy = sin(rZ); cxx = cos(rZ);
65  cxz = sin(rY); rY = cos(rY);
66  cyz = sin(rX); czz = cos(rX);
67  rX = cyz*cxz; rZ = czz*cxz;
68  cyx = czz * cxy + rX * cxx;
69  cyy = czz * cxx - rX * cxy;
70  czx = cyz * cxy - rZ * cxx;
71  czy = cyz * cxx + rZ * cxy;
72  cxx *= rY; cxy *= -rY; cyz *= -rY; czz *= rY;
73 }
74 
75 // ------------------------------------------------------------
76 double Rect3DDiagram::calcX_2D(double x, double y, double z)
77 {
78  return (cxx * x + cxy * y + cxz * z) * scaleX;
79 }
80 
81 // ------------------------------------------------------------
82 double Rect3DDiagram::calcY_2D(double x, double y, double z)
83 {
84  return (cyx * x + cyy * y + cyz * z) * scaleY;
85 }
86 
87 // ------------------------------------------------------------
88 double Rect3DDiagram::calcZ_2D(double x, double y, double z)
89 {
90  return czx * x + czy * y + czz * z;
91 }
92 
93 // ------------------------------------------------------------
94 // Determines the position of the coordinate cross, i.e. calculates
95 // "scaleX", "scaleY", "xorig" and "yorig". Returns the corner with
96 // the largest distance from the viewer.
97 int Rect3DDiagram::calcCross(int *Xses, int *Yses)
98 {
99  double x3D, y3D, z3D, x2D[8], y2D[8], z2D;
100  double XMIN_2D, XMAX_2D, YMIN_2D, YMAX_2D, ZMIN_2D;
101 
102  int z, Center = 0; // used to save minimum z (is center for axis cross)
103  scaleX = scaleY = 1.0; // used in "calcX_2D" and "calcY_2D"
104  XMIN_2D = YMIN_2D = XMAX_2D = YMAX_2D = ZMIN_2D = 0.0; // origin is zero
105  for(z=0; z<8; z++) { // check 2D coordinates of all 8 quadrat corners
106  if(z & 1) x3D = 1.0; else x3D = 0.0;
107  if(z & 2) y3D = 1.0; else y3D = 0.0;
108  if(z & 4) z3D = 1.0; else z3D = 0.0;
109  x2D[z] = calcX_2D(x3D, y3D, z3D);
110  y2D[z] = calcY_2D(x3D, y3D, z3D);
111  z2D = calcZ_2D(x3D, y3D, z3D);
112 
113  if(x2D[z] < XMIN_2D) XMIN_2D = x2D[z];
114  if(x2D[z] > XMAX_2D) XMAX_2D = x2D[z];
115  if(y2D[z] < YMIN_2D) YMIN_2D = y2D[z];
116  if(y2D[z] > YMAX_2D) YMAX_2D = y2D[z];
117  if(z2D < ZMIN_2D) { ZMIN_2D = z2D; Center = z; }
118  }
119 
120  scaleX = double(x2) / (XMAX_2D - XMIN_2D); // scaling 3D -> 2D transformation
121  scaleY = double(y2) / (YMAX_2D - YMIN_2D);
122  xorig = -XMIN_2D * scaleX; // position of origin
123  yorig = -YMIN_2D * scaleY;
124 
125  for(z=0; z<8; z++) { // calculate 2D coordinates of all corners
126  *(Xses+z) = int(x2D[z] * scaleX + 0.5 + xorig);
127  *(Yses+z) = int(y2D[z] * scaleY + 0.5 + yorig);
128  }
129  return Center;
130 }
131 
132 // ------------------------------------------------------------
133 // Is needed for markers.
134 void Rect3DDiagram::calcCoordinate(double* &xD, double* &zD, double* &yD,
135  float *px, float *py, Axis*)
136 {
137  double x3D = *(zD++);
138  double y3D = *(zD++);
139  double z3D;
140  if(zAxis.log) {
141  z3D = sqrt(x3D*x3D + y3D*y3D);
142 /* if(z3D <= 0.0) clipping not yet correct implemented
143  z3D = -1e5; // "negative infinity"
144  else*/
145  z3D = log10(z3D / fabs(zAxis.low)) / log10(zAxis.up / zAxis.low);
146  }
147  else {
148  if(fabs(y3D) > 1e-250) // preserve negative values if no complex number
149  x3D = sqrt(x3D*x3D + y3D*y3D);
150  z3D = (x3D - zAxis.low) / (zAxis.up - zAxis.low);
151  }
152 
153  x3D = *(xD++);
154  if(xAxis.log) {
155  x3D /= xAxis.low;
156 /* if(x3D <= 0.0) clipping not yet correct implemented
157  x3D = -1e5; // "negative infinity"
158  else*/
159  x3D = log10(x3D) / log10(xAxis.up / xAxis.low);
160  }
161  else
162  x3D = (x3D - xAxis.low) / (xAxis.up - xAxis.low);
163 
164  if(yAxis.log) {
165  y3D = (*yD) / yAxis.low;
166 /* if(y3D <= 0.0) clipping not yet correct implemented
167  y3D = -1e5; // "negative infinity"
168  else*/
169  y3D = log10(y3D) / log10(yAxis.up / yAxis.low);
170  }
171  else
172  y3D = (*yD - yAxis.low) / (yAxis.up - yAxis.low);
173 
174  *px = float(calcX_2D(x3D, y3D, z3D)) + xorig;
175  *py = float(calcY_2D(x3D, y3D, z3D)) + yorig;
176 
177  if(isfinite(*px))
178  if(isfinite(*py))
179  return;
180 
181  *px = float(xorig);
182  *py = float(yorig);
183 }
184 
185 // ------------------------------------------------------------
186 void Rect3DDiagram::calcCoordinate3D(double x, double y, double zr, double zi,
187  tPoint3D *p, tPointZ *pz)
188 {
189  if(zAxis.log) {
190  zr = sqrt(zr*zr + zi*zi);
191 /* if(zr <= 0.0) clipping not yet correct implemented
192  zr = -1e5; // "negative infinity"
193  else*/
194  zr = log10(zr / fabs(zAxis.low)) / log10(zAxis.up / zAxis.low);
195  }
196  else {
197  if(fabs(zi) > 1e-250) // preserve negative values if no complex number
198  zr = sqrt(zr*zr + zi*zi);
199  zr = (zr - zAxis.low) / (zAxis.up - zAxis.low);
200  }
201 
202  if(xAxis.log) {
203  x /= xAxis.low;
204 /* if(x <= 0.0) clipping not yet correct implemented
205  x = -1e5; // "negative infinity"
206  else*/
207  x = log10(x) / log10(xAxis.up / xAxis.low);
208  }
209  else
210  x = (x - xAxis.low) / (xAxis.up - xAxis.low);
211 
212  if(yAxis.log) {
213  y = y / yAxis.low;
214 /* if(y <= 0.0) clipping not yet correct implemented
215  y = -1e5; // "negative infinity"
216  else*/
217  y = log10(y) / log10(yAxis.up / yAxis.low);
218  }
219  else
220  y = (y - yAxis.low) / (yAxis.up - yAxis.low);
221 
222  p->x = int(calcX_2D(x, y, zr) + 0.5 + xorig);
223  p->y = int(calcY_2D(x, y, zr) + 0.5 + yorig);
224  p->No = pz->No = p-Mem;
225  p->done = 0;
226  pz->z = float(calcZ_2D(x, y, zr));
227 }
228 
229 // --------------------------------------------------------------
230 bool Rect3DDiagram::isHidden(int x, int y, tBound *Bounds, char *zBuffer)
231 {
232  // remember the boundings of the polygon
233  if( (Bounds+x)->max < y ) (Bounds+x)->max = y;
234  if( (Bounds+x)->min > y ) (Bounds+x)->min = y;
235 
236  // diagram area already used ?
237  return ( *(zBuffer + (y>>3) + x * ((y2+7)>>3)) & (1 << (y & 7)) ) != 0;
238 }
239 
240 // --------------------------------------------------------------
241 // Enlarge memory block if neccessary.
243 {
244  if(pMem >= MemEnd) {
245  int Size = MemEnd - Mem + 256;
246  MemEnd = Mem;
247  Mem = (tPoint3D*)realloc(Mem, Size*sizeof(tPoint3D));
248  pMem += Mem - MemEnd;
249  MemEnd = Mem + Size - 5;
250  }
251 }
252 
253 // --------------------------------------------------------------
254 // Calculate all 2D points of the line between point "p" and "p+1".
255 // Parameters: p - pointer on 3D coordinate of line start point
256 // (p+1 points onto line end point)
257 // MemEnd - pointer where memory block ends
258 // Bounds - memory block for occupied polygon area
259 // zBuffer - memory block for occupied diagram area
261  tBound *Bounds, char *zBuffer)
262 {
263  int Pos_;
264  int x1_ = p->x, y1_ = p->y;
265  int x2_ = (p+1)->x, y2_ = (p+1)->y;
266 
267  bool wasHidden = isHidden(x1_, y1_, Bounds, zBuffer);
268  if(wasHidden)
269  if((p->done & 1) == 0)
270  p->done |= 4; // mark as hidden
271 
272  int ax_ = 0, ay_ = 0;
273  int ix_, iy_, dx_, dy_, of_;
274 
275  if(x2_ >= x1_) {
276  dx_ = x2_ - x1_;
277  ix_ = 1;
278  }
279  else {
280  dx_ = x1_ - x2_;
281  ix_ = -1;
282  }
283 
284  if(y2_ >= y1_) {
285  dy_ = y2_ - y1_;
286  iy_ = 1;
287  }
288  else {
289  dy_ = y1_ - y2_;
290  iy_ = -1;
291  }
292 
293  if(dx_ < dy_) {
294  of_ = dx_; // exchange dx and dy
295  dx_ = dy_;
296  dy_ = of_;
297 
298  ax_ = iy_;
299  ay_ = ix_;
300  ix_ = iy_ = 0;
301  }
302 
303  of_ = dx_ >> 1;
304  for(int i=dx_; i>1; i--) { // calculate each point of the line
305  x1_ += ix_;
306  y1_ += ax_;
307  of_ += dy_;
308  if(of_ > dx_) {
309  of_ -= dx_;
310  x1_ += ay_;
311  y1_ += iy_;
312  }
313 
314  if( isHidden(x1_, y1_, Bounds, zBuffer) != wasHidden )
315  if((p->done & 1) == 0) {
316  wasHidden = !wasHidden;
317  pMem->x = x1_;
318  pMem->y = y1_;
319  pMem->No = p->No;
320  pMem->done = 0;
321  if(wasHidden) pMem->done = 4; // mark as hidden
322  pMem++;
323 
324  Pos_ = p - Mem;
325  // Enlarge memory block if neccessary.
326  enlargeMemoryBlock(MemEnd); // this may make "p" invalid (realloc)
327  p = Mem + Pos_; // rebuild "p"
328  }
329  }
330 
331  // extra treatment for last point (create no further point)
332  if(isHidden((p+1)->x, (p+1)->y, Bounds, zBuffer))
333  if(((p+1)->done & 1) == 0)
334  (p+1)->done |= 4; // mark as hidden
335 
336  p->done |= 1; // mark as already worked on
337 }
338 
339 // --------------------------------------------------------------
340 // Compare functions for GNU qsort routine.
341 int Rect3DDiagram::comparePoint3D(const void *Point1, const void *Point2)
342 {
343  return ((tPoint3D*)Point1)->No - ((tPoint3D*)Point2)->No;
344 }
345 int Rect3DDiagram::comparePointZ(const void *Point1, const void *Point2)
346 {
347  if((((tPointZ*)Point2)->z - ((tPointZ*)Point1)->z) < 0.0f)
348  return -1;
349  return 1;
350 }
351 
352 // --------------------------------------------------------------
353 // Removes the invisible parts of the graph.
354 void Rect3DDiagram::removeHiddenLines(char *zBuffer, tBound *Bounds)
355 {
356  double Dummy = 0.0; // number for 1-dimensional data in 3D cartesian
357  double *px, *py, *pz;
358 
359  Graph *g;
360  tPoint3D *p;
361  int i, j, z, dx, dy, Size=0;
362  // pre-calculate buffer size to avoid reallocations in the first step
363  for(g = Graphs.first(); g!=0; g = Graphs.next())
364  if(g->cPointsY)
365  Size += g->cPointsX.getFirst()->count * g->countY;
366 
367  // "Mem" should be the last malloc to simplify realloc
368  tPointZ *zMem = (tPointZ*)malloc( (Size+2)*sizeof(tPointZ) );
369  Mem = (tPoint3D*)malloc( 2*(Size+2)*sizeof(tPoint3D) );
370 
371  pMem = Mem;
372  tPointZ *zp = zMem, *zp_tmp;
373 
374  // ...............................................................
375  for(g = Graphs.first(); g!=0; g = Graphs.next()) {
376 
377  pz = g->cPointsY;
378  if(!pz) continue;
379  if(g->cPointsX.count() < 1) continue;
380 
381  py = &Dummy;
382  if(g->countY > 1) py = g->cPointsX.at(1)->Points;
383 
384  p = pMem; // save status for cross grid
385  zp_tmp = zp;
386  // ..........................................
387  // calculate coordinates of all lines
388  dx = g->cPointsX.first()->count;
389  if(g->countY > 1) dy = g->cPointsX.next()->count;
390  else dy = 0;
391  for(i=g->countY-1; i>=0; i--) { // y coordinates
392  px = g->cPointsX.getFirst()->Points;
393 
394  for(j=dx; j>0; j--) { // x coordinates
395  calcCoordinate3D(*(px++), *py, *pz, *(pz+1), pMem++, zp++);
396  pz += 2;
397  }
398 
399  (pMem-1)->done |= 8; // mark as "last in line"
400  py++;
401  if(dy > 0) if((i % dy) == 0)
402  py = g->cPointsX.at(1)->Points;
403  }
404  (pMem-1)->done |= 512; // mark as "last point before grid"
405 
406  // ..........................................
407  // copy points for cross lines ("dx", "dy" still unchanged ! )
408  if(g->countY > 1) {
409  zp = zp_tmp;
410  for(j=g->countY/dy; j>0; j--) { // every plane
411  for(i=dx; i>0; i--) { // every branch
412  for(z=dy; z>0; z--) { // every point
413  pMem->x = p->x;
414  pMem->y = p->y;
415  pMem->No = pMem-Mem;
416  pMem->done = 0;
417  zp->NoCross = pMem-Mem; // position of its cross grid
418  pMem++;
419  p += dx; // next coordinate
420  zp += dx;
421  }
422  (pMem-1)->done |= 8; // mark as "last in line"
423  p -= dx*dy - 1; // next z coordinate
424  zp -= dx*dy - 1;
425  }
426  p += dx*(dy-1);
427  zp += dx*(dy-1);
428  }
429  }
430  (pMem-1)->done |= 256; // mark as "very last point"
431 
432 
433  if(hideLines) {
434  // ..........................................
435  // Calculate the z-coordinate of all polygons by building the
436  // sum of the z-coordinates of all of its 4 corners.
437  // After this, each point represents one polygon. The unneccessary
438  // points are filled with "-FLTMAX".
439  zp = zp_tmp;
440  // "dx" and "dy" are still unchanged !
441  for(i=g->countY-1; i>=0; i--) { // all branches
442  if(dy > 0) if(i % dy) {
443  for(j=dx-1; j>0; j--) { // x coordinates
444  zp->z += (zp+1)->z + (zp+dx)->z + (zp+dx+1)->z;
445  zp++;
446  }
447  zp->z = -FLT_MAX; // last one not needed
448  zp++;
449  continue;
450  }
451 
452  // last line not needed
453  for(j=dx; j>0; j--) { // x coordinates
454  zp->z = -FLT_MAX; // last one not needed
455  zp++;
456  }
457  }
458  } // of "if(hideLines)"
459 
460  } // of "for(Graphs)"
461 
462 
463  if(!hideLines) { // do not hide invisible lines
464  free(zMem);
465  return;
466  }
467 
468 #if 0
469  qDebug("##########################################");
470  qDebug("Size 1b: Size=%d, %d, %d", Size, pMem-Mem, zp-zMem);
471  for(tPoint3D *p=Mem; p<pMem; p++)
472  qDebug("xyPoints: %d/%d - %d - %d", p->x, p->y, p->No, p->done);
473  qDebug("------------------------------------------");
474  for(tPointZ *p=zMem; p-zMem<Size; p++)
475  qDebug("zPoints: %g - %d", p->z, p->No);
476 #endif
477 
478 
479  // ..........................................
480  // Sort z-coordinates (greatest first).
481  // After this the polygons that have the smallest distance to the
482  // viewer are on top of the list and thus, will be processed first.
483  qsort(zMem, Size, sizeof(tPointZ), comparePointZ);
484 
485 #if 0
486  qDebug("--------------------------- z sorting");
487  for(tPointZ *p=zMem; p-zMem<Size; p++)
488  qDebug("zPoints: %g - %d", p->z, p->No);
489 #endif
490 
491 
492  // ..........................................
493  char *pc;
494  tPoint3D *MemEnd = Mem + 2*Size - 5; // limit of buffer
495 
496  zp = zMem;
497  for(g = Graphs.first(); g!=0; g = Graphs.next()) {
498  if(!g->cPointsY) continue;
499  dx = g->cPointsX.first()->count;
500  if(g->countY > 1) dy = g->cPointsX.next()->count;
501  else dy = 1;
502 
503  // look for hidden lines ...
504  for(int No = g->countY/dy * (dx-1)*(dy-1); No>0; No--) {
505 
506  // reset the polygon bounding buffer
507  for(i=x2; i>=0; i--) {
508  (Bounds+i)->max = INT_MIN;
509  (Bounds+i)->min = INT_MAX;
510  }
511 
512  // work on all 4 lines of polygon
513  p = Mem + zp->No; // polygon corner coordinates
514  calcLine(p, MemEnd, Bounds, zBuffer);
515 
516  p += dx;
517  calcLine(p, MemEnd, Bounds, zBuffer);
518 
519  p = Mem + zp->NoCross; // cross grid
520  calcLine(p, MemEnd, Bounds, zBuffer);
521 
522  p += dy;
523  calcLine(p, MemEnd, Bounds, zBuffer);
524 
525  // mark the area of the polygon (stored in "*Bounds") as used
526  for(i=x2-1; i>=0; i--) // all x coordinates
527  if( (Bounds+i)->max > INT_MIN) {
528  pc = zBuffer + i * ((y2+7)>>3);
529  for(j=(Bounds+i)->min; j<=(Bounds+i)->max; j++) // all y coordinates
530  *(pc + (j>>3)) |= (1 << (j & 7));
531  }
532 
533  zp++; // next polygon
534  }
535 
536  } // of "for(Graphs)"
537 
538 #if 0
539  qDebug("--------------------------- hidden lines %d", pMem-Mem);
540  for(tPoint3D *p=Mem; p<pMem; p++)
541  qDebug("xyPoints: %d/%d - %d - %d", p->x, p->y, p->No, p->done);
542 #endif
543 
544  free(zMem);
545 
546  // sort "No" (least one first)
547  qsort(Mem, pMem - Mem, sizeof(tPoint3D), comparePoint3D);
548 
549 #if 0
550  qDebug("--------------------------- last sorting %d", pMem-Mem);
551  for(tPoint3D *p=Mem; p<pMem; p++)
552  qDebug("xyPoints: %d/%d - %d - %d", p->x, p->y, p->No, p->done);
553  qDebug("\n");
554 #endif
555 }
556 
557 // --------------------------------------------------------------
558 // Removes the invisible parts of the coordinate cross.
559 void Rect3DDiagram::removeHiddenCross(int x1_, int y1_, int x2_, int y2_,
560  char *zBuffer, tBound *Bounds)
561 {
562  pMem = Mem;
563 
564  pMem->x = x1_;
565  pMem->y = y1_;
566  pMem->No = 0;
567  pMem->done = 0;
568  pMem++;
569 
570  pMem->x = x2_;
571  pMem->y = y2_;
572  pMem->No = 1;
573  pMem->done = 0;
574  pMem++;
575 
576  tPoint3D *p = Mem+6;
577  calcLine(Mem, p, Bounds, zBuffer);
578  *pMem = *(Mem+1);
579  *(Mem+1) = *Mem;
580  p = Mem+2;
581  do {
582  if(((p-1)->done & 4) == 0)
583  Lines.append(new Line((p-1)->x, (p-1)->y, p->x, p->y, QPen(Qt::black,0)));
584  p++;
585  } while(p <= pMem);
586 }
587 
588 // --------------------------------------------------------------
590 {
591  int i;
592  double a, b, c;
593 
594  if(xAxis.autoScale) {// check before, to preserve limit exchange (max < min)
595  if(xAxis.log) {
596  calcAxisLogScale(&xAxis, i, a, b, c, x2);
597  xAxis.step = 1.0;
598  }
599  else calcAxisScale(&xAxis, a, b, c, xAxis.step, double(x2));
602  }
603 
604  if(yAxis.autoScale) {// check before, to preserve limit exchange (max < min)
605  if(yAxis.log) {
606  calcAxisLogScale(&yAxis, i, a, b, c, y2);
607  yAxis.step = 1.0;
608  }
609  else calcAxisScale(&yAxis, a, b, c, yAxis.step, double(y2));
612  }
613 
614  if(zAxis.autoScale) {// check before, to preserve limit exchange (max < min)
615  if(zAxis.log) {
616  calcAxisLogScale(&zAxis, i, a, b, c, y2);
617  zAxis.step = 1.0;
618  }
619  else calcAxisScale(&zAxis, a, b, c, zAxis.step, double(y2));
622  }
623 }
624 
625 // --------------------------------------------------------------
626 int Rect3DDiagram::calcAxis(Axis *Axis, int x, int y,
627  double xD, double phi, bool Right)
628 {
629  double GridStep, corr, yD, stepD, GridNum, Expo;
630  double xstepD, ystepD;
631 
632  QString tmp;
633  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
634  int maxWidth = 0;
635  int count, gx, gy, w;
636 
637  if(phi > 0.0) Expo = phi - M_PI/2.0;
638  else Expo = phi + M_PI/2.0;
639  gx = int(5.4 * cos(Expo) + 0.5); // short grid marker lines
640  gy = int(5.4 * sin(Expo) + 0.5);
641 
642 
643 if(Axis->log) {
644 
645  bool back = calcAxisLogScale(Axis, w, yD, stepD, corr, int(xD));
646 
647  double upD = Axis->up;
648  if(yD > 1.5*stepD) yD = 10.0*stepD; // always start at power of 10
649  if(back) {
650  upD = Axis->low;
651  phi += M_PI;
652  xD = 0.0;
653  }
654 
655  int xLen, yLen;
656  ystepD = corr * log10(yD / fabs(Axis->low));
657  while(ystepD <= xD) { // create all grid lines
658 
659  tmp = StringNiceNum(yD);
660  if(Axis->up < 0.0) tmp = '-'+tmp;
661  w = metrics.width(tmp); // width of text
662  if(maxWidth < w) maxWidth = w;
663 
664  xLen = int(ystepD * cos(phi) + 0.5) + x;
665  yLen = int(ystepD * sin(phi) + 0.5) + y;
666  if(Qt::DockRight)
667  Texts.append(new Text(xLen+3+gx, yLen-6+gy, tmp));
668  else
669  Texts.append(new Text(xLen-w-2-gx, yLen-6-gy, tmp));
670 
671  // short grid marks
672  Lines.append(new Line(xLen-gx, yLen-gy, xLen+gx, yLen+gy,
673  QPen(Qt::black,0)));
674  yD *= 10.0;
675  ystepD += corr;
676  }
677 
678 }
679 else { // not logarithmical
680  calcAxisScale(Axis, GridNum, yD, stepD, GridStep, xD);
681  count = int((xD - yD) / stepD) + 1; // number of grids
682 
683  xstepD = stepD * cos(phi);
684  ystepD = stepD * sin(phi);
685  xD = yD * cos(phi) + 0.5 + double(x);
686  yD = yD * sin(phi) + 0.5 + double(y);
687 
688  if(Axis->up == 0.0) Expo = log10(fabs(Axis->up-Axis->low));
689  else Expo = log10(fabs(Axis->up));
690 
691  for(; count>0; count--) {
692  x = int(xD);
693  y = int(yD);
694  if(fabs(GridNum) < 0.01*pow(10.0, Expo)) GridNum = 0.0; // make 0 really 0
695  tmp = StringNiceNum(GridNum);
696 
697  w = metrics.width(tmp); // width of text
698  if(maxWidth < w) maxWidth = w;
699  if(Qt::DockRight)
700  Texts.append(new Text(x+3+gx, y-6+gy, tmp)); // place text right
701  else
702  Texts.append(new Text(x-w-2-gx, y-6-gy, tmp)); // place left
703  GridNum += GridStep;
704 
705  // short grid marks
706  Lines.append(new Line(x-gx, y-gy, x+gx, y+gy, QPen(Qt::black,0)));
707  xD += xstepD;
708  yD += ystepD;
709  }
710 } // of "if(ylog) ... else ..."
711 
712  return maxWidth+5;
713 }
714 
715 // --------------------------------------------------------------
717  int x1_, int y1_, int x2_, int y2_)
718 {
719  DataX *pD;
720  Graph *pg;
721  double phi, cos_phi, sin_phi;
722  int x, y, z, w, valid, Index = 0;
723  if(Axis == &yAxis) Index = 1;
724 
725  QString s;
726  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
727 
728  x = x2_ - x1_;
729  y = y2_ - y1_;
730  cos_phi = sqrt(double(x*x) + double(y*y));
731  phi = atan2(double(y), double(x));
732 
733  valid = calcAxis(Axis, x1_, y1_, cos_phi, phi, Qt::DockRight); // axis numbering
734  z = (int)cos_phi;
735  cos_phi = cos(phi);
736  sin_phi = sin(phi);
737 
738  if(fabs(phi-1e-5) > M_PI/2.0) {
739  x1_ = x2_; cos_phi *= -1;
740  y1_ = y2_; sin_phi *= -1;
741  }
742  x = x1_ + int(double(valid)*sin_phi);
743  y = y1_ - int(double(valid)*cos_phi);
744  if(Axis->Label.isEmpty()) {
745  // write all labels ----------------------------------------
746  for(pg = Graphs.first(); pg != 0; pg = Graphs.next()) {
747  if(Axis != &zAxis) {
748  if(!pg->cPointsY) continue;
749  if(valid < 0) {
750  delete[] pg->cPointsY;
751  pg->cPointsY = 0;
752  continue;
753  }
754  pD = pg->cPointsX.at(Index);
755  if(!pD) continue;
756  s = pD->Var;
757  }
758  else {
759  s = pg->Var;
760  if(!pg->cPointsY) s += INVALID_STR;
761  }
762  x += int(double(metrics.lineSpacing())*sin_phi);
763  y -= int(double(metrics.lineSpacing())*cos_phi);
764  w = metrics.width(s);
765  Texts.append(new Text(x+int(double((z-w)>>1)*cos_phi),
766  y+int(double((z-w)>>1)*sin_phi),
767  s, pg->Color, 12.0, cos_phi, sin_phi));
768  }
769  }
770  else {
771  x += int(double(metrics.lineSpacing())*sin_phi);
772  y -= int(double(metrics.lineSpacing())*cos_phi);
773  w = metrics.width(Axis->Label);
774  Texts.append(new Text(x+int(double((z-w)>>1)*cos_phi),
775  y+int(double((z-w)>>1)*sin_phi),
776  Axis->Label, Qt::black, 12.0, cos_phi, sin_phi));
777  }
778 }
779 
780 // --------------------------------------------------------------
782 {
783  Lines.clear();
784  Texts.clear();
785  Arcs.clear();
786 
787  double GridStep, corr, zD, zDstep, GridNum;
788  QFontMetrics metrics(((Schematic*)QucsMain->DocumentTab->currentPage())->font()); // get size of text
789 
790  x3 = x2 + 7;
791  int z, z2, o, w;
792 
793  char *zBuffer=0; // hidden line algorithm
794  tBound *Bounds=0;
795 
796 
797  // ===== give "step" the right sign ==================================
798  xAxis.step = fabs(xAxis.step);
800  xAxis.step *= -1.0;
801 
802  yAxis.step = fabs(yAxis.step);
804  yAxis.step *= -1.0;
805 
806  zAxis.step = fabs(zAxis.step);
808  zAxis.step *= -1.0;
809 
810 
811  // ===== calculate Axis.up and Axis.low ==============================
812  if(xAxis.log) {
813  if(xAxis.autoScale) {
814  if(xAxis.max*xAxis.min <= 0.0) goto Frame; // invalid
815  }
816  else if(xAxis.limit_min*xAxis.limit_max <= 0.0) goto Frame; // invalid
817  calcAxisLogScale(&xAxis, z, zD, zDstep, corr, x2);
818  }
819  else calcAxisScale(&xAxis, GridNum, zD, zDstep, GridStep, double(x2));
820 
821  if(yAxis.log) {
822  if(yAxis.autoScale) {
823  if(yAxis.max*yAxis.min <= 0.0) goto Frame; // invalid
824  }
825  else if(yAxis.limit_min*yAxis.limit_max <= 0.0) goto Frame; // invalid
826  calcAxisLogScale(&yAxis, z, zD, zDstep, corr, x2);
827  }
828  else calcAxisScale(&yAxis, GridNum, zD, zDstep, GridStep, double(x2));
829 
830  if(zAxis.log) {
831  if(zAxis.autoScale) {
832  if(zAxis.max*zAxis.min <= 0.0) goto Frame; // invalid
833  }
834  else if(zAxis.limit_min*zAxis.limit_max <= 0.0) goto Frame; // invalid
835  calcAxisLogScale(&zAxis, z, zD, zDstep, corr, x2);
836  }
837  else calcAxisScale(&zAxis, GridNum, zD, zDstep, GridStep, double(x2));
838 
839 
840  // === calculate transformation coefficients from rotation angles ===
842 
843  // ===== check calculate position of axes in 2D rectangle ===========
844  int X[8], Y[8];
845  o = calcCross(X, Y);
846  // "o" is now the index of the origin coordinates.
847 
848 
849  // ===== paint coordinate cross ====================================
850  // xy area
851  Lines.append(new Line(X[o^1], Y[o^1], X[o^3], Y[o^3], QPen(Qt::black,0)));
852  Lines.append(new Line(X[o^2], Y[o^2], X[o^3], Y[o^3], QPen(Qt::black,0)));
853 
854  // yz area
855  Lines.append(new Line(X[o^2], Y[o^2], X[o^6], Y[o^6], QPen(Qt::black,0)));
856  Lines.append(new Line(X[o^4], Y[o^4], X[o^6], Y[o^6], QPen(Qt::black,0)));
857 
858  // xz area
859  Lines.append(new Line(X[o^1], Y[o^1], X[o^5], Y[o^5], QPen(Qt::black,0)));
860  Lines.append(new Line(X[o^4], Y[o^4], X[o^5], Y[o^5], QPen(Qt::black,0)));
861 
862 
863  // ===== create axis =============================================
864  if(X[o^1] < X[o^2]) w = 2; // use which z axis ?
865  else w = 1;
866 
867  z = o^2;
868  if(z & 1) z ^= 1; // from where to where ?
869  z2 = z^1;
870  createAxis(&xAxis, w == 2, X[z], Y[z], X[z2], Y[z2]);
871 
872  z = o^1;
873  if(z & 2) z ^= 2; // from where to where ?
874  z2 = z^2;
875  createAxis(&yAxis, w == 1, X[z], Y[z], X[z2], Y[z2]);
876 
877  z = o^w;
878  if(z & 4) z ^= 4; // from where to where ?
879  z2 = z^4;
880  createAxis(&zAxis, true, X[z], Y[z], X[z2], Y[z2]);
881 
882 
883  if(hideLines) {
884  w = (x2+1) * (y2/8 + 1);
885  // To store the pixel coordinates that are already used (hidden).
886  // Use one bit per pixel.
887  zBuffer = (char*)malloc(w);
888  memset(zBuffer, 0, w);
889 
890  // To store the boundings of the current polygon.
891  Bounds = (tBound*)malloc((x2+1) * sizeof(tBound));
892  }
893 
894  // hide invisible parts of graphs
895  removeHiddenLines(zBuffer, Bounds);
896 
897  if(hideLines) {
898  // now hide invisible part of coordinate cross
899  tPoint3D *MemTmp = Mem;
900  Mem = (tPoint3D*)malloc( 10*sizeof(tPoint3D) );
901 
902  removeHiddenCross(X[o^1], Y[o^1], X[o], Y[o], zBuffer, Bounds); // x axis
903  removeHiddenCross(X[o^2], Y[o^2], X[o], Y[o], zBuffer, Bounds); // y axis
904  removeHiddenCross(X[o^4], Y[o^4], X[o], Y[o], zBuffer, Bounds); // z axis
905 
906  free(Mem);
907  Mem = MemTmp; // write back values
908 
909  free(Bounds);
910  free(zBuffer);
911  }
912  else {
913  Lines.append(new Line(X[o], Y[o], X[o^1], Y[o^1], QPen(Qt::black,0)));
914  Lines.append(new Line(X[o], Y[o], X[o^2], Y[o^2], QPen(Qt::black,0)));
915  Lines.append(new Line(X[o], Y[o], X[o^4], Y[o^4], QPen(Qt::black,0)));
916  }
917 
918  pMem = Mem;
919  return 3;
920 
921 
922 Frame: // jump here if error occurred (e.g. impossible log boundings)
923  Lines.append(new Line(0, y2, x2, y2, QPen(Qt::black,0)));
924  Lines.append(new Line(x2, y2, x2, 0, QPen(Qt::black,0)));
925  Lines.append(new Line(0, 0, x2, 0, QPen(Qt::black,0)));
926  Lines.append(new Line(0, y2, 0, 0, QPen(Qt::black,0)));
927  return 0;
928 }
929 
930 // ------------------------------------------------------------
931 // g->Points must already be empty!!!
933 {
934  if(!pMem) return;
935  if(!g->cPointsY) return;
936 
937  int tmp;
938  int Size = ((2*(g->cPointsX.getFirst()->count) + 1) * g->countY) + 10;
939  Size *= 2; // memory for cross grid lines
940 
941  double *py;
942  if(g->countY > 1) py = g->cPointsX.at(1)->Points;
943 
944  float *p = (float*)malloc( Size*sizeof(float) ); // create memory for points
945  float *p_end;
946  g->ScrPoints = p_end = p;
947  p_end += Size - 9; // limit of buffer
948 
949 
950  *(p++) = STROKEEND;
951  float dx=0.0, dy=0.0, xtmp=0.0, ytmp=0.0;
952  double Stroke=10.0, Space=10.0; // length of strokes and spaces in pixel
953  switch(g->Style) {
954  case 0: // ***** solid line **********************************
955  do {
956 
957  while(1) {
958  if(pMem->done & 11) // is grid point ?
959  if(pMem->done & 4) { // is hidden
960  if(pMem > Mem) {
961  if((pMem-1)->done & 12)
962  break;
963  }
964  else break;
965  }
966 
967  FIT_MEMORY_SIZE; // need to enlarge memory block ?
968  *(p++) = pMem->x;
969  *(p++) = pMem->y;
970  break;
971  }
972 
973  FIT_MEMORY_SIZE; // need to enlarge memory block ?
974  if(pMem->done & 8) *(p++) = BRANCHEND; // new branch
975 
976  if(pMem->done & 4) // point invisible ?
977  if( *(p-1) >= 0 ) // line already interrupted ?
978  *(p++) = STROKEEND;
979 
980  } while(((pMem++)->done & 256) == 0);
981  *p = GRAPHEND;
982  return;
983 
984  case GRAPHSTYLE_DASH:
985  Stroke = 10.0; Space = 6.0;
986  break;
987  case GRAPHSTYLE_DOT:
988  Stroke = 2.0; Space = 4.0;
989  break;
990  case GRAPHSTYLE_LONGDASH:
991  Stroke = 24.0; Space = 8.0;
992  break;
993 
994  default: // symbol (e.g. star) at each point **********************
995  do {
996  while(1) {
997  if(pMem->done & 11) // is grid point ?
998  if(pMem->done & 4) { // is hidden
999  if(pMem > Mem) {
1000  if((pMem-1)->done & 12)
1001  break;
1002  }
1003  else break;
1004  }
1005 
1006  *(p++) = pMem->x;
1007  *(p++) = pMem->y;
1008  break;
1009  }
1010 
1011  if(pMem->done & 8)
1012  *(p++) = BRANCHEND; // new branch
1013  } while(((pMem++)->done & 512) == 0);
1014  *p = GRAPHEND;
1015  return;
1016  }
1017 
1018 
1019  // ********** dashed, dotted, ... *******************************
1020  int Counter = 0; // counter for number of points in queue
1021  double alpha, dist = -Stroke;
1022  int Flag = 1; // current state: 1=stroke, 0=space
1023  do {
1024  while(1) {
1025  if(pMem->done & 11) // is grid point ?
1026  if(pMem->done & 4) { // is hidden
1027  if(pMem > Mem) {
1028  if((pMem-1)->done & 12)
1029  break;
1030  }
1031  else break;
1032  }
1033 
1034  xtmp = pMem->x;
1035  ytmp = pMem->y;
1036  Counter++;
1037  break;
1038  }
1039 
1040 
1041  if(Counter > 1) {
1042  if(Counter == 2) {
1043  *(p++) = dx; // if first points of branch -> paint first one
1044  *(p++) = dy;
1045  }
1046  dx = xtmp - dx;
1047  dy = ytmp - dy;
1048  dist += sqrt(double(dx*dx + dy*dy)); // distance between points
1049  if((Flag == 1) && (dist <= 0.0)) {
1050  FIT_MEMORY_SIZE; // need to enlarge memory block ?
1051  *(p++) = xtmp; // if stroke then save points
1052  *(p++) = ytmp;
1053  }
1054  else {
1055  alpha = atan2(double(dy), double(dx)); // slope for interpolation
1056  while(dist > 0) { // stroke or space finished ?
1057  FIT_MEMORY_SIZE; // need to enlarge memory block ?
1058 
1059  *(p++) = xtmp - float(dist*cos(alpha)); // linearly interpolate
1060  *(p++) = ytmp - float(dist*sin(alpha));
1061 
1062  if(Flag == 0) {
1063  dist -= Stroke;
1064  if(dist <= 0) {
1065  *(p++) = xtmp; // don't forget point after ...
1066  *(p++) = ytmp; // ... interpolated point
1067  }
1068  }
1069  else {
1070  dist -= Space;
1071  if(*(p-3) < 0) p -= 2;
1072  else *(p++) = STROKEEND;
1073  }
1074  Flag ^= 1; // toggle between stroke and space
1075  }
1076  }
1077 
1078  } // of "if(Counter > 1)"
1079 
1080 
1081  dx = xtmp;
1082  dy = ytmp;
1083 
1084  if(pMem->done & 8) {
1085  if(*(p-3) == STROKEEND)
1086  p -= 3; // no single point after "no stroke"
1087  else if(*(p-3) == BRANCHEND) {
1088  if((*(p-2) < 0) || (*(p-1) < 0))
1089  p -= 2; // erase last hidden point
1090  }
1091  *(p++) = BRANCHEND; // new branch
1092  Counter = 0;
1093  Flag = 1;
1094  dist = -Stroke;
1095  }
1096 
1097  if(pMem->done & 4) // point invisible ?
1098  if( *(p-1) >= 0 ) // line already interrupted ?
1099  *(p++) = STROKEEND;
1100 
1101  } while(((pMem++)->done & 256) == 0);
1102 
1103  *p = GRAPHEND;
1104 
1105 
1106 /*
1107 int z = p-g->Points+1;
1108 p = g->Points;
1109 qDebug("\n****** p=%p", p);
1110 for(int zz=0; zz<z; zz+=2)
1111  qDebug("c: %d/%d", *(p+zz), *(p+zz+1));
1112 qDebug("ENDE");*/
1113 }
1114 
1115 // ------------------------------------------------------------
1116 // The labels are created during "calcDiagram", but the memory
1117 // for the coordinates is released here.
1119 {
1120  if(Mem) free (Mem);
1121  Mem = 0;
1122  pMem = 0;
1123 }
1124 
1125 // ------------------------------------------------------------
1126 bool Rect3DDiagram::insideDiagram(float x, float y)
1127 {
1128  return (regionCode(x, y) == 0);
1129 }
1130 
1131 // ------------------------------------------------------------
1133 {
1134  return new Rect3DDiagram();
1135 }
1136 
1137 // ------------------------------------------------------------
1138 Element* Rect3DDiagram::info(QString& Name, char* &BitmapFile, bool getNewOne)
1139 {
1140  Name = QObject::tr("3D-Cartesian");
1141  BitmapFile = (char *) "rect3d";
1142 
1143  if(getNewOne) return new Rect3DDiagram();
1144  return 0;
1145 }
float z
Definition: rect3ddiagram.h:30
Axis xAxis
Definition: diagram.h:101
#define GRAPHSTYLE_DASH
Definition: graph.h:36
int regionCode(float, float)
Definition: diagram.cpp:287
int countY
Definition: graph.h:74
int y1
Definition: element.h:153
Definition: graph.h:57
static Element * info(QString &, char *&, bool getNewOne=false)
#define GRAPHSTYLE_LONGDASH
Definition: graph.h:38
int rotX
Definition: diagram.h:105
QString Name
Definition: diagram.h:92
Rect3DDiagram(int _cx=0, int _cy=0)
float * ScrPoints
Definition: graph.h:73
Diagram * newOne()
#define BRANCHEND
Definition: graph.h:32
int y2
Definition: element.h:153
int x1
Definition: element.h:153
bool hideLines
Definition: diagram.h:104
QString Var
Definition: graph.h:50
double calcX_2D(double, double, double)
Definition: graph.h:47
double limit_min
Definition: diagram.h:56
tPoint3D * pMem
Definition: rect3ddiagram.h:55
#define STROKEEND
Definition: graph.h:31
int rotZ
Definition: diagram.h:105
double calcZ_2D(double, double, double)
void removeHiddenLines(char *, tBound *)
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
int cx
Definition: element.h:153
static int comparePointZ(const void *, const void *)
bool insideDiagram(float, float)
void calcCoefficients()
void removeHiddenCross(int, int, int, int, char *, tBound *)
void calcCoordinate3D(double, double, double, double, tPoint3D *, tPointZ *)
void calcLine(tPoint3D *&, tPoint3D *&, tBound *, char *)
Axis zAxis
Definition: diagram.h:101
Q3PtrList< Graph > Graphs
Definition: diagram.h:95
Q3PtrList< struct Arc > Arcs
Definition: diagram.h:96
Definition: diagram.h:47
bool log
Definition: diagram.h:50
bool isHidden(int, int, tBound *, char *)
Definition: element.h:82
void enlargeMemoryBlock(tPoint3D *&)
int x3
Definition: diagram.h:100
Definition: element.h:48
bool calcAxisLogScale(Axis *, int &, double &, double &, double &, int)
Definition: diagram.cpp:1783
Superclass of all schematic drawing elements.
Definition: element.h:142
double calcY_2D(double, double, double)
int calcCross(int *, int *)
double max
Definition: diagram.h:48
double limit_max
Definition: diagram.h:56
QString Label
Definition: diagram.h:51
int Style
Definition: graph.h:78
tPoint3D * Mem
Definition: rect3ddiagram.h:54
int y3
Definition: diagram.h:100
QTabWidget * DocumentTab
Definition: qucs.h:164
void createAxis(Axis *, bool, int, int, int, int)
QColor Color
Definition: graph.h:76
Q3PtrList< Text > Texts
Definition: diagram.h:98
void calcData(Graph *)
#define FIT_MEMORY_SIZE
Definition: diagram.h:37
bool calcAxisScale(Axis *, double &, double &, double &, double &, double)
Definition: diagram.cpp:1665
int cy
Definition: element.h:153
int NoCross
Definition: rect3ddiagram.h:31
Axis yAxis
Definition: diagram.h:101
double step
Definition: diagram.h:56
#define M_PI
Definition: diagramdialog.h:25
Q3PtrList< DataX > cPointsX
Definition: graph.h:71
double up
Definition: diagram.h:49
#define INVALID_STR
Definition: diagram.h:33
static int comparePoint3D(const void *, const void *)
int calcAxis(Axis *, int, int, double, double, bool)
#define GRAPHEND
Definition: graph.h:33
int x2
Definition: element.h:153
double * cPointsY
Definition: graph.h:72
bool autoScale
Definition: diagram.h:55
Q3PtrList< Line > Lines
Definition: diagram.h:97
#define GRAPHSTYLE_DOT
Definition: graph.h:37
int rotY
Definition: diagram.h:105
double low
Definition: diagram.h:49
double min
Definition: diagram.h:48
void calcCoordinate(double *&, double *&, double *&, float *, float *, Axis *)