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.

1054 lines
36 KiB

  1. /*
  2. * This program source code file is part of KiCad, a free EDA CAD application.
  3. *
  4. * Copyright (C) 1992-2018 Jean-Pierre Charras jp.charras at wanadoo.fr
  5. * Copyright (C) 1992-2010 Lorenzo Marcantonio
  6. * Copyright (C) 2011 Wayne Stambaugh <stambaughw@gmail.com>
  7. * Copyright (C) 1992-2022 KiCad Developers, see AUTHORS.txt for contributors.
  8. *
  9. * This program is free software; you can redistribute it and/or
  10. * modify it under the terms of the GNU General Public License
  11. * as published by the Free Software Foundation; either version 2
  12. * of the License, or (at your option) any later version.
  13. *
  14. * This program is distributed in the hope that it will be useful,
  15. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. * GNU General Public License for more details.
  18. *
  19. * You should have received a copy of the GNU General Public License
  20. * along with this program; if not, you may find one here:
  21. * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
  22. * or you may search the http://www.gnu.org website for the version 2 license,
  23. * or you may write to the Free Software Foundation, Inc.,
  24. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
  25. */
  26. #include <common.h>
  27. #include <sch_plotter.h>
  28. #include <locale_io.h>
  29. #include <plotters/plotter_hpgl.h>
  30. #include <plotters/plotter_dxf.h>
  31. #include <plotters/plotters_pslike.h>
  32. #include <pgm_base.h>
  33. #include <trace_helpers.h>
  34. #include <sch_edit_frame.h>
  35. #include <sch_painter.h>
  36. #include <schematic.h>
  37. #include <sch_screen.h>
  38. #include <settings/settings_manager.h>
  39. static const wxChar* plot_sheet_list( HPGL_PAGE_SIZE aSize )
  40. {
  41. switch( aSize )
  42. {
  43. default:
  44. case HPGL_PAGE_SIZE::DEFAULT: return nullptr;
  45. case HPGL_PAGE_SIZE::SIZE_A5: return wxT( "A5" );
  46. case HPGL_PAGE_SIZE::SIZE_A4: return wxT( "A4" );
  47. case HPGL_PAGE_SIZE::SIZE_A3: return wxT( "A3" );
  48. case HPGL_PAGE_SIZE::SIZE_A2: return wxT( "A2" );
  49. case HPGL_PAGE_SIZE::SIZE_A1: return wxT( "A1" );
  50. case HPGL_PAGE_SIZE::SIZE_A0: return wxT( "A0" );
  51. case HPGL_PAGE_SIZE::SIZE_A: return wxT( "A" );
  52. case HPGL_PAGE_SIZE::SIZE_B: return wxT( "B" );
  53. case HPGL_PAGE_SIZE::SIZE_C: return wxT( "C" );
  54. case HPGL_PAGE_SIZE::SIZE_D: return wxT( "D" );
  55. case HPGL_PAGE_SIZE::SIZE_E: return wxT( "E" );
  56. }
  57. }
  58. SCH_PLOTTER::SCH_PLOTTER( SCHEMATIC* aSchematic ) :
  59. m_schFrame( nullptr ),
  60. m_schematic( aSchematic )
  61. {
  62. m_colorSettings = nullptr;
  63. }
  64. SCH_PLOTTER::SCH_PLOTTER( SCH_EDIT_FRAME* aFrame ) :
  65. m_schFrame( aFrame ),
  66. m_schematic( &aFrame->Schematic() )
  67. {
  68. m_colorSettings = nullptr;
  69. }
  70. wxFileName SCH_PLOTTER::getOutputFilenameSingle( const SCH_PLOT_SETTINGS& aPlotSettings,
  71. REPORTER* aReporter, const wxString& aExt )
  72. {
  73. if( !aPlotSettings.m_outputFile.empty() )
  74. return aPlotSettings.m_outputFile;
  75. else
  76. {
  77. wxString fname = m_schematic->GetUniqueFilenameForCurrentSheet();
  78. // The sub sheet can be in a sub_hierarchy, but we plot the file in the main
  79. // project folder (or the folder specified by the caller), so replace separators
  80. // to create a unique filename:
  81. fname.Replace( "/", "_" );
  82. fname.Replace( "\\", "_" );
  83. return createPlotFileName( aPlotSettings, fname, aExt, aReporter );
  84. }
  85. }
  86. void SCH_PLOTTER::createPDFFile( const SCH_PLOT_SETTINGS& aPlotSettings,
  87. RENDER_SETTINGS* aRenderSettings, REPORTER* aReporter )
  88. {
  89. SCH_SHEET_PATH oldsheetpath = m_schematic->CurrentSheet(); // sheetpath is saved here
  90. /* When printing all pages, the printed page is not the current page. In complex hierarchies,
  91. * we must update symbol references and other parameters in the given printed SCH_SCREEN,
  92. * according to the sheet path because in complex hierarchies a SCH_SCREEN (a drawing ) is
  93. * shared between many sheets and symbol references depend on the actual sheet path used.
  94. */
  95. SCH_SHEET_LIST sheetList;
  96. if( aPlotSettings.m_plotAll )
  97. {
  98. sheetList.BuildSheetList( &m_schematic->Root(), true );
  99. sheetList.SortByPageNumbers();
  100. }
  101. else
  102. {
  103. sheetList.push_back( m_schematic->CurrentSheet() );
  104. }
  105. // Allocate the plotter and set the job level parameter
  106. PDF_PLOTTER* plotter = new PDF_PLOTTER();
  107. plotter->SetRenderSettings( aRenderSettings );
  108. plotter->SetColorMode( !aPlotSettings.m_blackAndWhite );
  109. plotter->SetCreator( wxT( "Eeschema-PDF" ) );
  110. plotter->SetTitle( ExpandTextVars( m_schematic->RootScreen()->GetTitleBlock().GetTitle(),
  111. &m_schematic->Prj() ) );
  112. wxString msg;
  113. wxFileName plotFileName;
  114. LOCALE_IO toggle; // Switch the locale to standard C
  115. for( unsigned i = 0; i < sheetList.size(); i++ )
  116. {
  117. if( m_schFrame )
  118. m_schFrame->SetCurrentSheet( sheetList[i] );
  119. else
  120. m_schematic->SetCurrentSheet( sheetList[i] );
  121. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  122. if( m_schFrame )
  123. m_schFrame->SetSheetNumberAndCount();
  124. SCH_SCREEN* screen = m_schematic->CurrentSheet().LastScreen();
  125. if( i == 0 )
  126. {
  127. try
  128. {
  129. wxString ext = PDF_PLOTTER::GetDefaultFileExtension();
  130. plotFileName = getOutputFilenameSingle( aPlotSettings, aReporter, ext );
  131. m_lastOutputFilePath = plotFileName.GetFullPath();
  132. if( !plotFileName.IsOk() )
  133. return;
  134. if( !plotter->OpenFile( plotFileName.GetFullPath() ) )
  135. {
  136. if( aReporter )
  137. {
  138. msg.Printf( _( "Failed to create file '%s'." ),
  139. plotFileName.GetFullPath() );
  140. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  141. }
  142. delete plotter;
  143. return;
  144. }
  145. // Open the plotter and do the first page
  146. setupPlotPagePDF( plotter, screen, aPlotSettings );
  147. plotter->StartPlot( sheetList[i].GetPageNumber(), _( "Root" ) );
  148. }
  149. catch( const IO_ERROR& e )
  150. {
  151. // Cannot plot PDF file
  152. if( aReporter )
  153. {
  154. msg.Printf( wxT( "PDF Plotter exception: %s" ), e.What() );
  155. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  156. }
  157. restoreEnvironment( plotter, oldsheetpath );
  158. return;
  159. }
  160. }
  161. else
  162. {
  163. /* For the following pages you need to close the (finished) page,
  164. * reconfigure, and then start a new one */
  165. plotter->ClosePage();
  166. setupPlotPagePDF( plotter, screen, aPlotSettings );
  167. plotter->StartPage( sheetList[i].GetPageNumber(),
  168. sheetList[i].Last()->GetFields()[SHEETNAME].GetShownText() );
  169. }
  170. plotOneSheetPDF( plotter, screen, aPlotSettings );
  171. }
  172. // Everything done, close the plot and restore the environment
  173. if( aReporter )
  174. {
  175. msg.Printf( _( "Plotted to '%s'.\n" ), plotFileName.GetFullPath() );
  176. aReporter->Report( msg, RPT_SEVERITY_ACTION );
  177. aReporter->ReportTail( _( "Done." ), RPT_SEVERITY_INFO );
  178. }
  179. restoreEnvironment( plotter, oldsheetpath );
  180. }
  181. void SCH_PLOTTER::plotOneSheetPDF( PLOTTER* aPlotter, SCH_SCREEN* aScreen,
  182. const SCH_PLOT_SETTINGS& aPlotSettings )
  183. {
  184. if( aPlotSettings.m_useBackgroundColor && aPlotter->GetColorMode() )
  185. {
  186. aPlotter->SetColor( aPlotter->RenderSettings()->GetBackgroundColor() );
  187. wxPoint end( aPlotter->PageSettings().GetWidthIU( schIUScale.IU_PER_MILS ),
  188. aPlotter->PageSettings().GetHeightIU( schIUScale.IU_PER_MILS ) );
  189. aPlotter->Rect( wxPoint( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0 );
  190. }
  191. if( aPlotSettings.m_plotDrawingSheet )
  192. {
  193. COLOR4D color = COLOR4D::BLACK;
  194. if( aPlotter->GetColorMode() )
  195. color = aPlotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET );
  196. wxString sheetName = m_schematic->CurrentSheet().Last()->GetName();
  197. wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
  198. PlotDrawingSheet( aPlotter, &aScreen->Schematic()->Prj(),
  199. m_schematic->RootScreen()->GetTitleBlock(),
  200. aPlotter->PageSettings(),
  201. aScreen->Schematic()->GetProperties(),
  202. aScreen->GetPageNumber(), aScreen->GetPageCount(), sheetName, sheetPath,
  203. aScreen->GetFileName(), color, aScreen->GetVirtualPageNumber() == 1 );
  204. }
  205. aScreen->Plot( aPlotter );
  206. }
  207. void SCH_PLOTTER::setupPlotPagePDF( PLOTTER* aPlotter, SCH_SCREEN* aScreen,
  208. const SCH_PLOT_SETTINGS& aPlotSettings )
  209. {
  210. PAGE_INFO plotPage; // page size selected to plot
  211. // Considerations on page size and scaling requests
  212. const PAGE_INFO& actualPage = aScreen->GetPageSettings(); // page size selected in schematic
  213. switch( aPlotSettings.m_pageSizeSelect )
  214. {
  215. case PAGE_SIZE_A:
  216. plotPage.SetType( wxT( "A" ) );
  217. plotPage.SetPortrait( actualPage.IsPortrait() );
  218. break;
  219. case PAGE_SIZE_A4:
  220. plotPage.SetType( wxT( "A4" ) );
  221. plotPage.SetPortrait( actualPage.IsPortrait() );
  222. break;
  223. case PAGE_SIZE_AUTO:
  224. default:
  225. plotPage = actualPage;
  226. break;
  227. }
  228. double scalex = (double) plotPage.GetWidthMils() / actualPage.GetWidthMils();
  229. double scaley = (double) plotPage.GetHeightMils() / actualPage.GetHeightMils();
  230. double scale = std::min( scalex, scaley );
  231. aPlotter->SetPageSettings( plotPage );
  232. // Currently, plot units are in decimil
  233. aPlotter->SetViewport( wxPoint( 0, 0 ), schIUScale.IU_PER_MILS/10, scale, false );
  234. }
  235. void SCH_PLOTTER::createPSFiles( const SCH_PLOT_SETTINGS& aPlotSettings,
  236. RENDER_SETTINGS* aRenderSettings, REPORTER* aReporter )
  237. {
  238. SCH_SHEET_PATH oldsheetpath = m_schematic->CurrentSheet(); // sheetpath is saved here
  239. PAGE_INFO plotPage; // page size selected to plot
  240. wxString msg;
  241. /* When printing all pages, the printed page is not the current page.
  242. * In complex hierarchies, we must update symbol references and other parameters in the
  243. * given printed SCH_SCREEN, accordant to the sheet path because in complex hierarchies
  244. * a SCH_SCREEN (a drawing ) is shared between many sheets and symbol references
  245. * depend on the actual sheet path used.
  246. */
  247. SCH_SHEET_LIST sheetList;
  248. if( aPlotSettings.m_plotAll )
  249. {
  250. sheetList.BuildSheetList( &m_schematic->Root(), true );
  251. sheetList.SortByPageNumbers();
  252. }
  253. else
  254. {
  255. sheetList.push_back( m_schematic->CurrentSheet() );
  256. }
  257. for( unsigned i = 0; i < sheetList.size(); i++ )
  258. {
  259. if( m_schFrame )
  260. m_schFrame->SetCurrentSheet( sheetList[i] );
  261. else
  262. m_schematic->SetCurrentSheet( sheetList[i] );
  263. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  264. if( m_schFrame )
  265. m_schFrame->SetSheetNumberAndCount();
  266. SCH_SCREEN* screen = m_schematic->CurrentSheet().LastScreen();
  267. PAGE_INFO actualPage = screen->GetPageSettings();
  268. switch( aPlotSettings.m_pageSizeSelect )
  269. {
  270. case PAGE_SIZE_A:
  271. plotPage.SetType( wxT( "A" ) );
  272. plotPage.SetPortrait( actualPage.IsPortrait() );
  273. break;
  274. case PAGE_SIZE_A4:
  275. plotPage.SetType( wxT( "A4" ) );
  276. plotPage.SetPortrait( actualPage.IsPortrait() );
  277. break;
  278. case PAGE_SIZE_AUTO:
  279. default: plotPage = actualPage; break;
  280. }
  281. double scalex = (double) plotPage.GetWidthMils() / actualPage.GetWidthMils();
  282. double scaley = (double) plotPage.GetHeightMils() / actualPage.GetHeightMils();
  283. double scale = std::min( scalex, scaley );
  284. wxPoint plot_offset;
  285. try
  286. {
  287. wxString fname = m_schematic->GetUniqueFilenameForCurrentSheet();
  288. // The sub sheet can be in a sub_hierarchy, but we plot the file in the
  289. // main project folder (or the folder specified by the caller),
  290. // so replace separators to create a unique filename:
  291. fname.Replace( "/", "_" );
  292. fname.Replace( "\\", "_" );
  293. wxString ext = PS_PLOTTER::GetDefaultFileExtension();
  294. wxFileName plotFileName = createPlotFileName( aPlotSettings, fname, ext, aReporter );
  295. m_lastOutputFilePath = plotFileName.GetFullPath();
  296. if( !plotFileName.IsOk() )
  297. return;
  298. if( plotOneSheetPS( plotFileName.GetFullPath(), screen, aRenderSettings, plotPage,
  299. plot_offset, scale, aPlotSettings ) )
  300. {
  301. if( aReporter )
  302. {
  303. msg.Printf( _( "Plotted to '%s'." ), plotFileName.GetFullPath() );
  304. aReporter->Report( msg, RPT_SEVERITY_ACTION );
  305. }
  306. }
  307. else
  308. {
  309. if( aReporter )
  310. {
  311. // Error
  312. msg.Printf( _( "Failed to create file '%s'." ), plotFileName.GetFullPath() );
  313. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  314. }
  315. }
  316. }
  317. catch( IO_ERROR& e )
  318. {
  319. if( aReporter )
  320. {
  321. msg.Printf( wxT( "PS Plotter exception: %s" ), e.What() );
  322. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  323. }
  324. }
  325. }
  326. if( aReporter )
  327. {
  328. aReporter->ReportTail( _( "Done." ), RPT_SEVERITY_INFO );
  329. }
  330. if( m_schFrame )
  331. m_schFrame->SetCurrentSheet( oldsheetpath );
  332. else
  333. m_schematic->SetCurrentSheet( oldsheetpath );
  334. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  335. if( m_schFrame )
  336. m_schFrame->SetSheetNumberAndCount();
  337. }
  338. bool SCH_PLOTTER::plotOneSheetPS( const wxString& aFileName, SCH_SCREEN* aScreen,
  339. RENDER_SETTINGS* aRenderSettings,
  340. const PAGE_INFO& aPageInfo, const wxPoint& aPlot0ffset,
  341. double aScale, const SCH_PLOT_SETTINGS& aPlotSettings )
  342. {
  343. PS_PLOTTER* plotter = new PS_PLOTTER();
  344. plotter->SetRenderSettings( aRenderSettings );
  345. plotter->SetPageSettings( aPageInfo );
  346. plotter->SetColorMode( !aPlotSettings.m_blackAndWhite );
  347. // Currently, plot units are in decimil
  348. plotter->SetViewport( aPlot0ffset, schIUScale.IU_PER_MILS / 10, aScale, false );
  349. // Init :
  350. plotter->SetCreator( wxT( "Eeschema-PS" ) );
  351. if( !plotter->OpenFile( aFileName ) )
  352. {
  353. delete plotter;
  354. return false;
  355. }
  356. LOCALE_IO toggle; // Switch the locale to standard C
  357. plotter->StartPlot( m_schematic->CurrentSheet().GetPageNumber() );
  358. if( aPlotSettings.m_useBackgroundColor && plotter->GetColorMode() )
  359. {
  360. plotter->SetColor( plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
  361. wxPoint end( plotter->PageSettings().GetWidthIU( schIUScale.IU_PER_MILS ),
  362. plotter->PageSettings().GetHeightIU( schIUScale.IU_PER_MILS ) );
  363. plotter->Rect( wxPoint( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0 );
  364. }
  365. if( aPlotSettings.m_plotDrawingSheet )
  366. {
  367. wxString sheetName = m_schematic->CurrentSheet().Last()->GetName();
  368. wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
  369. COLOR4D color = plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET );
  370. PlotDrawingSheet( plotter, &aScreen->Schematic()->Prj(),
  371. m_schematic->RootScreen()->GetTitleBlock(),
  372. aPageInfo, aScreen->Schematic()->GetProperties(),
  373. aScreen->GetPageNumber(), aScreen->GetPageCount(), sheetName, sheetPath,
  374. aScreen->GetFileName(), plotter->GetColorMode() ? color : COLOR4D::BLACK,
  375. aScreen->GetVirtualPageNumber() == 1 );
  376. }
  377. aScreen->Plot( plotter );
  378. plotter->EndPlot();
  379. delete plotter;
  380. return true;
  381. }
  382. void SCH_PLOTTER::createSVGFiles( const SCH_PLOT_SETTINGS& aPlotSettings,
  383. RENDER_SETTINGS* aRenderSettings, REPORTER* aReporter )
  384. {
  385. wxString msg;
  386. SCH_SHEET_PATH oldsheetpath = m_schematic->CurrentSheet();
  387. SCH_SHEET_LIST sheetList;
  388. if( aPlotSettings.m_plotAll )
  389. {
  390. sheetList.BuildSheetList( &m_schematic->Root(), true );
  391. sheetList.SortByPageNumbers();
  392. }
  393. else
  394. {
  395. sheetList.push_back( m_schematic->CurrentSheet() );
  396. }
  397. for( unsigned i = 0; i < sheetList.size(); i++ )
  398. {
  399. SCH_SCREEN* screen;
  400. if( m_schFrame )
  401. m_schFrame->SetCurrentSheet( sheetList[i] );
  402. else
  403. m_schematic->SetCurrentSheet( sheetList[i] );
  404. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  405. if( m_schFrame )
  406. m_schFrame->SetSheetNumberAndCount();
  407. screen = m_schematic->CurrentSheet().LastScreen();
  408. try
  409. {
  410. wxString fname = m_schematic->GetUniqueFilenameForCurrentSheet();
  411. // The sub sheet can be in a sub_hierarchy, but we plot the file in the
  412. // main project folder (or the folder specified by the caller),
  413. // so replace separators to create a unique filename:
  414. fname.Replace( "/", "_" );
  415. fname.Replace( "\\", "_" );
  416. wxString ext = SVG_PLOTTER::GetDefaultFileExtension();
  417. wxFileName plotFileName = createPlotFileName( aPlotSettings, fname, ext, aReporter );
  418. m_lastOutputFilePath = plotFileName.GetFullPath();
  419. if( !plotFileName.IsOk() )
  420. return;
  421. bool success = plotOneSheetSVG( plotFileName.GetFullPath(), screen, aRenderSettings,
  422. aPlotSettings );
  423. if( !success )
  424. {
  425. if( aReporter )
  426. {
  427. msg.Printf( _( "Failed to create file '%s'." ), plotFileName.GetFullPath() );
  428. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  429. }
  430. }
  431. else
  432. {
  433. if( aReporter )
  434. {
  435. msg.Printf( _( "Plotted to '%s'." ), plotFileName.GetFullPath() );
  436. aReporter->Report( msg, RPT_SEVERITY_ACTION );
  437. }
  438. }
  439. }
  440. catch( const IO_ERROR& e )
  441. {
  442. if( aReporter )
  443. {
  444. // Cannot plot SVG file
  445. msg.Printf( wxT( "SVG Plotter exception: %s" ), e.What() );
  446. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  447. }
  448. break;
  449. }
  450. }
  451. if( aReporter )
  452. {
  453. aReporter->ReportTail( _( "Done" ), RPT_SEVERITY_INFO );
  454. }
  455. if( m_schFrame )
  456. m_schFrame->SetCurrentSheet( oldsheetpath );
  457. else
  458. m_schematic->SetCurrentSheet( oldsheetpath );
  459. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  460. if( m_schFrame )
  461. m_schFrame->SetSheetNumberAndCount();
  462. }
  463. bool SCH_PLOTTER::plotOneSheetSVG( const wxString& aFileName, SCH_SCREEN* aScreen,
  464. RENDER_SETTINGS* aRenderSettings,
  465. const SCH_PLOT_SETTINGS& aPlotSettings )
  466. {
  467. const PAGE_INFO& pageInfo = aScreen->GetPageSettings();
  468. SVG_PLOTTER* plotter = new SVG_PLOTTER();
  469. plotter->SetRenderSettings( aRenderSettings );
  470. plotter->SetPageSettings( pageInfo );
  471. plotter->SetColorMode( aPlotSettings.m_blackAndWhite ? false : true );
  472. wxPoint plot_offset;
  473. double scale = 1.0;
  474. // Currently, plot units are in decimil
  475. plotter->SetViewport( plot_offset, schIUScale.IU_PER_MILS / 10, scale, false );
  476. // Init :
  477. plotter->SetCreator( wxT( "Eeschema-SVG" ) );
  478. if( !plotter->OpenFile( aFileName ) )
  479. {
  480. delete plotter;
  481. return false;
  482. }
  483. LOCALE_IO toggle;
  484. plotter->StartPlot( m_schematic->CurrentSheet().GetPageNumber() );
  485. if( aPlotSettings.m_useBackgroundColor && plotter->GetColorMode() )
  486. {
  487. plotter->SetColor( plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_BACKGROUND ) );
  488. wxPoint end( plotter->PageSettings().GetWidthIU( schIUScale.IU_PER_MILS ),
  489. plotter->PageSettings().GetHeightIU( schIUScale.IU_PER_MILS ) );
  490. plotter->Rect( wxPoint( 0, 0 ), end, FILL_T::FILLED_SHAPE, 1.0 );
  491. }
  492. if( aPlotSettings.m_plotDrawingSheet )
  493. {
  494. wxString sheetName = m_schematic->CurrentSheet().Last()->GetName();
  495. wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
  496. COLOR4D color = plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET );
  497. PlotDrawingSheet( plotter, &aScreen->Schematic()->Prj(),
  498. m_schematic->RootScreen()->GetTitleBlock(),
  499. pageInfo, aScreen->Schematic()->GetProperties(), aScreen->GetPageNumber(),
  500. aScreen->GetPageCount(), sheetName, sheetPath, aScreen->GetFileName(),
  501. plotter->GetColorMode() ? color : COLOR4D::BLACK,
  502. aScreen->GetVirtualPageNumber() == 1 );
  503. }
  504. aScreen->Plot( plotter );
  505. plotter->EndPlot();
  506. delete plotter;
  507. return true;
  508. }
  509. void SCH_PLOTTER::createHPGLFiles( const SCH_PLOT_SETTINGS& aPlotSettings,
  510. RENDER_SETTINGS* aRenderSettings, REPORTER* aReporter )
  511. {
  512. SCH_SCREEN* screen = m_schematic->RootScreen();
  513. SCH_SHEET_PATH oldsheetpath = m_schematic->CurrentSheet();
  514. /* When printing all pages, the printed page is not the current page. In complex hierarchies,
  515. * we must update symbol references and other parameters in the given printed SCH_SCREEN,
  516. * according to the sheet path because in complex hierarchies a SCH_SCREEN (a drawing ) is
  517. * shared between many sheets and symbol references depend on the actual sheet path used.
  518. */
  519. SCH_SHEET_LIST sheetList;
  520. if( aPlotSettings.m_plotAll )
  521. {
  522. sheetList.BuildSheetList( &m_schematic->Root(), true );
  523. sheetList.SortByPageNumbers();
  524. }
  525. else
  526. {
  527. sheetList.push_back( m_schematic->CurrentSheet() );
  528. }
  529. for( unsigned i = 0; i < sheetList.size(); i++ )
  530. {
  531. if( m_schFrame )
  532. m_schFrame->SetCurrentSheet( sheetList[i] );
  533. else
  534. m_schematic->SetCurrentSheet( sheetList[i] );
  535. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  536. if( m_schFrame )
  537. m_schFrame->SetSheetNumberAndCount();
  538. screen = m_schematic->CurrentSheet().LastScreen();
  539. if( !screen ) // LastScreen() may return NULL
  540. screen = m_schematic->RootScreen();
  541. const PAGE_INFO& curPage = screen->GetPageSettings();
  542. PAGE_INFO plotPage = curPage;
  543. // if plotting on a page size other than curPage
  544. plotPage.SetType( plot_sheet_list( aPlotSettings.m_HPGLPaperSizeSelect ) );
  545. // Calculation of conversion scales.
  546. double plot_scale = (double) plotPage.GetWidthMils() / curPage.GetWidthMils();
  547. // Calculate offsets
  548. wxPoint plotOffset;
  549. wxString msg;
  550. if( aPlotSettings.m_HPGLPlotOrigin == HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_CENTER )
  551. {
  552. plotOffset.x = plotPage.GetWidthIU( schIUScale.IU_PER_MILS ) / 2;
  553. plotOffset.y = -plotPage.GetHeightIU( schIUScale.IU_PER_MILS ) / 2;
  554. }
  555. try
  556. {
  557. wxString fname = m_schematic->GetUniqueFilenameForCurrentSheet();
  558. // The sub sheet can be in a sub_hierarchy, but we plot the file in the
  559. // main project folder (or the folder specified by the caller),
  560. // so replace separators to create a unique filename:
  561. fname.Replace( "/", "_" );
  562. fname.Replace( "\\", "_" );
  563. wxString ext = HPGL_PLOTTER::GetDefaultFileExtension();
  564. wxFileName plotFileName = createPlotFileName( aPlotSettings, fname, ext, aReporter );
  565. if( !plotFileName.IsOk() )
  566. return;
  567. LOCALE_IO toggle;
  568. if( plotOneSheetHpgl( plotFileName.GetFullPath(), screen, plotPage, aRenderSettings,
  569. plotOffset, plot_scale, aPlotSettings ) )
  570. {
  571. if( aReporter )
  572. {
  573. msg.Printf( _( "Plotted to '%s'." ), plotFileName.GetFullPath() );
  574. aReporter->Report( msg, RPT_SEVERITY_ACTION );
  575. }
  576. }
  577. else
  578. {
  579. if( aReporter )
  580. {
  581. msg.Printf( _( "Failed to create file '%s'." ), plotFileName.GetFullPath() );
  582. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  583. }
  584. }
  585. }
  586. catch( IO_ERROR& e )
  587. {
  588. if( aReporter )
  589. {
  590. msg.Printf( wxT( "HPGL Plotter exception: %s" ), e.What() );
  591. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  592. }
  593. }
  594. }
  595. if( aReporter )
  596. {
  597. aReporter->ReportTail( _( "Done." ), RPT_SEVERITY_INFO );
  598. }
  599. if( m_schFrame )
  600. m_schFrame->SetCurrentSheet( oldsheetpath );
  601. else
  602. m_schematic->SetCurrentSheet( oldsheetpath );
  603. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  604. if( m_schFrame )
  605. m_schFrame->SetSheetNumberAndCount();
  606. }
  607. bool SCH_PLOTTER::plotOneSheetHpgl( const wxString& aFileName,
  608. SCH_SCREEN* aScreen,
  609. const PAGE_INFO& aPageInfo,
  610. RENDER_SETTINGS* aRenderSettings,
  611. const wxPoint& aPlot0ffset,
  612. double aScale,
  613. const SCH_PLOT_SETTINGS& aPlotSettings )
  614. {
  615. HPGL_PLOTTER* plotter = new HPGL_PLOTTER();
  616. // Currently, plot units are in decimil
  617. plotter->SetPageSettings( aPageInfo );
  618. plotter->SetRenderSettings( aRenderSettings );
  619. plotter->RenderSettings()->LoadColors( m_colorSettings );
  620. plotter->SetColorMode( !aPlotSettings.m_blackAndWhite );
  621. plotter->SetViewport( aPlot0ffset, schIUScale.IU_PER_MILS/10, aScale, false );
  622. // TODO this could be configurable
  623. plotter->SetTargetChordLength( schIUScale.mmToIU( 0.6 ) );
  624. switch( aPlotSettings.m_HPGLPlotOrigin )
  625. {
  626. case HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_BOT_LEFT:
  627. case HPGL_PLOT_ORIGIN_AND_UNITS::PLOTTER_CENTER:
  628. default:
  629. plotter->SetUserCoords( false );
  630. break;
  631. case HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_PAGE:
  632. plotter->SetUserCoords( true );
  633. plotter->SetUserCoordsFit( false );
  634. break;
  635. case HPGL_PLOT_ORIGIN_AND_UNITS::USER_FIT_CONTENT:
  636. plotter->SetUserCoords( true );
  637. plotter->SetUserCoordsFit( true );
  638. break;
  639. }
  640. // Init :
  641. plotter->SetCreator( wxT( "Eeschema-HPGL" ) );
  642. if( !plotter->OpenFile( aFileName ) )
  643. {
  644. delete plotter;
  645. return false;
  646. }
  647. LOCALE_IO toggle;
  648. // Pen num and pen speed are not initialized here.
  649. // Default HPGL driver values are used
  650. plotter->SetPenDiameter( aPlotSettings.m_HPGLPenSize );
  651. plotter->StartPlot( m_schematic->CurrentSheet().GetPageNumber() );
  652. if( aPlotSettings.m_plotDrawingSheet )
  653. {
  654. wxString sheetName = m_schematic->CurrentSheet().Last()->GetName();
  655. wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
  656. PlotDrawingSheet( plotter, &m_schematic->Prj(), m_schematic->RootScreen()->GetTitleBlock(),
  657. aPageInfo,
  658. aScreen->Schematic()->GetProperties(), aScreen->GetPageNumber(),
  659. aScreen->GetPageCount(), sheetName, sheetPath, aScreen->GetFileName(),
  660. COLOR4D::BLACK, aScreen->GetVirtualPageNumber() == 1 );
  661. }
  662. aScreen->Plot( plotter );
  663. plotter->EndPlot();
  664. delete plotter;
  665. return true;
  666. }
  667. void SCH_PLOTTER::createDXFFiles( const SCH_PLOT_SETTINGS& aPlotSettings,
  668. RENDER_SETTINGS* aRenderSettings, REPORTER* aReporter )
  669. {
  670. SCH_SHEET_PATH oldsheetpath = m_schematic->CurrentSheet();
  671. /* When printing all pages, the printed page is not the current page. In complex hierarchies,
  672. * we must update symbol references and other parameters in the given printed SCH_SCREEN,
  673. * according to the sheet path because in complex hierarchies a SCH_SCREEN (a drawing ) is
  674. * shared between many sheets and symbol references depend on the actual sheet path used.
  675. */
  676. SCH_SHEET_LIST sheetList;
  677. if( aPlotSettings.m_plotAll )
  678. {
  679. sheetList.BuildSheetList( &m_schematic->Root(), true );
  680. sheetList.SortByPageNumbers();
  681. }
  682. else
  683. {
  684. sheetList.push_back( m_schematic->CurrentSheet() );
  685. }
  686. for( unsigned i = 0; i < sheetList.size(); i++ )
  687. {
  688. if( m_schFrame )
  689. m_schFrame->SetCurrentSheet( sheetList[i] );
  690. else
  691. m_schematic->SetCurrentSheet( sheetList[i] );
  692. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  693. if( m_schFrame )
  694. m_schFrame->SetSheetNumberAndCount();
  695. SCH_SCREEN* screen = m_schematic->CurrentSheet().LastScreen();
  696. wxPoint plot_offset;
  697. wxString msg;
  698. try
  699. {
  700. wxString fname = m_schematic->GetUniqueFilenameForCurrentSheet();
  701. // The sub sheet can be in a sub_hierarchy, but we plot the file in the
  702. // main project folder (or the folder specified by the caller),
  703. // so replace separators to create a unique filename:
  704. fname.Replace( "/", "_" );
  705. fname.Replace( "\\", "_" );
  706. wxString ext = DXF_PLOTTER::GetDefaultFileExtension();
  707. wxFileName plotFileName = createPlotFileName( aPlotSettings, fname, ext, aReporter );
  708. m_lastOutputFilePath = plotFileName.GetFullPath();
  709. if( !plotFileName.IsOk() )
  710. return;
  711. if( plotOneSheetDXF( plotFileName.GetFullPath(), screen, aRenderSettings, plot_offset,
  712. 1.0, aPlotSettings ) )
  713. {
  714. if( aReporter )
  715. {
  716. msg.Printf( _( "Plotted to '%s'." ), plotFileName.GetFullPath() );
  717. aReporter->Report( msg, RPT_SEVERITY_ACTION );
  718. }
  719. }
  720. else // Error
  721. {
  722. if( aReporter )
  723. {
  724. msg.Printf( _( "Failed to create file '%s'." ), plotFileName.GetFullPath() );
  725. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  726. }
  727. }
  728. }
  729. catch( IO_ERROR& e )
  730. {
  731. if( aReporter )
  732. {
  733. msg.Printf( wxT( "DXF Plotter exception: %s" ), e.What() );
  734. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  735. }
  736. if( m_schFrame )
  737. m_schFrame->SetCurrentSheet( oldsheetpath );
  738. else
  739. m_schematic->SetCurrentSheet( oldsheetpath );
  740. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  741. if( m_schFrame )
  742. m_schFrame->SetSheetNumberAndCount();
  743. return;
  744. }
  745. }
  746. if( aReporter )
  747. aReporter->ReportTail( _( "Done." ), RPT_SEVERITY_INFO );
  748. if( m_schFrame )
  749. m_schFrame->SetCurrentSheet( oldsheetpath );
  750. else
  751. m_schematic->SetCurrentSheet( oldsheetpath );
  752. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  753. if( m_schFrame )
  754. m_schFrame->SetSheetNumberAndCount();
  755. }
  756. bool SCH_PLOTTER::plotOneSheetDXF( const wxString& aFileName, SCH_SCREEN* aScreen,
  757. RENDER_SETTINGS* aRenderSettings, const wxPoint& aPlotOffset,
  758. double aScale, const SCH_PLOT_SETTINGS& aPlotSettings )
  759. {
  760. aRenderSettings->LoadColors( m_colorSettings );
  761. aRenderSettings->SetDefaultPenWidth( 0 );
  762. const PAGE_INFO& pageInfo = aScreen->GetPageSettings();
  763. DXF_PLOTTER* plotter = new DXF_PLOTTER();
  764. plotter->SetRenderSettings( aRenderSettings );
  765. plotter->SetPageSettings( pageInfo );
  766. plotter->SetColorMode( !aPlotSettings.m_blackAndWhite );
  767. // Currently, plot units are in decimil
  768. plotter->SetViewport( aPlotOffset, schIUScale.IU_PER_MILS / 10, aScale, false );
  769. // Init :
  770. plotter->SetCreator( wxT( "Eeschema-DXF" ) );
  771. if( !plotter->OpenFile( aFileName ) )
  772. {
  773. delete plotter;
  774. return false;
  775. }
  776. LOCALE_IO toggle;
  777. plotter->StartPlot( m_schematic->CurrentSheet().GetPageNumber() );
  778. if( aPlotSettings.m_plotDrawingSheet )
  779. {
  780. wxString sheetName = m_schematic->CurrentSheet().Last()->GetName();
  781. wxString sheetPath = m_schematic->CurrentSheet().PathHumanReadable();
  782. COLOR4D color = plotter->RenderSettings()->GetLayerColor( LAYER_SCHEMATIC_DRAWINGSHEET );
  783. PlotDrawingSheet( plotter, &m_schematic->Prj(), m_schematic->RootScreen()->GetTitleBlock(),
  784. pageInfo,
  785. aScreen->Schematic()->GetProperties(), aScreen->GetPageNumber(),
  786. aScreen->GetPageCount(), sheetName, sheetPath, aScreen->GetFileName(),
  787. plotter->GetColorMode() ? color : COLOR4D::BLACK,
  788. aScreen->GetVirtualPageNumber() == 1 );
  789. }
  790. aScreen->Plot( plotter );
  791. // finish
  792. plotter->EndPlot();
  793. delete plotter;
  794. return true;
  795. }
  796. void SCH_PLOTTER::restoreEnvironment( PDF_PLOTTER* aPlotter, SCH_SHEET_PATH& aOldsheetpath )
  797. {
  798. aPlotter->EndPlot();
  799. delete aPlotter;
  800. // Restore the previous sheet
  801. if( m_schFrame )
  802. m_schFrame->SetCurrentSheet( aOldsheetpath );
  803. else
  804. m_schematic->SetCurrentSheet( aOldsheetpath );
  805. m_schematic->CurrentSheet().UpdateAllScreenReferences();
  806. if( m_schFrame )
  807. m_schFrame->SetSheetNumberAndCount();
  808. }
  809. wxFileName SCH_PLOTTER::createPlotFileName( const SCH_PLOT_SETTINGS& aPlotSettings,
  810. const wxString& aPlotFileName,
  811. const wxString& aExtension, REPORTER* aReporter )
  812. {
  813. wxFileName retv;
  814. wxFileName tmp;
  815. tmp.SetPath( aPlotSettings.m_outputDirectory );
  816. retv.SetPath( tmp.GetPath() );
  817. if( !aPlotFileName.IsEmpty() )
  818. retv.SetName( aPlotFileName );
  819. else
  820. retv.SetName( _( "Schematic" ) );
  821. retv.SetExt( aExtension );
  822. if( !EnsureFileDirectoryExists( &tmp, retv.GetFullName(), aReporter ) || !tmp.IsDirWritable() )
  823. {
  824. if( aReporter )
  825. {
  826. wxString msg = wxString::Format( _( "Failed to write plot files to folder '%s'." ),
  827. tmp.GetPath() );
  828. aReporter->Report( msg, RPT_SEVERITY_ERROR );
  829. }
  830. retv.Clear();
  831. SCHEMATIC_SETTINGS& settings = m_schematic->Settings();
  832. settings.m_PlotDirectoryName.Clear();
  833. }
  834. else
  835. {
  836. retv.SetPath( tmp.GetPath() );
  837. }
  838. wxLogTrace( tracePathsAndFiles, "Writing plot file '%s'.", retv.GetFullPath() );
  839. return retv;
  840. }
  841. void SCH_PLOTTER::Plot( PLOT_FORMAT aPlotFormat, const SCH_PLOT_SETTINGS& aPlotSettings,
  842. RENDER_SETTINGS* aRenderSettings, REPORTER* aReporter )
  843. {
  844. SETTINGS_MANAGER& settingsMgr = Pgm().GetSettingsManager();
  845. m_colorSettings = settingsMgr.GetColorSettings( aPlotSettings.m_theme );
  846. switch( aPlotFormat )
  847. {
  848. default:
  849. case PLOT_FORMAT::POST: createPSFiles( aPlotSettings, aRenderSettings, aReporter ); break;
  850. case PLOT_FORMAT::DXF: createDXFFiles( aPlotSettings, aRenderSettings, aReporter ); break;
  851. case PLOT_FORMAT::PDF: createPDFFile( aPlotSettings, aRenderSettings, aReporter ); break;
  852. case PLOT_FORMAT::SVG: createSVGFiles( aPlotSettings, aRenderSettings, aReporter ); break;
  853. case PLOT_FORMAT::HPGL: createHPGLFiles( aPlotSettings, aRenderSettings, aReporter ); break;
  854. }
  855. }