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.

936 lines
28 KiB

12 years ago
  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU General Public License
  8. * as published by the Free Software Foundation; either version 2
  9. * of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with this program; if not, you may find one here:
  18. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  19. * or you may search the http://www.gnu.org website for the version 2 license,
  20. * or you may write to the Free Software Foundation, Inc.,
  21. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  22. */
  23. #include <board_design_settings.h>
  24. #include <charconv>
  25. #include <layer_ids.h>
  26. #include <lset.h>
  27. #include <string_utils.h>
  28. #include <pcb_plot_params.h>
  29. #include <pcb_plot_params_parser.h>
  30. #include <plotters/plotter.h>
  31. #include <io/kicad/kicad_io_utils.h>
  32. #include <settings/color_settings.h>
  33. #define PLOT_LINEWIDTH_DEFAULT ( DEFAULT_TEXT_WIDTH * IU_PER_MM )
  34. #define HPGL_PEN_DIAMETER_MIN 0
  35. #define HPGL_PEN_DIAMETER_MAX 100.0 // Unit = mil
  36. #define HPGL_PEN_SPEED_MIN 1 // this param is always in cm/s
  37. #define HPGL_PEN_SPEED_MAX 99 // this param is always in cm/s
  38. #define HPGL_PEN_NUMBER_MIN 1
  39. #define HPGL_PEN_NUMBER_MAX 16
  40. #define SVG_PRECISION_MIN 3U
  41. #define SVG_PRECISION_MAX 6U
  42. #define SVG_PRECISION_DEFAULT 4
  43. // default trailing digits in Gerber coordinates, when units are mm
  44. // This is also the max usable precision (i.e. internal Pcbnew Units)
  45. static const int gbrDefaultPrecision = 6;
  46. using namespace PCBPLOTPARAMS_T;
  47. static const char* getTokenName( T aTok )
  48. {
  49. return PCB_PLOT_PARAMS_LEXER::TokenName( aTok );
  50. }
  51. static bool setInt( int* aTarget, int aValue, int aMin, int aMax )
  52. {
  53. int temp = aValue;
  54. if( aValue < aMin )
  55. temp = aMin;
  56. else if( aValue > aMax )
  57. temp = aMax;
  58. *aTarget = temp;
  59. return ( temp == aValue );
  60. }
  61. static bool setDouble( double* aTarget, double aValue, double aMin, double aMax )
  62. {
  63. double temp = aValue;
  64. if( aValue < aMin )
  65. temp = aMin;
  66. else if( aValue > aMax )
  67. temp = aMax;
  68. *aTarget = temp;
  69. return ( temp == aValue );
  70. }
  71. PCB_PLOT_PARAMS::PCB_PLOT_PARAMS()
  72. {
  73. m_useGerberProtelExtensions = false;
  74. m_gerberDisableApertMacros = false;
  75. m_useGerberX2format = true;
  76. m_includeGerberNetlistInfo = true;
  77. m_createGerberJobFile = true;
  78. m_gerberPrecision = gbrDefaultPrecision;
  79. m_dashedLineDashRatio = 12.0; // From ISO 128-2
  80. m_dashedLineGapRatio = 3.0; // From ISO 128-2
  81. // we used 0.1mils for SVG step before, but nm precision is more accurate, so we use nm
  82. m_svgPrecision = SVG_PRECISION_DEFAULT;
  83. m_plotDrawingSheet = false;
  84. m_plotMode = FILLED;
  85. m_DXFPolygonMode = true;
  86. m_DXFUnits = DXF_UNITS::INCHES;
  87. m_useAuxOrigin = false;
  88. m_HPGLPenNum = 1;
  89. m_HPGLPenSpeed = 20; // this param is always in cm/s
  90. m_HPGLPenDiam = 15; // in mils
  91. m_negative = false;
  92. m_A4Output = false;
  93. m_plotReference = true;
  94. m_plotValue = true;
  95. m_plotFPText = true;
  96. m_plotInvisibleText = false;
  97. m_sketchPadsOnFabLayers = false;
  98. m_hideDNPFPsOnFabLayers = false;
  99. m_sketchDNPFPsOnFabLayers = true;
  100. m_crossoutDNPFPsOnFabLayers = true;
  101. m_plotPadNumbers = false;
  102. m_subtractMaskFromSilk = false;
  103. m_format = PLOT_FORMAT::GERBER;
  104. m_mirror = false;
  105. m_drillMarks = DRILL_MARKS::SMALL_DRILL_SHAPE;
  106. m_autoScale = false;
  107. m_scale = 1.0;
  108. m_scaleSelection = 1;
  109. m_fineScaleAdjustX = 1.0;
  110. m_fineScaleAdjustY = 1.0;
  111. m_widthAdjust = 0.;
  112. m_textMode = PLOT_TEXT_MODE::DEFAULT;
  113. m_outputDirectory.clear();
  114. m_layerSelection = LSET( { F_SilkS, B_SilkS, F_Mask, B_Mask,
  115. F_Paste, B_Paste, Edge_Cuts } )
  116. | LSET::AllCuMask();
  117. m_PDFFrontFPPropertyPopups = true;
  118. m_PDFBackFPPropertyPopups = true;
  119. m_PDFMetadata = true;
  120. m_PDFSingle = false;
  121. // This parameter controls if the NPTH pads will be plotted or not
  122. // it is a "local" parameter
  123. m_skipNPTH_Pads = false;
  124. // line width to plot items in outline mode.
  125. m_sketchPadLineWidth = pcbIUScale.mmToIU( 0.1 );
  126. m_default_colors = std::make_shared<COLOR_SETTINGS>();
  127. m_colors = m_default_colors.get();
  128. m_blackAndWhite = true;
  129. }
  130. void PCB_PLOT_PARAMS::SetGerberPrecision( int aPrecision )
  131. {
  132. // Currently Gerber files use mm.
  133. // accepted precision is only 6 (max value, this is the resolution of Pcbnew)
  134. // or 5, min value for professional boards, when 6 creates problems
  135. // to board makers.
  136. m_gerberPrecision = aPrecision == gbrDefaultPrecision-1 ? gbrDefaultPrecision-1 :
  137. gbrDefaultPrecision;
  138. }
  139. void PCB_PLOT_PARAMS::SetSvgPrecision( unsigned aPrecision )
  140. {
  141. m_svgPrecision = std::clamp( aPrecision, SVG_PRECISION_MIN, SVG_PRECISION_MAX );
  142. }
  143. void PCB_PLOT_PARAMS::Format( OUTPUTFORMATTER* aFormatter ) const
  144. {
  145. aFormatter->Print( "(pcbplotparams" );
  146. aFormatter->Print( "(layerselection 0x%s)", m_layerSelection.FmtHex().c_str() );
  147. aFormatter->Print( "(plot_on_all_layers_selection 0x%s)",
  148. m_plotOnAllLayersSelection.FmtHex().c_str() );
  149. KICAD_FORMAT::FormatBool( aFormatter, "disableapertmacros", m_gerberDisableApertMacros );
  150. KICAD_FORMAT::FormatBool( aFormatter, "usegerberextensions", m_useGerberProtelExtensions );
  151. KICAD_FORMAT::FormatBool( aFormatter, "usegerberattributes", GetUseGerberX2format() );
  152. KICAD_FORMAT::FormatBool( aFormatter, "usegerberadvancedattributes", GetIncludeGerberNetlistInfo() );
  153. KICAD_FORMAT::FormatBool( aFormatter, "creategerberjobfile", GetCreateGerberJobFile() );
  154. // save this option only if it is not the default value,
  155. // to avoid incompatibility with older Pcbnew version
  156. if( m_gerberPrecision != gbrDefaultPrecision )
  157. aFormatter->Print( "(gerberprecision %d)", m_gerberPrecision );
  158. aFormatter->Print( "(dashed_line_dash_ratio %f)", GetDashedLineDashRatio() );
  159. aFormatter->Print( "(dashed_line_gap_ratio %f)", GetDashedLineGapRatio() );
  160. // SVG options
  161. aFormatter->Print( "(svgprecision %d)", m_svgPrecision );
  162. KICAD_FORMAT::FormatBool( aFormatter, "plotframeref", m_plotDrawingSheet );
  163. aFormatter->Print( "(mode %d)", GetPlotMode() == SKETCH ? 2 : 1 );
  164. KICAD_FORMAT::FormatBool( aFormatter, "useauxorigin", m_useAuxOrigin );
  165. // HPGL options
  166. aFormatter->Print( "(hpglpennumber %d)", m_HPGLPenNum );
  167. aFormatter->Print( "(hpglpenspeed %d)", m_HPGLPenSpeed );
  168. aFormatter->Print( "(hpglpendiameter %f)", m_HPGLPenDiam );
  169. // PDF options
  170. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_pdf_front_fp_property_popups ),
  171. m_PDFFrontFPPropertyPopups );
  172. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_pdf_back_fp_property_popups ),
  173. m_PDFBackFPPropertyPopups );
  174. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_pdf_metadata ), m_PDFMetadata );
  175. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_pdf_single_document ), m_PDFSingle );
  176. // DXF options
  177. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_dxfpolygonmode ), m_DXFPolygonMode );
  178. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_dxfimperialunits ),
  179. m_DXFUnits == DXF_UNITS::INCHES );
  180. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_dxfusepcbnewfont ),
  181. m_textMode != PLOT_TEXT_MODE::NATIVE );
  182. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_psnegative ), m_negative );
  183. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_psa4output ), m_A4Output );
  184. KICAD_FORMAT::FormatBool( aFormatter, getTokenName( T_plot_black_and_white ), m_blackAndWhite );
  185. KICAD_FORMAT::FormatBool( aFormatter, "plotinvisibletext", m_plotInvisibleText );
  186. KICAD_FORMAT::FormatBool( aFormatter, "sketchpadsonfab", m_sketchPadsOnFabLayers );
  187. KICAD_FORMAT::FormatBool( aFormatter, "plotpadnumbers", m_plotPadNumbers );
  188. KICAD_FORMAT::FormatBool( aFormatter, "hidednponfab", m_hideDNPFPsOnFabLayers );
  189. KICAD_FORMAT::FormatBool( aFormatter, "sketchdnponfab", m_sketchDNPFPsOnFabLayers );
  190. KICAD_FORMAT::FormatBool( aFormatter, "crossoutdnponfab", m_crossoutDNPFPsOnFabLayers );
  191. KICAD_FORMAT::FormatBool( aFormatter, "subtractmaskfromsilk", m_subtractMaskFromSilk );
  192. aFormatter->Print( "(outputformat %d)", static_cast<int>( m_format ) );
  193. KICAD_FORMAT::FormatBool( aFormatter, "mirror", m_mirror );
  194. aFormatter->Print( "(drillshape %d)", (int)m_drillMarks );
  195. aFormatter->Print( "(scaleselection %d)", m_scaleSelection );
  196. aFormatter->Print( "(outputdirectory %s)", aFormatter->Quotew( m_outputDirectory ).c_str() );
  197. aFormatter->Print( ")" );
  198. }
  199. void PCB_PLOT_PARAMS::Parse( PCB_PLOT_PARAMS_PARSER* aParser )
  200. {
  201. aParser->Parse( this );
  202. }
  203. bool PCB_PLOT_PARAMS::IsSameAs( const PCB_PLOT_PARAMS &aPcbPlotParams ) const
  204. {
  205. if( m_layerSelection != aPcbPlotParams.m_layerSelection )
  206. return false;
  207. if( m_plotOnAllLayersSelection != aPcbPlotParams.m_plotOnAllLayersSelection )
  208. return false;
  209. if( m_useGerberProtelExtensions != aPcbPlotParams.m_useGerberProtelExtensions )
  210. return false;
  211. if( m_gerberDisableApertMacros != aPcbPlotParams.m_gerberDisableApertMacros )
  212. return false;
  213. if( m_useGerberX2format != aPcbPlotParams.m_useGerberX2format )
  214. return false;
  215. if( m_includeGerberNetlistInfo != aPcbPlotParams.m_includeGerberNetlistInfo )
  216. return false;
  217. if( m_createGerberJobFile != aPcbPlotParams.m_createGerberJobFile )
  218. return false;
  219. if( m_gerberPrecision != aPcbPlotParams.m_gerberPrecision )
  220. return false;
  221. if( m_dashedLineDashRatio != aPcbPlotParams.m_dashedLineDashRatio )
  222. return false;
  223. if( m_dashedLineGapRatio != aPcbPlotParams.m_dashedLineGapRatio )
  224. return false;
  225. if( m_plotDrawingSheet != aPcbPlotParams.m_plotDrawingSheet )
  226. return false;
  227. if( m_plotMode != aPcbPlotParams.m_plotMode )
  228. return false;
  229. if( m_DXFPolygonMode != aPcbPlotParams.m_DXFPolygonMode )
  230. return false;
  231. if( m_DXFUnits != aPcbPlotParams.m_DXFUnits )
  232. return false;
  233. if( m_svgPrecision != aPcbPlotParams.m_svgPrecision )
  234. return false;
  235. if( m_useAuxOrigin != aPcbPlotParams.m_useAuxOrigin )
  236. return false;
  237. if( m_HPGLPenNum != aPcbPlotParams.m_HPGLPenNum )
  238. return false;
  239. if( m_HPGLPenSpeed != aPcbPlotParams.m_HPGLPenSpeed )
  240. return false;
  241. if( m_HPGLPenDiam != aPcbPlotParams.m_HPGLPenDiam )
  242. return false;
  243. if( m_negative != aPcbPlotParams.m_negative )
  244. return false;
  245. if( m_PDFFrontFPPropertyPopups != aPcbPlotParams.m_PDFFrontFPPropertyPopups )
  246. return false;
  247. if( m_PDFBackFPPropertyPopups != aPcbPlotParams.m_PDFBackFPPropertyPopups )
  248. return false;
  249. if( m_PDFMetadata != aPcbPlotParams.m_PDFMetadata )
  250. return false;
  251. if( m_A4Output != aPcbPlotParams.m_A4Output )
  252. return false;
  253. if( m_plotReference != aPcbPlotParams.m_plotReference )
  254. return false;
  255. if( m_plotValue != aPcbPlotParams.m_plotValue )
  256. return false;
  257. if( m_plotFPText != aPcbPlotParams.m_plotFPText )
  258. return false;
  259. if( m_plotInvisibleText != aPcbPlotParams.m_plotInvisibleText )
  260. return false;
  261. if( m_sketchPadsOnFabLayers != aPcbPlotParams.m_sketchPadsOnFabLayers )
  262. return false;
  263. if( m_plotPadNumbers != aPcbPlotParams.m_plotPadNumbers )
  264. return false;
  265. if( m_hideDNPFPsOnFabLayers != aPcbPlotParams.m_hideDNPFPsOnFabLayers )
  266. return false;
  267. if( m_sketchDNPFPsOnFabLayers != aPcbPlotParams.m_sketchDNPFPsOnFabLayers )
  268. return false;
  269. if( m_crossoutDNPFPsOnFabLayers != aPcbPlotParams.m_crossoutDNPFPsOnFabLayers )
  270. return false;
  271. if( m_subtractMaskFromSilk != aPcbPlotParams.m_subtractMaskFromSilk )
  272. return false;
  273. if( m_format != aPcbPlotParams.m_format )
  274. return false;
  275. if( m_mirror != aPcbPlotParams.m_mirror )
  276. return false;
  277. if( m_drillMarks != aPcbPlotParams.m_drillMarks )
  278. return false;
  279. if( m_scaleSelection != aPcbPlotParams.m_scaleSelection )
  280. return false;
  281. if( m_autoScale != aPcbPlotParams.m_autoScale )
  282. return false;
  283. if( m_scale != aPcbPlotParams.m_scale )
  284. return false;
  285. if( m_fineScaleAdjustX != aPcbPlotParams.m_fineScaleAdjustX )
  286. return false;
  287. if( m_fineScaleAdjustY != aPcbPlotParams.m_fineScaleAdjustY )
  288. return false;
  289. if( m_widthAdjust != aPcbPlotParams.m_widthAdjust )
  290. return false;
  291. if( m_textMode != aPcbPlotParams.m_textMode )
  292. return false;
  293. if( m_blackAndWhite != aPcbPlotParams.m_blackAndWhite )
  294. return false;
  295. if( !m_outputDirectory.IsSameAs( aPcbPlotParams.m_outputDirectory ) )
  296. return false;
  297. return true;
  298. }
  299. bool PCB_PLOT_PARAMS::SetHPGLPenDiameter( double aValue )
  300. {
  301. return setDouble( &m_HPGLPenDiam, aValue, HPGL_PEN_DIAMETER_MIN, HPGL_PEN_DIAMETER_MAX );
  302. }
  303. bool PCB_PLOT_PARAMS::SetHPGLPenSpeed( int aValue )
  304. {
  305. return setInt( &m_HPGLPenSpeed, aValue, HPGL_PEN_SPEED_MIN, HPGL_PEN_SPEED_MAX );
  306. }
  307. PCB_PLOT_PARAMS_PARSER::PCB_PLOT_PARAMS_PARSER( LINE_READER* aReader, int aBoardFileVersion ) :
  308. PCB_PLOT_PARAMS_LEXER( aReader ),
  309. m_boardFileVersion( aBoardFileVersion )
  310. {
  311. }
  312. PCB_PLOT_PARAMS_PARSER::PCB_PLOT_PARAMS_PARSER( char* aLine, const wxString& aSource ) :
  313. PCB_PLOT_PARAMS_LEXER( aLine, aSource ),
  314. m_boardFileVersion( 0 )
  315. {
  316. }
  317. /**
  318. * These are the layer IDs from before 5e0abadb23425765e164f49ee2f893e94ddb97fc,
  319. * and are needed for mapping old PCB files to the new layer numbering.
  320. */
  321. enum LEGACY_PCB_LAYER_ID: int
  322. {
  323. LEGACY_UNDEFINED_LAYER = -1,
  324. LEGACY_UNSELECTED_LAYER = -2,
  325. LEGACY_F_Cu = 0,
  326. LEGACY_In1_Cu,
  327. LEGACY_In2_Cu,
  328. LEGACY_In3_Cu,
  329. LEGACY_In4_Cu,
  330. LEGACY_In5_Cu,
  331. LEGACY_In6_Cu,
  332. LEGACY_In7_Cu,
  333. LEGACY_In8_Cu,
  334. LEGACY_In9_Cu,
  335. LEGACY_In10_Cu,
  336. LEGACY_In11_Cu,
  337. LEGACY_In12_Cu,
  338. LEGACY_In13_Cu,
  339. LEGACY_In14_Cu,
  340. LEGACY_In15_Cu,
  341. LEGACY_In16_Cu,
  342. LEGACY_In17_Cu,
  343. LEGACY_In18_Cu,
  344. LEGACY_In19_Cu,
  345. LEGACY_In20_Cu,
  346. LEGACY_In21_Cu,
  347. LEGACY_In22_Cu,
  348. LEGACY_In23_Cu,
  349. LEGACY_In24_Cu,
  350. LEGACY_In25_Cu,
  351. LEGACY_In26_Cu,
  352. LEGACY_In27_Cu,
  353. LEGACY_In28_Cu,
  354. LEGACY_In29_Cu,
  355. LEGACY_In30_Cu,
  356. LEGACY_B_Cu, // 31
  357. LEGACY_B_Adhes,
  358. LEGACY_F_Adhes,
  359. LEGACY_B_Paste,
  360. LEGACY_F_Paste,
  361. LEGACY_B_SilkS,
  362. LEGACY_F_SilkS,
  363. LEGACY_B_Mask,
  364. LEGACY_F_Mask, // 39
  365. LEGACY_Dwgs_User,
  366. LEGACY_Cmts_User,
  367. LEGACY_Eco1_User,
  368. LEGACY_Eco2_User,
  369. LEGACY_Edge_Cuts,
  370. LEGACY_Margin, // 45
  371. LEGACY_B_CrtYd,
  372. LEGACY_F_CrtYd,
  373. LEGACY_B_Fab,
  374. LEGACY_F_Fab, // 49
  375. // User definable layers.
  376. LEGACY_User_1,
  377. LEGACY_User_2,
  378. LEGACY_User_3,
  379. LEGACY_User_4,
  380. LEGACY_User_5,
  381. LEGACY_User_6,
  382. LEGACY_User_7,
  383. LEGACY_User_8,
  384. LEGACY_User_9,
  385. LEGACY_Rescue, // 59
  386. // Four reserved layers (60 - 63) for future expansion within the 64 bit integer limit.
  387. LEGACY_PCB_LAYER_ID_COUNT
  388. };
  389. /*
  390. * Mapping to translate a legacy layer ID into the new PCB layer IDs.
  391. */
  392. static const std::map<LEGACY_PCB_LAYER_ID, PCB_LAYER_ID> s_legacyLayerIdMap{
  393. {LEGACY_F_Cu, F_Cu},
  394. {LEGACY_B_Cu, B_Cu},
  395. {LEGACY_In1_Cu, In1_Cu},
  396. {LEGACY_In2_Cu, In2_Cu},
  397. {LEGACY_In3_Cu, In3_Cu},
  398. {LEGACY_In4_Cu, In4_Cu},
  399. {LEGACY_In5_Cu, In5_Cu},
  400. {LEGACY_In6_Cu, In6_Cu},
  401. {LEGACY_In7_Cu, In7_Cu},
  402. {LEGACY_In8_Cu, In8_Cu},
  403. {LEGACY_In9_Cu, In9_Cu},
  404. {LEGACY_In10_Cu, In10_Cu},
  405. {LEGACY_In11_Cu, In11_Cu},
  406. {LEGACY_In12_Cu, In12_Cu},
  407. {LEGACY_In13_Cu, In13_Cu},
  408. {LEGACY_In14_Cu, In14_Cu},
  409. {LEGACY_In15_Cu, In15_Cu},
  410. {LEGACY_In16_Cu, In16_Cu},
  411. {LEGACY_In17_Cu, In17_Cu},
  412. {LEGACY_In18_Cu, In18_Cu},
  413. {LEGACY_In19_Cu, In19_Cu},
  414. {LEGACY_In20_Cu, In20_Cu},
  415. {LEGACY_In21_Cu, In21_Cu},
  416. {LEGACY_In22_Cu, In22_Cu},
  417. {LEGACY_In23_Cu, In23_Cu},
  418. {LEGACY_In24_Cu, In24_Cu},
  419. {LEGACY_In25_Cu, In25_Cu},
  420. {LEGACY_In26_Cu, In26_Cu},
  421. {LEGACY_In27_Cu, In27_Cu},
  422. {LEGACY_In28_Cu, In28_Cu},
  423. {LEGACY_In29_Cu, In29_Cu},
  424. {LEGACY_In30_Cu, In30_Cu},
  425. {LEGACY_F_Mask, F_Mask},
  426. {LEGACY_B_Mask, B_Mask},
  427. {LEGACY_F_SilkS, F_SilkS},
  428. {LEGACY_B_SilkS, B_SilkS},
  429. {LEGACY_F_Adhes, F_Adhes},
  430. {LEGACY_B_Adhes, B_Adhes},
  431. {LEGACY_F_Paste, F_Paste},
  432. {LEGACY_B_Paste, B_Paste},
  433. {LEGACY_Dwgs_User, Dwgs_User},
  434. {LEGACY_Cmts_User, Cmts_User},
  435. {LEGACY_Eco1_User, Eco1_User},
  436. {LEGACY_Eco2_User, Eco2_User},
  437. {LEGACY_Edge_Cuts, Edge_Cuts},
  438. {LEGACY_Margin, Margin},
  439. {LEGACY_B_CrtYd, B_CrtYd},
  440. {LEGACY_F_CrtYd, F_CrtYd},
  441. {LEGACY_B_Fab, B_Fab},
  442. {LEGACY_F_Fab, F_Fab},
  443. {LEGACY_User_1, User_1},
  444. {LEGACY_User_2, User_2},
  445. {LEGACY_User_3, User_3},
  446. {LEGACY_User_4, User_4},
  447. {LEGACY_User_5, User_5},
  448. {LEGACY_User_6, User_6},
  449. {LEGACY_User_7, User_7},
  450. {LEGACY_User_8, User_8},
  451. {LEGACY_User_9, User_9},
  452. {LEGACY_Rescue, Rescue},
  453. };
  454. LSET remapLegacyLayerLSET( const BASE_SET& aLegacyLSET )
  455. {
  456. LSET newLayers;
  457. for( const auto& [legacyLayer, newLayer] : s_legacyLayerIdMap )
  458. newLayers[newLayer] = aLegacyLSET[legacyLayer];
  459. return newLayers;
  460. }
  461. void PCB_PLOT_PARAMS_PARSER::Parse( PCB_PLOT_PARAMS* aPcbPlotParams )
  462. {
  463. T token;
  464. while( ( token = NextTok() ) != T_RIGHT )
  465. {
  466. if( token == T_EOF)
  467. Unexpected( T_EOF );
  468. if( token == T_LEFT )
  469. token = NextTok();
  470. if( token == T_pcbplotparams )
  471. continue;
  472. bool skip_right = false;
  473. switch( token )
  474. {
  475. case T_layerselection:
  476. {
  477. token = NeedSYMBOLorNUMBER();
  478. const std::string& cur = CurStr();
  479. if( token == T_NUMBER ) // pretty 3 format had legacy Cu stack.
  480. {
  481. // It's not possible to convert a legacy Cu layer number to a new Cu layer
  482. // number without knowing the number or total Cu layers in the legacy board.
  483. // We do not have that information here, so simply set all layers ON. User
  484. // can turn them off in the UI.
  485. aPcbPlotParams->m_layerSelection = LSET( { F_SilkS, B_SilkS } ) | LSET::AllCuMask();
  486. }
  487. else if( cur.find_first_of( "0x" ) == 0 ) // pretty ver. 4.
  488. {
  489. // The layers were renumbered in 5e0abadb23425765e164f49ee2f893e94ddb97fc, but there wasn't
  490. // a board file version change with it, so this value is the one immediately after that happened.
  491. if( m_boardFileVersion < 20240819 )
  492. {
  493. BASE_SET legacyLSET( LEGACY_PCB_LAYER_ID_COUNT );
  494. // skip the leading 2 0x bytes.
  495. legacyLSET.ParseHex( cur.c_str() + 2, cur.size() - 2 );
  496. aPcbPlotParams->SetLayerSelection( remapLegacyLayerLSET( legacyLSET ) );
  497. }
  498. else
  499. {
  500. // skip the leading 2 0x bytes.
  501. aPcbPlotParams->m_layerSelection.ParseHex( cur.c_str() + 2, cur.size() - 2 );
  502. }
  503. }
  504. else
  505. {
  506. Expecting( "integer or hex layerSelection" );
  507. }
  508. break;
  509. }
  510. case T_plot_on_all_layers_selection:
  511. {
  512. token = NeedSYMBOLorNUMBER();
  513. const std::string& cur = CurStr();
  514. if( cur.find_first_of( "0x" ) == 0 )
  515. {
  516. // The layers were renumbered in 5e0abadb23425765e164f49ee2f893e94ddb97fc, but there wasn't
  517. // a board file version change with it, so this value is the one immediately after that happened.
  518. if( m_boardFileVersion < 20240819 )
  519. {
  520. BASE_SET legacyLSET( LEGACY_PCB_LAYER_ID_COUNT );
  521. // skip the leading 2 0x bytes.
  522. legacyLSET.ParseHex( cur.c_str() + 2, cur.size() - 2 );
  523. aPcbPlotParams->SetPlotOnAllLayersSelection( remapLegacyLayerLSET( legacyLSET ) );
  524. }
  525. else
  526. {
  527. // skip the leading 2 0x bytes.
  528. aPcbPlotParams->m_plotOnAllLayersSelection.ParseHex( cur.c_str() + 2,
  529. cur.size() - 2 );
  530. }
  531. }
  532. else
  533. {
  534. Expecting( "hex plot_on_all_layers_selection" );
  535. }
  536. break;
  537. }
  538. case T_disableapertmacros:
  539. aPcbPlotParams->m_gerberDisableApertMacros = parseBool();
  540. break;
  541. case T_usegerberextensions:
  542. aPcbPlotParams->m_useGerberProtelExtensions = parseBool();
  543. break;
  544. case T_usegerberattributes:
  545. aPcbPlotParams->m_useGerberX2format = parseBool();
  546. break;
  547. case T_usegerberadvancedattributes:
  548. aPcbPlotParams->m_includeGerberNetlistInfo = parseBool();
  549. break;
  550. case T_creategerberjobfile:
  551. aPcbPlotParams->m_createGerberJobFile = parseBool();
  552. break;
  553. case T_gerberprecision:
  554. aPcbPlotParams->m_gerberPrecision = parseInt( gbrDefaultPrecision - 1,
  555. gbrDefaultPrecision);
  556. break;
  557. case T_dashed_line_dash_ratio:
  558. aPcbPlotParams->m_dashedLineDashRatio = parseDouble();
  559. break;
  560. case T_dashed_line_gap_ratio:
  561. aPcbPlotParams->m_dashedLineGapRatio = parseDouble();
  562. break;
  563. case T_svgprecision:
  564. aPcbPlotParams->m_svgPrecision = parseInt( SVG_PRECISION_MIN, SVG_PRECISION_MAX );
  565. break;
  566. case T_svguseinch:
  567. parseBool(); // Unused. For compatibility
  568. break;
  569. case T_psa4output:
  570. aPcbPlotParams->m_A4Output = parseBool();
  571. break;
  572. case T_excludeedgelayer:
  573. if( !parseBool() )
  574. aPcbPlotParams->m_plotOnAllLayersSelection.set( Edge_Cuts );
  575. break;
  576. case T_plotframeref:
  577. aPcbPlotParams->m_plotDrawingSheet = parseBool();
  578. break;
  579. case T_viasonmask:
  580. aPcbPlotParams->m_plotViaOnMaskLayer = parseBool();
  581. break;
  582. case T_mode:
  583. aPcbPlotParams->SetPlotMode( parseInt( 0, 2 ) > 1 ? SKETCH : FILLED );
  584. break;
  585. case T_useauxorigin:
  586. aPcbPlotParams->m_useAuxOrigin = parseBool();
  587. break;
  588. case T_hpglpennumber:
  589. aPcbPlotParams->m_HPGLPenNum = parseInt( HPGL_PEN_NUMBER_MIN, HPGL_PEN_NUMBER_MAX );
  590. break;
  591. case T_hpglpenspeed:
  592. aPcbPlotParams->m_HPGLPenSpeed = parseInt( HPGL_PEN_SPEED_MIN, HPGL_PEN_SPEED_MAX );
  593. break;
  594. case T_hpglpendiameter:
  595. aPcbPlotParams->m_HPGLPenDiam = parseDouble();
  596. break;
  597. case T_hpglpenoverlay:
  598. // No more used. just here for compatibility with old versions
  599. parseInt( 0, HPGL_PEN_DIAMETER_MAX );
  600. break;
  601. case T_pdf_front_fp_property_popups:
  602. aPcbPlotParams->m_PDFFrontFPPropertyPopups = parseBool();
  603. break;
  604. case T_pdf_back_fp_property_popups:
  605. aPcbPlotParams->m_PDFBackFPPropertyPopups = parseBool();
  606. break;
  607. case T_pdf_metadata:
  608. aPcbPlotParams->m_PDFMetadata = parseBool();
  609. break;
  610. case T_pdf_single_document:
  611. aPcbPlotParams->m_PDFSingle = parseBool();
  612. break;
  613. case T_dxfpolygonmode:
  614. aPcbPlotParams->m_DXFPolygonMode = parseBool();
  615. break;
  616. case T_dxfimperialunits:
  617. aPcbPlotParams->m_DXFUnits = parseBool() ? DXF_UNITS::INCHES
  618. : DXF_UNITS::MILLIMETERS;
  619. break;
  620. case T_dxfusepcbnewfont:
  621. aPcbPlotParams->m_textMode = parseBool() ? PLOT_TEXT_MODE::DEFAULT
  622. : PLOT_TEXT_MODE::NATIVE;
  623. break;
  624. case T_pscolor:
  625. NeedSYMBOL(); // This actually was never used...
  626. break;
  627. case T_psnegative:
  628. aPcbPlotParams->m_negative = parseBool();
  629. break;
  630. case T_plot_black_and_white:
  631. aPcbPlotParams->m_blackAndWhite = parseBool();
  632. break;
  633. case T_plotinvisibletext:
  634. aPcbPlotParams->m_plotInvisibleText = parseBool();
  635. break;
  636. case T_sketchpadsonfab:
  637. aPcbPlotParams->m_sketchPadsOnFabLayers= parseBool();
  638. break;
  639. case T_plotpadnumbers:
  640. aPcbPlotParams->m_plotPadNumbers = parseBool();
  641. break;
  642. case T_hidednponfab:
  643. aPcbPlotParams->m_hideDNPFPsOnFabLayers = parseBool();
  644. break;
  645. case T_sketchdnponfab:
  646. aPcbPlotParams->m_sketchDNPFPsOnFabLayers = parseBool();
  647. break;
  648. case T_crossoutdnponfab:
  649. aPcbPlotParams->m_crossoutDNPFPsOnFabLayers = parseBool();
  650. break;
  651. case T_subtractmaskfromsilk:
  652. aPcbPlotParams->m_subtractMaskFromSilk = parseBool();
  653. break;
  654. case T_outputformat:
  655. aPcbPlotParams->m_format = static_cast<PLOT_FORMAT>(
  656. parseInt( static_cast<int>( PLOT_FORMAT::FIRST_FORMAT ),
  657. static_cast<int>( PLOT_FORMAT::LAST_FORMAT ) ) );
  658. break;
  659. case T_mirror:
  660. aPcbPlotParams->m_mirror = parseBool();
  661. break;
  662. case T_drillshape:
  663. aPcbPlotParams->m_drillMarks = static_cast<DRILL_MARKS> ( parseInt( 0, 2 ) );
  664. break;
  665. case T_scaleselection:
  666. aPcbPlotParams->m_scaleSelection = parseInt( 0, 4 );
  667. break;
  668. case T_outputdirectory:
  669. NeedSYMBOLorNUMBER(); // a dir name can be like a number
  670. aPcbPlotParams->m_outputDirectory = From_UTF8( CurText() );
  671. break;
  672. default:
  673. skipCurrent(); // skip unknown or outdated plot parameter
  674. skip_right = true; // the closing right token is already read.
  675. break;
  676. }
  677. if( ! skip_right )
  678. NeedRIGHT();
  679. }
  680. }
  681. bool PCB_PLOT_PARAMS_PARSER::parseBool()
  682. {
  683. T token = NeedSYMBOL();
  684. switch( token )
  685. {
  686. case T_false:
  687. case T_no:
  688. return false;
  689. case T_true:
  690. case T_yes:
  691. return true;
  692. default:
  693. Expecting( "true, false, yes, or no" );
  694. return false;
  695. }
  696. }
  697. int PCB_PLOT_PARAMS_PARSER::parseInt( int aMin, int aMax )
  698. {
  699. T token = NextTok();
  700. if( token != T_NUMBER )
  701. Expecting( T_NUMBER );
  702. int val = atoi( CurText() );
  703. if( val < aMin )
  704. val = aMin;
  705. else if( val > aMax )
  706. val = aMax;
  707. return val;
  708. }
  709. double PCB_PLOT_PARAMS_PARSER::parseDouble()
  710. {
  711. T token = NextTok();
  712. if( token != T_NUMBER )
  713. Expecting( T_NUMBER );
  714. return DSNLEXER::parseDouble();
  715. }
  716. void PCB_PLOT_PARAMS_PARSER::skipCurrent()
  717. {
  718. int curr_level = 0;
  719. T token;
  720. while( ( token = NextTok() ) != T_EOF )
  721. {
  722. if( token == T_LEFT )
  723. curr_level--;
  724. if( token == T_RIGHT )
  725. {
  726. curr_level++;
  727. if( curr_level > 0 )
  728. return;
  729. }
  730. }
  731. }