7
mirror of https://gitlab.com/kicad/code/kicad.git synced 2025-04-20 12:01:41 +00:00

GAL: provide constants for LoD HIDE/SHOW and a scale helper

Saves a mishmash of local HIDE/SHOW defs along with various literals.

Also provide a function that computes the scale at which a given
IU size becomes (notionally) a certain size on screen. While this
is a simple division, it's a bit opaque in terms of meaning.

Also it means the divide by zero case can be more universally
defended-against, which has traditionally been a bug opportunity.
This commit is contained in:
John Beard 2025-01-02 05:52:01 +08:00
parent 5705e928e1
commit 527faddbfd
15 changed files with 131 additions and 117 deletions

View File

@ -949,9 +949,11 @@ struct VIEW::DRAW_ITEM_VISITOR
return true;
}
const double itemLOD = aItem->ViewGetLOD( layer, view );
// Conditions that have to be fulfilled for an item to be drawn
bool drawCondition = aItem->viewPrivData()->isRenderable()
&& aItem->ViewGetLOD( layer, view ) < view->m_scale;
bool drawCondition = aItem->viewPrivData()->isRenderable() && itemLOD < view->m_scale;
if( !drawCondition )
return true;

View File

@ -112,7 +112,6 @@ void VIEW_GROUP::ViewDraw( int aLayer, VIEW* aView ) const
bool isSelection = m_layer == LAYER_SELECT_OVERLAY;
const std::vector<VIEW_ITEM*> drawList = updateDrawList();
constexpr double HIDE = std::numeric_limits<double>::max();
std::map<int, std::vector<VIEW_ITEM*>> layer_item_map;
@ -191,7 +190,7 @@ void VIEW_GROUP::ViewDraw( int aLayer, VIEW* aView ) const
{
// Ignore LOD scale for selected items, but don't ignore things explicitly
// hidden.
if( item->ViewGetLOD( layer, aView ) == HIDE )
if( item->ViewGetLOD( layer, aView ) == LOD_HIDE )
continue;
if( !painter->Draw( item, layer ) )

View File

@ -197,26 +197,23 @@ std::vector<int> SCH_LINE::ViewGetLayers() const
double SCH_LINE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
constexpr double SHOW = 0.0;
if( aLayer == LAYER_OP_VOLTAGES )
{
if( m_start == m_end )
return HIDE;
return LOD_HIDE;
int height = std::abs( m_end.y - m_start.y );
int width = std::abs( m_end.x - m_start.x );
const int height = std::abs( m_end.y - m_start.y );
// Operating points will be shown only if zoom is appropriate
if( height == 0 )
return (double) schIUScale.mmToIU( 15 ) / width;
else
return (double) schIUScale.mmToIU( 5 ) / height;
if( height > 0 )
return lodScaleForThreshold( height, schIUScale.mmToIU( 5 ) );
const int width = std::abs( m_end.x - m_start.x );
return lodScaleForThreshold( width, schIUScale.mmToIU( 15 ) );
}
// Other layers are always drawn.
return SHOW;
return LOD_SHOW;
}

View File

@ -1005,12 +1005,11 @@ double GERBER_DRAW_ITEM::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
// the level of details is chosen experimentally, to show
// only a readable text:
double level = (double) gerbIUScale.mmToIU( 3 );
return level / ( size + 1 );
return lodScaleForThreshold( size, gerbIUScale.mmToIU( 3.0 ) );
}
// Other layers are shown without any conditions
return 0.0;
return LOD_SHOW;
}

View File

@ -24,12 +24,13 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
*/
#ifndef __VIEW_ITEM_H
#define __VIEW_ITEM_H
#pragma once
#include <bitset>
#include <vector>
#include <limits>
#include <gal/gal.h>
#include <vector>
#include <bitset>
#include <math/box2.h>
#include <inspectable.h>
@ -134,15 +135,20 @@ public:
* A level of detail is the minimal #VIEW scale that is sufficient for an item to be shown
* on a given layer.
*
* Use @ref LOD_HIDE and @ref LOD_SHOW constants to hide or show the item unconditionally.
*
* Use @ref lodScaleForThreshold() to calculate the LOD scale for when the item
* passes a certain threshold size on screen.
*
* @param aLayer is the current drawing layer.
* @param aView is a pointer to the #VIEW device we are drawing on.
* @return the level of detail. 0 always show the item, because the actual zoom level
* @return the level of detail. 0 always shows the item, because the actual zoom level
* (or VIEW scale) is always > 0
*/
virtual double ViewGetLOD( int aLayer, VIEW* aView ) const
{
// By default always show the item
return 0.0;
return LOD_SHOW;
}
VIEW_ITEM_DATA* viewPrivData() const
@ -160,6 +166,40 @@ public:
return m_forcedTransparency;
}
protected:
/**
* Return this constant from ViewGetLOD() to hide the item unconditionally.
*/
static constexpr double LOD_HIDE = std::numeric_limits<double>::max();
/**
* Return this constant from ViewGetLOD() to show the item unconditionally.
*/
static constexpr double LOD_SHOW = 0.0;
/**
* Get the scale at which aWhatIu would be drawn at the same size as
* aThresholdIu on screen.
*
* This is useful when a level-of-detail is defined in terms of a threshold
* size (i.e. 'only draw X when it will be bigger than Y size on screen').
*
* E.g. if aWhatIu is 1000 and aThresholdIu is 100, then the item will be
* the same size as the threshold at 0.1 scale. Returning that 0.1 as the LoD
* will hide the item when the scale is less than 0.1 - i.e. smaller than the
* threshold.
*
* Because even at zoom 1.0, 1mm in KiCad may not be exactly 1mm on a physical
* screen, the threshold may not be exact in practice.
*/
static constexpr double lodScaleForThreshold( int aWhatIu, int aThresholdIu )
{
if( aWhatIu == 0 )
return LOD_HIDE;
return double( aThresholdIu ) / aWhatIu;
}
private:
friend class VIEW;
@ -174,5 +214,3 @@ private:
#if defined( _MSC_VER )
#pragma warning( pop )
#endif
#endif

View File

@ -2263,24 +2263,24 @@ double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
// The locked shadow shape is shown only if the footprint itself is visible
if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
return 0.0;
return LOD_SHOW;
if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
return 0.0;
return LOD_SHOW;
return std::numeric_limits<double>::max();
return LOD_HIDE;
}
if( aLayer == LAYER_CONFLICTS_SHADOW && IsConflicting() )
{
// The locked shadow shape is shown only if the footprint itself is visible
if( ( m_layer == F_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
return 0.0;
return LOD_SHOW;
if( ( m_layer == B_Cu ) && aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
return 0.0;
return LOD_SHOW;
return std::numeric_limits<double>::max();
return LOD_HIDE;
}
int layer = ( m_layer == F_Cu ) ? LAYER_FOOTPRINTS_FR :
@ -2289,12 +2289,12 @@ double FOOTPRINT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
// Currently this is only pertinent for the anchor layer; everything else is drawn from the
// children.
// The "good" value is experimentally chosen.
#define MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY 1.5
constexpr double MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY = 1.5;
if( aView->IsLayerVisible( layer ) )
return MINIMAL_ZOOM_LEVEL_FOR_VISIBILITY;
return std::numeric_limits<double>::max();
return LOD_HIDE;
}

View File

@ -1726,31 +1726,29 @@ std::vector<int> PAD::ViewGetLayers() const
double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
const BOARD* board = GetBoard();
// Meta control for hiding all pads
if( !aView->IsLayerVisible( LAYER_PADS ) )
return HIDE;
return LOD_HIDE;
// Handle Render tab switches
const PCB_LAYER_ID& pcbLayer = static_cast<PCB_LAYER_ID>( aLayer );
if( !IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
return HIDE;
return LOD_HIDE;
if( IsFlipped() && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
return HIDE;
return LOD_HIDE;
LSET visible = board->GetVisibleLayers() & board->GetEnabledLayers();
if( IsHoleLayer( aLayer ) )
{
if( !( visible & LSET::PhysicalLayersMask() ).any() )
return HIDE;
return LOD_HIDE;
}
else if( IsNetnameLayer( aLayer ) )
{
@ -1758,24 +1756,19 @@ double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
// Hide netnames unless pad is flashed to a high-contrast layer
if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
return HIDE;
return LOD_HIDE;
}
else
{
// Hide netnames unless pad is flashed to a visible layer
if( !FlashLayer( visible ) )
return HIDE;
return LOD_HIDE;
}
// Netnames will be shown only if zoom is appropriate
int divisor = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
const int minSize = std::min( GetBoundingBox().GetWidth(), GetBoundingBox().GetHeight() );
// Pad sizes can be zero briefly when someone is typing a number like "0.5" in the pad
// properties dialog
if( divisor == 0 )
return HIDE;
return ( double ) pcbIUScale.mmToIU( 5 ) / divisor;
return lodScaleForThreshold( minSize, pcbIUScale.mmToIU( 0.5 ) );
}
VECTOR2L padSize = GetShape( pcbLayer ) != PAD_SHAPE::CUSTOM
@ -1785,8 +1778,8 @@ double PAD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
if( minSide > 0 )
return std::min( (double) pcbIUScale.mmToIU( 0.2 ) / minSide, 3.5 );
else
return 0;
return LOD_SHOW;
}

View File

@ -169,10 +169,8 @@ wxString PCB_FIELD::GetItemDescription( UNITS_PROVIDER* aUnitsProvider, bool aFu
double PCB_FIELD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
if( !aView )
return 0.0;
return LOD_SHOW;
KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( aView->GetPainter() );
KIGFX::PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
@ -180,15 +178,15 @@ double PCB_FIELD::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
if( GetParentFootprint() && GetParentFootprint()->IsSelected()
&& renderSettings->m_ForceShowFieldsWhenFPSelected )
{
return 0.0;
return LOD_SHOW;
}
// Handle Render tab switches
if( IsValue() && !aView->IsLayerVisible( LAYER_FP_VALUES ) )
return HIDE;
return LOD_HIDE;
if( IsReference() && !aView->IsLayerVisible( LAYER_FP_REFERENCES ) )
return HIDE;
return LOD_HIDE;
return PCB_TEXT::ViewGetLOD( aLayer, aView );
}

View File

@ -338,9 +338,9 @@ std::vector<int> PCB_GROUP::ViewGetLayers() const
double PCB_GROUP::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
if( aView->IsLayerVisible( LAYER_ANCHOR ) )
return 0.0;
return LOD_SHOW;
return std::numeric_limits<double>::max();
return LOD_HIDE;
}

View File

@ -106,24 +106,25 @@ void PCB_REFERENCE_IMAGE::swapData( BOARD_ITEM* aItem )
double PCB_REFERENCE_IMAGE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
// All bitmaps are drawn on LAYER_DRAW_BITMAPS, but their
// associated board layer controls their visibility.
if( !GetBoard()->IsLayerVisible( m_layer ) )
return HIDE;
return LOD_HIDE;
if( renderSettings->GetHighContrast()
&& renderSettings->m_ContrastModeDisplay == HIGH_CONTRAST_MODE::HIDDEN
&& !renderSettings->GetLayerIsHighContrast( m_layer ) )
{
return HIDE;
return LOD_HIDE;
}
return aView->IsLayerVisible( LAYER_DRAW_BITMAPS ) ? 0.0 : HIDE;
if( aView->IsLayerVisible( LAYER_DRAW_BITMAPS ) )
return LOD_SHOW;
return LOD_HIDE;
}

View File

@ -571,9 +571,6 @@ void PCB_SHAPE::SetIsProxyItem( bool aIsProxy )
double PCB_SHAPE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
constexpr double SHOW = 0.0;
KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( aView->GetPainter() );
KIGFX::PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
@ -581,26 +578,26 @@ double PCB_SHAPE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
// Hide shadow if the main layer is not shown
if( !aView->IsLayerVisible( m_layer ) )
return HIDE;
return LOD_HIDE;
// Hide shadow on dimmed tracks
if( renderSettings->GetHighContrast() )
{
if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
return HIDE;
return LOD_HIDE;
}
}
if( FOOTPRINT* parent = GetParentFootprint() )
{
if( parent->GetLayer() == F_Cu && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
return HIDE;
return LOD_HIDE;
if( parent->GetLayer() == B_Cu && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
return HIDE;
return LOD_HIDE;
}
return SHOW;
return LOD_SHOW;
}

View File

@ -211,16 +211,14 @@ std::vector<int> PCB_TEXT::ViewGetLayers() const
double PCB_TEXT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
if( !aView )
return 0.0;
return LOD_SHOW;
KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( aView->GetPainter() );
KIGFX::PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
if( !aView->IsLayerVisible( GetLayer() ) )
return HIDE;
return LOD_HIDE;
if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
{
@ -228,7 +226,7 @@ double PCB_TEXT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
if( renderSettings->GetHighContrast() )
{
if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
return HIDE;
return LOD_HIDE;
}
}
@ -238,26 +236,26 @@ double PCB_TEXT::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
if( GetText() == wxT( "${VALUE}" ) )
{
if( !aView->IsLayerVisible( LAYER_FP_VALUES ) )
return HIDE;
return LOD_HIDE;
}
if( GetText() == wxT( "${REFERENCE}" ) )
{
if( !aView->IsLayerVisible( LAYER_FP_REFERENCES ) )
return HIDE;
return LOD_HIDE;
}
if( parentFP->GetLayer() == F_Cu && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
return HIDE;
return LOD_HIDE;
if( parentFP->GetLayer() == B_Cu && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
return HIDE;
return LOD_HIDE;
if( !aView->IsLayerVisible( LAYER_FP_TEXT ) )
return HIDE;
return LOD_HIDE;
}
return 0.0;
return LOD_SHOW;
}

View File

@ -395,8 +395,6 @@ VECTOR2I PCB_TEXTBOX::GetDrawPos( bool aIsFlipped ) const
double PCB_TEXTBOX::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
KIGFX::PCB_PAINTER* painter = static_cast<KIGFX::PCB_PAINTER*>( aView->GetPainter() );
KIGFX::PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
@ -404,17 +402,17 @@ double PCB_TEXTBOX::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
// Hide shadow if the main layer is not shown
if( !aView->IsLayerVisible( m_layer ) )
return HIDE;
return LOD_HIDE;
// Hide shadow on dimmed tracks
if( renderSettings->GetHighContrast() )
{
if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
return HIDE;
return LOD_HIDE;
}
}
return 0.0;
return LOD_SHOW;
}

View File

@ -1352,24 +1352,22 @@ std::vector<int> PCB_TRACK::ViewGetLayers() const
double PCB_TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
if( !aView->IsLayerVisible( LAYER_TRACKS ) )
return HIDE;
return LOD_HIDE;
if( IsNetnameLayer( aLayer ) )
{
if( GetNetCode() <= NETINFO_LIST::UNCONNECTED )
return HIDE;
return LOD_HIDE;
// Hide netnames on dimmed tracks
if( renderSettings->GetHighContrast() )
{
if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
return HIDE;
return LOD_HIDE;
}
VECTOR2I start( GetStart() );
@ -1379,35 +1377,35 @@ double PCB_TRACK::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
SEG::ecoord nameSize = GetDisplayNetname().size() * GetWidth();
if( VECTOR2I( end - start ).SquaredEuclideanNorm() < nameSize * nameSize )
return HIDE;
return LOD_HIDE;
BOX2I clipBox = BOX2ISafe( aView->GetViewport() );
ClipLine( &clipBox, start.x, start.y, end.x, end.y );
if( VECTOR2I( end - start ).SquaredEuclideanNorm() == 0 )
return HIDE;
return LOD_HIDE;
// Netnames will be shown only if zoom is appropriate
return ( double ) pcbIUScale.mmToIU( 4 ) / ( m_width + 1 );
return lodScaleForThreshold( m_width, pcbIUScale.mmToIU( 4.0 ) );
}
if( aLayer == LAYER_LOCKED_ITEM_SHADOW )
{
// Hide shadow if the main layer is not shown
if( !aView->IsLayerVisible( m_layer ) )
return HIDE;
return LOD_HIDE;
// Hide shadow on dimmed tracks
if( renderSettings->GetHighContrast() )
{
if( m_layer != renderSettings->GetPrimaryHighContrastLayer() )
return HIDE;
return LOD_HIDE;
}
}
// Other layers are shown without any conditions
return 0.0;
return LOD_SHOW;
}
@ -1471,15 +1469,13 @@ std::vector<int> PCB_VIA::ViewGetLayers() const
double PCB_VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = (double)std::numeric_limits<double>::max();
PCB_PAINTER* painter = static_cast<PCB_PAINTER*>( aView->GetPainter() );
PCB_RENDER_SETTINGS* renderSettings = painter->GetSettings();
LSET visible = LSET::AllLayersMask();
// Meta control for hiding all vias
if( !aView->IsLayerVisible( LAYER_VIAS ) )
return HIDE;
return LOD_HIDE;
// Handle board visibility
if( const BOARD* board = GetBoard() )
@ -1498,14 +1494,14 @@ double PCB_VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
highContrastLayer = B_Cu;
if( !IsCopperLayer( highContrastLayer ) )
return HIDE;
return LOD_HIDE;
if( GetViaType() != VIATYPE::THROUGH )
{
if( IsCopperLayerLowerThan( Padstack().Drill().start, highContrastLayer )
|| IsCopperLayerLowerThan( highContrastLayer, Padstack().Drill().end ) )
{
return HIDE;
return LOD_HIDE;
}
}
}
@ -1516,13 +1512,13 @@ double PCB_VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
// Show a through via's hole if any physical layer is shown
if( !( visible & LSET::PhysicalLayersMask() ).any() )
return HIDE;
return LOD_HIDE;
}
else
{
// Show a blind or micro via's hole if it crosses a visible layer
if( !( visible & GetLayerSet() ).any() )
return HIDE;
return LOD_HIDE;
}
// The hole won't be visible anyway at this scale
@ -1534,23 +1530,23 @@ double PCB_VIA::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
// Hide netnames unless via is flashed to a high-contrast layer
if( !FlashLayer( renderSettings->GetPrimaryHighContrastLayer() ) )
return HIDE;
return LOD_HIDE;
}
else
{
// Hide netnames unless pad is flashed to a visible layer
if( !FlashLayer( visible ) )
return HIDE;
return LOD_HIDE;
}
// Netnames will be shown only if zoom is appropriate
return width == 0 ? HIDE : ( (double)pcbIUScale.mmToIU( 10 ) / width );
return width == 0 ? LOD_HIDE : ( (double) pcbIUScale.mmToIU( 10 ) / width );
}
if( !IsCopperLayer( aLayer ) )
return (double) pcbIUScale.mmToIU( 0.6 ) / width;
return 0.0;
return LOD_SHOW;
}

View File

@ -538,13 +538,11 @@ std::vector<int> ZONE::ViewGetLayers() const
double ZONE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
{
constexpr double HIDE = std::numeric_limits<double>::max();
if( !aView )
return 0;
return LOD_SHOW;
if( !aView->IsLayerVisible( LAYER_ZONES ) )
return HIDE;
return LOD_HIDE;
if( FOOTPRINT* parentFP = GetParentFootprint() )
{
@ -552,14 +550,14 @@ double ZONE::ViewGetLOD( int aLayer, KIGFX::VIEW* aView ) const
// Handle Render tab switches
if( !flipped && !aView->IsLayerVisible( LAYER_FOOTPRINTS_FR ) )
return HIDE;
return LOD_HIDE;
if( flipped && !aView->IsLayerVisible( LAYER_FOOTPRINTS_BK ) )
return HIDE;
return LOD_HIDE;
}
// Other layers are shown without any conditions
return 0.0;
return LOD_SHOW;
}