From 0fc4ccf8d9b6331e083e7e2dbdad4c266db34a52 Mon Sep 17 00:00:00 2001 From: Jeff Young <jeff@rokeby.ie> Date: Sun, 6 Mar 2022 13:35:46 +0000 Subject: [PATCH] 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 (cherry picked from commit 0dc857b5ab026be3ab64c1acbdb8defaba4d30bc) --- .../3d_canvas/create_3Dgraphic_brd_items.cpp | 36 +++++++----- 3d-viewer/3d_canvas/create_layer_items.cpp | 5 +- .../3d_rendering/opengl/create_scene.cpp | 40 ++++++++++--- .../3d_rendering/opengl/render_3d_opengl.cpp | 30 +++------- .../3d_rendering/opengl/render_3d_opengl.h | 2 + pcbnew/footprint.cpp | 58 ++++++------------- pcbnew/pad.cpp | 53 ++++++++--------- 7 files changed, 107 insertions(+), 117 deletions(-) diff --git a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp index 61efe94c16..e1c97c2d92 100644 --- a/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp +++ b/3d-viewer/3d_canvas/create_3Dgraphic_brd_items.cpp @@ -493,15 +493,10 @@ void BOARD_ADAPTER::addPadsWithClearance( const FOOTPRINT* aFootprint, { 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 ) ) @@ -526,19 +521,28 @@ void BOARD_ADAPTER::addPadsWithClearance( const FOOTPRINT* aFootprint, } } - 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; - wxSize margin( aInflateValue, aInflateValue ); 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->GetSolderMaskMargin(); diff --git a/3d-viewer/3d_canvas/create_layer_items.cpp b/3d-viewer/3d_canvas/create_layer_items.cpp index e2bfb3a858..f5b7dd2f2c 100644 --- a/3d-viewer/3d_canvas/create_layer_items.cpp +++ b/3d-viewer/3d_canvas/create_layer_items.cpp @@ -549,7 +549,6 @@ void BOARD_ADAPTER::createLayers( REPORTER* aStatusReporter ) for( FOOTPRINT* footprint : m_board->Footprints() ) { addPadsWithClearance( footprint, m_platedPadsFront, F_Cu, 0, true, false, true ); - addPadsWithClearance( footprint, m_platedPadsBack, B_Cu, 0, true, false, true ); } @@ -569,8 +568,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, diff --git a/3d-viewer/3d_rendering/opengl/create_scene.cpp b/3d-viewer/3d_rendering/opengl/create_scene.cpp index 1d20248762..b465d0cc32 100644 --- a/3d-viewer/3d_rendering/opengl/create_scene.cpp +++ b/3d-viewer/3d_rendering/opengl/create_scene.cpp @@ -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; @@ -563,7 +578,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 @@ -580,9 +595,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.GetFlag( FL_SUBTRACT_MASK_FROM_SILK ) ) @@ -600,10 +614,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 ) @@ -626,6 +640,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() ) @@ -640,6 +658,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 ); } } diff --git a/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp b/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp index 3e81a7ee7c..822376de2d 100644 --- a/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp +++ b/3d-viewer/3d_rendering/opengl/render_3d_opengl.cpp @@ -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 ); } @@ -704,18 +704,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 ); } @@ -751,16 +749,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, @@ -769,6 +761,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, @@ -785,21 +778,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 ); diff --git a/3d-viewer/3d_rendering/opengl/render_3d_opengl.h b/3d-viewer/3d_rendering/opengl/render_3d_opengl.h index 183eebbeef..d5c51abc62 100644 --- a/3d-viewer/3d_rendering/opengl/render_3d_opengl.h +++ b/3d-viewer/3d_rendering/opengl/render_3d_opengl.h @@ -84,6 +84,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 ); diff --git a/pcbnew/footprint.cpp b/pcbnew/footprint.cpp index cfe6e85e43..4433156797 100644 --- a/pcbnew/footprint.cpp +++ b/pcbnew/footprint.cpp @@ -2214,51 +2214,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() == wxPoint( 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; wxSize 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->GetSolderMaskMargin(); diff --git a/pcbnew/pad.cpp b/pcbnew/pad.cpp index 5de9dba81a..8ff264ed49 100644 --- a/pcbnew/pad.cpp +++ b/pcbnew/pad.cpp @@ -216,31 +216,11 @@ bool PAD::FlashLayer( int aLayer ) const std::vector<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( aLayer != UNDEFINED_LAYER && !IsOnLayer( static_cast<PCB_LAYER_ID>( aLayer ) ) ) + return false; - switch( GetAttribute() ) + if( GetAttribute() == PAD_ATTRIB::NPTH && IsCopperLayer( aLayer ) ) { - 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() == wxPoint( 0, 0 ) && GetDrillSize().x >= GetSize().x ) @@ -254,17 +234,32 @@ bool PAD::FlashLayer( int aLayer ) const return false; } } + } - KI_FALLTHROUGH; + if( LSET::FrontBoardTechMask().test( aLayer ) ) + aLayer = F_Cu; + else if( LSET::BackBoardTechMask().test( aLayer ) ) + aLayer = B_Cu; - case PAD_ATTRIB::SMD: - case PAD_ATTRIB::CONN: - default: - if( aLayer == UNDEFINED_LAYER ) + 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; }