2018-09-19 13:06:29 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2009 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
|
2020-08-22 14:40:56 +00:00
|
|
|
* Copyright (C) 1992-2020 KiCad Developers, see AUTHORS.txt for contributors.
|
2018-09-19 13:06:29 +00:00
|
|
|
* Copyright (C) 2018 CERN
|
|
|
|
* Author: Maciej Suminski <maciej.suminski@cern.ch>
|
|
|
|
* Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, you may find one here:
|
|
|
|
* http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
|
|
|
|
* or you may search the http://www.gnu.org website for the version 2 license,
|
|
|
|
* or you may write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "pcbnew_printout.h"
|
|
|
|
#include <class_board.h>
|
2020-01-07 17:12:59 +00:00
|
|
|
#include <math/util.h> // for KiROUND
|
2018-09-19 13:06:29 +00:00
|
|
|
#include <pcb_painter.h>
|
2020-01-13 01:44:19 +00:00
|
|
|
#include <pcbnew_settings.h>
|
2018-09-28 08:10:08 +00:00
|
|
|
#include <view/view.h>
|
2018-10-05 14:41:17 +00:00
|
|
|
#include <pcbplot.h>
|
2018-09-19 13:06:29 +00:00
|
|
|
|
2018-10-05 14:41:17 +00:00
|
|
|
PCBNEW_PRINTOUT_SETTINGS::PCBNEW_PRINTOUT_SETTINGS( const PAGE_INFO& aPageInfo )
|
|
|
|
: BOARD_PRINTOUT_SETTINGS( aPageInfo )
|
|
|
|
{
|
|
|
|
m_drillMarks = SMALL_DRILL_SHAPE;
|
|
|
|
m_pagination = ALL_LAYERS;
|
|
|
|
m_noEdgeLayer = false;
|
2020-08-22 14:40:56 +00:00
|
|
|
m_asItemCheckboxes = false;
|
2018-10-05 14:41:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-13 01:44:19 +00:00
|
|
|
void PCBNEW_PRINTOUT_SETTINGS::Load( APP_SETTINGS_BASE* aConfig )
|
2018-10-05 14:41:17 +00:00
|
|
|
{
|
|
|
|
BOARD_PRINTOUT_SETTINGS::Load( aConfig );
|
2020-01-13 01:44:19 +00:00
|
|
|
|
|
|
|
if( auto cfg = dynamic_cast<PCBNEW_SETTINGS*>( aConfig ) )
|
|
|
|
{
|
|
|
|
m_drillMarks = static_cast<DRILL_MARK_SHAPE_T>( cfg->m_Plot.pads_drill_mode );
|
|
|
|
m_pagination = static_cast<PAGINATION_T>( cfg->m_Plot.one_page_per_layer );
|
2020-10-08 12:26:40 +00:00
|
|
|
m_mirror = cfg->m_Plot.mirror;
|
2020-01-13 01:44:19 +00:00
|
|
|
}
|
2018-10-05 14:41:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-13 01:44:19 +00:00
|
|
|
void PCBNEW_PRINTOUT_SETTINGS::Save( APP_SETTINGS_BASE* aConfig )
|
2018-10-05 14:41:17 +00:00
|
|
|
{
|
|
|
|
BOARD_PRINTOUT_SETTINGS::Save( aConfig );
|
2020-01-13 01:44:19 +00:00
|
|
|
|
|
|
|
if( auto cfg = dynamic_cast<PCBNEW_SETTINGS*>( aConfig ) )
|
|
|
|
{
|
|
|
|
cfg->m_Plot.pads_drill_mode = m_drillMarks;
|
|
|
|
cfg->m_Plot.one_page_per_layer = m_pagination;
|
2020-10-08 12:26:40 +00:00
|
|
|
cfg->m_Plot.mirror = m_mirror;
|
2020-01-13 01:44:19 +00:00
|
|
|
}
|
2018-10-05 14:41:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
PCBNEW_PRINTOUT::PCBNEW_PRINTOUT( BOARD* aBoard, const PCBNEW_PRINTOUT_SETTINGS& aParams,
|
2018-10-06 16:51:46 +00:00
|
|
|
const KIGFX::VIEW* aView, const wxString& aTitle ) :
|
|
|
|
BOARD_PRINTOUT( aParams, aView, aTitle ), m_pcbnewSettings( aParams )
|
2018-09-19 13:06:29 +00:00
|
|
|
{
|
|
|
|
m_board = aBoard;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool PCBNEW_PRINTOUT::OnPrintPage( int aPage )
|
|
|
|
{
|
2020-04-20 16:00:00 +00:00
|
|
|
// Store the layerset, as it is going to be modified below and the original settings are
|
|
|
|
// needed.
|
2020-08-30 21:20:37 +00:00
|
|
|
LSET lset = m_settings.m_layerSet;
|
|
|
|
int pageCount = lset.count();
|
|
|
|
wxString layerName;
|
2018-09-19 13:06:29 +00:00
|
|
|
PCB_LAYER_ID extractLayer;
|
|
|
|
|
|
|
|
// compute layer mask from page number if we want one page per layer
|
2020-04-20 16:00:00 +00:00
|
|
|
if( m_pcbnewSettings.m_pagination == PCBNEW_PRINTOUT_SETTINGS::LAYER_PER_PAGE )
|
2018-09-19 13:06:29 +00:00
|
|
|
{
|
2020-04-20 16:00:00 +00:00
|
|
|
// This sequence is TBD, call a different sequencer if needed, such as Seq().
|
|
|
|
// Could not find documentation on page order.
|
2018-09-19 13:06:29 +00:00
|
|
|
LSEQ seq = lset.UIOrder();
|
|
|
|
|
|
|
|
// aPage starts at 1, not 0
|
|
|
|
if( unsigned( aPage - 1 ) < seq.size() )
|
2018-10-05 14:41:17 +00:00
|
|
|
m_settings.m_layerSet = LSET( seq[aPage - 1] );
|
2018-09-19 13:06:29 +00:00
|
|
|
}
|
|
|
|
|
2018-10-05 14:41:17 +00:00
|
|
|
if( !m_settings.m_layerSet.any() )
|
2018-09-19 13:06:29 +00:00
|
|
|
return false;
|
|
|
|
|
2018-10-05 14:41:17 +00:00
|
|
|
extractLayer = m_settings.m_layerSet.ExtractLayer();
|
2018-09-19 13:06:29 +00:00
|
|
|
|
|
|
|
if( extractLayer == UNDEFINED_LAYER )
|
2020-08-30 21:20:37 +00:00
|
|
|
layerName = _( "Multiple Layers" );
|
2018-09-19 13:06:29 +00:00
|
|
|
else
|
2020-08-30 21:20:37 +00:00
|
|
|
layerName = LSET::Name( extractLayer );
|
2018-09-19 13:06:29 +00:00
|
|
|
|
|
|
|
// In Pcbnew we can want the layer EDGE always printed
|
2018-10-05 14:41:17 +00:00
|
|
|
if( !m_pcbnewSettings.m_noEdgeLayer )
|
|
|
|
m_settings.m_layerSet.set( Edge_Cuts );
|
2018-09-19 13:06:29 +00:00
|
|
|
|
2020-08-30 21:20:37 +00:00
|
|
|
DrawPage( layerName, aPage, pageCount );
|
2018-09-19 13:06:29 +00:00
|
|
|
|
2018-09-28 08:10:08 +00:00
|
|
|
// Restore the original layer set, so the next page can be printed
|
2018-10-05 14:41:17 +00:00
|
|
|
m_settings.m_layerSet = lset;
|
2018-09-19 13:06:29 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-10-06 16:51:46 +00:00
|
|
|
int PCBNEW_PRINTOUT::milsToIU( double aMils ) const
|
|
|
|
{
|
|
|
|
return KiROUND( IU_PER_MILS * aMils );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-17 11:56:07 +00:00
|
|
|
void PCBNEW_PRINTOUT::setupViewLayers( KIGFX::VIEW& aView, const LSET& aLayerSet )
|
2018-09-28 08:10:08 +00:00
|
|
|
{
|
|
|
|
BOARD_PRINTOUT::setupViewLayers( aView, aLayerSet );
|
|
|
|
|
2018-10-05 14:41:17 +00:00
|
|
|
for( LSEQ layerSeq = m_settings.m_layerSet.Seq(); layerSeq; ++layerSeq )
|
2020-08-30 21:20:37 +00:00
|
|
|
{
|
2020-01-17 11:56:07 +00:00
|
|
|
aView.SetLayerVisible( PCBNEW_LAYER_ID_START + *layerSeq, true );
|
2018-09-28 08:10:08 +00:00
|
|
|
|
2020-08-30 21:20:37 +00:00
|
|
|
// Enable the corresponding zone layer
|
|
|
|
if( IsCopperLayer( *layerSeq ) )
|
|
|
|
aView.SetLayerVisible( LAYER_ZONE_START + *layerSeq, true );
|
|
|
|
}
|
|
|
|
|
2020-08-11 19:41:01 +00:00
|
|
|
if( m_pcbnewSettings.m_asItemCheckboxes )
|
|
|
|
{
|
2020-10-19 22:14:46 +00:00
|
|
|
auto setVisibility =
|
|
|
|
[&]( GAL_LAYER_ID aLayer )
|
|
|
|
{
|
|
|
|
if( m_board->IsElementVisible( aLayer ) )
|
|
|
|
aView.SetLayerVisible( aLayer );
|
|
|
|
};
|
2020-08-11 19:41:01 +00:00
|
|
|
|
|
|
|
setVisibility( LAYER_MOD_FR );
|
|
|
|
setVisibility( LAYER_MOD_BK );
|
|
|
|
setVisibility( LAYER_MOD_VALUES );
|
|
|
|
setVisibility( LAYER_MOD_REFERENCES );
|
|
|
|
setVisibility( LAYER_MOD_TEXT_FR );
|
|
|
|
setVisibility( LAYER_MOD_TEXT_BK );
|
|
|
|
setVisibility( LAYER_MOD_TEXT_INVISIBLE );
|
|
|
|
setVisibility( LAYER_PAD_FR );
|
|
|
|
setVisibility( LAYER_PAD_BK );
|
|
|
|
setVisibility( LAYER_PADS_TH );
|
|
|
|
|
|
|
|
setVisibility( LAYER_TRACKS );
|
2020-08-24 12:59:58 +00:00
|
|
|
setVisibility( LAYER_VIAS );
|
2020-08-11 19:41:01 +00:00
|
|
|
|
|
|
|
setVisibility( LAYER_NO_CONNECTS );
|
|
|
|
setVisibility( LAYER_DRC_WARNING );
|
|
|
|
setVisibility( LAYER_DRC_ERROR );
|
|
|
|
setVisibility( LAYER_DRC_EXCLUSION );
|
|
|
|
setVisibility( LAYER_ANCHOR );
|
|
|
|
setVisibility( LAYER_WORKSHEET );
|
|
|
|
setVisibility( LAYER_GRID );
|
2020-08-30 21:20:37 +00:00
|
|
|
|
|
|
|
// Keep certain items always enabled and just rely on either the finer or coarser
|
|
|
|
// visibility controls
|
2020-10-19 22:14:46 +00:00
|
|
|
const int alwaysEnabled[] =
|
|
|
|
{
|
|
|
|
LAYER_ZONES, LAYER_PADS, LAYER_VIA_MICROVIA, LAYER_VIA_BBLIND,
|
|
|
|
LAYER_VIA_THROUGH
|
|
|
|
};
|
2020-08-30 21:20:37 +00:00
|
|
|
|
|
|
|
for( int item : alwaysEnabled )
|
|
|
|
aView.SetLayerVisible( item, true );
|
2020-08-11 19:41:01 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Enable pad layers corresponding to the selected copper layers
|
|
|
|
if( aLayerSet.test( F_Cu ) )
|
|
|
|
aView.SetLayerVisible( LAYER_PAD_FR, true );
|
2018-09-28 08:10:08 +00:00
|
|
|
|
2020-08-11 19:41:01 +00:00
|
|
|
if( aLayerSet.test( B_Cu ) )
|
|
|
|
aView.SetLayerVisible( LAYER_PAD_BK, true );
|
2018-09-28 08:10:08 +00:00
|
|
|
|
2020-08-11 19:41:01 +00:00
|
|
|
if( ( aLayerSet & LSET::AllCuMask() ).any() ) // Items visible on any copper layer
|
2018-09-28 21:45:48 +00:00
|
|
|
{
|
2020-08-11 19:41:01 +00:00
|
|
|
// Enable items on copper layers, but do not draw holes
|
2020-10-19 22:14:46 +00:00
|
|
|
for( GAL_LAYER_ID item : { LAYER_PADS_TH, LAYER_VIA_THROUGH } )
|
2020-08-11 19:41:01 +00:00
|
|
|
{
|
|
|
|
aView.SetLayerVisible( item, true );
|
|
|
|
}
|
2018-09-28 21:45:48 +00:00
|
|
|
}
|
2018-09-28 08:10:08 +00:00
|
|
|
|
2020-08-11 19:41:01 +00:00
|
|
|
// Keep certain items always enabled/disabled and just rely on the layer visibility
|
2020-10-19 22:14:46 +00:00
|
|
|
const int alwaysEnabled[] =
|
|
|
|
{
|
|
|
|
LAYER_MOD_TEXT_FR, LAYER_MOD_TEXT_BK, LAYER_MOD_FR, LAYER_MOD_BK,
|
|
|
|
LAYER_MOD_VALUES, LAYER_MOD_REFERENCES, LAYER_TRACKS, LAYER_ZONES, LAYER_PADS,
|
|
|
|
LAYER_VIAS, LAYER_VIA_MICROVIA, LAYER_VIA_BBLIND
|
|
|
|
};
|
2018-09-28 08:10:08 +00:00
|
|
|
|
2020-08-11 19:41:01 +00:00
|
|
|
for( int item : alwaysEnabled )
|
|
|
|
aView.SetLayerVisible( item, true );
|
|
|
|
}
|
2020-10-19 22:14:46 +00:00
|
|
|
|
|
|
|
if( m_pcbnewSettings.m_drillMarks != PCBNEW_PRINTOUT_SETTINGS::NO_DRILL_SHAPE )
|
|
|
|
{
|
|
|
|
// Enable hole layers to draw drill marks
|
|
|
|
for( GAL_LAYER_ID holeLayer : { LAYER_PADS_PLATEDHOLES, LAYER_NON_PLATEDHOLES,
|
|
|
|
LAYER_VIAS_HOLES } )
|
|
|
|
{
|
|
|
|
aView.SetLayerVisible( holeLayer, true );
|
|
|
|
aView.SetTopLayer( holeLayer, true );
|
|
|
|
}
|
|
|
|
}
|
2018-09-28 08:10:08 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-01-17 11:56:07 +00:00
|
|
|
void PCBNEW_PRINTOUT::setupPainter( KIGFX::PAINTER& aPainter )
|
2018-09-28 21:45:48 +00:00
|
|
|
{
|
|
|
|
BOARD_PRINTOUT::setupPainter( aPainter );
|
|
|
|
|
2020-01-17 11:56:07 +00:00
|
|
|
KIGFX::PCB_PRINT_PAINTER& painter = dynamic_cast<KIGFX::PCB_PRINT_PAINTER&>( aPainter );
|
2018-09-28 21:45:48 +00:00
|
|
|
|
2018-10-05 14:41:17 +00:00
|
|
|
switch( m_pcbnewSettings.m_drillMarks )
|
2018-09-28 21:45:48 +00:00
|
|
|
{
|
2020-10-19 22:14:46 +00:00
|
|
|
case PCBNEW_PRINTOUT_SETTINGS::NO_DRILL_SHAPE:
|
|
|
|
painter.SetDrillMarks( false, 0 );
|
|
|
|
break;
|
2018-09-28 21:45:48 +00:00
|
|
|
|
2020-10-19 22:14:46 +00:00
|
|
|
case PCBNEW_PRINTOUT_SETTINGS::SMALL_DRILL_SHAPE:
|
|
|
|
painter.SetDrillMarks( false, Millimeter2iu( 0.3 ) );
|
2018-09-28 21:45:48 +00:00
|
|
|
|
2020-10-19 22:14:46 +00:00
|
|
|
painter.GetSettings()->SetLayerColor( LAYER_PADS_PLATEDHOLES, COLOR4D::BLACK );
|
|
|
|
painter.GetSettings()->SetLayerColor( LAYER_NON_PLATEDHOLES, COLOR4D::BLACK );
|
|
|
|
painter.GetSettings()->SetLayerColor( LAYER_VIAS_HOLES, COLOR4D::BLACK );
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PCBNEW_PRINTOUT_SETTINGS::FULL_DRILL_SHAPE:
|
|
|
|
painter.SetDrillMarks( true );
|
|
|
|
|
|
|
|
painter.GetSettings()->SetLayerColor( LAYER_PADS_PLATEDHOLES, COLOR4D::BLACK );
|
|
|
|
painter.GetSettings()->SetLayerColor( LAYER_NON_PLATEDHOLES, COLOR4D::BLACK );
|
|
|
|
painter.GetSettings()->SetLayerColor( LAYER_VIAS_HOLES, COLOR4D::BLACK );
|
|
|
|
break;
|
2018-09-28 21:45:48 +00:00
|
|
|
}
|
|
|
|
|
2020-01-17 11:56:07 +00:00
|
|
|
painter.GetSettings()->SetDrawIndividualViaLayers(
|
2020-04-20 16:00:00 +00:00
|
|
|
m_pcbnewSettings.m_pagination == PCBNEW_PRINTOUT_SETTINGS::LAYER_PER_PAGE );
|
2018-09-28 21:45:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-29 10:13:06 +00:00
|
|
|
void PCBNEW_PRINTOUT::setupGal( KIGFX::GAL* aGal )
|
|
|
|
{
|
2018-10-05 14:41:17 +00:00
|
|
|
BOARD_PRINTOUT::setupGal( aGal );
|
2018-09-29 10:13:06 +00:00
|
|
|
aGal->SetWorldUnitLength( 1e-9 /* 1 nm */ / 0.0254 /* 1 inch in meters */ );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-19 13:06:29 +00:00
|
|
|
EDA_RECT PCBNEW_PRINTOUT::getBoundingBox()
|
|
|
|
{
|
|
|
|
return m_board->ComputeBoundingBox();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<KIGFX::PAINTER> PCBNEW_PRINTOUT::getPainter( KIGFX::GAL* aGal )
|
|
|
|
{
|
2018-09-28 21:45:48 +00:00
|
|
|
return std::unique_ptr<KIGFX::PAINTER>( new KIGFX::PCB_PRINT_PAINTER( aGal ) );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-10-08 13:50:59 +00:00
|
|
|
KIGFX::PCB_PRINT_PAINTER::PCB_PRINT_PAINTER( GAL* aGal )
|
|
|
|
: PCB_PAINTER( aGal ), m_drillMarkReal( false ), m_drillMarkSize( 0 )
|
|
|
|
{
|
|
|
|
m_pcbSettings.EnableZoneOutlines( false );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-09-28 21:45:48 +00:00
|
|
|
int KIGFX::PCB_PRINT_PAINTER::getDrillShape( const D_PAD* aPad ) const
|
|
|
|
{
|
|
|
|
return m_drillMarkReal ? KIGFX::PCB_PAINTER::getDrillShape( aPad ) : PAD_DRILL_SHAPE_CIRCLE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
VECTOR2D KIGFX::PCB_PRINT_PAINTER::getDrillSize( const D_PAD* aPad ) const
|
|
|
|
{
|
|
|
|
// TODO should it depend on the pad size?
|
|
|
|
return m_drillMarkReal ? KIGFX::PCB_PAINTER::getDrillSize( aPad ) :
|
|
|
|
VECTOR2D( m_drillMarkSize, m_drillMarkSize );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int KIGFX::PCB_PRINT_PAINTER::getDrillSize( const VIA* aVia ) const
|
|
|
|
{
|
|
|
|
// TODO should it depend on the via size?
|
|
|
|
return m_drillMarkReal ? KIGFX::PCB_PAINTER::getDrillSize( aVia ) : m_drillMarkSize;
|
2018-09-19 13:06:29 +00:00
|
|
|
}
|