You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							326 lines
						
					
					
						
							11 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							326 lines
						
					
					
						
							11 KiB
						
					
					
				| /* | |
|  * 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 | |
|  * Copyright (C) 1992-2023 KiCad Developers, see AUTHORS.txt for contributors. | |
|  * 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 <board.h> | |
| #include <math/util.h>      // for KiROUND | |
| #include <gal/graphics_abstraction_layer.h> | |
| #include <pcb_painter.h> | |
| #include <pcbnew_settings.h> | |
| #include <view/view.h> | |
| #include <pcbplot.h> | |
| #include <geometry/shape_segment.h> | |
| #include <pad.h> | |
|  | |
| #include <advanced_config.h> | |
|  | |
| PCBNEW_PRINTOUT_SETTINGS::PCBNEW_PRINTOUT_SETTINGS( const PAGE_INFO& aPageInfo ) : | |
|         BOARD_PRINTOUT_SETTINGS( aPageInfo ) | |
| { | |
|     m_DrillMarks = DRILL_MARKS::SMALL_DRILL_SHAPE; | |
|     m_Pagination = ALL_LAYERS; | |
|     m_PrintEdgeCutsOnAllPages = true; | |
|     m_AsItemCheckboxes = false; | |
| } | |
| 
 | |
| 
 | |
| void PCBNEW_PRINTOUT_SETTINGS::Load( APP_SETTINGS_BASE* aConfig ) | |
| { | |
|     BOARD_PRINTOUT_SETTINGS::Load( aConfig ); | |
| 
 | |
|     if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( aConfig ) ) | |
|     { | |
|         m_DrillMarks = static_cast<DRILL_MARKS>( cfg->m_Plot.pads_drill_mode ); | |
|         m_Pagination = static_cast<PAGINATION_T>( cfg->m_Plot.all_layers_on_one_page ); | |
|         m_PrintEdgeCutsOnAllPages = cfg->m_Plot.edgecut_on_all_layers; | |
|         m_Mirror                  = cfg->m_Plot.mirror; | |
|         m_AsItemCheckboxes        = cfg->m_Plot.as_item_checkboxes; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void PCBNEW_PRINTOUT_SETTINGS::Save( APP_SETTINGS_BASE* aConfig ) | |
| { | |
|     BOARD_PRINTOUT_SETTINGS::Save( aConfig ); | |
| 
 | |
|     if( PCBNEW_SETTINGS* cfg = dynamic_cast<PCBNEW_SETTINGS*>( aConfig ) ) | |
|     { | |
|         cfg->m_Plot.pads_drill_mode        = (int)m_DrillMarks; | |
|         cfg->m_Plot.all_layers_on_one_page = m_Pagination; | |
|         cfg->m_Plot.edgecut_on_all_layers  = m_PrintEdgeCutsOnAllPages; | |
|         cfg->m_Plot.mirror                 = m_Mirror; | |
|         cfg->m_Plot.as_item_checkboxes     = m_AsItemCheckboxes; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| PCBNEW_PRINTOUT::PCBNEW_PRINTOUT( BOARD* aBoard, const PCBNEW_PRINTOUT_SETTINGS& aParams, | |
|                                   const KIGFX::VIEW* aView, const wxString& aTitle ) : | |
|         BOARD_PRINTOUT( aParams, aView, aTitle ), m_pcbnewSettings( aParams ) | |
| { | |
|     m_board = aBoard; | |
| } | |
| 
 | |
| 
 | |
| bool PCBNEW_PRINTOUT::OnPrintPage( int aPage ) | |
| { | |
|     // Store the layerset, as it is going to be modified below and the original settings are | |
|     // needed. | |
|     LSET         lset = m_settings.m_LayerSet; | |
|     int          pageCount = lset.count(); | |
|     wxString     layerName; | |
|     PCB_LAYER_ID extractLayer; | |
| 
 | |
|     // compute layer mask from page number if we want one page per layer | |
|     if( m_pcbnewSettings.m_Pagination == PCBNEW_PRINTOUT_SETTINGS::LAYER_PER_PAGE ) | |
|     { | |
|         // This sequence is TBD, call a different sequencer if needed, such as Seq(). | |
|         // Could not find documentation on page order. | |
|         LSEQ seq = lset.UIOrder(); | |
| 
 | |
|         // aPage starts at 1, not 0 | |
|         if( unsigned( aPage - 1 ) < seq.size() ) | |
|             m_settings.m_LayerSet = LSET( seq[ aPage - 1] ); | |
|     } | |
| 
 | |
|     if( !m_settings.m_LayerSet.any() ) | |
|         return false; | |
| 
 | |
|     extractLayer = m_settings.m_LayerSet.ExtractLayer(); | |
| 
 | |
|     if( extractLayer == UNDEFINED_LAYER ) | |
|         layerName = _( "Multiple Layers" ); | |
|     else | |
|         layerName = m_board->GetLayerName( extractLayer ); | |
| 
 | |
|     // In Pcbnew we can want the layer EDGE always printed | |
|     if( m_pcbnewSettings.m_PrintEdgeCutsOnAllPages ) | |
|         m_settings.m_LayerSet.set( Edge_Cuts ); | |
| 
 | |
|     DrawPage( layerName, aPage, pageCount ); | |
| 
 | |
|     // Restore the original layer set, so the next page can be printed | |
|     m_settings.m_LayerSet = lset; | |
| 
 | |
|     return true; | |
| } | |
| 
 | |
| 
 | |
| int PCBNEW_PRINTOUT::milsToIU( double aMils ) const | |
| { | |
|     return KiROUND( pcbIUScale.IU_PER_MILS * aMils ); | |
| } | |
| 
 | |
| 
 | |
| void PCBNEW_PRINTOUT::setupViewLayers( KIGFX::VIEW& aView, const LSET& aLayerSet ) | |
| { | |
|     BOARD_PRINTOUT::setupViewLayers( aView, aLayerSet ); | |
| 
 | |
|     for( PCB_LAYER_ID layer : m_settings.m_LayerSet.Seq() ) | |
|     { | |
|         aView.SetLayerVisible( PCBNEW_LAYER_ID_START + layer, true ); | |
| 
 | |
|         // Enable the corresponding zone layer (copper layers and other layers) | |
|         aView.SetLayerVisible( LAYER_ZONE_START + layer, true ); | |
|     } | |
| 
 | |
|     RENDER_SETTINGS* renderSettings = aView.GetPainter()->GetSettings(); | |
|     // A color to do not print objects on some layers, when the layer must be enabled | |
|     // to print some other objects | |
|     COLOR4D invisible_color = COLOR4D::UNSPECIFIED; | |
| 
 | |
|     if( m_pcbnewSettings.m_AsItemCheckboxes ) | |
|     { | |
|         auto setVisibility = | |
|                 [&]( GAL_LAYER_ID aLayer ) | |
|                 { | |
|                     if( m_board->IsElementVisible( aLayer ) ) | |
|                         aView.SetLayerVisible( aLayer, true ); | |
|                     else | |
|                         renderSettings->SetLayerColor( aLayer, invisible_color ); | |
|                 }; | |
| 
 | |
|         setVisibility( LAYER_FOOTPRINTS_FR ); | |
|         setVisibility( LAYER_FOOTPRINTS_BK ); | |
|         setVisibility( LAYER_FP_VALUES ); | |
|         setVisibility( LAYER_FP_REFERENCES ); | |
|         setVisibility( LAYER_FP_TEXT ); | |
|         setVisibility( LAYER_HIDDEN_TEXT ); | |
|         setVisibility( LAYER_PADS ); | |
|         setVisibility( LAYER_PADS_SMD_FR ); | |
|         setVisibility( LAYER_PADS_SMD_BK ); | |
|         setVisibility( LAYER_PADS_TH ); | |
| 
 | |
|         setVisibility( LAYER_TRACKS ); | |
|         setVisibility( LAYER_VIAS ); | |
|         setVisibility( LAYER_VIA_MICROVIA ); | |
|         setVisibility( LAYER_VIA_BBLIND ); | |
|         setVisibility( LAYER_VIA_THROUGH ); | |
|         setVisibility( LAYER_ZONES ); | |
| 
 | |
|         setVisibility( LAYER_DRC_WARNING ); | |
|         setVisibility( LAYER_DRC_ERROR ); | |
|         setVisibility( LAYER_DRC_EXCLUSION ); | |
|         setVisibility( LAYER_ANCHOR ); | |
|         setVisibility( LAYER_DRAWINGSHEET ); | |
|         setVisibility( LAYER_GRID ); | |
|     } | |
|     else | |
|     { | |
|         // Draw layers that must be not visible on printing are set to an invisible layer | |
|         // LAYER_PADS_SMD_FR, LAYER_PADS_SMD_BK and LAYER_PADS_TH must be enabled to print pads on | |
|         // technical layers, but not the pad on copper layer(s) if they are not enabled | |
|  | |
|         if( !aLayerSet.test( F_Cu ) ) | |
|             renderSettings->SetLayerColor( LAYER_PADS_SMD_FR, invisible_color ); | |
| 
 | |
|         if( !aLayerSet.test( B_Cu ) ) | |
|             renderSettings->SetLayerColor( LAYER_PADS_SMD_BK, invisible_color ); | |
| 
 | |
|         // Enable items on copper layers, but do not draw holes | |
|         for( GAL_LAYER_ID layer : { LAYER_PADS_TH, LAYER_VIA_THROUGH, LAYER_VIA_MICROVIA, LAYER_VIA_BBLIND } ) | |
|         { | |
|             if( ( aLayerSet & LSET::AllCuMask() ).any() )   // Items visible on any copper layer | |
|                 aView.SetLayerVisible( layer, true ); | |
|             else | |
|                 renderSettings->SetLayerColor( layer, invisible_color ); | |
|         } | |
| 
 | |
|         // Keep certain items always enabled/disabled and just rely on the layer visibility | |
|         // Note LAYER_PADS_SMD_FR, LAYER_PADS_SMD_BK, LAYER_PADS_TH are enabled here because paths must | |
|         // be drawn on some other (technical) layers. | |
|         const int alwaysEnabled[] = | |
|                 { | |
|                     LAYER_FP_TEXT, LAYER_FP_VALUES, LAYER_FP_REFERENCES, | |
|                     LAYER_FOOTPRINTS_FR, LAYER_FOOTPRINTS_BK, | |
|                     LAYER_TRACKS, LAYER_VIAS, | |
|                     LAYER_ZONES, | |
|                     LAYER_PADS, LAYER_PADS_SMD_FR, LAYER_PADS_SMD_BK, LAYER_PADS_TH | |
|                 }; | |
| 
 | |
|         for( int layer : alwaysEnabled ) | |
|             aView.SetLayerVisible( layer, true ); | |
|     } | |
| 
 | |
|     if( m_pcbnewSettings.m_DrillMarks != DRILL_MARKS::NO_DRILL_SHAPE ) | |
|     { | |
|         // Enable hole layers to draw drill marks | |
|         for( int layer : { LAYER_PAD_PLATEDHOLES, LAYER_NON_PLATEDHOLES, LAYER_VIA_HOLES } ) | |
|         { | |
|             aView.SetLayerVisible( layer, true ); | |
|             aView.SetTopLayer( layer, true ); | |
|         } | |
| 
 | |
|         if( m_pcbnewSettings.m_DrillMarks == DRILL_MARKS::FULL_DRILL_SHAPE | |
|                 && !m_settings.m_blackWhite ) | |
|         { | |
|             for( int layer : { LAYER_PAD_HOLEWALLS, LAYER_VIA_HOLEWALLS } ) | |
|             { | |
|                 aView.SetLayerVisible( layer, true ); | |
|                 aView.SetTopLayer( layer, true ); | |
|             } | |
|         } | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void PCBNEW_PRINTOUT::setupPainter( KIGFX::PAINTER& aPainter ) | |
| { | |
|     BOARD_PRINTOUT::setupPainter( aPainter ); | |
| 
 | |
|     KIGFX::PCB_PRINT_PAINTER& painter = dynamic_cast<KIGFX::PCB_PRINT_PAINTER&>( aPainter ); | |
| 
 | |
|     switch( m_pcbnewSettings.m_DrillMarks ) | |
|     { | |
|     case DRILL_MARKS::NO_DRILL_SHAPE: | |
|         painter.SetDrillMarks( false, 0 ); | |
|         break; | |
| 
 | |
|     case DRILL_MARKS::SMALL_DRILL_SHAPE: | |
|         painter.SetDrillMarks( false, pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize ) ); | |
| 
 | |
|         painter.GetSettings()->SetLayerColor( LAYER_PAD_PLATEDHOLES, COLOR4D::BLACK ); | |
|         painter.GetSettings()->SetLayerColor( LAYER_NON_PLATEDHOLES, COLOR4D::BLACK ); | |
|         painter.GetSettings()->SetLayerColor( LAYER_VIA_HOLES, COLOR4D::BLACK ); | |
|         break; | |
| 
 | |
|     case DRILL_MARKS::FULL_DRILL_SHAPE: | |
|         painter.SetDrillMarks( true ); | |
| 
 | |
|         painter.GetSettings()->SetLayerColor( LAYER_PAD_PLATEDHOLES, COLOR4D::BLACK ); | |
|         painter.GetSettings()->SetLayerColor( LAYER_NON_PLATEDHOLES, COLOR4D::BLACK ); | |
|         painter.GetSettings()->SetLayerColor( LAYER_VIA_HOLES, COLOR4D::BLACK ); | |
|         break; | |
|     } | |
| } | |
| 
 | |
| 
 | |
| void PCBNEW_PRINTOUT::setupGal( KIGFX::GAL* aGal ) | |
| { | |
|     BOARD_PRINTOUT::setupGal( aGal ); | |
|     aGal->SetWorldUnitLength( 0.001/pcbIUScale.IU_PER_MM /* 1 nm */ / 0.0254 /* 1 inch in meters */ ); | |
| } | |
| 
 | |
| 
 | |
| BOX2I PCBNEW_PRINTOUT::getBoundingBox() | |
| { | |
|     return m_board->ComputeBoundingBox(); | |
| } | |
| 
 | |
| 
 | |
| std::unique_ptr<KIGFX::PAINTER> PCBNEW_PRINTOUT::getPainter( KIGFX::GAL* aGal ) | |
| { | |
|     return std::make_unique<KIGFX::PCB_PRINT_PAINTER>( aGal ); | |
| } | |
| 
 | |
| 
 | |
| KIGFX::PCB_PRINT_PAINTER::PCB_PRINT_PAINTER( GAL* aGal ) : | |
|         PCB_PAINTER( aGal, FRAME_PCB_EDITOR ), | |
|         m_drillMarkReal( false ), | |
|         m_drillMarkSize( 0 ) | |
| { } | |
| 
 | |
| 
 | |
| int KIGFX::PCB_PRINT_PAINTER::getDrillShape( const PAD* aPad ) const | |
| { | |
|     return m_drillMarkReal ? KIGFX::PCB_PAINTER::getDrillShape( aPad ) : PAD_DRILL_SHAPE_CIRCLE; | |
| } | |
| 
 | |
| 
 | |
| SHAPE_SEGMENT KIGFX::PCB_PRINT_PAINTER::getPadHoleShape( const PAD* aPad ) const | |
| { | |
|     if( m_drillMarkReal ) | |
|         return KIGFX::PCB_PAINTER::getPadHoleShape( aPad ); | |
|     else | |
|         return SHAPE_SEGMENT( aPad->GetPosition(), aPad->GetPosition(), m_drillMarkSize ); | |
| } | |
| 
 | |
| 
 | |
| int KIGFX::PCB_PRINT_PAINTER::getViaDrillSize( const PCB_VIA* aVia ) const | |
| { | |
|     return m_drillMarkReal ? KIGFX::PCB_PAINTER::getViaDrillSize( aVia ) : m_drillMarkSize; | |
| }
 |