Clean up pad handling in 3D viewer.

Most importantly, create F_Cu/B_Cu layers if they're otherwise empty
but we have plated pads to render on them.

Fixes https://gitlab.com/kicad/code/kicad/issues/10207
This commit is contained in:
Jeff Young 2022-03-06 13:35:46 +00:00
parent dbfdd3fb56
commit 0dc857b5ab
7 changed files with 111 additions and 120 deletions

View File

@ -421,15 +421,10 @@ void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aCo
{
for( PAD* pad : aFootprint->Pads() )
{
if( !pad->IsOnLayer( aLayerId ) )
if( !pad->FlashLayer( aLayerId ) )
continue;
// Skip pad annulus when not connected on this layer (if removing is enabled)
if( !pad->FlashLayer( aLayerId ) && IsCopperLayer( aLayerId ) )
continue;
// NPTH pads are not drawn on layers if the
// shape size and pos is the same as their hole:
// NPTH pads are not drawn on layers if the shape size and pos is the same as their hole:
if( aSkipNPTHPadsWihNoCopper && ( pad->GetAttribute() == PAD_ATTRIB::NPTH ) )
{
if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == wxPoint( 0, 0 ) )
@ -454,19 +449,28 @@ void BOARD_ADAPTER::addPads( const FOOTPRINT* aFootprint, CONTAINER_2D_BASE* aCo
}
}
const bool isPlated = ( ( aLayerId == F_Cu ) && pad->FlashLayer( F_Mask ) ) ||
( ( aLayerId == B_Cu ) && pad->FlashLayer( B_Mask ) );
if( aSkipPlatedPads && isPlated )
continue;
if( aSkipNonPlatedPads && !isPlated )
continue;
VECTOR2I margin( 0, 0 );
switch( aLayerId )
{
case F_Cu:
if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
continue;
if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
continue;
break;
case B_Cu:
if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
continue;
if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
continue;
break;
case F_Mask:
case B_Mask:
margin.x += pad->GetSolderMaskExpansion();

View File

@ -544,7 +544,6 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
for( FOOTPRINT* footprint : m_board->Footprints() )
{
addPads( footprint, m_platedPadsFront, F_Cu, true, false, true );
addPads( footprint, m_platedPadsBack, B_Cu, true, false, true );
}
@ -564,8 +563,8 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter )
// Add pads to polygon list
for( FOOTPRINT* footprint : m_board->Footprints() )
{
// Note: NPTH pads are not drawn on copper layers when the pad
// has same shape as its hole
// Note: NPTH pads are not drawn on copper layers when the pad has same shape as
// its hole
footprint->TransformPadsWithClearanceToPolygon( *layerPoly, curr_layer_id,
0, ARC_HIGH_DEF, ERROR_INSIDE,
true, renderPlatedPadsAsPlated,

View File

@ -374,6 +374,22 @@ OPENGL_RENDER_LIST* RENDER_3D_OPENGL::generateLayerList( const BVH_CONTAINER_2D*
}
OPENGL_RENDER_LIST* RENDER_3D_OPENGL::generateEmptyLayerList( PCB_LAYER_ID aLayerId )
{
float layer_z_bot = 0.0f;
float layer_z_top = 0.0f;
getLayerZPos( aLayerId, layer_z_top, layer_z_bot );
TRIANGLE_DISPLAY_LIST* layerTriangles = new TRIANGLE_DISPLAY_LIST( 1 );
// store in a list so it will be latter deleted
m_triangles.push_back( layerTriangles );
return new OPENGL_RENDER_LIST( *layerTriangles, m_circleTexture, layer_z_bot, layer_z_top );
}
OPENGL_RENDER_LIST* RENDER_3D_OPENGL::createBoard( const SHAPE_POLY_SET& aBoardPoly,
const BVH_CONTAINER_2D* aThroughHoles )
{
@ -388,9 +404,8 @@ OPENGL_RENDER_LIST* RENDER_3D_OPENGL::createBoard( const SHAPE_POLY_SET& aBoardP
if( listBoardObject2d.size() > 0 )
{
// We will set a unitary Z so it will in future used with transformations
// since the board poly will be used not only to draw itself but also the
// solder mask layers.
// We will set a unitary Z so it will in future used with transformations since the
// board poly will be used not only to draw itself but also the solder mask layers.
const float layer_z_top = 1.0f;
const float layer_z_bot = 0.0f;
@ -565,7 +580,7 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
const BVH_CONTAINER_2D* container2d = ii.second;
SHAPE_POLY_SET polyListSubtracted;
SHAPE_POLY_SET* aPolyList = nullptr;
SHAPE_POLY_SET* polyList = nullptr;
// Load the vertical (Z axis) component of shapes
@ -582,9 +597,8 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
{
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetThroughHoleOdPolys(),
SHAPE_POLY_SET::PM_FAST );
polyListSubtracted.BooleanSubtract(
m_boardAdapter.GetOuterNonPlatedThroughHolePoly(),
SHAPE_POLY_SET::PM_FAST );
polyListSubtracted.BooleanSubtract( m_boardAdapter.GetOuterNonPlatedThroughHolePoly(),
SHAPE_POLY_SET::PM_FAST );
}
if( m_boardAdapter.m_Cfg->m_Render.subtract_mask_from_silk )
@ -602,10 +616,10 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
}
}
aPolyList = &polyListSubtracted;
polyList = &polyListSubtracted;
}
OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, aPolyList, layer_id,
OPENGL_RENDER_LIST* oglList = generateLayerList( container2d, polyList, layer_id,
&m_boardAdapter.GetThroughHoleIds() );
if( oglList != nullptr )
@ -628,6 +642,10 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
m_platedPadsFront = generateLayerList( m_boardAdapter.GetPlatedPadsFront(),
&polySubtracted, F_Cu );
// An entry for F_Cu must exist in m_layers or we'll never look at m_platedPadsFront
if( m_layers.count( F_Cu ) == 0 )
m_layers[F_Cu] = generateEmptyLayerList( F_Cu );
}
if( m_boardAdapter.GetBackPlatedPadPolys() )
@ -642,6 +660,10 @@ void RENDER_3D_OPENGL::reload( REPORTER* aStatusReporter, REPORTER* aWarningRepo
m_platedPadsBack = generateLayerList( m_boardAdapter.GetPlatedPadsBack(),
&polySubtracted, B_Cu );
// An entry for B_Cu must exist in m_layers or we'll never look at m_platedPadsBack
if( m_layers.count( B_Cu ) == 0 )
m_layers[B_Cu] = generateEmptyLayerList( B_Cu );
}
}

View File

@ -504,7 +504,7 @@ void RENDER_3D_OPENGL::setCopperMaterial()
void RENDER_3D_OPENGL::setPlatedCopperAndDepthOffset( PCB_LAYER_ID aLayer_id )
{
glEnable( GL_POLYGON_OFFSET_FILL );
glPolygonOffset(-0.1f, -2.0f );
glPolygonOffset( -0.1f, -2.0f );
setLayerMaterial( aLayer_id );
}
@ -700,20 +700,16 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
{
pLayerDispList->DrawAllCameraCulled( m_camera.GetPos().z, drawMiddleSegments );
// Draw copper plated pads
if( ( layer_id == F_Cu || layer_id == B_Cu )
&& ( m_platedPadsFront || m_platedPadsBack ) )
{
setPlatedCopperAndDepthOffset( layer_id );
}
// Draw plated pads
if( layer_id == F_Cu && m_platedPadsFront )
{
setPlatedCopperAndDepthOffset( layer_id );
m_platedPadsFront->DrawAllCameraCulled( m_camera.GetPos().z,
drawMiddleSegments );
}
else if( layer_id == B_Cu && m_platedPadsBack )
{
setPlatedCopperAndDepthOffset( layer_id );
m_platedPadsBack->DrawAllCameraCulled( m_camera.GetPos().z,
drawMiddleSegments );
}
@ -749,16 +745,10 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
viasHolesLayer,
m_antiBoard );
// Draw copper plated pads
if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
( m_platedPadsFront || m_platedPadsBack ) )
{
setPlatedCopperAndDepthOffset( layer_id );
}
// Draw plated pads
if( layer_id == F_Cu && m_platedPadsFront )
{
setPlatedCopperAndDepthOffset( layer_id );
m_platedPadsFront->DrawAllCameraCulledSubtractLayer(
drawMiddleSegments,
m_outerThroughHoles,
@ -767,6 +757,7 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
}
else if( layer_id == B_Cu && m_platedPadsBack )
{
setPlatedCopperAndDepthOffset( layer_id );
m_platedPadsBack->DrawAllCameraCulledSubtractLayer(
drawMiddleSegments,
m_outerThroughHoles,
@ -783,21 +774,16 @@ bool RENDER_3D_OPENGL::Redraw( bool aIsMoving, REPORTER* aStatusReporter,
m_outerThroughHoles,
m_antiBoard );
// Draw copper plated pads
if( ( ( layer_id == F_Cu ) || ( layer_id == B_Cu ) ) &&
( m_platedPadsFront || m_platedPadsBack ) )
{
setPlatedCopperAndDepthOffset( layer_id );
}
if( layer_id == F_Cu && m_platedPadsFront )
{
setPlatedCopperAndDepthOffset( layer_id );
m_platedPadsFront->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
m_outerThroughHoles,
m_antiBoard );
}
else if( layer_id == B_Cu && m_platedPadsBack )
{
setPlatedCopperAndDepthOffset( layer_id );
m_platedPadsBack->DrawAllCameraCulledSubtractLayer( drawMiddleSegments,
m_outerThroughHoles,
m_antiBoard );

View File

@ -82,6 +82,8 @@ private:
PCB_LAYER_ID aLayerId,
const BVH_CONTAINER_2D* aThroughHoles = nullptr );
OPENGL_RENDER_LIST* generateEmptyLayerList( PCB_LAYER_ID aLayerId );
void addTopAndBottomTriangles( TRIANGLE_DISPLAY_LIST* aDst, const SFVEC2F& v0,
const SFVEC2F& v1, const SFVEC2F& v2, float top, float bot );

View File

@ -2336,51 +2336,31 @@ void FOOTPRINT::TransformPadsWithClearanceToPolygon( SHAPE_POLY_SET& aCornerBuff
{
for( const PAD* pad : m_pads )
{
if( aLayer != UNDEFINED_LAYER && !pad->IsOnLayer(aLayer) )
continue;
if( !pad->FlashLayer( aLayer ) && IsCopperLayer( aLayer ) )
continue;
// NPTH pads are not drawn on layers if the shape size and pos is the same
// as their hole:
if( aSkipNPTHPadsWihNoCopper && pad->GetAttribute() == PAD_ATTRIB::NPTH )
{
if( pad->GetDrillSize() == pad->GetSize() && pad->GetOffset() == VECTOR2I( 0, 0 ) )
{
switch( pad->GetShape() )
{
case PAD_SHAPE::CIRCLE:
if( pad->GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
continue;
break;
case PAD_SHAPE::OVAL:
if( pad->GetDrillShape() != PAD_DRILL_SHAPE_CIRCLE )
continue;
break;
default:
break;
}
}
}
const bool isPlated = ( ( aLayer == F_Cu ) && pad->FlashLayer( F_Mask ) ) ||
( ( aLayer == B_Cu ) && pad->FlashLayer( B_Mask ) );
if( aSkipPlatedPads && isPlated )
continue;
if( aSkipNonPlatedPads && !isPlated )
if( !pad->FlashLayer( aLayer ) )
continue;
VECTOR2I clearance( aClearance, aClearance );
switch( aLayer )
{
case F_Cu:
if( aSkipPlatedPads && pad->FlashLayer( F_Mask ) )
continue;
if( aSkipNonPlatedPads && !pad->FlashLayer( F_Mask ) )
continue;
break;
case B_Cu:
if( aSkipPlatedPads && pad->FlashLayer( B_Mask ) )
continue;
if( aSkipNonPlatedPads && !pad->FlashLayer( B_Mask ) )
continue;
break;
case F_Mask:
case B_Mask:
clearance.x += pad->GetSolderMaskExpansion();

View File

@ -232,34 +232,14 @@ bool PAD::FlashLayer( LSET aLayers ) const
bool PAD::FlashLayer( int aLayer ) const
{
std::initializer_list<KICAD_T> types
static std::initializer_list<KICAD_T> types
{ PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T, PCB_PAD_T, PCB_ZONE_T, PCB_FP_ZONE_T };
const BOARD* board = GetBoard();
if( !IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) ) )
return false;
switch( GetAttribute() )
if( GetAttribute() == PAD_ATTRIB::NPTH )
{
case PAD_ATTRIB::PTH:
if( aLayer == UNDEFINED_LAYER )
return true;
/// Heat sink pads always get copper
if( GetProperty() == PAD_PROP::HEATSINK )
return IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
if( !m_removeUnconnectedLayer )
return IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
// Plated through hole pads need copper on the top/bottom layers for proper soldering
// Unless the user has removed them in the pad dialog
if( m_keepTopBottomLayer && ( aLayer == F_Cu || aLayer == B_Cu ) )
return IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
return board && board->GetConnectivity()->IsConnectedOnLayer( this,
static_cast<int>( aLayer ),
types, true );
case PAD_ATTRIB::NPTH:
if( GetShape() == PAD_SHAPE::CIRCLE && GetDrillShape() == PAD_DRILL_SHAPE_CIRCLE )
{
if( GetOffset() == VECTOR2I( 0, 0 ) && GetDrillSize().x >= GetSize().x )
@ -273,17 +253,35 @@ bool PAD::FlashLayer( int aLayer ) const
return false;
}
}
}
KI_FALLTHROUGH;
if( aLayer == UNDEFINED_LAYER )
return true;
case PAD_ATTRIB::SMD:
case PAD_ATTRIB::CONN:
default:
if( aLayer == UNDEFINED_LAYER )
if( LSET::FrontBoardTechMask().test( aLayer ) )
aLayer = F_Cu;
else if( LSET::BackBoardTechMask().test( aLayer ) )
aLayer = B_Cu;
if( GetAttribute() == PAD_ATTRIB::PTH && IsCopperLayer( aLayer ) )
{
/// Heat sink pads always get copper
if( GetProperty() == PAD_PROP::HEATSINK )
return true;
return IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) );
if( !m_removeUnconnectedLayer )
return true;
// Plated through hole pads need copper on the top/bottom layers for proper soldering
// Unless the user has removed them in the pad dialog
if( m_keepTopBottomLayer && ( aLayer == F_Cu || aLayer == B_Cu ) )
return true;
if( const BOARD* board = GetBoard() )
return board->GetConnectivity()->IsConnectedOnLayer( this, aLayer, types, true );
}
return true;
}