00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include "basicgraph.h"
00018
00019 #include <cmath>
00020 #include <sstream>
00021
00022 #include <qcursor.h>
00023 #include <qpixmap.h>
00024 #include <qpainter.h>
00025
00026 #ifdef KDE_APP
00027 #include <kprinter.h>
00028 #else
00029 #include <qprinter.h>
00030 #endif //KDE_APP
00031
00032 #include "polarcoord.h"
00033 #include "rectcoord.h"
00034 #include "graphevent.h"
00035 #include "distancefunction.h"
00036
00037 BasicGraph::BasicGraph( QWidget *parent, const char *name ) :
00038 QWidget ( parent, name ),
00039 xMin(-15), xMax(15), xScale2(2),
00040 yMin(-15), yMax(15), yScale2(2),
00041 xScale(1), yScale(1),
00042 xZoom(1), yZoom(1),
00043 doingZoomBox(false), snapToGrid(false),
00044 showAxis(true), showGrid(true), showGridNum(true), showScale(true)
00045 {
00046 _axisColor = QColor(255,0,0);
00047 _gridColor = QColor(0,5,150);
00048 _backgroundColor = QColor(0,0,0);
00049 _scaleColor = QColor(60,120,0);
00050
00051 axisWidth = 1;
00052 graphFont = QFont("helvetica",10,QFont::Black);
00053 scaleFont = QFont("helvetica",8);
00054 mouseDown = false;
00055
00056
00057 mode = RECTANGULAR;
00058
00059 setPaletteBackgroundColor(_backgroundColor);
00060 setMouseTracking(true);
00061
00062 buffer = new QPixmap(size());
00063 buffer->fill(_backgroundColor);
00064 p = new QPainter();
00065
00066 updateGraph();
00067 }
00068
00069 BasicGraph::~BasicGraph()
00070 {
00071 delete buffer;
00072 delete p;
00073 }
00074
00075 void BasicGraph::load_key( const char *key, const char *value )
00076 {
00077 if (strcmp(key,"angle=") == 0)
00078 {
00079 setAngle(QString(value).toInt());
00080 }
00081 else if (strcmp(key,"BackgroundColor=") == 0)
00082 {
00083 QColor c(value);
00084 setBackgroundColor(c);
00085 }
00086 else if (strcmp(key,"AxisColor=") == 0)
00087 {
00088 QColor c(value);
00089 setAxisColor(c);
00090 }
00091 else if (strcmp(key,"GridColor=") == 0)
00092 {
00093 QColor c(value);
00094 setGridColor(c);
00095 }
00096 else if (strcmp(key,"ScaleColor=") == 0)
00097 {
00098 QColor c(value);
00099 setScaleColor(c);
00100 }
00101 else if (strcmp(key,"showGrid=") == 0)
00102 {
00103 bool show;
00104 if ( strcmp( value,"0" ) == 0 )
00105 show = false;
00106 else
00107 show = true;
00108 setGrid(show);
00109 }
00110 else if (strcmp(key,"showAxis=") == 0)
00111 {
00112 bool show;
00113 if ( strcmp( value,"0" ) == 0 )
00114 show = false;
00115 else
00116 show = true;
00117 setAxis(show);
00118 }
00119 else if (strcmp(key,"showScale=") == 0)
00120 {
00121 bool show;
00122 if ( strcmp( value,"0" ) == 0 )
00123 show = false;
00124 else
00125 show = true;
00126 setScale(show);
00127 }
00128 else if (strcmp(key,"snapToGrid=") == 0)
00129 {
00130 bool snap;
00131 if ( strcmp( value,"0" ) == 0 )
00132 snap = false;
00133 else
00134 snap = true;
00135 setSnapToGrid(snap);
00136 }
00137 else if (strcmp(key,"dimensions=") == 0)
00138 {
00139 char xMin[256], xMax[256], yMin[256], yMax[256];
00140
00141 std::stringstream valueStream(value);
00142 valueStream>>xMin;
00143 valueStream>>xMax;
00144 valueStream>>yMin;
00145 valueStream>>yMax;
00146 setRange(QString(xMin).toDouble(),QString(xMax).toDouble(),QString(yMin).toDouble(),QString(yMax).toDouble());
00147 }
00148 #ifndef NO_SUPPORT_OLD //loading the dimensions this way is deprecated
00149 else if (strcmp(key,"xMin=") == 0)
00150 {
00151 setXMin(QString(value).toDouble());
00152 }
00153 else if (strcmp(key,"xMax=") == 0)
00154 {
00155 setXMax(QString(value).toDouble());
00156 }
00157 else if (strcmp(key,"yMin=") == 0)
00158 {
00159 setYMin(QString(value).toDouble());
00160 }
00161 else if (strcmp(key,"yMax=") == 0)
00162 {
00163 setYMax(QString(value).toDouble());
00164 }
00165 #endif
00166 }
00167
00168 void BasicGraph::updateGraph()
00169 {
00170 origin.setX( int(-xMin * width() / (xMax - xMin)) );
00171 origin.setY( int(-yMax * height() / (yMin - yMax)) );
00172 xScale = width() / (xMax - xMin);
00173 yScale = height() / (yMin - yMax);
00174
00175 cancelMathFunctions();
00176
00177 repaint(false);
00178 }
00179
00180
00181
00182
00183
00184
00185
00186
00187 void BasicGraph::drawGrid(QPainter *painter)
00188 {
00189 painter->save();
00190 painter->setPen(QPen(_gridColor,1,Qt::DotLine));
00191
00192
00193
00194
00195 for (int i = 0; i < -xMin / xScale2; i++)
00196 {
00197
00198 painter->drawLine((int) (origin.x() - i * xScale * xScale2), 0, (int) (origin.x() - i * xScale * xScale2), height());
00199 }
00200
00201 for (int i = 1; i < xMax / xScale2; i++)
00202 {
00203 painter->drawLine((int) (origin.x() + i * xScale * xScale2), 0, (int) (origin.x() + i * xScale * xScale2), height());
00204 }
00205
00206 for (int i = 0; i < -yMin / yScale2; i++)
00207 {
00208 painter->drawLine(0, (int) (origin.y() + i * -yScale * yScale2), width(), (int) (origin.y() + i * -yScale * yScale2));
00209 }
00210
00211 for (int i = 1; i < yMax / yScale2; i++)
00212 {
00213 painter->drawLine(0, (int) (origin.y() - i * -yScale * yScale2), width(), (int) (origin.y() - i * -yScale * yScale2));
00214 }
00215
00216
00217
00218
00219
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245 painter->restore();
00246 }
00247
00248 void BasicGraph::drawAxis(QPainter *painter)
00249 {
00250 painter->save();
00251 painter->setPen(QPen(_axisColor,axisWidth,Qt::SolidLine));
00252 painter->drawLine(origin.x(), 0, origin.x(), height());
00253 painter->drawLine(0, origin.y(), width(), origin.y());
00254 painter->restore();
00255 }
00256
00257 void BasicGraph::drawScale(QPainter *painter)
00258 {
00259 painter->save();
00260 painter->setFont(scaleFont);
00261 painter->setPen(QColor(_scaleColor));
00262 QFontMetrics metrics(painter->font());
00263
00264 for (int i = 0; i < -xMin / xScale2; i++)
00265 {
00266 QString scale;
00267 scale = QString::number(toGraphXCoord(origin.x() - i * xScale * xScale2));
00268 painter->drawText((int) (origin.x() - i * xScale * xScale2) - metrics.width(scale)/2, metrics.height(), scale);
00269 }
00270
00271 for (int i = 1; i < xMax / xScale2; i++)
00272 {
00273 QString scale;
00274 scale = QString::number(toGraphXCoord(origin.x() + i * xScale * xScale2));
00275 painter->drawText((int) (origin.x() + i * xScale * xScale2) - metrics.width(scale)/2, metrics.height(), scale);
00276 }
00277
00278 for (int i = 0; i < -yMin / yScale2; i++)
00279 {
00280 QString scale;
00281 scale = QString::number(toGraphYCoord(origin.y() + i * -yScale * yScale2));
00282 painter->drawText(0, (int) (origin.y() + i * -yScale * yScale2) + metrics.height()/2, scale);
00283 }
00284
00285 for (int i = 1; i < yMax / yScale2; i++)
00286 {
00287 QString scale;
00288 scale = QString::number(toGraphYCoord(origin.y() - i * -yScale * yScale2));
00289 painter->drawText(0, (int) (origin.y() - i * -yScale * yScale2) + metrics.height()/2, scale);
00290 }
00291 painter->restore();
00292 }
00293
00294 void BasicGraph::paintEvent(QPaintEvent *)
00295 {
00296 bitBlt(this,0,0,buffer);
00297 }
00298
00299 void BasicGraph::paint(QPainter* painter)
00300 {
00301 painter->setPen( Qt::blue );
00302 painter->setFont(graphFont);
00303
00304 if (showGrid)
00305 drawGrid(painter);
00306 drawAfterAxis(painter);
00307 if (showAxis)
00308 drawAxis(painter);
00309 if (showScale)
00310 drawScale(painter);
00311 drawMathFunctions(p);
00312 if (doingZoomBox)
00313 {
00314 painter->setPen( QColor(255,130,20) );
00315 painter->drawText(30,height()-30,QString(tr("Click and drag to create box")));
00316 if (mouseDown)
00317 painter->drawRect( QRect( QPoint(lastClick.x(),lastClick.y()), QPoint(toPixelXCoord(getMouseX()),toPixelYCoord(getMouseY())) ) );
00318 }
00319 }
00320
00321 void BasicGraph::offscreenResize(int width, int height)
00322 {
00323 resize(width,height);
00324 resizeEvent(0);
00325 }
00326
00327 void BasicGraph::resizeEvent(QResizeEvent *)
00328 {
00329 buffer->resize(size());
00330 updateGraph();
00331 }
00332
00333 double BasicGraph::toGraphXCoord(double x) const
00334 {
00335 return ((x - origin.x()) / xScale);
00336 }
00337
00338 double BasicGraph::toGraphYCoord(double y) const
00339 {
00340 return ((y - origin.y()) / yScale);
00341 }
00342
00343 int BasicGraph::toPixelXCoord(double x) const
00344 {
00345 return static_cast<int>(origin.x() + x * (xScale));
00346 }
00347
00348 int BasicGraph::toPixelYCoord(double y) const
00349 {
00350 return static_cast<int>(origin.y() + y * (yScale));
00351 }
00352
00353 void BasicGraph::mouseDoubleClickEvent(QMouseEvent *e)
00354 {
00355 int x = e->x();
00356 int y = e->y();
00357
00358
00359 yMin += (y - height() / 2) / yScale;
00360 yMax += (y - height() / 2) / yScale;
00361 xMin += (x - width() / 2) / xScale;
00362 xMax += (x - width() / 2) / xScale;
00363
00364 emitDimensionsChanged();
00365 updateGraph();
00366 }
00367
00368 void BasicGraph::mouseMoveEvent(QMouseEvent *e)
00369 {
00370 setMouseX(toGraphXCoord(e->x()));
00371 setMouseY(toGraphYCoord(e->y()));
00372
00373 updateCoords();
00374 if (mouseDown)
00375 {
00376 if (doingZoomBox)
00377 repaint(false);
00378 else
00379 {
00380 double deltax = toGraphXCoord(e->x())-toGraphXCoord(lastClick.x());
00381 double deltay = toGraphYCoord(e->y())-toGraphYCoord(lastClick.y());
00382
00383
00384 yMin -= deltay;
00385 yMax -= deltay;
00386 xMin -= deltax;
00387 xMax -= deltax;
00388 emitDimensionsChanged();
00389 updateGraph();
00390
00391 lastClick.setX(e->x());
00392 lastClick.setY(e->y());
00393 }
00394 }
00395 }
00396
00397 void BasicGraph::mousePressEvent(QMouseEvent *e)
00398 {
00399 mouseDown = true;
00400
00401 mathFunctionClick(e,getMouseX(),getMouseY());
00402
00403 lastClick.setX(toPixelXCoord(getMouseX()));
00404 lastClick.setY(toPixelYCoord(getMouseY()));
00405 lastClickGraphCoordX = getMouseX();
00406 lastClickGraphCoordY = getMouseY();
00407
00408 setCursor(QCursor(Qt::PointingHandCursor));
00409 }
00410
00411 void BasicGraph::mouseReleaseEvent(QMouseEvent *)
00412 {
00413 if (doingZoomBox && mouseDown)
00414 {
00415 double _xMin = (lastClickGraphCoordX < getMouseX()) ? lastClickGraphCoordX : getMouseX();
00416 double _xMax = (lastClickGraphCoordX > getMouseX()) ? lastClickGraphCoordX : getMouseX();
00417 double _yMin = (lastClickGraphCoordY < getMouseY()) ? lastClickGraphCoordY : getMouseY();
00418 double _yMax = (lastClickGraphCoordY > getMouseY()) ? lastClickGraphCoordY : getMouseY();
00419
00420 setRange(_xMin, _xMax, _yMin, _yMax);
00421 emitDimensionsChanged();
00422 doingZoomBox = false;
00423 repaint(false);
00424 }
00425
00426 mouseDown = false;
00427 setCursor(QCursor(Qt::ArrowCursor));
00428 }
00429
00430 void BasicGraph::updateCoords()
00431 {
00432 emit activeCoordinateChanged( QString("x = %1").arg(mouseX), QString("y = %1").arg(mouseY) );
00433 }
00434
00435 void BasicGraph::emitDimensionsChanged()
00436 {
00437 GraphEvent event(xMin,xMax,xScale2,yMin,yMax,yScale2);
00438 emit dimensionsChanged(event);
00439 }
00440
00441 int BasicGraph::setRange(double _xMin, double _xMax, double _yMin, double _yMax)
00442 {
00443 if (_xMin < _xMax && _yMin < _yMax)
00444 {
00445 xMin = _xMin;
00446 xMax = _xMax;
00447 yMin = _yMin;
00448 yMax = _yMax;
00449 updateGraph();
00450 return 0;
00451 }
00452 else
00453 return 1;
00454 }
00455
00456 int BasicGraph::setXMin(double _xMin)
00457 {
00458 if (_xMin < xMax)
00459 {
00460 xMin = _xMin;
00461 updateGraph();
00462 return 0;
00463 }
00464 else
00465 return 1;
00466 }
00467
00468 int BasicGraph::setXMax(double _xMax)
00469 {
00470 if (_xMax > xMin)
00471 {
00472 xMax = _xMax;
00473 updateGraph();
00474 return 0;
00475 }
00476 else
00477 return 1;
00478 }
00479
00480 int BasicGraph::setXScale(double _xScale)
00481 {
00482 if (_xScale > 0)
00483 {
00484 xScale2 = _xScale;
00485 repaint(false);
00486 return 0;
00487 }
00488 else
00489 return 1;
00490 }
00491
00492 int BasicGraph::setYMin(double _yMin)
00493 {
00494 if (_yMin < yMax)
00495 {
00496 yMin = _yMin;
00497 updateGraph();
00498 return 0;
00499 }
00500 else
00501 return 1;
00502 }
00503
00504 int BasicGraph::setYMax(double _yMax)
00505 {
00506 if (_yMax > yMin)
00507 {
00508 yMax = _yMax;
00509 updateGraph();
00510 return 0;
00511 }
00512 else
00513 return 1;
00514 }
00515
00516 int BasicGraph::setYScale(double _yScale)
00517 {
00518 if (_yScale > 0)
00519 {
00520 yScale2 = _yScale;
00521 repaint(false);
00522 return 0;
00523 }
00524 else
00525 return 1;
00526 }
00527
00528 void BasicGraph::setAxis(bool state)
00529 {
00530 showAxis = state;
00531 repaint(false);
00532 }
00533
00534 void BasicGraph::setGrid(bool state)
00535 {
00536 showGrid = state;
00537 repaint(false);
00538 }
00539
00540 void BasicGraph::setGridNum(bool state)
00541 {
00542 showGridNum = state;
00543 repaint(false);
00544 }
00545
00546 void BasicGraph::setScale(bool state)
00547 {
00548 showScale = state;
00549 repaint(false);
00550 }
00551
00552 void BasicGraph::setAxisColor(const QColor &c)
00553 {
00554 _axisColor = c;
00555 repaint(false);
00556 }
00557
00558 void BasicGraph::setGridColor(const QColor &c)
00559 {
00560 _gridColor = c;
00561 repaint(false);
00562 }
00563
00564 void BasicGraph::setBackgroundColor(const QColor &c)
00565 {
00566 _backgroundColor = c;
00567 setPaletteBackgroundColor(_backgroundColor);
00568 repaint(false);
00569 }
00570
00571 void BasicGraph::setScaleColor(const QColor &c)
00572 {
00573 _scaleColor = c;
00574 repaint(false);
00575 }
00576
00577 void BasicGraph::setXZoomFactor(int zoom)
00578 {
00579 xZoom = zoom;
00580 }
00581
00582 void BasicGraph::setYZoomFactor(int zoom)
00583 {
00584 yZoom = zoom;
00585 }
00586
00587 QColor BasicGraph::axisColor() const
00588 {
00589 return _axisColor;
00590 }
00591
00592 QColor BasicGraph::gridColor() const
00593 {
00594 return _gridColor;
00595 }
00596
00597 QColor BasicGraph::backgroundColor() const
00598 {
00599 return _backgroundColor;
00600 }
00601
00602 QColor BasicGraph::scaleColor() const
00603 {
00604 return _scaleColor;
00605 }
00606
00607 int BasicGraph::getXZoomFactor() const
00608 {
00609 return xZoom;
00610 }
00611
00612 int BasicGraph::getYZoomFactor() const
00613 {
00614 return yZoom;
00615 }
00616
00617 void BasicGraph::zoomIn()
00618 {
00619 double half_x = (xMax-xMin)/2;
00620 double half_y = (yMax-yMin)/2;
00621 (void)setRange( xMin + half_x - (xMax-xMin) / ( pow(2,xZoom+1) ),
00622 xMin + half_x + (xMax-xMin)/(pow(2,xZoom+1)),
00623 yMin + half_y - (yMax-yMin)/(pow(2,yZoom+1)),
00624 yMin + half_y + (yMax-yMin)/(pow(2,yZoom+1))
00625 );
00626 emitDimensionsChanged();
00627 }
00628
00629 void BasicGraph::zoomOut()
00630 {
00631 double half_x = (xMax-xMin)/2;
00632 double half_y = (yMax-yMin)/2;
00633 (void)setRange( xMin + half_x - (xMax-xMin)*( pow(2,xZoom-1) ),
00634 xMin + half_x + (xMax-xMin)*(pow(2,xZoom-1)),
00635 yMin + half_y - (yMax-yMin)*(pow(2,yZoom-1)),
00636 yMin + half_y + (yMax-yMin)*(pow(2,yZoom-1))
00637 );
00638 emitDimensionsChanged();
00639 }
00640
00641 void BasicGraph::zoomStd()
00642 {
00643 yScale2 = 2;
00644 xScale2 = 2;
00645 setRange(-15,15,-15,15);
00646 emitDimensionsChanged();
00647 }
00648
00649 void BasicGraph::zoomBox()
00650 {
00651 doingZoomBox = true;
00652 repaint(false);
00653 }
00654
00655 void BasicGraph::setAxisWidth(int i)
00656 {
00657 axisWidth = i;
00658 repaint(false);
00659 }
00660
00661 void BasicGraph::print(
00662 #ifdef KDE_APP
00663 KPrinter *printer
00664 #else
00665 QPrinter *printer
00666 #endif
00667 )
00668 {
00669 if ( printer->setup(this) )
00670 {
00671 qDebug( "Printing...");
00672 QPainter p;
00673 if ( !p.begin( printer ) )
00674 return;
00675 paint(&p);
00676 p.end();
00677 qDebug( "Printing completed");
00678 }
00679 else
00680 qDebug( "Printing aborted" );
00681 }
00682
00683 void BasicGraph::setMouseX(double x, bool snap)
00684 {
00685 if (snapToGrid && snap)
00686 {
00687 double interval = snapIntervalX();
00688 double remainder = fmod(x - startSnap(), interval);
00689 if (remainder < 0)
00690 {
00691 if ( fabs(remainder) < (interval/2) )
00692 mouseX = x - remainder;
00693 else
00694 mouseX = x - (interval + remainder);
00695 }
00696 else
00697 {
00698 if ( fabs(remainder) < (interval/2) )
00699 mouseX = x - remainder;
00700 else
00701 mouseX = x + (interval - remainder);
00702 }
00703 }
00704 else
00705 mouseX = x;
00706 }
00707
00708 void BasicGraph::setMouseY(double y, bool snap)
00709 {
00710 if (snapToGrid && snap)
00711 {
00712 double interval = snapIntervalY();
00713 double remainder = fmod(y, interval);
00714 if (remainder < 0)
00715 {
00716 if ( fabs(remainder) < (interval/2) )
00717 mouseY = y - remainder;
00718 else
00719 mouseY = y - (interval + remainder);
00720 }
00721 else
00722 {
00723 if ( fabs(remainder) < (interval/2) )
00724 mouseY = y - remainder;
00725 else
00726 mouseY = y + (interval - remainder);
00727 }
00728 }
00729 else
00730 mouseY = y;
00731 }
00732
00733 void BasicGraph::installMathFunctions()
00734 {
00735 addMathFunction( new DistanceFunction(this,0), "Distance" );
00736 }
00737
00738 int BasicGraph::execMathFunction( const char * id )
00739 {
00740 getMathFunction(id)->exec();
00741 return 0;
00742 }