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.

325 lines
11 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 2009 Jean-Pierre Charras, jean-pierre.charras@ujf-grenoble.fr
  5. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  6. * Copyright (C) 2018 CERN
  7. * Author: Maciej Suminski <maciej.suminski@cern.ch>
  8. * Author: Tomasz Wlostowski <tomasz.wlostowski@cern.ch>
  9. *
  10. * This program is free software; you can redistribute it and/or
  11. * modify it under the terms of the GNU General Public License
  12. * as published by the Free Software Foundation; either version 2
  13. * of the License, or (at your option) any later version.
  14. *
  15. * This program is distributed in the hope that it will be useful,
  16. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  18. * GNU General Public License for more details.
  19. *
  20. * You should have received a copy of the GNU General Public License
  21. * along with this program; if not, you may find one here:
  22. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  23. * or you may search the http://www.gnu.org website for the version 2 license,
  24. * or you may write to the Free Software Foundation, Inc.,
  25. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  26. */
  27. #include "pcbnew_printout.h"
  28. #include <board.h>
  29. #include <math/util.h> // for KiROUND
  30. #include <gal/graphics_abstraction_layer.h>
  31. #include <lset.h>
  32. #include <pcb_painter.h>
  33. #include <pcbnew_settings.h>
  34. #include <view/view.h>
  35. #include <pcbplot.h>
  36. #include <geometry/shape_segment.h>
  37. #include <pad.h>
  38. #include <advanced_config.h>
  39. #include <pgm_base.h>
  40. PCBNEW_PRINTOUT_SETTINGS::PCBNEW_PRINTOUT_SETTINGS( const PAGE_INFO& aPageInfo ) :
  41. BOARD_PRINTOUT_SETTINGS( aPageInfo )
  42. {
  43. m_DrillMarks = DRILL_MARKS::SMALL_DRILL_SHAPE;
  44. m_Pagination = ALL_LAYERS;
  45. m_PrintEdgeCutsOnAllPages = true;
  46. m_AsItemCheckboxes = false;
  47. }
  48. void PCBNEW_PRINTOUT_SETTINGS::Load( APP_SETTINGS_BASE* aConfig )
  49. {
  50. BOARD_PRINTOUT_SETTINGS::Load( aConfig );
  51. SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
  52. PCBNEW_SETTINGS* cfg = mgr.GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
  53. if( cfg )
  54. {
  55. m_DrillMarks = static_cast<DRILL_MARKS>( cfg->m_Plot.pads_drill_mode );
  56. m_Pagination = static_cast<PAGINATION_T>( cfg->m_Plot.all_layers_on_one_page );
  57. m_PrintEdgeCutsOnAllPages = cfg->m_Plot.edgecut_on_all_layers;
  58. m_Mirror = cfg->m_Plot.mirror;
  59. m_AsItemCheckboxes = cfg->m_Plot.as_item_checkboxes;
  60. }
  61. }
  62. void PCBNEW_PRINTOUT_SETTINGS::Save( APP_SETTINGS_BASE* aConfig )
  63. {
  64. BOARD_PRINTOUT_SETTINGS::Save( aConfig );
  65. SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager();
  66. PCBNEW_SETTINGS* cfg = mgr.GetAppSettings<PCBNEW_SETTINGS>( "pcbnew" );
  67. if( cfg )
  68. {
  69. cfg->m_Plot.pads_drill_mode = (int)m_DrillMarks;
  70. cfg->m_Plot.all_layers_on_one_page = m_Pagination;
  71. cfg->m_Plot.edgecut_on_all_layers = m_PrintEdgeCutsOnAllPages;
  72. cfg->m_Plot.mirror = m_Mirror;
  73. cfg->m_Plot.as_item_checkboxes = m_AsItemCheckboxes;
  74. }
  75. }
  76. PCBNEW_PRINTOUT::PCBNEW_PRINTOUT( BOARD* aBoard, const PCBNEW_PRINTOUT_SETTINGS& aParams,
  77. const KIGFX::VIEW* aView, const wxString& aTitle ) :
  78. BOARD_PRINTOUT( aParams, aView, aTitle ), m_pcbnewSettings( aParams )
  79. {
  80. m_board = aBoard;
  81. }
  82. bool PCBNEW_PRINTOUT::OnPrintPage( int aPage )
  83. {
  84. // Store the layerset, as it is going to be modified below and the original settings are
  85. // needed.
  86. LSET lset = m_settings.m_LayerSet;
  87. int pageCount = lset.count();
  88. wxString layerName;
  89. PCB_LAYER_ID extractLayer;
  90. // compute layer mask from page number if we want one page per layer
  91. if( m_pcbnewSettings.m_Pagination == PCBNEW_PRINTOUT_SETTINGS::LAYER_PER_PAGE )
  92. {
  93. // This sequence is TBD, call a different sequencer if needed, such as Seq().
  94. // Could not find documentation on page order.
  95. LSEQ seq = lset.UIOrder();
  96. // aPage starts at 1, not 0
  97. if( unsigned( aPage - 1 ) < seq.size() )
  98. m_settings.m_LayerSet = LSET( { seq[aPage - 1] } );
  99. }
  100. if( !m_settings.m_LayerSet.any() )
  101. return false;
  102. extractLayer = m_settings.m_LayerSet.ExtractLayer();
  103. if( extractLayer == UNDEFINED_LAYER )
  104. layerName = _( "Multiple Layers" );
  105. else
  106. layerName = m_board->GetLayerName( extractLayer );
  107. // In Pcbnew we can want the layer EDGE always printed
  108. if( m_pcbnewSettings.m_PrintEdgeCutsOnAllPages )
  109. m_settings.m_LayerSet.set( Edge_Cuts );
  110. DrawPage( layerName, aPage, pageCount );
  111. // Restore the original layer set, so the next page can be printed
  112. m_settings.m_LayerSet = lset;
  113. return true;
  114. }
  115. int PCBNEW_PRINTOUT::milsToIU( double aMils ) const
  116. {
  117. return KiROUND( pcbIUScale.IU_PER_MILS * aMils );
  118. }
  119. void PCBNEW_PRINTOUT::setupViewLayers( KIGFX::VIEW& aView, const LSET& aLayerSet )
  120. {
  121. BOARD_PRINTOUT::setupViewLayers( aView, aLayerSet );
  122. for( PCB_LAYER_ID layer : m_settings.m_LayerSet.Seq() )
  123. {
  124. aView.SetLayerVisible( PCBNEW_LAYER_ID_START + layer, true );
  125. // Enable the corresponding zone layer (copper layers and other layers)
  126. aView.SetLayerVisible( LAYER_ZONE_START + layer, true );
  127. aView.SetLayerVisible( LAYER_PAD_COPPER_START + layer, true );
  128. aView.SetLayerVisible( LAYER_VIA_COPPER_START + layer, true );
  129. }
  130. RENDER_SETTINGS* renderSettings = aView.GetPainter()->GetSettings();
  131. // A color to do not print objects on some layers, when the layer must be enabled
  132. // to print some other objects
  133. COLOR4D invisible_color = COLOR4D::UNSPECIFIED;
  134. if( m_pcbnewSettings.m_AsItemCheckboxes )
  135. {
  136. auto setVisibility =
  137. [&]( GAL_LAYER_ID aLayer )
  138. {
  139. if( m_board->IsElementVisible( aLayer ) )
  140. aView.SetLayerVisible( aLayer, true );
  141. else
  142. renderSettings->SetLayerColor( aLayer, invisible_color );
  143. };
  144. setVisibility( LAYER_FOOTPRINTS_FR );
  145. setVisibility( LAYER_FOOTPRINTS_BK );
  146. setVisibility( LAYER_FP_VALUES );
  147. setVisibility( LAYER_FP_REFERENCES );
  148. setVisibility( LAYER_FP_TEXT );
  149. setVisibility( LAYER_PADS );
  150. setVisibility( LAYER_TRACKS );
  151. setVisibility( LAYER_VIAS );
  152. setVisibility( LAYER_VIA_MICROVIA );
  153. setVisibility( LAYER_VIA_BBLIND );
  154. setVisibility( LAYER_VIA_THROUGH );
  155. setVisibility( LAYER_ZONES );
  156. setVisibility( LAYER_SHAPES );
  157. setVisibility( LAYER_DRC_WARNING );
  158. setVisibility( LAYER_DRC_ERROR );
  159. setVisibility( LAYER_DRC_SHAPE1 );
  160. setVisibility( LAYER_DRC_SHAPE2 );
  161. setVisibility( LAYER_DRC_EXCLUSION );
  162. setVisibility( LAYER_ANCHOR );
  163. setVisibility( LAYER_DRAWINGSHEET );
  164. setVisibility( LAYER_GRID );
  165. }
  166. else
  167. {
  168. // Enable items on copper layers, but do not draw holes
  169. for( GAL_LAYER_ID layer : { LAYER_VIA_THROUGH, LAYER_VIA_MICROVIA, LAYER_VIA_BBLIND } )
  170. {
  171. if( ( aLayerSet & LSET::AllCuMask() ).any() ) // Items visible on any copper layer
  172. aView.SetLayerVisible( layer, true );
  173. else
  174. renderSettings->SetLayerColor( layer, invisible_color );
  175. }
  176. // Keep certain items always enabled/disabled and just rely on the layer visibility
  177. // Note LAYER_PADS_SMD_FR, LAYER_PADS_SMD_BK, LAYER_PADS_TH are enabled here because paths must
  178. // be drawn on some other (technical) layers.
  179. const int alwaysEnabled[] =
  180. {
  181. LAYER_FP_TEXT, LAYER_FP_VALUES, LAYER_FP_REFERENCES,
  182. LAYER_FOOTPRINTS_FR, LAYER_FOOTPRINTS_BK,
  183. LAYER_TRACKS, LAYER_VIAS,
  184. LAYER_ZONES, LAYER_SHAPES,
  185. LAYER_PADS
  186. };
  187. for( int layer : alwaysEnabled )
  188. aView.SetLayerVisible( layer, true );
  189. }
  190. if( m_pcbnewSettings.m_DrillMarks != DRILL_MARKS::NO_DRILL_SHAPE )
  191. {
  192. // Enable hole layers to draw drill marks
  193. for( int layer : { LAYER_PAD_PLATEDHOLES, LAYER_NON_PLATEDHOLES, LAYER_VIA_HOLES } )
  194. {
  195. aView.SetLayerVisible( layer, true );
  196. aView.SetTopLayer( layer, true );
  197. }
  198. if( m_pcbnewSettings.m_DrillMarks == DRILL_MARKS::FULL_DRILL_SHAPE
  199. && !m_settings.m_blackWhite )
  200. {
  201. for( int layer : { LAYER_PAD_HOLEWALLS, LAYER_VIA_HOLEWALLS } )
  202. {
  203. aView.SetLayerVisible( layer, true );
  204. aView.SetTopLayer( layer, true );
  205. }
  206. }
  207. }
  208. }
  209. void PCBNEW_PRINTOUT::setupPainter( KIGFX::PAINTER& aPainter )
  210. {
  211. BOARD_PRINTOUT::setupPainter( aPainter );
  212. KIGFX::PCB_PRINT_PAINTER& painter = dynamic_cast<KIGFX::PCB_PRINT_PAINTER&>( aPainter );
  213. switch( m_pcbnewSettings.m_DrillMarks )
  214. {
  215. case DRILL_MARKS::NO_DRILL_SHAPE:
  216. painter.SetDrillMarks( false, 0 );
  217. break;
  218. case DRILL_MARKS::SMALL_DRILL_SHAPE:
  219. painter.SetDrillMarks( false, pcbIUScale.mmToIU( ADVANCED_CFG::GetCfg().m_SmallDrillMarkSize ) );
  220. painter.GetSettings()->SetLayerColor( LAYER_PAD_PLATEDHOLES, COLOR4D::BLACK );
  221. painter.GetSettings()->SetLayerColor( LAYER_NON_PLATEDHOLES, COLOR4D::BLACK );
  222. painter.GetSettings()->SetLayerColor( LAYER_VIA_HOLES, COLOR4D::BLACK );
  223. break;
  224. case DRILL_MARKS::FULL_DRILL_SHAPE:
  225. painter.SetDrillMarks( true );
  226. painter.GetSettings()->SetLayerColor( LAYER_PAD_PLATEDHOLES, COLOR4D::BLACK );
  227. painter.GetSettings()->SetLayerColor( LAYER_NON_PLATEDHOLES, COLOR4D::BLACK );
  228. painter.GetSettings()->SetLayerColor( LAYER_VIA_HOLES, COLOR4D::BLACK );
  229. break;
  230. }
  231. }
  232. void PCBNEW_PRINTOUT::setupGal( KIGFX::GAL* aGal )
  233. {
  234. BOARD_PRINTOUT::setupGal( aGal );
  235. aGal->SetWorldUnitLength( 0.001/pcbIUScale.IU_PER_MM /* 1 nm */ / 0.0254 /* 1 inch in meters */ );
  236. }
  237. BOX2I PCBNEW_PRINTOUT::getBoundingBox()
  238. {
  239. return m_board->ComputeBoundingBox( false );
  240. }
  241. std::unique_ptr<KIGFX::PAINTER> PCBNEW_PRINTOUT::getPainter( KIGFX::GAL* aGal )
  242. {
  243. return std::make_unique<KIGFX::PCB_PRINT_PAINTER>( aGal );
  244. }
  245. KIGFX::PCB_PRINT_PAINTER::PCB_PRINT_PAINTER( GAL* aGal ) :
  246. PCB_PAINTER( aGal, FRAME_PCB_EDITOR ),
  247. m_drillMarkReal( false ),
  248. m_drillMarkSize( 0 )
  249. { }
  250. PAD_DRILL_SHAPE KIGFX::PCB_PRINT_PAINTER::getDrillShape( const PAD* aPad ) const
  251. {
  252. return m_drillMarkReal ? KIGFX::PCB_PAINTER::getDrillShape( aPad ) : PAD_DRILL_SHAPE::CIRCLE;
  253. }
  254. SHAPE_SEGMENT KIGFX::PCB_PRINT_PAINTER::getPadHoleShape( const PAD* aPad ) const
  255. {
  256. if( m_drillMarkReal )
  257. return KIGFX::PCB_PAINTER::getPadHoleShape( aPad );
  258. else
  259. return SHAPE_SEGMENT( aPad->GetPosition(), aPad->GetPosition(), m_drillMarkSize );
  260. }
  261. int KIGFX::PCB_PRINT_PAINTER::getViaDrillSize( const PCB_VIA* aVia ) const
  262. {
  263. return m_drillMarkReal ? KIGFX::PCB_PAINTER::getViaDrillSize( aVia ) : m_drillMarkSize;
  264. }