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
This commit is contained in:
Hal Gentz 2018-10-04 22:45:22 +02:00 committed by Maciej Suminski
parent 70c1de3275
commit 416e64a334
1 changed files with 84 additions and 58 deletions

View File

@ -42,6 +42,7 @@
#include <cmath> #include <cmath>
#include <cstdio> // used only for debug #include <cstdio> // used only for debug
#include <ctime> // used for representation of x axes involving date #include <ctime> // used for representation of x axes involving date
#include <set>
// Memory leak debugging // Memory leak debugging
#ifdef _DEBUG #ifdef _DEBUG
@ -642,103 +643,128 @@ void mpFXY::Plot( wxDC& dc, mpWindow& w )
dc.SetClippingRegion( startPx, minYpx, endPx - startPx + 1, maxYpx - minYpx + 1 ); dc.SetClippingRegion( startPx, minYpx, endPx - startPx + 1, maxYpx - minYpx + 1 );
wxCoord ix = std::numeric_limits<wxCoord>::min(), iy = 0;
if( !m_continuous ) if( !m_continuous )
{ {
// for some reason DrawPoint does not use the current pen, bool first = true;
// so we use DrawLine for fat pens wxCoord ix;
if( m_pen.GetWidth() <= 1 ) std::set<wxCoord> 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 ); ix = newX;
double py = m_scaleY->TransformToPlot( y ); first = false;
wxCoord newX = w.x2p( px ); }
if( newX == ix ) // continue until a new X coordinate is reached if( newX == ix ) // continue until a new X coordinate is reached
continue; {
// collect all unique points
ix = newX; ys.insert( w.y2p( py ) );
iy = w.y2p( py ); continue;
}
for( auto& iy: ys )
{
if( m_drawOutsideMargins if( m_drawOutsideMargins
|| ( (ix >= startPx) && (ix <= endPx) && (iy >= minYpx) || ( (ix >= startPx) && (ix <= endPx) && (iy >= minYpx)
&& (iy <= maxYpx) ) ) && (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 ); 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 ); ys.clear();
ix = newX;
if( newX == ix ) // continue until a new X coordinate is reached ys.insert( w.y2p( py ) );
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);
}
} }
} }
else else
{ {
int n = 0; wxCoord x0, y0;
// Old code bool first = true;
wxCoord x0 = 0, c0 = 0;
bool first = true; wxCoord minY, maxY;
bool minFirst = true;
while( GetNextXY( x, y ) ) while( GetNextXY( x, y ) )
{ {
double px = m_scaleX->TransformToPlot( x ); double px = m_scaleX->TransformToPlot( x );
double py = m_scaleY->TransformToPlot( y ); double py = m_scaleY->TransformToPlot( y );
if( py >= 0.0 && py <= 1.0 )
n++;
wxCoord x1 = w.x2p( px ); wxCoord x1 = w.x2p( px );
wxCoord c1 = w.y2p( py ); wxCoord y1 = w.y2p( py );
if( first ) if( first )
{ {
first = false; first = false;
x0 = x1; c0 = c1; x0 = x1; y0 = y1;
} minY = y1;
else if( x0 == x1 ) // continue until a new X coordinate is reached maxY = y1;
{
continue; continue;
} }
if( ( x1 >= startPx ) && ( x0 <= endPx ) ) if( x0 == x1 ) // continue until a new X coordinate is reached
{ {
bool outDown = ( c0 > maxYpx ) && ( c1 > maxYpx ); // determine min and max, so they can also be marked on the plot
bool outUp = ( c0 < minYpx ) && ( c1 < minYpx ); 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 ) if( !outUp && !outDown )
{ {
dc.DrawLine( x0, c0, x1, c1 ); dc.DrawLine( x0, y0, x0, firstY );
// UpdateViewBoundary(x1, c1); // 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;
} }
} }