mirror of
https://gitlab.com/kicad/code/kicad.git
synced 2025-04-02 18:46:54 +00:00
Handle clipping silk to mask when there is more than one layer.
This commit is contained in:
parent
4959b480c3
commit
b44261c2bd
@ -484,7 +484,7 @@ bool PLOT_CONTROLLER::PlotLayer()
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Fully delegated to the parent
|
// Fully delegated to the parent
|
||||||
PlotOneBoardLayer( m_board, m_plotter, ToLAYER_ID( GetLayer() ), GetPlotOptions() );
|
PlotOneBoardLayer( m_board, m_plotter, ToLAYER_ID( GetLayer() ), GetPlotOptions(), true );
|
||||||
PlotInteractiveLayer( m_board, m_plotter, GetPlotOptions() );
|
PlotInteractiveLayer( m_board, m_plotter, GetPlotOptions() );
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -192,7 +192,7 @@ void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARA
|
|||||||
* @param aPlotOpt is the plot options (files, sketch). Has meaning for some formats only.
|
* @param aPlotOpt is the plot options (files, sketch). Has meaning for some formats only.
|
||||||
*/
|
*/
|
||||||
void PlotOneBoardLayer( BOARD* aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
void PlotOneBoardLayer( BOARD* aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
||||||
const PCB_PLOT_PARAMS& aPlotOpt );
|
const PCB_PLOT_PARAMS& aPlotOpt, bool isPrimaryLayer );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plot copper or technical layers.
|
* Plot copper or technical layers.
|
||||||
|
@ -46,12 +46,84 @@
|
|||||||
#include <gbr_metadata.h>
|
#include <gbr_metadata.h>
|
||||||
#include <advanced_config.h>
|
#include <advanced_config.h>
|
||||||
|
|
||||||
/*
|
|
||||||
* Plot a solder mask layer. Solder mask layers have a minimum thickness value and cannot be
|
void GenerateLayerPoly( SHAPE_POLY_SET* aResult, BOARD *aBoard, PCB_LAYER_ID aLayer,
|
||||||
* drawn like standard layers, unless the minimum thickness is 0.
|
bool aPlotFPText, bool aPlotReferences, bool aPlotValues );
|
||||||
|
|
||||||
|
|
||||||
|
void PlotLayer( BOARD* aBoard, PLOTTER* aPlotter, const LSET& layerMask,
|
||||||
|
const PCB_PLOT_PARAMS& plotOpts )
|
||||||
|
{
|
||||||
|
// PlotLayerOutlines() is designed only for DXF plotters.
|
||||||
|
if( plotOpts.GetFormat() == PLOT_FORMAT::DXF && plotOpts.GetDXFPlotPolygonMode() )
|
||||||
|
PlotLayerOutlines( aBoard, aPlotter, layerMask, plotOpts );
|
||||||
|
else
|
||||||
|
PlotStandardLayer( aBoard, aPlotter, layerMask, plotOpts );
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
void PlotPolySet( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARAMS& aPlotOpt,
|
||||||
|
SHAPE_POLY_SET* aPolySet, PCB_LAYER_ID aLayer )
|
||||||
|
{
|
||||||
|
BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
|
||||||
|
LSET layers = { aLayer };
|
||||||
|
|
||||||
|
itemplotter.SetLayerSet( layers );
|
||||||
|
|
||||||
|
// To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
|
||||||
|
// exactly like filled areas in zones.
|
||||||
|
// Note, also this code is not optimized: it creates a lot of copy/duplicate data.
|
||||||
|
// However it is not complex, and fast enough for plot purposes (copy/convert data is only a
|
||||||
|
// very small calculation time for these calculations).
|
||||||
|
ZONE zone( aBoard );
|
||||||
|
zone.SetMinThickness( 0 );
|
||||||
|
zone.SetLayer( aLayer );
|
||||||
|
|
||||||
|
aPolySet->Fracture();
|
||||||
|
itemplotter.PlotZone( &zone, aLayer, *aPolySet );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Plot a solder mask layer.
|
||||||
|
*
|
||||||
|
* Solder mask layers have a minimum thickness value and cannot be drawn like standard layers,
|
||||||
|
* unless the minimum thickness is 0.
|
||||||
*/
|
*/
|
||||||
static void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
void PlotSolderMaskLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness );
|
const PCB_PLOT_PARAMS& aPlotOpt )
|
||||||
|
{
|
||||||
|
if( aBoard->GetDesignSettings().m_SolderMaskMinWidth == 0 )
|
||||||
|
{
|
||||||
|
PlotLayer( aBoard, aPlotter, aLayerMask, aPlotOpt );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHAPE_POLY_SET solderMask;
|
||||||
|
PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
|
||||||
|
|
||||||
|
GenerateLayerPoly( &solderMask, aBoard, layer, aPlotOpt.GetPlotFPText(),
|
||||||
|
aPlotOpt.GetPlotReference(), aPlotOpt.GetPlotValue() );
|
||||||
|
|
||||||
|
PlotPolySet( aBoard, aPlotter, aPlotOpt, &solderMask, layer );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PlotClippedSilkLayer( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
||||||
|
const PCB_PLOT_PARAMS& aPlotOpt )
|
||||||
|
{
|
||||||
|
SHAPE_POLY_SET silkscreen, solderMask;
|
||||||
|
PCB_LAYER_ID silkLayer = aLayerMask[F_SilkS] ? F_SilkS : B_SilkS;
|
||||||
|
PCB_LAYER_ID maskLayer = aLayerMask[F_SilkS] ? F_Mask : B_Mask;
|
||||||
|
|
||||||
|
GenerateLayerPoly( &silkscreen, aBoard, silkLayer, aPlotOpt.GetPlotFPText(),
|
||||||
|
aPlotOpt.GetPlotReference(), aPlotOpt.GetPlotValue() );
|
||||||
|
GenerateLayerPoly( &solderMask, aBoard, maskLayer, aPlotOpt.GetPlotFPText(),
|
||||||
|
aPlotOpt.GetPlotReference(), aPlotOpt.GetPlotValue() );
|
||||||
|
|
||||||
|
silkscreen.BooleanSubtract( solderMask );
|
||||||
|
PlotPolySet( aBoard, aPlotter, aPlotOpt, &silkscreen, silkLayer );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayers,
|
void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayers,
|
||||||
@ -68,8 +140,7 @@ void PlotBoardLayers( BOARD* aBoard, PLOTTER* aPlotter, const LSEQ& aLayers,
|
|||||||
&& !aPlotOptions.GetLayerSelection().ClearNonCopperLayers().empty() );
|
&& !aPlotOptions.GetLayerSelection().ClearNonCopperLayers().empty() );
|
||||||
|
|
||||||
for( PCB_LAYER_ID layer : aLayers )
|
for( PCB_LAYER_ID layer : aLayers )
|
||||||
PlotOneBoardLayer( aBoard, aPlotter, layer, aPlotOptions );
|
PlotOneBoardLayer( aBoard, aPlotter, layer, aPlotOptions, layer == aLayers[0] );
|
||||||
|
|
||||||
|
|
||||||
if( plot_mark )
|
if( plot_mark )
|
||||||
{
|
{
|
||||||
@ -122,8 +193,7 @@ void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARA
|
|||||||
properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), _( "Library Description" ),
|
properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), _( "Library Description" ),
|
||||||
fp->GetLibDescription() ) );
|
fp->GetLibDescription() ) );
|
||||||
|
|
||||||
properties.emplace_back( wxString::Format( wxT( "!%s = %s" ),
|
properties.emplace_back( wxString::Format( wxT( "!%s = %s" ), _( "Keywords" ),
|
||||||
_( "Keywords" ),
|
|
||||||
fp->GetKeywords() ) );
|
fp->GetKeywords() ) );
|
||||||
#endif
|
#endif
|
||||||
// Draw items are plotted with a position offset. So we need to move
|
// Draw items are plotted with a position offset. So we need to move
|
||||||
@ -147,20 +217,9 @@ void PlotInteractiveLayer( BOARD* aBoard, PLOTTER* aPlotter, const PCB_PLOT_PARA
|
|||||||
|
|
||||||
|
|
||||||
void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
||||||
const PCB_PLOT_PARAMS& aPlotOpt )
|
const PCB_PLOT_PARAMS& aPlotOpt, bool isPrimaryLayer )
|
||||||
{
|
{
|
||||||
auto plotLayer =
|
|
||||||
[&]( LSET layerMask, PCB_PLOT_PARAMS& plotOpts )
|
|
||||||
{
|
|
||||||
// PlotLayerOutlines() is designed only for DXF plotters.
|
|
||||||
if( plotOpts.GetFormat() == PLOT_FORMAT::DXF && plotOpts.GetDXFPlotPolygonMode() )
|
|
||||||
PlotLayerOutlines( aBoard, aPlotter, layerMask, plotOpts );
|
|
||||||
else
|
|
||||||
PlotStandardLayer( aBoard, aPlotter, layerMask, plotOpts );
|
|
||||||
};
|
|
||||||
|
|
||||||
PCB_PLOT_PARAMS plotOpt = aPlotOpt;
|
PCB_PLOT_PARAMS plotOpt = aPlotOpt;
|
||||||
int soldermask_min_thickness = aBoard->GetDesignSettings().m_SolderMaskMinWidth;
|
|
||||||
|
|
||||||
// Set a default color and the text mode for this layer
|
// Set a default color and the text mode for this layer
|
||||||
aPlotter->SetColor( BLACK );
|
aPlotter->SetColor( BLACK );
|
||||||
@ -179,7 +238,7 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
|||||||
else
|
else
|
||||||
plotOpt.SetSkipPlotNPTH_Pads( true );
|
plotOpt.SetSkipPlotNPTH_Pads( true );
|
||||||
|
|
||||||
plotLayer( layer_mask, plotOpt );
|
PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -194,15 +253,7 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
|||||||
plotOpt.SetDXFPlotPolygonMode( true );
|
plotOpt.SetDXFPlotPolygonMode( true );
|
||||||
|
|
||||||
// Plot solder mask:
|
// Plot solder mask:
|
||||||
if( soldermask_min_thickness == 0 )
|
PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
{
|
|
||||||
plotLayer( layer_mask, plotOpt );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt,
|
|
||||||
soldermask_min_thickness );
|
|
||||||
}
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -216,36 +267,45 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
|||||||
// Use outline mode for DXF
|
// Use outline mode for DXF
|
||||||
plotOpt.SetDXFPlotPolygonMode( true );
|
plotOpt.SetDXFPlotPolygonMode( true );
|
||||||
|
|
||||||
plotLayer( layer_mask, plotOpt );
|
PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case F_SilkS:
|
case F_SilkS:
|
||||||
case B_SilkS:
|
case B_SilkS:
|
||||||
plotLayer( layer_mask, plotOpt );
|
if( plotOpt.GetSubtractMaskFromSilk() )
|
||||||
|
|
||||||
// Gerber: Subtract soldermask from silkscreen if enabled
|
|
||||||
if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER
|
|
||||||
&& plotOpt.GetSubtractMaskFromSilk() )
|
|
||||||
{
|
{
|
||||||
if( aLayer == F_SilkS )
|
if( aPlotter->GetPlotterType() == PLOT_FORMAT::GERBER && isPrimaryLayer )
|
||||||
layer_mask = LSET( { F_Mask } );
|
{
|
||||||
|
// Use old-school, positive/negative mask plotting which preserves utilization
|
||||||
|
// of Gerber aperture masks. This method can only be used when the given silk
|
||||||
|
// layer is the primary layer as the negative mask will also knockout any other
|
||||||
|
// (non-silk) layers that were plotted before the silk layer.
|
||||||
|
|
||||||
|
PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
|
|
||||||
|
// Create the mask to subtract by creating a negative layer polarity
|
||||||
|
aPlotter->SetLayerPolarity( false );
|
||||||
|
|
||||||
|
// Disable plot pad holes
|
||||||
|
plotOpt.SetDrillMarksType( DRILL_MARKS::NO_DRILL_SHAPE );
|
||||||
|
|
||||||
|
// Plot the mask
|
||||||
|
layer_mask = ( aLayer == F_SilkS ) ? LSET( { F_Mask } ) : LSET( { B_Mask } );
|
||||||
|
PlotSolderMaskLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
|
|
||||||
|
// Disable the negative polarity
|
||||||
|
aPlotter->SetLayerPolarity( true );
|
||||||
|
}
|
||||||
else
|
else
|
||||||
layer_mask = LSET( { B_Mask } );
|
{
|
||||||
|
PlotClippedSilkLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
|
}
|
||||||
|
|
||||||
// Create the mask to subtract by creating a negative layer polarity
|
break;
|
||||||
aPlotter->SetLayerPolarity( false );
|
|
||||||
|
|
||||||
// Disable plot pad holes
|
|
||||||
plotOpt.SetDrillMarksType( DRILL_MARKS::NO_DRILL_SHAPE );
|
|
||||||
|
|
||||||
// Plot the mask
|
|
||||||
PlotStandardLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
|
||||||
|
|
||||||
// Disable the negative polarity
|
|
||||||
aPlotter->SetLayerPolarity( true );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Dwgs_User:
|
case Dwgs_User:
|
||||||
@ -259,7 +319,7 @@ void PlotOneBoardLayer( BOARD *aBoard, PLOTTER* aPlotter, PCB_LAYER_ID aLayer,
|
|||||||
case F_Fab:
|
case F_Fab:
|
||||||
case B_Fab:
|
case B_Fab:
|
||||||
default:
|
default:
|
||||||
plotLayer( layer_mask, plotOpt );
|
PlotLayer( aBoard, aPlotter, layer_mask, plotOpt );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -858,59 +918,57 @@ void PlotLayerOutlines( BOARD* aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Plot a solder mask layer.
|
* Generates a SHAPE_POLY_SET representing the plotted items on a layer.
|
||||||
*
|
|
||||||
* Solder mask layers have a minimum thickness value and cannot be drawn like standard layers,
|
|
||||||
* unless the minimum thickness is 0.
|
|
||||||
*/
|
*/
|
||||||
|
void GenerateLayerPoly( SHAPE_POLY_SET* aResult, BOARD *aBoard, PCB_LAYER_ID aLayer,
|
||||||
void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
bool aPlotFPText, bool aPlotReferences, bool aPlotValues )
|
||||||
const PCB_PLOT_PARAMS& aPlotOpt, int aMinThickness )
|
|
||||||
{
|
{
|
||||||
|
#define ERROR maxError, ERROR_OUTSIDE
|
||||||
|
|
||||||
int maxError = aBoard->GetDesignSettings().m_MaxError;
|
int maxError = aBoard->GetDesignSettings().m_MaxError;
|
||||||
PCB_LAYER_ID layer = aLayerMask[B_Mask] ? B_Mask : F_Mask;
|
|
||||||
SHAPE_POLY_SET buffer;
|
SHAPE_POLY_SET buffer;
|
||||||
SHAPE_POLY_SET* boardOutline = nullptr;
|
SHAPE_POLY_SET* boardOutline = nullptr;
|
||||||
|
int inflate = 0;
|
||||||
|
|
||||||
if( aBoard->GetBoardPolygonOutlines( buffer ) )
|
if( aBoard->GetBoardPolygonOutlines( buffer ) )
|
||||||
boardOutline = &buffer;
|
boardOutline = &buffer;
|
||||||
|
|
||||||
// We remove 1nm as we expand both sides of the shapes, so allowing for a strictly greater
|
if( aLayer == F_Mask || aLayer == B_Mask )
|
||||||
// than or equal comparison in the shape separation (boolean add)
|
{
|
||||||
int inflate = aMinThickness / 2 - 1;
|
// 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)
|
||||||
BRDITEMS_PLOTTER itemplotter( aPlotter, aBoard, aPlotOpt );
|
inflate = aBoard->GetDesignSettings().m_SolderMaskMinWidth / 2 - 1;
|
||||||
itemplotter.SetLayerSet( aLayerMask );
|
}
|
||||||
|
|
||||||
// Build polygons for each pad shape. The size of the shape on solder mask should be size
|
// 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.
|
// 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
|
// Extra margin is half the min width for solder mask, which is used to merge too-close shapes
|
||||||
// (distance < aMinThickness), and will be removed when creating the actual shapes.
|
// (distance < SolderMaskMinWidth).
|
||||||
|
|
||||||
// Will contain shapes inflated by inflate value that will be merged and deflated by inflate
|
// Will contain exact shapes of all items on solder mask. We add this back in at the end just
|
||||||
// value to build final polygons
|
// to make sure that any artefacts introduced by the inflate/deflate don't remove parts of the
|
||||||
SHAPE_POLY_SET areas;
|
// individual shapes.
|
||||||
|
SHAPE_POLY_SET exactPolys;
|
||||||
// Will contain exact shapes of all items on solder mask
|
|
||||||
SHAPE_POLY_SET initialPolys;
|
|
||||||
|
|
||||||
auto handleFPTextItem =
|
auto handleFPTextItem =
|
||||||
[&]( const PCB_TEXT& aText )
|
[&]( const PCB_TEXT& aText )
|
||||||
{
|
{
|
||||||
if( !itemplotter.GetPlotFPText() )
|
if( !aPlotFPText )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( aText.GetText() == wxT( "${REFERENCE}" ) && !itemplotter.GetPlotReference() )
|
if( !aText.IsVisible() )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if( aText.GetText() == wxT( "${VALUE}" ) && !itemplotter.GetPlotValue() )
|
if( aText.GetText() == wxT( "${REFERENCE}" ) && !aPlotReferences )
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// add shapes with their exact mask layer size in initialPolys
|
if( aText.GetText() == wxT( "${VALUE}" ) && !aPlotValues )
|
||||||
aText.TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
|
return;
|
||||||
|
|
||||||
// add shapes inflated by aMinThickness/2 in areas
|
if( inflate != 0 )
|
||||||
aText.TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
|
aText.TransformTextToPolySet( exactPolys, 0, ERROR );
|
||||||
|
|
||||||
|
aText.TransformTextToPolySet( *aResult, inflate, ERROR );
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate polygons with arcs inside the shape or exact shape to minimize shape changes
|
// Generate polygons with arcs inside the shape or exact shape to minimize shape changes
|
||||||
@ -920,29 +978,26 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||||||
// Plot footprint pads and graphics
|
// Plot footprint pads and graphics
|
||||||
for( const FOOTPRINT* footprint : aBoard->Footprints() )
|
for( const FOOTPRINT* footprint : aBoard->Footprints() )
|
||||||
{
|
{
|
||||||
// add shapes with their exact mask layer size in initialPolys
|
if( inflate != 0 )
|
||||||
footprint->TransformPadsToPolySet( initialPolys, layer, 0, maxError, ERROR_OUTSIDE );
|
footprint->TransformPadsToPolySet( exactPolys, aLayer, 0, ERROR );
|
||||||
// add shapes inflated by aMinThickness/2 in areas
|
|
||||||
footprint->TransformPadsToPolySet( areas, layer, inflate, maxError, ERROR_OUTSIDE );
|
footprint->TransformPadsToPolySet( *aResult, aLayer, inflate, ERROR );
|
||||||
|
|
||||||
for( const PCB_FIELD* field : footprint->GetFields() )
|
for( const PCB_FIELD* field : footprint->GetFields() )
|
||||||
{
|
{
|
||||||
if( field->IsReference() && !itemplotter.GetPlotReference() )
|
if( field->IsReference() && !aPlotReferences )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( field->IsValue() && !itemplotter.GetPlotValue() )
|
if( field->IsValue() && !aPlotValues )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !field->IsVisible() && !itemplotter.GetPlotInvisibleText() )
|
if( field->IsOnLayer( aLayer ) )
|
||||||
continue;
|
|
||||||
|
|
||||||
if( field->IsOnLayer( layer ) )
|
|
||||||
handleFPTextItem( static_cast<const PCB_TEXT&>( *field ) );
|
handleFPTextItem( static_cast<const PCB_TEXT&>( *field ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
for( const BOARD_ITEM* item : footprint->GraphicalItems() )
|
for( const BOARD_ITEM* item : footprint->GraphicalItems() )
|
||||||
{
|
{
|
||||||
if( item->IsOnLayer( layer ) )
|
if( item->IsOnLayer( aLayer ) )
|
||||||
{
|
{
|
||||||
if( item->Type() == PCB_TEXT_T )
|
if( item->Type() == PCB_TEXT_T )
|
||||||
{
|
{
|
||||||
@ -950,13 +1005,10 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// add shapes with their exact mask layer size in initialPolys
|
if( inflate != 0 )
|
||||||
item->TransformShapeToPolygon( initialPolys, layer, 0, maxError,
|
item->TransformShapeToPolygon( exactPolys, aLayer, 0, ERROR );
|
||||||
ERROR_OUTSIDE );
|
|
||||||
|
|
||||||
// add shapes inflated by aMinThickness/2 in areas
|
item->TransformShapeToPolygon( *aResult, aLayer, inflate, ERROR );
|
||||||
item->TransformShapeToPolygon( areas, layer, inflate, maxError,
|
|
||||||
ERROR_OUTSIDE );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -971,90 +1023,67 @@ void PlotSolderMaskLayer( BOARD *aBoard, PLOTTER* aPlotter, LSET aLayerMask,
|
|||||||
const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
|
const PCB_VIA* via = static_cast<const PCB_VIA*>( track );
|
||||||
|
|
||||||
// Note: IsOnLayer() checks relevant mask layers of untented vias
|
// Note: IsOnLayer() checks relevant mask layers of untented vias
|
||||||
if( !via->IsOnLayer( layer ) )
|
if( !via->IsOnLayer( aLayer ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
int clearance = via->GetSolderMaskExpansion();
|
int clearance = via->GetSolderMaskExpansion();
|
||||||
|
|
||||||
// add shapes with their exact mask layer size in initialPolys
|
if( inflate != 0 )
|
||||||
via->TransformShapeToPolygon( initialPolys, layer, clearance, maxError, ERROR_OUTSIDE );
|
via->TransformShapeToPolygon( exactPolys, aLayer, clearance, ERROR );
|
||||||
|
|
||||||
// add shapes inflated by aMinThickness/2 in areas
|
via->TransformShapeToPolygon( *aResult, aLayer, clearance + inflate, ERROR );
|
||||||
clearance += inflate;
|
|
||||||
via->TransformShapeToPolygon( areas, layer, clearance, maxError, ERROR_OUTSIDE );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add filled zone areas.
|
|
||||||
#if 0 // Set to 1 if a solder mask expansion must be applied to zones on solder mask
|
|
||||||
int zone_margin = aBoard->GetDesignSettings().m_SolderMaskExpansion;
|
|
||||||
#else
|
|
||||||
int zone_margin = 0;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for( const BOARD_ITEM* item : aBoard->Drawings() )
|
for( const BOARD_ITEM* item : aBoard->Drawings() )
|
||||||
{
|
{
|
||||||
if( item->IsOnLayer( layer ) )
|
if( item->IsOnLayer( aLayer ) )
|
||||||
{
|
{
|
||||||
if( item->Type() == PCB_TEXT_T )
|
if( item->Type() == PCB_TEXT_T )
|
||||||
{
|
{
|
||||||
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
|
const PCB_TEXT* text = static_cast<const PCB_TEXT*>( item );
|
||||||
|
|
||||||
// add shapes with their exact mask layer size in initialPolys
|
if( inflate != 0 )
|
||||||
text->TransformTextToPolySet( initialPolys, 0, maxError, ERROR_OUTSIDE );
|
text->TransformTextToPolySet( exactPolys, 0, ERROR );
|
||||||
|
|
||||||
// add shapes inflated by aMinThickness/2 in areas
|
text->TransformTextToPolySet( *aResult, inflate, ERROR );
|
||||||
text->TransformTextToPolySet( areas, inflate, maxError, ERROR_OUTSIDE );
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// add shapes with their exact mask layer size in initialPolys
|
if( inflate != 0 )
|
||||||
item->TransformShapeToPolygon( initialPolys, layer, 0, maxError,
|
item->TransformShapeToPolygon( exactPolys, aLayer, 0, ERROR );
|
||||||
ERROR_OUTSIDE );
|
|
||||||
|
|
||||||
// add shapes inflated by aMinThickness/2 in areas
|
item->TransformShapeToPolygon( *aResult, aLayer, inflate, ERROR );
|
||||||
item->TransformShapeToPolygon( areas, layer, inflate, maxError, ERROR_OUTSIDE );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Add filled zone areas.
|
||||||
for( ZONE* zone : aBoard->Zones() )
|
for( ZONE* zone : aBoard->Zones() )
|
||||||
{
|
{
|
||||||
if( zone->GetIsRuleArea() )
|
if( zone->GetIsRuleArea() )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if( !zone->IsOnLayer( layer ) )
|
if( !zone->IsOnLayer( aLayer ) )
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// add shapes inflated by aMinThickness/2 in areas
|
if( inflate != 0 )
|
||||||
zone->TransformSmoothedOutlineToPolygon( areas, inflate + zone_margin, maxError,
|
zone->TransformSmoothedOutlineToPolygon( exactPolys, 0, ERROR, boardOutline );
|
||||||
ERROR_OUTSIDE, boardOutline );
|
|
||||||
|
|
||||||
// add shapes with their exact mask layer size in initialPolys
|
zone->TransformSmoothedOutlineToPolygon( *aResult, inflate, ERROR, boardOutline );
|
||||||
zone->TransformSmoothedOutlineToPolygon( initialPolys, zone_margin, maxError,
|
|
||||||
ERROR_OUTSIDE, boardOutline );
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Merge all polygons: After deflating, not merged (not overlapping) polygons will have the
|
// Merge all polygons
|
||||||
// initial shape (with perhaps small changes due to deflating transform)
|
aResult->Simplify();
|
||||||
areas.Simplify();
|
|
||||||
areas.Deflate( inflate, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
|
|
||||||
|
|
||||||
// To avoid a lot of code, use a ZONE to handle and plot polygons, because our polygons look
|
if( inflate != 0 )
|
||||||
// exactly like filled areas in zones.
|
{
|
||||||
// Note, also this code is not optimized: it creates a lot of copy/duplicate data.
|
aResult->Deflate( inflate, CORNER_STRATEGY::CHAMFER_ALL_CORNERS, maxError );
|
||||||
// However it is not complex, and fast enough for plot purposes (copy/convert data is only a
|
// Add back in the exact polys. This is mandatory because inflate/deflate transform is
|
||||||
// very small calculation time for these calculations).
|
// not perfect, and we want the initial areas perfectly kept.
|
||||||
ZONE zone( aBoard );
|
aResult->BooleanAdd( exactPolys );
|
||||||
zone.SetMinThickness( 0 ); // trace polygons only
|
}
|
||||||
zone.SetLayer( layer );
|
#undef ERROR
|
||||||
|
|
||||||
// Combine the current areas to initial areas. This is mandatory because inflate/deflate
|
|
||||||
// transform is not perfect, and we want the initial areas perfectly kept
|
|
||||||
areas.BooleanAdd( initialPolys );
|
|
||||||
areas.Fracture();
|
|
||||||
|
|
||||||
itemplotter.PlotZone( &zone, layer, areas );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user