mirror of
https://github.com/jkriege2/JKQtPlotter.git
synced 2024-12-24 09:31:40 +08:00
JKQTPlotter: improved plotting speed for line-graphs by drawing a series of single lines instead of a polyline in some cases
This commit is contained in:
parent
abd62dc341
commit
4ef29635ea
@ -33,6 +33,7 @@ Changes, compared to \ref page_whatsnew_V4_0_0 "v4.0.0" include:
|
||||
<li>NEW/BREAKING CHANGE: changed JKQTPColorDerivationMode into a struct, which extends its capabilities above the previously available few enum-items</li>
|
||||
<li>NEW: added debug-feature to show boxes around text in the plot</li>
|
||||
<li>BREAKING: Print-Support can now be switched off with a CMAKE-option JKQtPlotter_BUILD_FORCE_NO_PRINTER_SUPPORT=ON. This also switches off PDF and SVG export, partly solves issue <a href="https://github.com/jkriege2/JKQtPlotter/issues/81">#81</a>, many thanks to <a href="https://github.com/sufuk">user:sufuk</a> for contributing part of the code and supplying the idea! </li>
|
||||
<li>NEW: improved plotting speed for line-graphs by drawing a series of single lines instead of a polyline in some cases</li>
|
||||
<li>NEW: improved plotting speed for line-graphs by a compression algorithm (see JKQTPGraphLinesCompressionMixin) that removes overlaying lines (e.g. in JKQTPXYLineGraph)</li>
|
||||
<li>NEW: improved plotting speed for line-graphs by a clipping algorithm (applies to JKQTPXYLineGraph, JKQTPGraphErrorStyleMixin, JKQTPSpecialLineHorizontalGraph, JKQTPSpecialLineVerticalGraph and others)</li>
|
||||
<li>NEW: improved plotting speed for scatter-graphs by not calling draw functions for symbols outside the plot window (e.g. in JKQTPXYLineGraph)</li>
|
||||
|
@ -41,13 +41,16 @@ SpeedTestPlot::SpeedTestPlot():
|
||||
graph->setYColumn(columnY);
|
||||
graph->setTitle(QObject::tr("live sin() graph"));
|
||||
graph->setLineWidth(1);
|
||||
graph->setSymbolType(JKQTPNoSymbol);
|
||||
addGraph(graph);
|
||||
|
||||
graph2=new JKQTPXYLineGraph(this);
|
||||
graph2->setXColumn(columnX);
|
||||
graph2->setYColumn(columnY2);
|
||||
graph2->setTitle(QObject::tr("live cos() graph"));
|
||||
graph2->setLineWidth(1);
|
||||
graph2->setLineWidth(2);
|
||||
graph2->setSymbolType(JKQTPNoSymbol);
|
||||
|
||||
addGraph(graph2);
|
||||
|
||||
// 6. scale the plot so the graph is contained
|
||||
@ -87,7 +90,7 @@ SpeedTestPlot::SpeedTestPlot():
|
||||
|
||||
actSymbols=new QAction(QObject::tr("Show Graph Symbols"));
|
||||
actSymbols->setCheckable(true);
|
||||
actSymbols->setChecked(true);
|
||||
actSymbols->setChecked(false);
|
||||
connect(actSymbols, &QAction::toggled, std::bind([](bool enabled, JKQTPXYLineGraph* g, JKQTPXYLineGraph* g2,SpeedTestPlot* p){
|
||||
g->setSymbolType(enabled?JKQTPCross:JKQTPNoSymbol);
|
||||
g2->setSymbolType(enabled?JKQTPCircle:JKQTPNoSymbol);
|
||||
|
@ -23,7 +23,8 @@
|
||||
|
||||
|
||||
JKQTPEnhancedPainter::JKQTPEnhancedPainter(QPaintDevice *device):
|
||||
QPainter(device)
|
||||
QPainter(device),
|
||||
m_flags(DefaultPaintMode)
|
||||
{
|
||||
initQEnhacedPainter();
|
||||
}
|
||||
@ -34,6 +35,51 @@ JKQTPEnhancedPainter::JKQTPEnhancedPainter():
|
||||
initQEnhacedPainter();
|
||||
}
|
||||
|
||||
void JKQTPEnhancedPainter::setPainterFlag(PainterFlag flag, bool enabled)
|
||||
{
|
||||
if (!enabled && m_flags.testFlag(flag)) m_flags &= ~flag;
|
||||
else if (enabled && !m_flags.testFlag(flag)) m_flags |= flag;
|
||||
}
|
||||
|
||||
void JKQTPEnhancedPainter::setPainterFlag(PainterFlags flags)
|
||||
{
|
||||
m_flags=flags;
|
||||
}
|
||||
|
||||
void JKQTPEnhancedPainter::drawPolylineFast(const QPointF *points, int pointCount)
|
||||
{
|
||||
if (!points || pointCount<2) return;
|
||||
if (m_flags.testFlag(VectorPainting) || pen().style()!=Qt::SolidLine || pen().widthF()>device()->devicePixelRatioF()+0.01 || pen().widthF()<device()->devicePixelRatioF()*0.8) {
|
||||
//qDebug()<<"drawFastPolyline(): widthF="<<pen().widthF();
|
||||
drawPolyline(points, pointCount);
|
||||
} else {
|
||||
//qDebug()<<"drawFastPolyline()";
|
||||
// we use a specialized algorithm only in a very defined circumstances
|
||||
for (int i=1; i<pointCount; i++) {
|
||||
QLineF l(points[i-1], points[i]);
|
||||
if (!l.isNull() && l.length()>0) drawLine(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void JKQTPEnhancedPainter::drawPolylineFast(const QPoint *points, int pointCount)
|
||||
{
|
||||
if (!points || pointCount<2) return;
|
||||
if (m_flags.testFlag(VectorPainting) || pen().style()!=Qt::SolidLine || pen().widthF()>1.01) {
|
||||
drawPolyline(points, pointCount);
|
||||
} else {
|
||||
// we use a specialized algorithm only in a very defined circumstances
|
||||
for (int i=1; i<pointCount; i++) {
|
||||
QLine l(points[i-1], points[i]);
|
||||
if (!l.isNull() && (l.dx()>0||l.dy()>0)) drawLine(l);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JKQTPEnhancedPainter::PainterFlags JKQTPEnhancedPainter::painterFlags() const {
|
||||
return m_flags;
|
||||
}
|
||||
|
||||
|
||||
void JKQTPEnhancedPainter::initQEnhacedPainter()
|
||||
{
|
||||
|
@ -32,17 +32,46 @@
|
||||
*/
|
||||
class JKQTCOMMON_LIB_EXPORT JKQTPEnhancedPainter : public QPainter {
|
||||
public:
|
||||
|
||||
enum PainterFlag { DefaultPaintMode = 0x00, /*!< \brief the default mode, the JKQTPEnhancedPainter draws on a pixel-device */
|
||||
VectorPainting = 0x01, /*!< \brief if set, the JKQTPEnhancedPainter draws onto a vector-device, like a printer, PDF or SVG-output */
|
||||
};
|
||||
Q_ENUMS(PainterFlag)
|
||||
Q_FLAGS(PainterFlags)
|
||||
Q_DECLARE_FLAGS(PainterFlags, PainterFlag)
|
||||
|
||||
JKQTPEnhancedPainter(QPaintDevice* device);
|
||||
JKQTPEnhancedPainter();
|
||||
/** \copydoc m_flags */
|
||||
PainterFlags painterFlags() const ;
|
||||
/** \copydoc m_flags */
|
||||
void setPainterFlag(PainterFlag flag, bool enabled=true);
|
||||
/** \copydoc m_flags */
|
||||
void setPainterFlag(PainterFlags flags);
|
||||
|
||||
/** \brief faster variant of QPainter::drawPolyline(),it turns out that drawing single lines is way faster than drawing with drawPolyLine()
|
||||
*
|
||||
* At least for thin (1 Pixel) lines on non-vector-devices, this does not make much difference in appearance
|
||||
*/
|
||||
void drawPolylineFast(const QPointF *points, int pointCount);
|
||||
inline void drawPolylineFast(const QPolygonF &polyline) {
|
||||
drawPolylineFast(polyline.constData(), int(polyline.size()));
|
||||
}
|
||||
void drawPolylineFast(const QPoint *points, int pointCount);
|
||||
inline void drawPolylineFast(const QPolygon &polyline) {
|
||||
drawPolylineFast(polyline.constData(), int(polyline.size()));
|
||||
}
|
||||
|
||||
protected:
|
||||
void initQEnhacedPainter();
|
||||
private:
|
||||
|
||||
/** \brief flags, specifying how the JKQTPEnhancedPainter works
|
||||
*
|
||||
* \see PainterFlags */
|
||||
PainterFlags m_flags;
|
||||
};
|
||||
|
||||
|
||||
Q_DECLARE_OPERATORS_FOR_FLAGS(JKQTPEnhancedPainter::PainterFlags)
|
||||
|
||||
|
||||
|
||||
|
@ -126,7 +126,7 @@ void JKQTPContourPlot::draw(JKQTPEnhancedPainter &painter)
|
||||
//qDebug()<<lineTranformed;
|
||||
}
|
||||
for (const QPolygonF& poly: contourLinesTransformedSingleLevel) {
|
||||
painter.drawPolyline(poly);
|
||||
painter.drawPolylineFast(poly);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -299,14 +299,14 @@ void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::drawXGraph(JKQTPEnhancedP
|
||||
if (getDrawLine()) {
|
||||
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(p);
|
||||
painter.drawPolyline(linePolygon);
|
||||
painter.drawPolylineFast(linePolygon);
|
||||
}
|
||||
|
||||
if (drawErrorLines && (static_cast<bool>(errorPlotFunction))) {
|
||||
painter.save(); auto __finalpainterrline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(ep);
|
||||
painter.drawPolyline(errorLineTop);
|
||||
painter.drawPolyline(errorLineBottom);
|
||||
painter.drawPolylineFast(errorLineTop);
|
||||
painter.drawPolylineFast(errorLineBottom);
|
||||
}
|
||||
|
||||
|
||||
@ -425,14 +425,14 @@ void JKQTPEvaluatedFunctionWithErrorsGraphDrawingBase::drawYGraph(JKQTPEnhancedP
|
||||
if (getDrawLine()) {
|
||||
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(p);
|
||||
painter.drawPolyline(linePolygon);
|
||||
painter.drawPolylineFast(linePolygon);
|
||||
}
|
||||
|
||||
if (drawErrorLines && (static_cast<bool>(errorPlotFunction))) {
|
||||
painter.save(); auto __finalpainterrline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(ep);
|
||||
painter.drawPolyline(errorLineTop);
|
||||
painter.drawPolyline(errorLineBottom);
|
||||
painter.drawPolylineFast(errorLineTop);
|
||||
painter.drawPolylineFast(errorLineBottom);
|
||||
}
|
||||
|
||||
|
||||
|
@ -108,7 +108,7 @@ void JKQTPXYFunctionLineGraphBase::draw(JKQTPEnhancedPainter& painter) {
|
||||
{
|
||||
painter.save(); auto __finalpaintline=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(p);
|
||||
painter.drawPolyline(data);
|
||||
painter.drawPolylineFast(data);
|
||||
}
|
||||
|
||||
|
||||
|
@ -466,14 +466,14 @@ void JKQTPFilledVerticalRangeGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
if (isHighlighted()) {
|
||||
|
||||
painter.setPen(ps);
|
||||
painter.drawPolyline(phigh);
|
||||
painter.drawPolyline(plow);
|
||||
painter.drawPolylineFast(phigh);
|
||||
painter.drawPolylineFast(plow);
|
||||
}
|
||||
|
||||
|
||||
painter.setPen(p);
|
||||
painter.drawPolyline(phigh);
|
||||
painter.drawPolyline(plow);
|
||||
painter.drawPolylineFast(phigh);
|
||||
painter.drawPolylineFast(plow);
|
||||
|
||||
}
|
||||
}
|
||||
@ -581,14 +581,14 @@ void JKQTPFilledHorizontalRangeGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
if (isHighlighted()) {
|
||||
|
||||
painter.setPen(ps);
|
||||
painter.drawPolyline(phigh);
|
||||
painter.drawPolyline(plow);
|
||||
painter.drawPolylineFast(phigh);
|
||||
painter.drawPolylineFast(plow);
|
||||
}
|
||||
|
||||
|
||||
painter.setPen(p);
|
||||
painter.drawPolyline(phigh);
|
||||
painter.drawPolyline(plow);
|
||||
painter.drawPolylineFast(phigh);
|
||||
painter.drawPolylineFast(plow);
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -142,7 +142,7 @@ void JKQTPGeoLine::draw(JKQTPEnhancedPainter& painter) {
|
||||
if (drawHead) JKQTPPlotLineDecorator(painter, xx2.x(), xx2.y(), angle2, getHeadDecoratorStyle(), calcHeadDecoratorSize(getLinePen(painter, getParent()).widthF()));//, &lx2);
|
||||
//points[0]=lx1;
|
||||
//points[points.size()-1]=lx2;
|
||||
painter.drawPolyline(points.data(), points.size());
|
||||
painter.drawPolylineFast(points.data(), points.size());
|
||||
/*for (auto& p: points) {
|
||||
JKQTPPlotSymbol(painter, p.x(), p.y(), JKQTPPlus, 5, 1, QColor("green"), QColor("darkgreen"));
|
||||
}*/
|
||||
@ -421,7 +421,7 @@ void JKQTPGeoInfiniteLine::draw(JKQTPEnhancedPainter& painter) {
|
||||
xx1=points[0];
|
||||
const QPointF xx1p=points[1];
|
||||
angle1=atan2(xx1p.y()-xx1.y(), xx1p.x()-xx1.x());
|
||||
painter.drawPolyline(points.data(), points.size());
|
||||
painter.drawPolylineFast(points.data(), points.size());
|
||||
/*for (auto& p: points) {
|
||||
JKQTPPlotSymbol(painter, p.x(), p.y(), JKQTPPlus, 5, 1, QColor("green"), QColor("darkgreen"));
|
||||
}*/
|
||||
@ -592,7 +592,7 @@ void JKQTPGeoPolyLines::draw(JKQTPEnhancedPainter& painter) {
|
||||
xx1=path[0];
|
||||
xx2=path[path.size()-1];
|
||||
// draw corrected line
|
||||
painter.drawPolyline(path.data(), path.size());
|
||||
painter.drawPolylineFast(path.data(), path.size());
|
||||
doDrawDecorator=true;
|
||||
} else {
|
||||
// for non-linear axes, a line might not be drawn as a line, so we need to segment the line (i.e. linear function in coordinate space)
|
||||
@ -607,7 +607,7 @@ void JKQTPGeoPolyLines::draw(JKQTPEnhancedPainter& painter) {
|
||||
xx2=points_poly[points_poly.size()-1];
|
||||
const QPointF xx2p=points_poly[points_poly.size()-2];
|
||||
angle2=atan2(xx2p.y()-xx2.y(), xx2p.x()-xx2.x());
|
||||
painter.drawPolyline(points_poly.data(), points_poly.size());
|
||||
painter.drawPolylineFast(points_poly.data(), points_poly.size());
|
||||
doDrawDecorator=true;
|
||||
/*for (auto& p: points_poly) {
|
||||
JKQTPPlotSymbol(painter, p.x(), p.y(), JKQTPPlus, 5, 1, QColor("green"), QColor("darkgreen"));
|
||||
@ -719,7 +719,7 @@ void JKQTPGeoArc::draw(JKQTPEnhancedPainter& painter) {
|
||||
|
||||
painter.save(); auto __finalpaint=JKQTPFinally([&painter]() {painter.restore();});
|
||||
painter.setPen(getLinePen(painter, parent));
|
||||
painter.drawPolyline(rect);
|
||||
painter.drawPolylineFast(rect);
|
||||
}
|
||||
|
||||
void JKQTPGeoArc::setAngleStart(double __value)
|
||||
|
@ -134,10 +134,10 @@ void JKQTPXYLineGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
if (linesP.size()>0) {
|
||||
if (isHighlighted()) {
|
||||
painter.setPen(penSelection);
|
||||
painter.drawPolyline(linesP);
|
||||
painter.drawPolylineFast(linesP);
|
||||
}
|
||||
painter.setPen(p);
|
||||
painter.drawPolyline(linesP);
|
||||
painter.drawPolylineFast(linesP);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -393,7 +393,7 @@ void JKQTPXYParametrizedScatterGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
} else {
|
||||
pp.setColor(getHighlightingLineColor());
|
||||
painter.setPen(pp);
|
||||
painter.drawPolyline(linesP);
|
||||
painter.drawPolylineFast(linesP);
|
||||
}
|
||||
}
|
||||
QPen pp=p;
|
||||
@ -407,7 +407,7 @@ void JKQTPXYParametrizedScatterGraph::draw(JKQTPEnhancedPainter &painter)
|
||||
} else {
|
||||
pp.setColor(getHighlightingLineColor());
|
||||
painter.setPen(pp);
|
||||
painter.drawPolyline(linesP);
|
||||
painter.drawPolylineFast(linesP);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -276,7 +276,7 @@ void JKQTPSpecialLineHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.setPen(ph);
|
||||
for (const QPolygonF& lines : pl_fordrawing) {
|
||||
painter.drawPolyline(lines);
|
||||
painter.drawPolylineFast(lines);
|
||||
}
|
||||
}
|
||||
|
||||
@ -284,7 +284,7 @@ void JKQTPSpecialLineHorizontalGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.setPen(p);
|
||||
for (const QPolygonF& lines : pl_fordrawing) {
|
||||
painter.drawPolyline(lines);
|
||||
painter.drawPolylineFast(lines);
|
||||
}
|
||||
}
|
||||
|
||||
@ -464,7 +464,7 @@ void JKQTPSpecialLineVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.setPen(ph);
|
||||
for (const QPolygonF& lines : pl_fordrawing) {
|
||||
painter.drawPolyline(lines);
|
||||
painter.drawPolylineFast(lines);
|
||||
}
|
||||
}
|
||||
|
||||
@ -472,7 +472,7 @@ void JKQTPSpecialLineVerticalGraph::draw(JKQTPEnhancedPainter& painter) {
|
||||
painter.setBrush(Qt::NoBrush);
|
||||
painter.setPen(p);
|
||||
for (const QPolygonF& lines : pl_fordrawing) {
|
||||
painter.drawPolyline(lines);
|
||||
painter.drawPolylineFast(lines);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1965,6 +1965,7 @@ void JKQTBasePlotter::printpreviewPaintRequested(QPrinter* printer) {
|
||||
}
|
||||
|
||||
JKQTPEnhancedPainter painter;
|
||||
painter.setPainterFlag(JKQTPEnhancedPainter::VectorPainting);
|
||||
painter.begin(printer);
|
||||
if (!printSetAbsolutePageSize) {
|
||||
#ifdef SHOW_JKQTPLOTTER_DEBUG
|
||||
@ -2065,6 +2066,7 @@ void JKQTBasePlotter::printpreviewPaintRequestedNewPaintDevice(QPaintDevice *pai
|
||||
if (printer) painter.begin(printer);
|
||||
else if (svg) painter.begin(svg);
|
||||
else painter.begin(paintDevice);
|
||||
if (printer||svg) painter.setPainterFlag(JKQTPEnhancedPainter::VectorPainting);
|
||||
#else
|
||||
painter.begin(paintDevice);
|
||||
#endif
|
||||
@ -3916,6 +3918,7 @@ void JKQTBasePlotter::copyPixelImage(bool showPreview) {
|
||||
svg->setSize(size);
|
||||
svg->setOutputDevice(&buffer);
|
||||
JKQTPEnhancedPainter painter;
|
||||
painter.setPainterFlag(JKQTPEnhancedPainter::VectorPainting);
|
||||
painter.begin(svg);
|
||||
painter.scale(factor,factor);
|
||||
printAspect=printSizeY_Millimeter/printSizeX_Millimeter;
|
||||
|
Binary file not shown.
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
Binary file not shown.
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
Binary file not shown.
Before Width: | Height: | Size: 51 KiB After Width: | Height: | Size: 52 KiB |
Loading…
Reference in New Issue
Block a user