KiCad PCB EDA Suite
printout_controler.cpp
Go to the documentation of this file.
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 (C) 1992-2018 KiCad Developers, see AUTHORS.txt for contributors.
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, you may find one here:
19  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
20  * or you may search the http://www.gnu.org website for the version 2 license,
21  * or you may write to the Free Software Foundation, Inc.,
22  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
23  */
24 
31 // Set this to 1 if you want to test PostScript printing under MSW.
32 #define wxTEST_POSTSCRIPT_IN_MSW 1
33 
34 #include <fctsys.h>
35 #include <pgm_base.h>
36 #include <gr_basic.h>
37 #include <class_drawpanel.h>
38 #include <confirm.h>
39 #include <base_units.h>
40 #include <pcb_base_frame.h>
41 #include <class_board.h>
42 #include <pcbnew.h>
43 #include <trace_helpers.h>
44 
45 #include <printout_controler.h>
46 
47 
49 {
50  m_PenDefaultSize = Millimeter2iu( 0.2 ); // A reasonable default value to draw items
51  // which do not have a specified line width
52  m_PrintScale = 1.0;
53  m_XScaleAdjust = 1.0;
54  m_YScaleAdjust = 1.0;
55  m_Print_Sheet_Ref = false;
56  m_PrintMaskLayer.set();
57  m_PrintMirror = false;
60  m_PageCount = 1;
61  m_ForceCentered = false;
62  m_Flags = 0;
64  m_PageSetupData = NULL;
65 }
66 
67 
69  EDA_DRAW_FRAME* aParent,
70  const wxString& aTitle ) :
71  wxPrintout( aTitle )
72 {
73  m_PrintParams = aParams; // Make a local copy of the print parameters.
74  m_Parent = aParent;
75 }
76 
77 
79 {
81  int pageCount = lset.count();
82  wxString layer;
83  PCB_LAYER_ID extractLayer;
84 
85  // compute layer mask from page number if we want one page per layer
86  if( m_PrintParams.m_OptionPrintPage == 0 ) // One page per layer
87  {
88  // This sequence is TBD, call a different
89  // sequencer if needed, such as Seq(). Could not find documentation on
90  // page order.
91  LSEQ seq = lset.UIOrder();
92 
93  // aPage starts at 1, not 0
94  if( unsigned( aPage-1 ) < seq.size() )
95  m_PrintParams.m_PrintMaskLayer = LSET( seq[aPage-1] );
96  }
97 
98  if( !m_PrintParams.m_PrintMaskLayer.any() )
99  return false;
100 
102  if( extractLayer == UNDEFINED_LAYER )
103  layer = _( "Multiple Layers" );
104  else
105  layer = LSET::Name( extractLayer );
106 
107  // In Pcbnew we can want the layer EDGE always printed
108  if( m_PrintParams.m_Flags == 1 )
110 
111  DrawPage( layer, aPage, pageCount );
112 
114 
115  return true;
116 }
117 
118 
119 void BOARD_PRINTOUT_CONTROLLER::GetPageInfo( int* minPage, int* maxPage,
120  int* selPageFrom, int* selPageTo )
121 {
122  *minPage = 1;
123  *selPageFrom = 1;
124 
125  int icnt = 1;
126 
128  icnt = m_PrintParams.m_PageCount;
129 
130  *maxPage = icnt;
131  *selPageTo = icnt;
132 }
133 
134 
135 void BOARD_PRINTOUT_CONTROLLER::DrawPage( const wxString& aLayerName, int aPageNum, int aPageCount )
136 {
137  wxPoint offset;
138  double userscale;
139  EDA_RECT boardBoundingBox;
140  EDA_RECT drawRect;
141  wxDC* dc = GetDC();
142  BASE_SCREEN* screen = m_Parent->GetScreen();
143  bool printMirror = m_PrintParams.m_PrintMirror;
144  wxSize pageSizeIU = m_Parent->GetPageSizeIU();
145  int tempScreenNumber;
146  int tempNumberOfScreens;
147 
148  wxBusyCursor dummy;
149 
150  BOARD* brd = ((PCB_BASE_FRAME*) m_Parent)->GetBoard();
151  boardBoundingBox = brd->ComputeBoundingBox();
152  const wxString& titleblockFilename = brd->GetFileName();
153 
154  // Use the page size as the drawing area when the board is shown or the user scale
155  // is less than 1.
157  boardBoundingBox = EDA_RECT( wxPoint( 0, 0 ), pageSizeIU );
158 
159  wxLogTrace( tracePrinting, wxT( "Drawing bounding box: x=%d, y=%d, w=%d, h=%d" ),
160  boardBoundingBox.GetX(), boardBoundingBox.GetY(),
161  boardBoundingBox.GetWidth(), boardBoundingBox.GetHeight() );
162 
163  // Compute the PCB size in internal units
164  userscale = m_PrintParams.m_PrintScale;
165 
166  if( m_PrintParams.m_PrintScale == 0 ) // fit in page option
167  {
168  if( boardBoundingBox.GetWidth() && boardBoundingBox.GetHeight() )
169  {
170  int margin = Millimeter2iu( 10.0 ); // add a margin around the drawings
171  double scaleX = (double)(pageSizeIU.x - (2 * margin)) /
172  boardBoundingBox.GetWidth();
173  double scaleY = (double)(pageSizeIU.y - (2 * margin)) /
174  boardBoundingBox.GetHeight();
175  userscale = (scaleX < scaleY) ? scaleX : scaleY;
176  }
177  else
178  userscale = 1.0;
179  }
180 
181  wxSize scaledPageSize = pageSizeIU;
182  drawRect.SetSize( scaledPageSize );
183  scaledPageSize.x = wxRound( scaledPageSize.x / userscale );
184  scaledPageSize.y = wxRound( scaledPageSize.y / userscale );
185 
186 
188  {
189  wxLogTrace( tracePrinting, wxT( "Fit size to page margins: x=%d, y=%d" ),
190  scaledPageSize.x, scaledPageSize.y );
191 
192  // Always scale to the size of the paper.
193  FitThisSizeToPageMargins( scaledPageSize, *m_PrintParams.m_PageSetupData );
194  }
195 
196  // Compute Accurate scale 1
197  if( m_PrintParams.m_PrintScale == 1.0 )
198  {
199  // We want a 1:1 scale, regardless the page setup
200  // like page size, margin ...
201  MapScreenSizeToPaper(); // set best scale and offset (scale is not used)
202  int w, h;
203  GetPPIPrinter( &w, &h );
204  double accurate_Xscale = (double) w / (IU_PER_MILS*1000);
205  double accurate_Yscale = (double) h / (IU_PER_MILS*1000);
206 
207  if( IsPreview() ) // Scale must take in account the DC size in Preview
208  {
209  // Get the size of the DC in pixels
210  wxSize PlotAreaSize;
211  dc->GetSize( &PlotAreaSize.x, &PlotAreaSize.y );
212  GetPageSizePixels( &w, &h );
213  accurate_Xscale *= (double)PlotAreaSize.x / w;
214  accurate_Yscale *= (double)PlotAreaSize.y / h;
215  }
216  // Fine scale adjust
217  accurate_Xscale *= m_PrintParams.m_XScaleAdjust;
218  accurate_Yscale *= m_PrintParams.m_YScaleAdjust;
219 
220  // Set print scale for 1:1 exact scale
221  dc->SetUserScale( accurate_Xscale, accurate_Yscale );
222  }
223 
224  // Get the final size of the DC in pixels
225  wxSize PlotAreaSizeInPixels;
226  dc->GetSize( &PlotAreaSizeInPixels.x, &PlotAreaSizeInPixels.y );
227  wxLogTrace( tracePrinting, wxT( "Plot area in pixels: x=%d, y=%d" ),
228  PlotAreaSizeInPixels.x, PlotAreaSizeInPixels.y );
229  double scalex, scaley;
230  dc->GetUserScale( &scalex, &scaley );
231  wxLogTrace( tracePrinting, wxT( "DC user scale: x=%g, y=%g" ),
232  scalex, scaley );
233 
234  wxSize PlotAreaSizeInUserUnits;
235  PlotAreaSizeInUserUnits.x = KiROUND( PlotAreaSizeInPixels.x / scalex );
236  PlotAreaSizeInUserUnits.y = KiROUND( PlotAreaSizeInPixels.y / scaley );
237  wxLogTrace( tracePrinting, wxT( "Scaled plot area in user units: x=%d, y=%d" ),
238  PlotAreaSizeInUserUnits.x, PlotAreaSizeInUserUnits.y );
239 
240  // In module editor, the module is located at 0,0 but for printing
241  // it is moved to pageSizeIU.x/2, pageSizeIU.y/2.
242  // So the equivalent board must be moved to the center of the page:
244  {
245  boardBoundingBox.Move( wxPoint( pageSizeIU.x/2, pageSizeIU.y/2 ) );
246  }
247 
248  // In some cases the plot origin is the centre of the board outline rather than the center
249  // of the selected paper size.
251  {
252  // Here we are only drawing the board and it's contents.
253  drawRect = boardBoundingBox;
254  offset.x += wxRound( (double) -scaledPageSize.x / 2.0 );
255  offset.y += wxRound( (double) -scaledPageSize.y / 2.0 );
256 
257  wxPoint center = boardBoundingBox.Centre();
258 
259  if( printMirror )
260  {
261  // Calculate the mirrored center of the board.
262  center.x = m_Parent->GetPageSizeIU().x - boardBoundingBox.Centre().x;
263  }
264 
265  offset += center;
266  }
267 
268  GRResetPenAndBrush( dc );
269 
270  EDA_DRAW_PANEL* panel = m_Parent->GetCanvas();
271  EDA_RECT tmp = *panel->GetClipBox();
272 
273  // Set clip box to the max size
274  #define MAX_VALUE (INT_MAX/2) // MAX_VALUE is the max we can use in an integer
275  // and that allows calculations without overflow
276  panel->SetClipBox( EDA_RECT( wxPoint( 0, 0 ), wxSize( MAX_VALUE, MAX_VALUE ) ) );
277 
278  screen->m_IsPrinting = true;
279  COLOR4D bg_color = m_Parent->GetDrawBgColor();
280 
281  // Print frame reference, if requested, before
283  GRForceBlackPen( true );
284 
286  {
287  tempScreenNumber = screen->m_ScreenNumber;
288  tempNumberOfScreens = screen->m_NumberOfScreens;
289  screen->m_ScreenNumber = aPageNum;
290  screen->m_NumberOfScreens = aPageCount;
292  IU_PER_MILS, titleblockFilename, aLayerName );
293  screen->m_ScreenNumber = tempScreenNumber;
294  screen->m_NumberOfScreens = tempNumberOfScreens;
295  }
296 
297  if( printMirror )
298  {
299  // To plot mirror, we reverse the x axis, and modify the plot x origin
300  dc->SetAxisOrientation( false, false);
301 
302  /* Plot offset x is moved by the x plot area size in order to have
303  * the old draw area in the new draw area, because the draw origin has not moved
304  * (this is the upper left corner) but the X axis is reversed, therefore the plotting area
305  * is the x coordinate values from - PlotAreaSize.x to 0 */
306  int x_dc_offset = PlotAreaSizeInPixels.x;
307  x_dc_offset = KiROUND( x_dc_offset * userscale );
308  dc->SetDeviceOrigin( x_dc_offset, 0 );
309 
310  wxLogTrace( tracePrinting, wxT( "Device origin: x=%d, y=%d" ),
311  x_dc_offset, 0 );
312 
313  panel->SetClipBox( EDA_RECT( wxPoint( -MAX_VALUE/2, -MAX_VALUE/2 ),
314  panel->GetClipBox()->GetSize() ) );
315  }
316 
317  // screen->m_DrawOrg = offset;
318  dc->SetLogicalOrigin( offset.x, offset.y );
319 
320  wxLogTrace( tracePrinting, wxT( "Logical origin: x=%d, y=%d" ),
321  offset.x, offset.y );
322 
323 #if defined(wxUSE_LOG_TRACE) && defined( DEBUG )
324  wxRect paperRect = GetPaperRectPixels();
325  wxLogTrace( tracePrinting, wxT( "Paper rectangle: left=%d, top=%d, "
326  "right=%d, bottom=%d" ),
327  paperRect.GetLeft(), paperRect.GetTop(), paperRect.GetRight(),
328  paperRect.GetBottom() );
329 
330  int devLeft = dc->LogicalToDeviceX( drawRect.GetX() );
331  int devTop = dc->LogicalToDeviceY( drawRect.GetY() );
332  int devRight = dc->LogicalToDeviceX( drawRect.GetRight() );
333  int devBottom = dc->LogicalToDeviceY( drawRect.GetBottom() );
334  wxLogTrace( tracePrinting, wxT( "Final device rectangle: left=%d, top=%d, "
335  "right=%d, bottom=%d\n" ),
336  devLeft, devTop, devRight, devBottom );
337 #endif
338 
340 
341  /* when printing in color mode, we use the graphic OR mode that gives the same look as
342  * the screen but because the background is white when printing, we must use a trick:
343  * In order to plot on a white background in OR mode we must:
344  * 1 - Plot all items in black, this creates a local black background
345  * 2 - Plot in OR mode on black "local" background
346  */
348  {
349  // Creates a "local" black background
350  GRForceBlackPen( true );
352  printMirror, &m_PrintParams );
353  GRForceBlackPen( false );
354  }
355  else
356  GRForceBlackPen( true );
357 
358 
360  &m_PrintParams );
361 
362  m_Parent->SetDrawBgColor( bg_color );
363  screen->m_IsPrinting = false;
364  panel->SetClipBox( tmp );
365  GRForceBlackPen( false );
366 }
void GRResetPenAndBrush(wxDC *DC)
Definition: gr_basic.cpp:218
BOARD_PRINTOUT_CONTROLLER(const PRINT_PARAMETERS &aParams, EDA_DRAW_FRAME *aParent, const wxString &aTitle)
void Move(const wxPoint &aMoveVector)
Function Move moves the rectangle by the aMoveVector.
int m_ScreenNumber
Definition: base_screen.h:216
static int KiROUND(double v)
Round a floating point number to an integer using "round halfway cases away from zero".
Definition: common.h:106
Board print handler definition file.
Implementation of conversion functions that require both schematic and board internal units...
This file is part of the common library.
EDA_DRAW_PANEL * GetCanvas()
Definition: draw_frame.h:359
const wxSize GetSize() const
Definition: eda_rect.h:101
EDA_RECT ComputeBoundingBox(bool aBoardEdgesOnly=false) const
Function ComputeBoundingBox calculates the bounding box containing all board items (or board edge seg...
Class BOARD to handle a board.
const wxChar *const tracePrinting
Flag to enable print controller debug output.
Class PRINT_PARAMETERS handles the parameters used to print a board drawing.
bool PrintBorderAndTitleBlock() const
Function PrintBorderAndTitleBlock returns true if the drawing border and title block should be printe...
int GetHeight() const
Definition: eda_rect.h:118
virtual void SetDrawBgColor(COLOR4D aColor)
Definition: draw_frame.h:351
void GetPageInfo(int *minPage, int *maxPage, int *selPageFrom, int *selPageTo) override
void DrawPage(const wxString &aLayerName=wxEmptyString, int aPageNum=1, int aPageCount=1)
Print a page ( or a set of pages ).
Class EDA_DRAW_FRAME is the base class for create windows for drawing purpose.
Definition: draw_frame.h:63
virtual const wxSize GetPageSizeIU() const =0
Function GetPageSizeIU works off of GetPageSettings() to return the size of the paper page in the int...
void SetClipBox(const EDA_RECT &aRect)
PCB_LAYER_ID ExtractLayer() const
Find the first set PCB_LAYER_ID.
Definition: lset.cpp:612
Classes used in Pcbnew, CvPcb and GerbView.
PCB_LAYER_ID
A quick note on layer IDs:
virtual BASE_SCREEN * GetScreen() const
Function GetScreen returns a pointer to a BASE_SCREEN or one of its derivatives.
Definition: draw_frame.h:369
Class LSET is a set of PCB_LAYER_IDs.
virtual COLOR4D GetDrawBgColor() const
Definition: draw_frame.h:346
virtual void PrintPage(wxDC *aDC, LSET aPrintMask, bool aPrintMirrorMode, void *aData=NULL)
Function PrintPage used to print a page Print the page pointed by current screen, set by the calling ...
Definition: draw_frame.cpp:450
void GRForceBlackPen(bool flagforce)
Function GRForceBlackPen.
Definition: gr_basic.cpp:299
static const wxChar * Name(PCB_LAYER_ID aLayerId)
Function Name returns the fixed name association with aLayerId.
Definition: lset.cpp:73
const wxString & GetFileName() const
Definition: class_board.h:236
Class BASE_SCREEN handles how to draw a screen (a board, a schematic ...)
Definition: base_screen.h:76
bool OnPrintPage(int aPage) override
EDA_RECT * GetClipBox()
DrillShapeOptT m_DrillShapeOpt
wxLogTrace helper definitions.
int GetBottom() const
Definition: eda_rect.h:122
wxPoint Centre() const
Definition: eda_rect.h:60
int GetRight() const
Definition: eda_rect.h:119
bool m_IsPrinting
Definition: base_screen.h:220
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
wxPageSetupDialogData * m_PageSetupData
void SetSize(const wxSize &size)
Definition: eda_rect.h:126
#define MAX_VALUE
see class PGM_BASE
static LIB_PART * dummy()
Used when a LIB_PART is not found in library to draw a dummy shape This component is a 400 mils squar...
Class BOARD holds information pertinent to a Pcbnew printed circuit board.
Definition: class_board.h:169
Class EDA_RECT handles the component boundary box.
Definition: eda_rect.h:44
int GetX() const
Definition: eda_rect.h:109
int GetWidth() const
Definition: eda_rect.h:117
bool CenterOnBoardOutline() const
Function CenterOnBoardOutline returns true if the print should be centered by the board outline inste...
Definition: colors.h:49
int GetY() const
Definition: eda_rect.h:110
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
int m_NumberOfScreens
Definition: base_screen.h:217
bool IsType(FRAME_T aType) const
void DrawWorkSheet(wxDC *aDC, BASE_SCREEN *aScreen, int aLineWidth, double aScale, const wxString &aFilename, const wxString &aSheetLayer=wxEmptyString)
Function DrawWorkSheet Draws on screen the page layout with the frame and the basic inscriptions...
Definition: worksheet.cpp:76
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
LSEQ UIOrder() const
Definition: lset.cpp:786
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39