rect3ddiagram.cpp
-------------------
begin : Sat Mar 5 2005
copyright : (C) 2005 by Michael Margraf
email : michael.margraf@alumni.tu-berlin.de
***************************************************************************/
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
\class Rect3DDiagram
\brief The Rect3DDiagram class implements the 3D-Cartesian diagram
*/
#include <QFontMetrics>
#if HAVE_CONFIG_H
# include <config.h>
#endif
#include <stdlib.h>
#include <cmath>
#include <float.h>
#include <limits.h>
#if HAVE_IEEEFP_H
# include <ieeefp.h>
#endif
#include "rect3ddiagram.h"
#include "main.h"
#include "misc.h"
Rect3DDiagram::Rect3DDiagram(int _cx, int _cy) : Diagram(_cx, _cy)
{
x1 = 10;
y1 = y3 = 7;
x2 = 200;
y2 = 200;
x3 = 207;
Mem = pMem = 0;
Name = "Rect3D";
Lines.append(new qucs::Line(0, 0, cx, 0, QPen(Qt::black,0)));
Lines.append(new qucs::Line(0, 0, 0, cy, QPen(Qt::black,0)));
Lines.append(new qucs::Line(0, 0, cx/2, cy/2, QPen(Qt::black,0)));
}
Rect3DDiagram::~Rect3DDiagram()
{
}
void Rect3DDiagram::calcCoefficients()
{
double rX = double(rotX) * pi/180.0;
double rY = double(rotY) * pi/180.0;
double rZ = double(rotZ) * pi/180.0;
cxy = sin(rZ); cxx = cos(rZ);
cxz = sin(rY); rY = cos(rY);
cyz = sin(rX); czz = cos(rX);
rX = cyz*cxz; rZ = czz*cxz;
cyx = czz * cxy + rX * cxx;
cyy = czz * cxx - rX * cxy;
czx = cyz * cxy - rZ * cxx;
czy = cyz * cxx + rZ * cxy;
cxx *= rY; cxy *= -rY; cyz *= -rY; czz *= rY;
}
double Rect3DDiagram::calcX_2D(double x, double y, double z) const
{
return (cxx * x + cxy * y + cxz * z) * scaleX;
}
double Rect3DDiagram::calcY_2D(double x, double y, double z) const
{
return (cyx * x + cyy * y + cyz * z) * scaleY;
}
double Rect3DDiagram::calcZ_2D(double x, double y, double z) const
{
return czx * x + czy * y + czz * z;
}
int Rect3DDiagram::calcCross(int *Xses, int *Yses)
{
double x3D, y3D, z3D, x2D[8], y2D[8], z2D;
double XMIN_2D, XMAX_2D, YMIN_2D, YMAX_2D, ZMIN_2D;
int z, Center = 0;
scaleX = scaleY = 1.0;
XMIN_2D = YMIN_2D = XMAX_2D = YMAX_2D = ZMIN_2D = 0.0;
for(z=0; z<8; z++) {
if(z & 1) x3D = 1.0; else x3D = 0.0;
if(z & 2) y3D = 1.0; else y3D = 0.0;
if(z & 4) z3D = 1.0; else z3D = 0.0;
x2D[z] = calcX_2D(x3D, y3D, z3D);
y2D[z] = calcY_2D(x3D, y3D, z3D);
z2D = calcZ_2D(x3D, y3D, z3D);
if(x2D[z] < XMIN_2D) XMIN_2D = x2D[z];
if(x2D[z] > XMAX_2D) XMAX_2D = x2D[z];
if(y2D[z] < YMIN_2D) YMIN_2D = y2D[z];
if(y2D[z] > YMAX_2D) YMAX_2D = y2D[z];
if(z2D < ZMIN_2D) { ZMIN_2D = z2D; Center = z; }
}
scaleX = double(x2) / (XMAX_2D - XMIN_2D);
scaleY = double(y2) / (YMAX_2D - YMIN_2D);
xorig = -XMIN_2D * scaleX;
yorig = -YMIN_2D * scaleY;
for(z=0; z<8; z++) {
*(Xses+z) = int(x2D[z] * scaleX + 0.5 + xorig);
*(Yses+z) = int(y2D[z] * scaleY + 0.5 + yorig);
}
return Center;
}
void Rect3DDiagram::calcCoordinate(const double* xD, const double* zD, const double* yD,
float *px, float *py, Axis const*) const
{
double x3D = zD[0];
double y3D = zD[1];
double z3D;
if(zAxis.log) {
z3D = sqrt(x3D*x3D + y3D*y3D);
z3D = -1e5; // "negative infinity"
else*/
z3D = log10(z3D / fabs(zAxis.low)) / log10(zAxis.up / zAxis.low);
}
else {
if(fabs(y3D) > 1e-250)
x3D = sqrt(x3D*x3D + y3D*y3D);
z3D = (x3D - zAxis.low) / (zAxis.up - zAxis.low);
}
x3D = *(xD++);
if(xAxis.log) {
x3D /= xAxis.low;
x3D = -1e5; // "negative infinity"
else*/
x3D = log10(x3D) / log10(xAxis.up / xAxis.low);
}
else
x3D = (x3D - xAxis.low) / (xAxis.up - xAxis.low);
if(yAxis.log) {
y3D = (*yD) / yAxis.low;
y3D = -1e5; // "negative infinity"
else*/
y3D = log10(y3D) / log10(yAxis.up / yAxis.low);
}
else
y3D = (*yD - yAxis.low) / (yAxis.up - yAxis.low);
*px = float(calcX_2D(x3D, y3D, z3D)) + xorig;
*py = float(calcY_2D(x3D, y3D, z3D)) + yorig;
if(std::isfinite(*px))
if(std::isfinite(*py))
return;
*px = float(xorig);
*py = float(yorig);
}
void Rect3DDiagram::finishMarkerCoordinates(float& fCX, float& fCY) const
{
if(!insideDiagram(fCX, fCY)) {
fCX = fCY = 0.0;
}
}
void Rect3DDiagram::calcCoordinate3D(double x, double y, double zr, double zi,
tPoint3D *p, tPointZ *pz)
{
if(zAxis.log) {
zr = sqrt(zr*zr + zi*zi);
zr = -1e5; // "negative infinity"
else*/
zr = log10(zr / fabs(zAxis.low)) / log10(zAxis.up / zAxis.low);
}
else {
if(fabs(zi) > 1e-250)
zr = sqrt(zr*zr + zi*zi);
zr = (zr - zAxis.low) / (zAxis.up - zAxis.low);
}
if(xAxis.log) {
x /= xAxis.low;
x = -1e5; // "negative infinity"
else*/
x = log10(x) / log10(xAxis.up / xAxis.low);
}
else
x = (x - xAxis.low) / (xAxis.up - xAxis.low);
if(yAxis.log) {
y = y / yAxis.low;
y = -1e5; // "negative infinity"
else*/
y = log10(y) / log10(yAxis.up / yAxis.low);
}
else
y = (y - yAxis.low) / (yAxis.up - yAxis.low);
p->x = int(calcX_2D(x, y, zr) + 0.5 + xorig);
p->y = int(calcY_2D(x, y, zr) + 0.5 + yorig);
p->No = pz->No = p-Mem;
p->done = 0;
pz->z = float(calcZ_2D(x, y, zr));
}
bool Rect3DDiagram::isHidden(int x, int y, tBound *Bounds, char *zBuffer)
{
if( (Bounds+x)->max < y ) (Bounds+x)->max = y;
if( (Bounds+x)->min > y ) (Bounds+x)->min = y;
return ( *(zBuffer + (y>>3) + x * ((y2+7)>>3)) & (1 << (y & 7)) ) != 0;
}
void Rect3DDiagram::enlargeMemoryBlock(tPoint3D* &MemEnd)
{
if(pMem >= MemEnd) {
int Size = MemEnd - Mem + 256;
MemEnd = Mem;
Mem = (tPoint3D*)realloc(Mem, Size*sizeof(tPoint3D));
pMem += Mem - MemEnd;
MemEnd = Mem + Size - 5;
}
}
void Rect3DDiagram::calcLine(tPoint3D* &p, tPoint3D* &MemEnd,
tBound *Bounds, char *zBuffer)
{
int Pos_;
int x1_ = p->x, y1_ = p->y;
int x2_ = (p+1)->x, y2_ = (p+1)->y;
bool wasHidden = isHidden(x1_, y1_, Bounds, zBuffer);
if(wasHidden)
if((p->done & 1) == 0)
p->done |= 4;
int ax_ = 0, ay_ = 0;
int ix_, iy_, dx_, dy_, of_;
if(x2_ >= x1_) {
dx_ = x2_ - x1_;
ix_ = 1;
}
else {
dx_ = x1_ - x2_;
ix_ = -1;
}
if(y2_ >= y1_) {
dy_ = y2_ - y1_;
iy_ = 1;
}
else {
dy_ = y1_ - y2_;
iy_ = -1;
}
if(dx_ < dy_) {
of_ = dx_;
dx_ = dy_;
dy_ = of_;
ax_ = iy_;
ay_ = ix_;
ix_ = iy_ = 0;
}
of_ = dx_ >> 1;
for(int i=dx_; i>1; i--) {
x1_ += ix_;
y1_ += ax_;
of_ += dy_;
if(of_ > dx_) {
of_ -= dx_;
x1_ += ay_;
y1_ += iy_;
}
if( isHidden(x1_, y1_, Bounds, zBuffer) != wasHidden )
if((p->done & 1) == 0) {
wasHidden = !wasHidden;
pMem->x = x1_;
pMem->y = y1_;
pMem->No = p->No;
pMem->done = 0;
if(wasHidden) pMem->done = 4;
pMem++;
Pos_ = p - Mem;
enlargeMemoryBlock(MemEnd);
p = Mem + Pos_;
}
}
if(!isHidden((p+1)->x, (p+1)->y, Bounds, zBuffer))
{
if(!isHidden((p)->x, (p)->y, Bounds, zBuffer))
{
(p+1)->done &= ~4;
}
else
{
(p)->done &= ~4;
}
}
p->done |= 1;
}
int Rect3DDiagram::comparePoint3D(const void *Point1, const void *Point2)
{
return ((tPoint3D*)Point1)->No - ((tPoint3D*)Point2)->No;
}
int Rect3DDiagram::comparePointZ(const void *Point1, const void *Point2)
{
if((((tPointZ*)Point2)->z - ((tPointZ*)Point1)->z) < 0.0f)
return -1;
return 1;
}
void Rect3DDiagram::removeHiddenLines(char *zBuffer, tBound *Bounds)
{
double Dummy = 0.0;
double *px, *py, *pz;
tPoint3D *p;
int i, j, z, dx, dy, Size=0;
for (Graph *g : Graphs)
if(g->cPointsY)
Size += g->axis(0)->count * g->countY;
int malloc_8xsize=8;
tPointZ *zMem = (tPointZ*)malloc( malloc_8xsize*(Size+2)*sizeof(tPointZ) );
Mem = (tPoint3D*)malloc( malloc_8xsize*2*(Size+2)*sizeof(tPoint3D) );
pMem = Mem;
tPointZ *zp = zMem, *zp_tmp;
for (Graph *g : Graphs) {
pz = g->cPointsY;
if(!pz) continue;
if(g->numAxes() < 1) continue;
py = &Dummy;
if(g->countY > 1) py = g->axis(1)->Points;
p = pMem;
zp_tmp = zp;
dx = g->axis(0)->count;
if(g->countY > 1) dy = g->axis(1)->count;
else dy = 0;
for(i=g->countY-1; i>=0; i--) {
px = g->axis(0)->Points;
for(j=dx; j>0; j--) {
calcCoordinate3D(*(px++), *py, *pz, *(pz+1), pMem++, zp++);
pz += 2;
}
(pMem-1)->done |= 8;
py++;
if(dy > 0) if((i % dy) == 0)
py = g->axis(1)->Points;
}
(pMem-1)->done |= 512;
if(g->countY > 1) {
zp = zp_tmp;
for(j=g->countY/dy; j>0; j--) {
for(i=dx; i>0; i--) {
for(z=dy; z>0; z--) {
pMem->x = p->x;
pMem->y = p->y;
pMem->No = pMem-Mem;
pMem->done = 0;
zp->NoCross = pMem-Mem;
pMem++;
p += dx;
zp += dx;
}
(pMem-1)->done |= 8;
p -= dx*dy - 1;
zp -= dx*dy - 1;
}
p += dx*(dy-1);
zp += dx*(dy-1);
}
}
(pMem-1)->done |= 256;
if(hideLines) {
zp = zp_tmp;
for(i=g->countY-1; i>=0; i--) {
if(dy > 0) if(i % dy) {
for(j=dx-1; j>0; j--) {
zp->z += (zp+1)->z + (zp+dx)->z + (zp+dx+1)->z;
zp++;
}
zp->z = -FLT_MAX;
zp++;
continue;
}
for(j=dx; j>0; j--) {
zp->z = -FLT_MAX;
zp++;
}
}
}
}
if(!hideLines) {
free(zMem);
return;
}
#if 0
qDebug("##########################################");
qDebug("Size 1b: Size=%d, %d, %d", Size, pMem-Mem, zp-zMem);
for(tPoint3D *p=Mem; p<pMem; p++)
qDebug("xyPoints: %d/%d - %d - %d", p->x, p->y, p->No, p->done);
qDebug("------------------------------------------");
for(tPointZ *p=zMem; p-zMem<Size; p++)
qDebug("zPoints: %g - %d", p->z, p->No);
#endif
qsort(zMem, Size, sizeof(tPointZ), comparePointZ);
#if 0
qDebug("--------------------------- z sorting");
for(tPointZ *p=zMem; p-zMem<Size; p++)
qDebug("zPoints: %g - %d", p->z, p->No);
#endif
char *pc;
tPoint3D *MemEnd = Mem + malloc_8xsize*2*Size - 5;
zp = zMem;
for (Graph *g : Graphs) {
if(!g->cPointsY) continue;
dx = g->axis(0)->count;
if(g->countY > 1) dy = g->axis(1)->count;
else dy = 1;
for(int No = g->countY/dy * (dx-1)*(dy-1); No>0; No--) {
for(i=x2; i>=0; i--) {
(Bounds+i)->max = INT_MIN;
(Bounds+i)->min = INT_MAX;
}
p = Mem + zp->No;
calcLine(p, MemEnd, Bounds, zBuffer);
p += dx;
calcLine(p, MemEnd, Bounds, zBuffer);
p = Mem + zp->NoCross;
calcLine(p, MemEnd, Bounds, zBuffer);
p += dy;
calcLine(p, MemEnd, Bounds, zBuffer);
for(i=x2-1; i>=0; i--)
if( (Bounds+i)->max > INT_MIN) {
pc = zBuffer + i * ((y2+7)>>3);
for(j=(Bounds+i)->min; j<=(Bounds+i)->max; j++)
*(pc + (j>>3)) |= (1 << (j & 7));
}
zp++;
}
}
#if 0
qDebug("--------------------------- hidden lines %d", pMem-Mem);
for(tPoint3D *p=Mem; p<pMem; p++)
qDebug("xyPoints: %d/%d - %d - %d", p->x, p->y, p->No, p->done);
#endif
free(zMem);
qsort(Mem, pMem - Mem, sizeof(tPoint3D), comparePoint3D);
#if 0
qDebug("--------------------------- last sorting %d", pMem-Mem);
for(tPoint3D *p=Mem; p<pMem; p++)
qDebug("xyPoints: %d/%d - %d - %d", p->x, p->y, p->No, p->done);
qDebug("\n");
#endif
}
void Rect3DDiagram::removeHiddenCross(int x1_, int y1_, int x2_, int y2_,
char *zBuffer, tBound *Bounds)
{
pMem = Mem;
pMem->x = x1_;
pMem->y = y1_;
pMem->No = 0;
pMem->done = 0;
pMem++;
pMem->x = x2_;
pMem->y = y2_;
pMem->No = 1;
pMem->done = 0;
pMem++;
tPoint3D *p = Mem+6;
calcLine(Mem, p, Bounds, zBuffer);
*pMem = *(Mem+1);
*(Mem+1) = *Mem;
p = Mem+2;
do {
if(((p-1)->done & 4) == 0)
Lines.append(new qucs::Line((p-1)->x, (p-1)->y, p->x, p->y, QPen(Qt::black,0)));
p++;
} while(p <= pMem);
}
void Rect3DDiagram::calcLimits()
{
int i;
double a, b, c;
if(xAxis.autoScale) {
if(xAxis.log) {
calcAxisLogScale(&xAxis, i, a, b, c, x2);
xAxis.step = 1.0;
}
else calcAxisScale(&xAxis, a, b, c, xAxis.step, double(x2));
xAxis.limit_min = xAxis.low;
xAxis.limit_max = xAxis.up;
}
if(yAxis.autoScale) {
if(yAxis.log) {
calcAxisLogScale(&yAxis, i, a, b, c, y2);
yAxis.step = 1.0;
}
else calcAxisScale(&yAxis, a, b, c, yAxis.step, double(y2));
yAxis.limit_min = yAxis.low;
yAxis.limit_max = yAxis.up;
}
if(zAxis.autoScale) {
if(zAxis.log) {
calcAxisLogScale(&zAxis, i, a, b, c, y2);
zAxis.step = 1.0;
}
else calcAxisScale(&zAxis, a, b, c, zAxis.step, double(y2));
zAxis.limit_min = zAxis.low;
zAxis.limit_max = zAxis.up;
}
}
int Rect3DDiagram::calcAxis(Axis *Axis, int x, int y,
double xD, double phi)
{
double GridStep, corr, yD, stepD, GridNum, Expo;
double xstepD, ystepD;
QString tmp;
QFontMetrics metrics(QucsSettings.font, 0);
int maxWidth = 0;
int count, gx, gy, w;
if(phi > 0.0) Expo = phi - pi/2.0;
else Expo = phi + pi/2.0;
gx = int(5.4 * cos(Expo) + 0.5);
gy = int(5.4 * sin(Expo) + 0.5);
if(Axis->log) {
bool back = calcAxisLogScale(Axis, w, yD, stepD, corr, int(xD));
if(yD > 1.5*stepD) yD = 10.0*stepD;
if(back) {
phi += pi;
xD = 0.0;
}
int xLen, yLen;
ystepD = corr * log10(yD / fabs(Axis->low));
while(ystepD <= xD) {
if (engineeringNotation) tmp = misc::num2str(yD);
else tmp = misc::StringNiceNum(yD);
if(Axis->up < 0.0) tmp = '-'+tmp;
w = metrics.boundingRect(tmp).width();
if(maxWidth < w) maxWidth = w;
xLen = int(ystepD * cos(phi) + 0.5) + x;
yLen = int(ystepD * sin(phi) + 0.5) + y;
Texts.append(new Text(xLen+3+gx, yLen-6+gy, tmp));
Lines.append(new qucs::Line(xLen-gx, yLen-gy, xLen+gx, yLen+gy,
QPen(Qt::black,0)));
yD *= 10.0;
ystepD += corr;
}
}
else {
calcAxisScale(Axis, GridNum, yD, stepD, GridStep, xD);
count = int((xD - yD) / stepD) + 1;
xstepD = stepD * cos(phi);
ystepD = stepD * sin(phi);
xD = yD * cos(phi) + 0.5 + double(x);
yD = yD * sin(phi) + 0.5 + double(y);
if(Axis->up == 0.0) Expo = log10(fabs(Axis->up-Axis->low));
else Expo = log10(fabs(Axis->up));
for(; count>0; count--) {
x = int(xD);
y = int(yD);
if(fabs(GridNum) < 0.01*pow(10.0, Expo)) GridNum = 0.0;
if (engineeringNotation) tmp = misc::num2str(GridNum);
else tmp = misc::StringNiceNum(GridNum);
w = metrics.boundingRect(tmp).width();
if(maxWidth < w) maxWidth = w;
Texts.append(new Text(x+3+gx, y-6+gy, tmp));
GridNum += GridStep;
Lines.append(new qucs::Line(x-gx, y-gy, x+gx, y+gy, QPen(Qt::black,0)));
xD += xstepD;
yD += ystepD;
}
}
return maxWidth+5;
}
void Rect3DDiagram::createAxis(Axis *Axis, bool Right,
int x1_, int y1_, int x2_, int y2_)
{
Q_UNUSED(Right);
DataX const *pD;
double phi, cos_phi, sin_phi;
int x, y, z, w, valid, Index = 0;
if(Axis == &yAxis) Index = 1;
QString s;
QFontMetrics metrics(QucsSettings.font, 0);
x = x2_ - x1_;
y = y2_ - y1_;
cos_phi = sqrt(double(x*x) + double(y*y));
phi = atan2(double(y), double(x));
valid = calcAxis(Axis, x1_, y1_, cos_phi, phi);
z = (int)cos_phi;
cos_phi = cos(phi);
sin_phi = sin(phi);
if(fabs(phi-1e-5) > pi/2.0) {
x1_ = x2_; cos_phi *= -1;
y1_ = y2_; sin_phi *= -1;
}
x = x1_ + int(double(valid)*sin_phi);
y = y1_ - int(double(valid)*cos_phi);
if(Axis->Label.isEmpty()) {
for (Graph *pg : Graphs) {
if(Axis != &zAxis) {
if(!pg->cPointsY) continue;
if(valid < 0) {
delete[] pg->cPointsY;
pg->cPointsY = 0;
continue;
}
pD = pg->axis(Index);
if(!pD) continue;
s = pD->Var;
}
else {
s = pg->Var;
if(!pg->cPointsY) s += INVALID_STR;
}
x += int(double(metrics.lineSpacing())*sin_phi);
y -= int(double(metrics.lineSpacing())*cos_phi);
w = metrics.boundingRect(s).width();
Texts.append(new Text(x+int(double((z-w)>>1)*cos_phi),
y+int(double((z-w)>>1)*sin_phi),
s, pg->Color, 12.0, cos_phi, sin_phi));
}
}
else {
x += int(double(metrics.lineSpacing())*sin_phi);
y -= int(double(metrics.lineSpacing())*cos_phi);
w = metrics.boundingRect(Axis->Label).width();
Texts.append(new Text(x+int(double((z-w)>>1)*cos_phi),
y+int(double((z-w)>>1)*sin_phi),
Axis->Label, Qt::black, 12.0, cos_phi, sin_phi));
}
}
int Rect3DDiagram::calcDiagram()
{
Lines.clear();
Texts.clear();
Arcs.clear();
double GridStep, corr, zD, zDstep, GridNum;
QFontMetrics metrics(QucsSettings.font, 0);
x3 = x2 + 7;
int z, z2, o, w;
char *zBuffer=0;
tBound *Bounds=0;
xAxis.step = fabs(xAxis.step);
if(xAxis.limit_min > xAxis.limit_max)
xAxis.step *= -1.0;
yAxis.step = fabs(yAxis.step);
if(yAxis.limit_min > yAxis.limit_max)
yAxis.step *= -1.0;
zAxis.step = fabs(zAxis.step);
if(zAxis.limit_min > zAxis.limit_max)
zAxis.step *= -1.0;
if(xAxis.log) {
if(xAxis.autoScale) {
if(xAxis.max*xAxis.min <= 0.0) goto Frame;
}
else if(xAxis.limit_min*xAxis.limit_max <= 0.0) goto Frame;
calcAxisLogScale(&xAxis, z, zD, zDstep, corr, x2);
}
else calcAxisScale(&xAxis, GridNum, zD, zDstep, GridStep, double(x2));
if(yAxis.log) {
if(yAxis.autoScale) {
if(yAxis.max*yAxis.min <= 0.0) goto Frame;
}
else if(yAxis.limit_min*yAxis.limit_max <= 0.0) goto Frame;
calcAxisLogScale(&yAxis, z, zD, zDstep, corr, x2);
}
else calcAxisScale(&yAxis, GridNum, zD, zDstep, GridStep, double(x2));
if(zAxis.log) {
if(zAxis.autoScale) {
if(zAxis.max*zAxis.min <= 0.0) goto Frame;
}
else if(zAxis.limit_min*zAxis.limit_max <= 0.0) goto Frame;
calcAxisLogScale(&zAxis, z, zD, zDstep, corr, x2);
}
else calcAxisScale(&zAxis, GridNum, zD, zDstep, GridStep, double(x2));
calcCoefficients();
int X[8], Y[8];
o = calcCross(X, Y);
Lines.append(new qucs::Line(X[o^1], Y[o^1], X[o^3], Y[o^3], QPen(Qt::black,0)));
Lines.append(new qucs::Line(X[o^2], Y[o^2], X[o^3], Y[o^3], QPen(Qt::black,0)));
Lines.append(new qucs::Line(X[o^2], Y[o^2], X[o^6], Y[o^6], QPen(Qt::black,0)));
Lines.append(new qucs::Line(X[o^4], Y[o^4], X[o^6], Y[o^6], QPen(Qt::black,0)));
Lines.append(new qucs::Line(X[o^1], Y[o^1], X[o^5], Y[o^5], QPen(Qt::black,0)));
Lines.append(new qucs::Line(X[o^4], Y[o^4], X[o^5], Y[o^5], QPen(Qt::black,0)));
if(X[o^1] < X[o^2]) w = 2;
else w = 1;
z = o^2;
if(z & 1) z ^= 1;
z2 = z^1;
createAxis(&xAxis, w == 2, X[z], Y[z], X[z2], Y[z2]);
z = o^1;
if(z & 2) z ^= 2;
z2 = z^2;
createAxis(&yAxis, w == 1, X[z], Y[z], X[z2], Y[z2]);
z = o^w;
if(z & 4) z ^= 4;
z2 = z^4;
createAxis(&zAxis, true, X[z], Y[z], X[z2], Y[z2]);
if(hideLines) {
w = (x2+1) * (y2/8 + 1);
zBuffer = (char*)malloc(w);
memset(zBuffer, 0, w);
Bounds = (tBound*)malloc((x2+1) * sizeof(tBound));
}
removeHiddenLines(zBuffer, Bounds);
if(hideLines) {
tPoint3D *MemTmp = Mem;
Mem = (tPoint3D*)malloc( 10*sizeof(tPoint3D) );
removeHiddenCross(X[o^1], Y[o^1], X[o], Y[o], zBuffer, Bounds);
removeHiddenCross(X[o^2], Y[o^2], X[o], Y[o], zBuffer, Bounds);
removeHiddenCross(X[o^4], Y[o^4], X[o], Y[o], zBuffer, Bounds);
free(Mem);
Mem = MemTmp;
free(Bounds);
free(zBuffer);
}
else {
Lines.append(new qucs::Line(X[o], Y[o], X[o^1], Y[o^1], QPen(Qt::black,0)));
Lines.append(new qucs::Line(X[o], Y[o], X[o^2], Y[o^2], QPen(Qt::black,0)));
Lines.append(new qucs::Line(X[o], Y[o], X[o^4], Y[o^4], QPen(Qt::black,0)));
}
pMem = Mem;
return 3;
Frame:
Lines.append(new qucs::Line(0, y2, x2, y2, QPen(Qt::black,0)));
Lines.append(new qucs::Line(x2, y2, x2, 0, QPen(Qt::black,0)));
Lines.append(new qucs::Line(0, 0, x2, 0, QPen(Qt::black,0)));
Lines.append(new qucs::Line(0, y2, 0, 0, QPen(Qt::black,0)));
return 0;
}
void Rect3DDiagram::calcData(Graph *g)
{
if(!pMem) return;
if(!g->cPointsY) return;
int Size = ((2*(g->axis(0)->count) + 1) * g->countY) + 10;
Size *= 2;
g->resizeScrPoints(Size);
auto p = g->begin();
auto p_end = g->begin();
p_end += Size - 9;
p->setStrokeEnd();
++p;
switch(g->Style) {
case GRAPHSTYLE_SOLID:
case GRAPHSTYLE_DASH:
case GRAPHSTYLE_DOT:
case GRAPHSTYLE_LONGDASH:
do {
while(1) {
if(pMem->done & 11)
if(pMem->done & 4) {
if(pMem > Mem) {
if((pMem-1)->done & 12)
break;
}
else break;
}
FIT_MEMORY_SIZE;
(p++)->setScr(pMem->x, pMem->y);
break;
}
FIT_MEMORY_SIZE;
if(pMem->done & 8) (p++)->setBranchEnd();
if(pMem->done & 4)
if((p-1)->isPt())
(p++)->setStrokeEnd();
} while(((pMem++)->done & 256) == 0);
p->setGraphEnd();
break;
default:
do {
while(1) {
if(pMem->done & 11)
if(pMem->done & 4) {
if(pMem > Mem) {
if((pMem-1)->done & 12)
break;
}
else break;
}
(p++)->setScr(pMem->x, pMem->y);
break;
}
if(pMem->done & 8)
(p++)->setBranchEnd();
} while(((pMem++)->done & 512) == 0);
p->setGraphEnd();
}
return;
}
void Rect3DDiagram::createAxisLabels()
{
if(Mem) free (Mem);
Mem = 0;
pMem = 0;
}
bool Rect3DDiagram::insideDiagram(float x, float y) const
{
return (regionCode(x, y) == 0);
}
Diagram* Rect3DDiagram::newOne()
{
return new Rect3DDiagram();
}
Element* Rect3DDiagram::info(QString& Name, char* &BitmapFile, bool getNewOne)
{
Name = QObject::tr("3D-Cartesian");
BitmapFile = (char *) "rect3d";
if(getNewOne) return new Rect3DDiagram();
return 0;
}