static QPoint cutPoint(QPoint p11, QPoint p12, QPoint p21, QPoint p22) { double dx1 = p12.x() - p11.x(); double dy1 = p12.y() - p11.y(); double dx2 = p22.x() - p21.x(); double dy2 = p22.y() - p21.y(); if ( dx1 == 0.0 && dx2 == 0.0 ) return QPoint(); if ( dx1 == 0.0 ) { const double m = dy2 / dx2; const double t = p21.y() - m * p21.x(); return QPoint(p11.x(), qwtInt(m * p11.x() + t)); } if ( dx2 == 0 ) { const double m = dy1 / dx1; const double t = p11.y() - m * p11.x(); return QPoint(p21.x(), qwtInt(m * p21.x() + t)); } const double m1 = dy1 / dx1; const double t1 = p11.y() - m1 * p11.x(); const double m2 = dy2 / dx2; const double t2 = p21.y() - m2 * p21.x(); if ( m1 == m2 ) return QPoint(); const double x = ( t2 - t1 ) / ( m1 - m2 ); const double y = t1 + m1 * x; return QPoint(qwtInt(x), qwtInt(y)); }
/*! \brief Paint the plot into a given rectangle. Paint the contents of a QwtPlot instance into a given rectangle. \param painter Painter \param plotRect Bounding rectangle \param pfilter Print filter \sa QwtPlotPrintFilter */ void QwtPlot::print(QPainter *painter, const QRect &plotRect, const QwtPlotPrintFilter &pfilter) const { int axis; if ( painter == 0 || !painter->isActive() || !plotRect.isValid() || size().isNull() ) return; painter->save(); // All paint operations need to be scaled according to // the paint device metrics. QwtPainter::setMetricsMap(this, painter->device()); #if QT_VERSION < 300 if ( painter->device()->isExtDev() ) { QPaintDeviceMetrics metrics(painter->device()); if ( metrics.logicalDpiX() == 72 && metrics.logicalDpiY() == 72 ) { // In Qt 2.x QPrinter returns hardcoded wrong metrics. // So scaling won´t work: we reset to screen resolution QwtPainter::setMetricsMap(this, this); } } #endif const QwtMetricsMap &metricsMap = QwtPainter::metricsMap(); // It is almost impossible to integrate into the Qt layout // framework, when using different fonts for printing // and screen. To avoid writing different and Qt unconform // layout engines we change the widget attributes, print and // reset the widget attributes again. This way we produce a lot of // useless layout events ... pfilter.apply((QwtPlot *)this); int baseLineDists[QwtPlot::axisCnt]; if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) ) { // In case of no background we set the backbone of // the scale on the frame of the canvas. for (axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( d_scale[axis] ) { baseLineDists[axis] = d_scale[axis]->baseLineDist(); d_scale[axis]->setBaselineDist(0); } } } // Calculate the layout for the print. int layoutOptions = QwtPlotLayout::IgnoreScrollbars | QwtPlotLayout::IgnoreFrames; if ( !(pfilter.options() & QwtPlotPrintFilter::PrintMargin) ) layoutOptions |= QwtPlotLayout::IgnoreMargin; if ( !(pfilter.options() & QwtPlotPrintFilter::PrintLegend) ) layoutOptions |= QwtPlotLayout::IgnoreLegend; d_layout->activate(this, QwtPainter::metricsMap().deviceToLayout(plotRect), layoutOptions); if ((pfilter.options() & QwtPlotPrintFilter::PrintTitle) && (!d_lblTitle->text().isEmpty())) { printTitle(painter, d_layout->titleRect()); } if ( (pfilter.options() & QwtPlotPrintFilter::PrintLegend) && !d_legend->isEmpty() ) { printLegend(painter, d_layout->legendRect()); } for ( axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if (d_scale[axis]) { int baseDist = d_scale[axis]->baseLineDist(); int startDist, endDist; d_scale[axis]->minBorderDist(startDist, endDist); printScale(painter, axis, startDist, endDist, baseDist, d_layout->scaleRect(axis)); } } const QRect canvasRect = metricsMap.layoutToDevice(d_layout->canvasRect()); // When using QwtPainter all sizes where computed in pixel // coordinates and scaled by QwtPainter later. This limits // the precision to screen resolution. A much better solution // is to scale the maps and print in unlimited resolution. QwtArray<QwtDiMap> map(axisCnt); for (axis = 0; axis < axisCnt; axis++) { const QwtScaleDiv &scaleDiv = d_as[axis].scaleDiv(); map[axis].setDblRange(scaleDiv.lBound(), scaleDiv.hBound(), scaleDiv.logScale()); double from, to; if ( axisEnabled(axis) ) { const int sDist = d_scale[axis]->startBorderDist(); const int eDist = d_scale[axis]->endBorderDist(); const QRect &scaleRect = d_layout->scaleRect(axis); if ( axis == xTop || axis == xBottom ) { from = metricsMap.layoutToDeviceX(scaleRect.left() + sDist); to = metricsMap.layoutToDeviceX(scaleRect.right() - eDist); } else { from = metricsMap.layoutToDeviceY(scaleRect.bottom() - sDist); to = metricsMap.layoutToDeviceY(scaleRect.top() + eDist); } } else { const int margin = plotLayout()->canvasMargin(axis); const QRect &canvasRect = plotLayout()->canvasRect(); if ( axis == yLeft || axis == yRight ) { from = metricsMap.layoutToDeviceX(canvasRect.bottom() - margin); to = metricsMap.layoutToDeviceX(canvasRect.top() + margin); } else { from = metricsMap.layoutToDeviceY(canvasRect.left() + margin); to = metricsMap.layoutToDeviceY(canvasRect.right() - margin); } } map[axis].setIntRange( qwtInt(from), qwtInt(to)); } // The maps are already scaled. QwtPainter::setMetricsMap(painter->device(), painter->device()); printCanvas(painter, canvasRect, map, pfilter); QwtPainter::resetMetricsMap(); d_layout->invalidate(); // reset all widgets with their original attributes. if ( !(pfilter.options() & QwtPlotPrintFilter::PrintCanvasBackground) ) { // restore the previous base line dists for (axis = 0; axis < QwtPlot::axisCnt; axis++ ) { if ( d_scale[axis] ) d_scale[axis]->setBaselineDist(baseLineDists[axis]); } } pfilter.reset((QwtPlot *)this); painter->restore(); }