From 416e64a33419cc33c8cd37dbd1e1155bb0b6efc5 Mon Sep 17 00:00:00 2001 From: Hal Gentz Date: Thu, 4 Oct 2018 22:45:22 +0200 Subject: [PATCH] Spice plot widget: more accurate rendering Patch modifies the way graphs are displayed: instead of drawing one point for each X coordinate, there is a line segment joining min and max values for continuous graphs and all unique points are displayed for discrete graphs. Fixes: lp:1674143 * https://bugs.launchpad.net/kicad/+bug/1674143 --- common/widgets/mathplot.cpp | 142 +++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 58 deletions(-) diff --git a/common/widgets/mathplot.cpp b/common/widgets/mathplot.cpp index 6537991bb0..51d342f7db 100644 --- a/common/widgets/mathplot.cpp +++ b/common/widgets/mathplot.cpp @@ -42,6 +42,7 @@ #include #include // used only for debug #include // used for representation of x axes involving date +#include // Memory leak debugging #ifdef _DEBUG @@ -642,103 +643,128 @@ void mpFXY::Plot( wxDC& dc, mpWindow& w ) dc.SetClippingRegion( startPx, minYpx, endPx - startPx + 1, maxYpx - minYpx + 1 ); - wxCoord ix = std::numeric_limits::min(), iy = 0; - if( !m_continuous ) { - // for some reason DrawPoint does not use the current pen, - // so we use DrawLine for fat pens - if( m_pen.GetWidth() <= 1 ) + bool first = true; + wxCoord ix; + std::set ys; + + while( GetNextXY( x, y ) ) { - while( GetNextXY( x, y ) ) + double px = m_scaleX->TransformToPlot( x ); + double py = m_scaleY->TransformToPlot( y ); + wxCoord newX = w.x2p( px ); + + if( first ) { - double px = m_scaleX->TransformToPlot( x ); - double py = m_scaleY->TransformToPlot( y ); - wxCoord newX = w.x2p( px ); + ix = newX; + first = false; + } - if( newX == ix ) // continue until a new X coordinate is reached - continue; - - ix = newX; - iy = w.y2p( py ); + if( newX == ix ) // continue until a new X coordinate is reached + { + // collect all unique points + ys.insert( w.y2p( py ) ); + continue; + } + for( auto& iy: ys ) + { if( m_drawOutsideMargins || ( (ix >= startPx) && (ix <= endPx) && (iy >= minYpx) && (iy <= maxYpx) ) ) { - dc.DrawPoint( ix, iy ); + // for some reason DrawPoint does not use the current pen, + // so we use DrawLine for fat pens + if( m_pen.GetWidth() <= 1 ) + { + dc.DrawPoint( ix, iy ); + } + else + { + dc.DrawLine( ix, iy, ix, iy ); + } + UpdateViewBoundary( ix, iy ); } } - } - else - { - while( GetNextXY( x, y ) ) - { - double px = m_scaleX->TransformToPlot( x ); - double py = m_scaleY->TransformToPlot( y ); - wxCoord newX = w.x2p( px ); - - if( newX == ix ) // continue until a new X coordinate is reached - continue; - - ix = newX; - iy = w.y2p( py ); - - if( m_drawOutsideMargins - || ( (ix >= startPx) && (ix <= endPx) && (iy >= minYpx) - && (iy <= maxYpx) ) ) - { - dc.DrawLine( ix, iy, ix, iy ); - UpdateViewBoundary( ix, iy ); - } - - // dc.DrawLine(cx, cy, cx, cy); - } + ys.clear(); + ix = newX; + ys.insert( w.y2p( py ) ); } } else { - int n = 0; - // Old code - wxCoord x0 = 0, c0 = 0; - bool first = true; + wxCoord x0, y0; + bool first = true; + + wxCoord minY, maxY; + bool minFirst = true; while( GetNextXY( x, y ) ) { double px = m_scaleX->TransformToPlot( x ); double py = m_scaleY->TransformToPlot( y ); - if( py >= 0.0 && py <= 1.0 ) - n++; - wxCoord x1 = w.x2p( px ); - wxCoord c1 = w.y2p( py ); + wxCoord y1 = w.y2p( py ); if( first ) { first = false; - x0 = x1; c0 = c1; - } - else if( x0 == x1 ) // continue until a new X coordinate is reached - { + x0 = x1; y0 = y1; + minY = y1; + maxY = y1; continue; } - if( ( x1 >= startPx ) && ( x0 <= endPx ) ) + if( x0 == x1 ) // continue until a new X coordinate is reached { - bool outDown = ( c0 > maxYpx ) && ( c1 > maxYpx ); - bool outUp = ( c0 < minYpx ) && ( c1 < minYpx ); + // determine min and max, so they can also be marked on the plot + if( y1 > maxY ) + { + maxY = y1; + minFirst = true; + } + + if( y1 < minY ) + { + minY = y1; + minFirst = false; + } + continue; + } + + wxCoord firstY = minFirst ? minY : maxY; + wxCoord secondY = minFirst ? maxY : minY; + + if( ( x0 >= startPx ) && ( x0 <= endPx ) ) + { + bool outDown = ( y0 > maxYpx ) && ( firstY > maxYpx ); + bool outUp = ( y0 < minYpx ) && ( firstY < minYpx ); if( !outUp && !outDown ) { - dc.DrawLine( x0, c0, x1, c1 ); - // UpdateViewBoundary(x1, c1); + dc.DrawLine( x0, y0, x0, firstY ); + // UpdateViewBoundary(x1, firstY); } } - x0 = x1; c0 = c1; + bool outDown = ( firstY > maxYpx ) && ( secondY > maxYpx ); + bool outUp = ( firstY < minYpx ) && ( secondY < minYpx ); + bool outLeft = ( x1 < startPx ) && ( x0 < startPx ); + bool outRight = ( x1 > endPx ) && ( x0 > endPx ); + if( !( outUp || outDown || outLeft || outRight ) ) + { + dc.DrawLine( x0, firstY, x1, secondY ); + // UpdateViewBoundary(x1, secondY); + } + + x0 = x1; + y0 = secondY; + minY = y1; + maxY = y1; } }