Fix solder mask plotting issues.

1) Don't plot all footprint texts for each footprint graphic item.

2) Enforce min web thickness around board shapes and board text.

3) Enforce min web thickness around footprint shapes

4) Correctly handle multi-layer zones.

(1) and (4) will get cherry-picked back to 6.0, so after rebasing
won't actually appear in this changelist anymore....
This commit is contained in:
Jeff Young 2021-08-23 11:25:02 +01:00
parent ef10b36948
commit b2dff6fa55
4 changed files with 87 additions and 80 deletions

View File

@ -153,8 +153,6 @@ void DRC_TEST_PROVIDER_SOLDER_MASK::addItemToRTrees( BOARD_ITEM* item )
}
else
{
// JEY TODO: plotter doesn't currently expand graphics by web thickness...
for( PCB_LAYER_ID layer : { F_Mask, B_Mask } )
{
if( item->IsOnLayer( layer ) )

View File

@ -28,6 +28,7 @@
#include <pcb_plot_params.h>
#include <settings/color_settings.h>
#include <settings/settings_manager.h>
#include <board_item.h>
class PLOTTER;
class PCB_TEXT;
@ -105,6 +106,7 @@ public:
* Plot items like text and graphics but not tracks and footprints.
*/
void PlotBoardGraphicItems();
void PlotPcbGraphicItem( const BOARD_ITEM* item );
/**
* Draw a drill mark for pads and vias.

View File

@ -821,31 +821,16 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
if( aBoard->GetBoardPolygonOutlines( buffer ) )
boardOutline = &buffer;
// We remove 1nm as we expand both sides of the shapes, so allowing for
// a strictly greater than or equal comparison in the shape separation (boolean add)
// means that we will end up with separate shapes that then are shrunk
// We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater
// than or equal comparison in the shape separation (boolean add)
int inflate = aMinThickness/2 - 1;
BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
itemplotter.SetLayerSet( aLayerMask );
// Plot edge layer and graphic items.
// They do not have a solder Mask margin, because they are graphic items
// on this layer (like logos), not actually areas around pads.
itemplotter.PlotBoardGraphicItems();
for( FOOTPRINT* footprint : aBoard->Footprints() )
{
itemplotter.PlotFootprintTextItems( footprint );
for( BOARD_ITEM* item : footprint->GraphicalItems() )
{
if( item->Type() == PCB_FP_SHAPE_T && item->GetLayer() == layer )
itemplotter.PlotFootprintGraphicItem( (FP_SHAPE*) item );
}
}
// Build polygons for each pad shape. The size of the shape on solder mask should be size
// of pad + clearance around the pad, where clearance = solder mask clearance + extra margin.
// Extra margin is half the min width for solder mask, which is used to merge too-close shapes
@ -860,13 +845,13 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
SHAPE_POLY_SET initialPolys;
#if NEW_ALGO
// Generate polygons with arcs inside the shape or exact shape
// to minimize shape changes created by arc to segment size correction.
// Generate polygons with arcs inside the shape or exact shape to minimize shape changes
// created by arc to segment size correction.
DISABLE_ARC_RADIUS_CORRECTION disabler;
#endif
{
// Plot pads
for( FOOTPRINT* footprint : aBoard->Footprints() )
// Plot footprint pads and graphics
for( const FOOTPRINT* footprint : aBoard->Footprints() )
{
// add shapes with their exact mask layer size in initialPolys
footprint->TransformPadsWithClearanceToPolygon( initialPolys, layer, 0, maxError,
@ -874,40 +859,41 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
// add shapes inflated by aMinThickness/2 in areas
footprint->TransformPadsWithClearanceToPolygon( areas, layer, inflate, maxError,
ERROR_OUTSIDE );
for( const BOARD_ITEM* item : footprint->GraphicalItems() )
{
if( item->Type() == PCB_FP_SHAPE_T && item->IsOnLayer( layer ) )
{
// add shapes with their exact mask layer size in initialPolys
item->TransformShapeWithClearanceToPolygon( initialPolys, layer, 0, maxError,
ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas
item->TransformShapeWithClearanceToPolygon( areas, layer, inflate, maxError,
ERROR_OUTSIDE );
}
else if( item->Type() == PCB_FP_SHAPE_T && item->IsOnLayer( Edge_Cuts ) )
{
itemplotter.PlotFootprintGraphicItem( static_cast<const FP_SHAPE*>( item ) );
}
}
}
// Plot vias on solder masks, if aPlotOpt.GetPlotViaOnMaskLayer() is true,
if( aPlotOpt.GetPlotViaOnMaskLayer() )
{
for( PCB_TRACK* track : aBoard->Tracks() )
// Plot (untented) vias
for( const PCB_TRACK* track : aBoard->Tracks() )
{
const PCB_VIA* via = dyn_cast<const PCB_VIA*>( track );
int via_clearance = via->GetSolderMaskExpansion();
int via_margin = via_clearance + inflate;
int clearance = via->GetSolderMaskExpansion();
if( !via )
continue;
// vias are plotted only if they are on the corresponding external copper layer
LSET via_set = via->GetLayerSet();
if( via_set[B_Cu] )
via_set.set( B_Mask );
if( via_set[F_Cu] )
via_set.set( F_Mask );
if( !( via_set & aLayerMask ).any() )
// Note: IsOnLayer() checks relevant mask layers of untented vias
if( !via || !via->IsOnLayer( layer ) )
continue;
// add shapes with their exact mask layer size in initialPolys
via->TransformShapeWithClearanceToPolygon( initialPolys, layer, via_clearance,
maxError, ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas
via->TransformShapeWithClearanceToPolygon( areas, layer, via_margin, maxError,
via->TransformShapeWithClearanceToPolygon( initialPolys, layer, clearance, maxError,
ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas
via->TransformShapeWithClearanceToPolygon( areas, layer, clearance + inflate, maxError,
ERROR_OUTSIDE );
}
}
// Add filled zone areas.
@ -917,6 +903,23 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
int zone_margin = 0;
#endif
for( const BOARD_ITEM* item : aBoard->Drawings() )
{
if( item->IsOnLayer( layer ) )
{
// add shapes with their exact mask layer size in initialPolys
item->TransformShapeWithClearanceToPolygon( initialPolys, layer, 0, maxError,
ERROR_OUTSIDE );
// add shapes inflated by aMinThickness/2 in areas
item->TransformShapeWithClearanceToPolygon( areas, layer, inflate, maxError,
ERROR_OUTSIDE );
}
else if( item->IsOnLayer( Edge_Cuts ) )
{
itemplotter.PlotPcbGraphicItem( item );
}
}
for( ZONE* zone : aBoard->Zones() )
{
if( !zone->IsOnLayer( layer ) )

View File

@ -340,18 +340,16 @@ void BRDITEMS_PLOTTER::PlotFootprintTextItems( const FOOTPRINT* aFootprint )
}
void BRDITEMS_PLOTTER::PlotBoardGraphicItems()
{
for( BOARD_ITEM* item : m_board->Drawings() )
void BRDITEMS_PLOTTER::PlotPcbGraphicItem( const BOARD_ITEM* item )
{
switch( item->Type() )
{
case PCB_SHAPE_T:
PlotPcbShape( (PCB_SHAPE*) item );
PlotPcbShape( static_cast<const PCB_SHAPE*>( item ) );
break;
case PCB_TEXT_T:
PlotPcbText( (PCB_TEXT*) item );
PlotPcbText( static_cast<const PCB_TEXT*>( item ) );
break;
case PCB_DIM_ALIGNED_T:
@ -359,17 +357,23 @@ void BRDITEMS_PLOTTER::PlotBoardGraphicItems()
case PCB_DIM_RADIAL_T:
case PCB_DIM_ORTHOGONAL_T:
case PCB_DIM_LEADER_T:
PlotDimension( (PCB_DIMENSION_BASE*) item );
PlotDimension( static_cast<const PCB_DIMENSION_BASE*>( item ) );
break;
case PCB_TARGET_T:
PlotPcbTarget( (PCB_TARGET*) item );
PlotPcbTarget( static_cast<const PCB_TARGET*>( item ) );
break;
default:
break;
}
}
void BRDITEMS_PLOTTER::PlotBoardGraphicItems()
{
for( const BOARD_ITEM* item : m_board->Drawings() )
PlotPcbGraphicItem( item );
}