diff --git a/qad_graphic/graphic.cpp b/qad_graphic/graphic.cpp index 20f283d..77b98ee 100644 --- a/qad_graphic/graphic.cpp +++ b/qad_graphic/graphic.cpp @@ -112,6 +112,7 @@ Graphic::Graphic(QWidget * parent): QFrame(parent), line_x_min(this), line_x_max visible_time = -1.; pause_phase = 0.; selrect.setRect(0., 0., 1., 1.); + def_rect = selrect; margins_.setRect(4, 4, 4, 4); curaction = gaMove; selbrush.setStyle(Qt::SolidPattern); @@ -629,6 +630,12 @@ void Graphic::setVisualRect(const QRectF & rect) { } +void Graphic::setDefaultRect(const QRectF & rect) { + def_rect = rect; + if (isFit) autofit(); +} + + void Graphic::saveImage() { QString str = QFileDialog::getSaveFileName(this, tr("Save Image"), ppath, "PNG(*.png);;JPEG(*.jpg *.jpeg);;BMP(*.bmp);;TIFF(*.tiff *.tif);;PPM(*.ppm)"); if (str == "") return; @@ -744,7 +751,7 @@ void Graphic::findGraphicsRect(double start_x, double end_x, double start_y, dou } } if (isEmpty) { - grect.setRect(0., 0., 1., 1.); + grect = def_rect; setRectToLines(); return; } @@ -886,8 +893,12 @@ void Graphic::drawGrid() { cy = chei - font_sz.height() / 4; if (hasLblX) cy -= font_sz.height(); range = selrect.right() - selrect.left(); - if (grad_x == Graphic::Auto) step = splitRange(range, wid / gridx / font_sz.width() * 1.4); - else step = gridx;//range / wid * gridx; + QString df; + if (axis_type_x == Graphic::Numeric) { + if (grad_x == Graphic::Auto) step = splitRange(range, wid / gridx / font_sz.width() * 1.4); + else step = gridx;//range / wid * gridx; + } else + step = splitRangeDate(range, wid / gridx / font_sz.width() * 1.4, &df); start = roundTo(canvas2realX(wid), step) + step; px = start + step; if (step > 0.) { @@ -901,11 +912,11 @@ void Graphic::drawGrid() { painter->setPen(grid_pen); painter->drawLine(cx, hei + 5, cx, 0); painter->setPen(text_color); + int dx = -font_sz.height() / 4.; + painter->setFont(nf); if (axis_type_x == Graphic::Numeric) { - int dx = -font_sz.height() / 4.; str = gridMark(px * grid_numbers_x); rect = fm.boundingRect(str.first); - painter->setFont(nf); painter->drawText(cx + dx, cy, str.first); dx += rect.width() + font_sz.height() / 6.; if (!str.second.isEmpty()) { @@ -914,7 +925,8 @@ void Graphic::drawGrid() { painter->drawText(cx + dx, cy - font_sz.height() / 2.5, str.second); } } else { - + str.first = QDateTime::fromMSecsSinceEpoch(px * grid_numbers_x).toString(df); + painter->drawText(cx + dx, cy, str.first); } } } @@ -996,11 +1008,18 @@ void Graphic::drawGraphics() { } +QString Graphic::pointCoords(QPointF point) { + if (axis_type_x == Numeric) + return "(" + QString::number(point.x(), 'f', 3) + " ; " + QString::number(point.y(), 'f', 3) + ")"; + return "(" + QDateTime::fromMSecsSinceEpoch(point.x()).toString() + " ; " + QString::number(point.y(), 'f', 3) + ")"; +} + + void Graphic::drawGuides() { if (!guides || !isHover) return; int wid = canvas->width(), hei = canvas->height(); painter->setRenderHint(QPainter::Antialiasing, false); - painter->setPen(grid_pen.color()); + painter->setPen(QPen(grid_pen.color(), qMax(qRound(thick / 1.4), 1))); painter->resetTransform(); painter->setClipping(true); painter->setClipRect(QRect(gridborder.x(), 0, wid - gridborder.x(), hei - gridborder.y())); @@ -1009,9 +1028,9 @@ void Graphic::drawGuides() { QString str = pointCoords(canvas2real(curpos)); QFontMetrics fm(font()); QRect r = fm.boundingRect(str); - QPoint p = curpos + QPoint(2, -2); - if (r.width() + curpos.x() > wid - 5) p.setX(curpos.x() - r.width() - 3); - if (curpos.y() - r.height() < 2) p.setY(curpos.y() + r.height() - 2); + QPoint p = curpos + QPoint(font_sz.height() / 4., -font_sz.height() / 4.); + if (r.width() + curpos.x() > wid - font_sz.height() / 2.) p.setX(curpos.x() - r.width() - font_sz.height() / 4.); + if (curpos.y() - r.height() < font_sz.height() / 8.) p.setY(curpos.y() + r.height() - font_sz.height() / 8.); painter->setPen(text_color); painter->drawText(p, str); } @@ -1020,7 +1039,7 @@ void Graphic::drawGuides() { void Graphic::drawPause() { painter->setClipping(false); painter->resetMatrix(); - painter->translate(canvas->width() - icon_pause_b.width() - 4, 4); + painter->translate(canvas->width() - icon_pause_b.width() - 6, 6); double o = (0.5 - pause_phase) * 2; painter->setOpacity(o*o); painter->drawImage(0, 0, icon_pause_b); @@ -1031,32 +1050,34 @@ void Graphic::drawPause() { double Graphic::splitRange(double range, int count) { double digits, step, tln; - //bool neg = range < 0; - //if (neg) range = -range; range = qAbs(range); tln = qFloor(qLn(range) / LN10); - /*double mul = 1.; - if (tln >= 4) { - mul = qPow(10, tln); - tln = 2; - range /= mul; - }*/ for (int i = 0; i <= 5; ++i) { digits = qPow(10., tln - i); step = qRound(range / count / digits); if (step > 0.) { digits = qPow(10., tln - i - 1); step = qRound(range / count / digits); - //qDebug() << "break at" << i; break; } } - //qDebug() << step << digits; double step5 = qRound(step / 5.) * 5., step10 = qRound(step / 10.) * 10.; double err5 = qAbs(step - step5), err10 = qAbs(step - step10); step = (err5 < err10 ? step5 : step10) * digits; - //qDebug() << step; - return step;// * mul; + return step; +} + + +double Graphic::splitRangeDate(double range, int count, QString * format) { + double ret = splitRange(range, count); + if (ret < 1000. * 1) *format = "ss.zzz"; + else if (ret < 1000. * 60) *format = "h:m:ss"; + else if (ret < 1000. * 60 * 60) *format = "h:mm"; + else if (ret < 1000. * 60 * 60 * 24) *format = "dd(ddd) hh"; + else if (ret < 1000. * 60 * 60 * 24 * 30) *format = "MMM dd"; + else if (ret < 1000. * 60 * 60 * 24 * 30 * 12) *format = "yyyy MMM"; + else *format = "yyyy"; + return ret; } @@ -1066,28 +1087,28 @@ double Graphic::roundTo(double value, double round_to) { } -double Graphic::canvas2realX(double px) { +double Graphic::canvas2realX(double px) const { int gbx = gridborder.x() + margins_.left(), cwid = lastw, wid = cwid - gbx - margins_.width(); double cx = px - gbx, sclx = selrect.width() / (double)wid; return cx * sclx + selrect.x(); } -double Graphic::canvas2realY(double py) { +double Graphic::canvas2realY(double py) const { int gby = gridborder.y() + margins_.top(), chei = lasth - legy, hei = chei - gby - margins_.height(); double cy = chei - py - gby, scly = selrect.height() / (double)hei; return cy * scly + selrect.y(); } -double Graphic::real2canvasX(double px) { +double Graphic::real2canvasX(double px) const { int gbx = gridborder.x() + margins_.left(), cwid = lastw, wid = cwid - gbx - margins_.width(); double sclx = selrect.width() / (double)wid; return (px - selrect.x()) / sclx + gbx; } -double Graphic::real2canvasY(double py) { +double Graphic::real2canvasY(double py) const { int gby = gridborder.y() + margins_.top(), chei = lasth - legy, hei = chei - gby - margins_.height(); double scly = selrect.height() / (double)hei; return chei - gby - (py - selrect.y()) / scly; @@ -1200,7 +1221,7 @@ void Graphic::on_buttonAutofit_clicked() { break; } } - if (isEmpty) grect.setRect(0., 0., 1., 1.); + if (isEmpty) grect = def_rect; selrect = grect; findGraphicsRect(); update(); diff --git a/qad_graphic/graphic.h b/qad_graphic/graphic.h index 08ee7c9..3cdf8b5 100644 --- a/qad_graphic/graphic.h +++ b/qad_graphic/graphic.h @@ -106,6 +106,7 @@ class Graphic: public QFrame Q_PROPERTY(QRectF limit READ limit WRITE setLimit) Q_PROPERTY(QRect margins READ margins WRITE setMargins) Q_PROPERTY(QRectF visualRect READ visualRect WRITE setVisualRect) + Q_PROPERTY(QRectF defaultRect READ defaultRect WRITE setDefaultRect) Q_PROPERTY(int minimumRepaintInterval READ minimumRepaintInterval WRITE setMinimumRepaintInterval) Q_PROPERTY(double gridNumbersMultiplierX READ gridNumbersMultiplierX WRITE setGridNumbersMultiplierX) @@ -191,6 +192,7 @@ public: double maxVisibleTime() const {return visible_time;} double autoXIncrement() const {return inc_x;} QRectF visualRect() const {return selrect;} + QRectF defaultRect() const {return def_rect;} QRectF limit() const {return limit_;} QRect margins() const {return margins_;} int minimumRepaintInterval() const {return min_repaint_int;} @@ -207,12 +209,28 @@ public: QVector graphicData(const int index = 0) const {return graphics[index].polyline;} GraphicsData graphicsData() const; QWidget * viewport() const {return canvas;} - QByteArray save(); - void load(QByteArray ba); - void lock() {mutex_.lock();} - void unlock() {mutex_.unlock();} + QByteArray save(); + void load(QByteArray ba); + void lock() {mutex_.lock();} + void unlock() {mutex_.unlock();} void reset() {mutex.lock(); clear(); mutex.unlock();} + + GraphicType graphic(int arg) {if (arg < 0 || arg >= graphics.size()) return GraphicType(); return graphics[arg];} + const QVector & allGraphics() const {return graphics;} + void setAllGraphics(const QVector & g, bool update = true) {graphics = g; if (update) updateLegend();} + void setHistogramData(const QVector & g, int graphic); + void setHistogramData(const QVector & g) {setHistogramData(g, curGraphic);} + + double canvas2realX(double px) const; + double canvas2realY(double py) const; + double real2canvasX(double px) const; + double real2canvasY(double py) const; + QPointF canvas2real(QPointF canvas_point) const {return QPointF(canvas2realX(canvas_point.x()), canvas2realY(canvas_point.y()));} + QPointF real2canvas(QPointF real_point) const {return QPointF(real2canvasX(real_point.x()), real2canvasY(real_point.y()));} + double getScaleX() const {return real2canvasX(1.) - real2canvasX(0.);} + double getScaleY() const {return real2canvasY(1.) - real2canvasY(0.);} + QPointF getScale() const {return QPointF(getScaleX(), getScaleY());} public slots: void setCaption(const QString & str); @@ -299,30 +317,19 @@ public slots: void addGraphic(const QString & name, const QColor & color = Qt::darkRed, Qt::PenStyle style = Qt::SolidLine, double width = 0., bool visible = true); void addGraphic(const GraphicType & gd, bool update = true) {graphics << gd; if (update) updateLegend();} void setVisualRect(const QRectF & rect); + void setDefaultRect(const QRectF & rect); void autofit() {on_buttonAutofit_clicked();} void saveImage(); void clear(); void update(bool force = false); void updateGraphics() {findGraphicsRect(); update();} - GraphicType graphic(int arg) {if (arg < 0 || arg >= graphics.size()) return GraphicType(); return graphics[arg];} - const QVector & allGraphics() const {return graphics;} - void setAllGraphics(const QVector & g, bool update = true) {graphics = g; if (update) updateLegend();} void setCurrentGraphic(int arg) {if (arg < 0 || arg >= graphics.size()) return; curGraphic = arg;} void setGraphicsCount(int arg, bool update = true); - void setHistogramData(const QVector & g, int graphic); - void setHistogramData(const QVector & g) {setHistogramData(g, curGraphic);} void zoom(float factor); void zoomIn() {zoom(1. / 1.2);} void zoomOut() {zoom(1.2);} void fullscreen(); - - double canvas2realX(double px); - double canvas2realY(double py); - double real2canvasX(double px); - double real2canvasY(double py); - QPointF canvas2real(QPointF canvas_point) {return QPointF(canvas2realX(canvas_point.x()), canvas2realY(canvas_point.y()));} - QPointF real2canvas(QPointF real_point) {return QPointF(real2canvasX(real_point.x()), real2canvasY(real_point.y()));} protected: virtual void changeEvent(QEvent * e); @@ -348,9 +355,10 @@ protected: void setRectToLines(); void checkLines(); double splitRange(double range, int count = 1); + double splitRangeDate(double range, int count = 1, QString * format = 0); double roundTo(double value, double round_to); QPointF absPoint(QPointF point) {return QPointF(qAbs(point.x()), qAbs(point.y()));} - QString pointCoords(QPointF point) {return "(" + QString::number(point.x(), 'f', 3) + " ; " + QString::number(point.y(), 'f', 3) + ")";} + QString pointCoords(QPointF point); QPair gridMark(double v) const; Ui::Graphic * ui; @@ -364,7 +372,7 @@ protected: QVector graphics; int curGraphic; GraphicAction curaction, prevaction; - QRectF grect, rrect, selrect, limit_; + QRectF grect, rrect, selrect, limit_, def_rect; QRect margins_; QSize font_sz; QPoint startpos, curpos, prevpos, gridborder;