Cache display netnames.

Also changes the redraw behaviour to not try and redraw
only when things entered the view (this didn't work
because it may be the netname that's entering the view,
not the whole track).  Instead we only process a finite
number of tracks on each idle event (in order to avoid
#12436).

Note that we don't need the timer at all anymore as the
netnames are in fixed locations on the track and never
make the track look like it's being dragged.

Also improves performance by avoiding sqrt.
This commit is contained in:
Jeff Young 2024-06-11 16:30:44 +01:00
parent 74070afbc6
commit d865bda4f2
10 changed files with 114 additions and 126 deletions

View File

@ -138,9 +138,18 @@ wxString BOARD_CONNECTED_ITEM::GetShortNetname() const
}
wxString BOARD_CONNECTED_ITEM::GetUnescapedShortNetname() const
wxString BOARD_CONNECTED_ITEM::GetDisplayNetname() const
{
return m_netinfo ? m_netinfo->GetUnescapedShortNetname() : wxString();
if( !m_netinfo )
return wxString();
if( const BOARD* board = GetBoard() )
{
if( board->GetNetInfo().m_DisplayNetnamesDirty )
board->GetNetInfo().RebuildDisplayNetnames();
}
return m_netinfo->GetDisplayNetname();
}

View File

@ -129,7 +129,7 @@ public:
/**
* @return the unescaped short netname.
*/
wxString GetUnescapedShortNetname() const;
wxString GetDisplayNetname() const;
/**
* Return an item's "own" clearance in internal units.

View File

@ -121,7 +121,7 @@ public:
/**
* @return the unescaped short netname.
*/
const wxString& GetUnescapedShortNetname() const { return m_unescapedShortNetname; }
const wxString& GetDisplayNetname() const { return m_displayNetname; }
/**
* @return true if the net was not labelled by the user.
@ -145,7 +145,7 @@ public:
else
m_shortNetname = aNewName;
m_unescapedShortNetname = UnescapeString( m_shortNetname );
m_displayNetname = UnescapeString( m_shortNetname );
}
bool IsCurrent() const { return m_isCurrent; }
@ -189,10 +189,14 @@ protected:
private:
friend class NETINFO_LIST;
int m_netCode; ///< A number equivalent to the net name.
wxString m_netname; ///< Full net name like /sheet/subsheet/vout used by Eeschema.
wxString m_shortNetname; ///< Short net name, like vout from /sheet/subsheet/vout.
wxString m_unescapedShortNetname; ///< Unescaped short net name.
int m_netCode; ///< A number equivalent to the net name.
wxString m_netname; ///< Full net name like /sheet/subsheet/vout used by Eeschema.
wxString m_shortNetname; ///< Short net name, like vout from /sheet/subsheet/vout.
wxString m_displayNetname; ///< Unescaped netname for display. Usually the short netname,
///< but will be the full netname if disambiguation required.
///< The NETINFO_LIST is repsonsible for the management of when
///< these need to be updated/disambiguated.
std::shared_ptr<NETCLASS> m_netClass;
@ -370,6 +374,8 @@ public:
/// Return the netcode map, at least for python.
const NETCODES_MAP& NetsByNetcode() const { return m_netCodes; }
void RebuildDisplayNetnames() const;
/// Constant that holds the "unconnected net" number (typically 0)
/// all items "connected" to this net are actually not connected items
static const int UNCONNECTED;
@ -490,6 +496,10 @@ private:
*/
int getFreeNetCode();
public:
mutable bool m_DisplayNetnamesDirty;
private:
BOARD* m_parent;
NETNAMES_MAP m_netNames; ///< map of <wxString, NETINFO_ITEM*>, is NETINFO_ITEM owner

View File

@ -44,7 +44,7 @@ NETINFO_ITEM::NETINFO_ITEM( BOARD* aParent, const wxString& aNetName, int aNetCo
m_netCode( aNetCode ),
m_netname( aNetName ),
m_shortNetname( m_netname.AfterLast( '/' ) ),
m_unescapedShortNetname( UnescapeString( m_shortNetname ) ),
m_displayNetname( UnescapeString( m_shortNetname ) ),
m_isCurrent( true )
{
m_parent = aParent;

View File

@ -110,7 +110,10 @@ void NETINFO_LIST::RemoveNet( NETINFO_ITEM* aNet )
}
if( removed )
{
m_newNetCode = std::min( m_newNetCode, aNet->m_netCode - 1 );
m_DisplayNetnamesDirty = true;
}
}
@ -129,9 +132,12 @@ void NETINFO_LIST::RemoveUnusedNets( BOARD_COMMIT* aCommit )
m_netNames.insert( std::make_pair( netInfo->GetNetname(), netInfo ) );
m_netCodes.insert( std::make_pair( netCode, netInfo ) );
}
else if( aCommit )
else
{
aCommit->Removed( netInfo );
m_DisplayNetnamesDirty = true;
if( aCommit )
aCommit->Removed( netInfo );
}
}
}
@ -162,6 +168,8 @@ void NETINFO_LIST::AppendNet( NETINFO_ITEM* aNewElement )
// add an entry for fast look up by a net name using a map
m_netNames.insert( std::make_pair( aNewElement->GetNetname(), aNewElement ) );
m_netCodes.insert( std::make_pair( aNewElement->GetNetCode(), aNewElement ) );
m_DisplayNetnamesDirty = true;
}
@ -176,6 +184,25 @@ void NETINFO_LIST::buildListOfNets()
}
void NETINFO_LIST::RebuildDisplayNetnames() const
{
std::map<wxString, int> shortNames;
for( NETINFO_ITEM* net : *this )
shortNames[net->m_shortNetname]++;
for( NETINFO_ITEM* net : *this )
{
if( shortNames[net->m_shortNetname] == 1 )
net->m_displayNetname = UnescapeString( net->m_shortNetname );
else
net->m_displayNetname = UnescapeString( net->m_netname );
}
m_DisplayNetnamesDirty = false;
}
#if defined(DEBUG)
void NETINFO_LIST::Show() const
{

View File

@ -398,20 +398,11 @@ PCB_EDIT_FRAME::PCB_EDIT_FRAME( KIWAY* aKiway, wxWindow* aParent ) :
// to calculate the wrong zoom size. See PCB_EDIT_FRAME::onSize().
Bind( wxEVT_SIZE, &PCB_EDIT_FRAME::onSize, this );
// Redraw netnames (so that they fall within the current viewport) after the viewport
// has stopped changing. Redrawing them without the timer moves them smoothly with scrolling,
// making it look like the tracks are being dragged -- which we don't want.
m_redrawNetnamesTimer.SetOwner( this );
Connect( wxEVT_TIMER, wxTimerEventHandler( PCB_EDIT_FRAME::redrawNetnames ), nullptr, this );
Bind( wxEVT_IDLE,
[this]( wxIdleEvent& aEvent )
{
if( GetCanvas()->GetView()->GetViewport() != m_lastViewport )
{
m_lastViewport = GetCanvas()->GetView()->GetViewport();
m_redrawNetnamesTimer.StartOnce( 500 );
}
if( GetCanvas()->GetView()->GetViewport() != m_lastNetnamesViewport )
redrawNetnames();
// Do not forget to pass the Idle event to other clients:
aEvent.Skip();
@ -585,38 +576,38 @@ BOARD_ITEM_CONTAINER* PCB_EDIT_FRAME::GetModel() const
}
void PCB_EDIT_FRAME::redrawNetnames( wxTimerEvent& aEvent )
void PCB_EDIT_FRAME::redrawNetnames()
{
bool needs_refresh = false;
// Don't stomp on the auto-save timer event.
if( aEvent.GetId() == ID_AUTO_SAVE_TIMER )
{
aEvent.Skip();
return;
}
PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( Kiface().KifaceSettings() );
if( !cfg || cfg->m_Display.m_NetNames < 2 )
return;
KIGFX::VIEW* view = GetCanvas()->GetView();
double scale = view->GetScale();
BOX2D viewport = view->GetViewport();
int maxCount = 200;
int count = 0;
for( PCB_TRACK* track : GetBoard()->Tracks() )
{
double lod = track->ViewGetLOD( GetNetnameLayer( track->GetLayer() ), view );
if( lod < scale )
continue;
if( lod != track->GetCachedLOD() || scale != track->GetCachedScale() )
if( track->ViewGetLOD( GetNetnameLayer( track->GetLayer() ), view ) < view->GetScale() )
{
view->Update( track, KIGFX::REPAINT );
needs_refresh = true;
track->SetCachedLOD( lod );
track->SetCachedScale( scale );
if( viewport != track->GetCachedViewport() )
{
if( ++count > maxCount )
{
// We've used up enough time for now. Zero out m_lastNetnamesViewport so
// the idle handler will give us another crack at it.
m_lastNetnamesViewport = BOX2D();
break;
}
view->Update( track, KIGFX::REPAINT );
needs_refresh = true;
track->SetCachedViewport( viewport );
}
}
}

View File

@ -821,7 +821,7 @@ protected:
int inferLegacyEdgeClearance( BOARD* aBoard, bool aShowUserMsg = true );
void redrawNetnames( wxTimerEvent& aEvent );
void redrawNetnames();
void saveProjectSettings() override;
@ -869,8 +869,7 @@ private:
/**
* Keep track of viewport so that track net labels can be adjusted when it changes.
*/
BOX2D m_lastViewport;
wxTimer m_redrawNetnamesTimer;
BOX2D m_lastNetnamesViewport;
wxTimer* m_eventCounterTimer;

View File

@ -717,15 +717,7 @@ void PCB_PAINTER::draw( const PCB_TRACK* aTrack, int aLayer )
return;
SHAPE_SEGMENT trackShape( { aTrack->GetStart(), aTrack->GetEnd() }, aTrack->GetWidth() );
wxString netname = aTrack->GetUnescapedShortNetname();
for( const auto& netinfo : aTrack->GetBoard()->GetNetInfo() )
{
if( netinfo->GetUnescapedShortNetname() == netname )
netname = UnescapeString( aTrack->GetNetname() );
}
renderNetNameForSegment( trackShape, color, netname );
renderNetNameForSegment( trackShape, color, aTrack->GetDisplayNetname() );
return;
}
else if( IsCopperLayer( aLayer ) || aLayer == LAYER_LOCKED_ITEM_SHADOW )
@ -773,17 +765,13 @@ void PCB_PAINTER::renderNetNameForSegment( const SHAPE_SEGMENT& aSeg, const COLO
viewport.SetEnd( VECTOR2D( matrix * screenSize ) );
viewport.Normalize();
BOX2I clipBox = BOX2ISafe( viewport );
SEG visibleSeg( aSeg.GetSeg().A, aSeg.GetSeg().B );
ClipLine( &clipBox, visibleSeg.A.x, visibleSeg.A.y, visibleSeg.B.x, visibleSeg.B.y );
size_t num_char = aNetName.size();
int num_char = aNetName.size();
// Check if the track is long enough to have a netname displayed
int seg_minlength = aSeg.GetWidth() * num_char;
int seg_minlength = aSeg.GetWidth() * num_char;
SEG::ecoord seg_minlength_sq = seg_minlength * seg_minlength;
if( visibleSeg.Length() < seg_minlength )
if( aSeg.GetSeg().SquaredLength() < seg_minlength_sq )
return;
double textSize = aSeg.GetWidth();
@ -793,27 +781,25 @@ void PCB_PAINTER::renderNetNameForSegment( const SHAPE_SEGMENT& aSeg, const COLO
VECTOR2I start = aSeg.GetSeg().A;
VECTOR2I end = aSeg.GetSeg().B;
VECTOR2D segV = end - start;
if( end.y == start.y ) // horizontal
{
textOrientation = ANGLE_HORIZONTAL;
num_names = std::max( num_names,
static_cast<int>( aSeg.GetSeg().Length() / viewport.GetWidth() ) );
num_names = std::max( num_names, KiROUND( aSeg.GetSeg().Length() / viewport.GetWidth() ) );
}
else if( end.x == start.x ) // vertical
{
textOrientation = ANGLE_VERTICAL;
num_names = std::max( num_names,
static_cast<int>( aSeg.GetSeg().Length() / viewport.GetHeight() ) );
num_names = std::max( num_names, KiROUND( aSeg.GetSeg().Length() / viewport.GetHeight() ) );
}
else
{
textOrientation = -EDA_ANGLE( visibleSeg.B - visibleSeg.A );
textOrientation = -EDA_ANGLE( segV );
textOrientation.Normalize90();
double min_size = std::min( viewport.GetWidth(), viewport.GetHeight() );
num_names = std::max( num_names,
static_cast<int>( aSeg.GetSeg().Length() / ( M_SQRT2 * min_size ) ) );
num_names = std::max( num_names, KiROUND( aSeg.GetSeg().Length() / ( M_SQRT2 * min_size ) ) );
}
m_gal->SetIsStroke( true );
@ -828,13 +814,13 @@ void PCB_PAINTER::renderNetNameForSegment( const SHAPE_SEGMENT& aSeg, const COLO
m_gal->SetHorizontalJustify( GR_TEXT_H_ALIGN_CENTER );
m_gal->SetVerticalJustify( GR_TEXT_V_ALIGN_CENTER );
for( int ii = 0; ii < num_names; ++ii )
{
VECTOR2I textPosition =
VECTOR2D( start ) * static_cast<double>( num_names - ii ) / ( num_names + 1 )
+ VECTOR2D( end ) * static_cast<double>( ii + 1 ) / ( num_names + 1 );
int divisions = num_names + 1;
if( clipBox.Contains( textPosition ) )
for( int ii = 1; ii < divisions; ++ii )
{
VECTOR2I textPosition = start + segV * ( (double) ii / divisions );
if( viewport.Contains( textPosition ) )
m_gal->BitmapText( aNetName, textPosition, textOrientation );
}
}
@ -975,7 +961,7 @@ void PCB_PAINTER::draw( const PCB_VIA* aVia, int aLayer )
// the netname
VECTOR2D textpos( 0.0, 0.0 );
wxString netname = aVia->GetUnescapedShortNetname();
wxString netname = aVia->GetDisplayNetname();
int topLayer = aVia->TopLayer() + 1;
int bottomLayer = std::min( aVia->BottomLayer() + 1, board->GetCopperLayerCount() );
@ -1180,7 +1166,7 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
if( displayOpts && !dynamic_cast<CVPCB_SETTINGS*>( viewer_settings() ) )
{
if( displayOpts->m_NetNames == 1 || displayOpts->m_NetNames == 3 )
netname = aPad->GetUnescapedShortNetname();
netname = aPad->GetDisplayNetname();
if( aPad->IsNoConnectPad() )
netname = wxT( "x" );
@ -1191,12 +1177,6 @@ void PCB_PAINTER::draw( const PAD* aPad, int aLayer )
if( netname.IsEmpty() && padNumber.IsEmpty() )
return;
for( const auto& netinfo : board->GetNetInfo() )
{
if( netinfo->GetUnescapedShortNetname() == netname )
netname = UnescapeString( aPad->GetNetname() );
}
BOX2I padBBox = aPad->GetBoundingBox();
VECTOR2D position = padBBox.Centre();
VECTOR2D padsize = VECTOR2D( padBBox.GetSize() );
@ -1744,7 +1724,7 @@ void PCB_PAINTER::draw( const PCB_SHAPE* aShape, int aLayer )
if( aShape->GetNetCode() <= NETINFO_LIST::UNCONNECTED )
return;
wxString netname = aShape->GetUnescapedShortNetname();
wxString netname = aShape->GetDisplayNetname();
if( netname.IsEmpty() )
return;

View File

@ -56,8 +56,6 @@ PCB_TRACK::PCB_TRACK( BOARD_ITEM* aParent, KICAD_T idtype ) :
BOARD_CONNECTED_ITEM( aParent, idtype )
{
m_Width = pcbIUScale.mmToIU( 0.2 ); // Gives a reasonable default width
m_CachedScale = -1.0; // Set invalid to force update
m_CachedLOD = 0.0; // Set to always display
}
@ -123,8 +121,7 @@ PCB_VIA& PCB_VIA::operator=( const PCB_VIA &aOther )
m_Width = aOther.m_Width;
m_Start = aOther.m_Start;
m_End = aOther.m_End;
m_CachedLOD = aOther.m_CachedLOD;
m_CachedScale = aOther.m_CachedScale;
m_CachedViewport = aOther.m_CachedViewport;
m_viaType = aOther.m_viaType;
m_padStack = aOther.m_padStack;
@ -1066,7 +1063,7 @@ double PCB_TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
}
// Pick the approximate size of the netname (square chars)
wxString netName = GetUnescapedShortNetname();
wxString netName = GetDisplayNetname();
size_t num_chars = netName.size();
if( GetLength() < num_chars * GetWidth() )
@ -1080,9 +1077,7 @@ double PCB_TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
ClipLine( &clipBox, start.x, start.y, end.x, end.y );
VECTOR2I line = ( end - start );
if( line.EuclideanNorm() == 0 )
if( VECTOR2I( end - start ).SquaredEuclideanNorm() == 0 )
return HIDE;
// Netnames will be shown only if zoom is appropriate

View File

@ -213,33 +213,21 @@ public:
}
/**
* Get last used LOD for the track net name.
*
* @return LOD from ViewGetLOD()
* @return last viewport used to render track net names.
*/
double GetCachedLOD()
BOX2D GetCachedViewport()
{
return m_CachedLOD;
return m_CachedViewport;
}
/**
* Set the cached LOD.
* Set the cached viewport used to render track net names.
*
* @param aLOD value from ViewGetLOD() or 0.0 to always display.
* @param aViewport
*/
void SetCachedLOD( double aLOD )
void SetCachedViewport( const BOX2D& aViewport )
{
m_CachedLOD = aLOD;
}
/**
* Get last used zoom scale for the track net name.
*
* @return scale from GetScale()
*/
double GetCachedScale()
{
return m_CachedScale;
m_CachedViewport = aViewport;
}
virtual double Similarity( const BOARD_ITEM& aOther ) const override;
@ -247,16 +235,6 @@ public:
virtual bool operator==( const BOARD_ITEM& aOther ) const override;
virtual bool operator==( const PCB_TRACK& aOther ) const;
/**
* Set the cached scale.
*
* @param aScale value from GetScale()
*/
void SetCachedScale( double aScale )
{
m_CachedScale = aScale;
}
struct cmp_tracks
{
bool operator()( const PCB_TRACK* aFirst, const PCB_TRACK* aSecond ) const;
@ -276,12 +254,11 @@ protected:
std::vector<MSG_PANEL_ITEM>& aList ) const;
protected:
int m_Width; ///< Thickness of track, or via diameter
VECTOR2I m_Start; ///< Line start point
VECTOR2I m_End; ///< Line end point
int m_Width; ///< Thickness of track, or via diameter
VECTOR2I m_Start; ///< Line start point
VECTOR2I m_End; ///< Line end point
double m_CachedLOD; ///< Last LOD used to draw this track's net
double m_CachedScale; ///< Last zoom scale used to draw this track's net.
BOX2D m_CachedViewport; ///> Last viewport used to draw this track's net
};