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-2017 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 
44 #include <printout_controler.h>
45 
46 
52 static const wxString tracePrinting = wxT( "KICAD_TRACE_PCB_PRINT" );
53 
54 
56 {
57  m_PenDefaultSize = Millimeter2iu( 0.2 ); // A reasonable default value to draw items
58  // which do not have a specified line width
59  m_PrintScale = 1.0;
60  m_XScaleAdjust = 1.0;
61  m_YScaleAdjust = 1.0;
62  m_Print_Sheet_Ref = false;
63  m_PrintMaskLayer.set();
64  m_PrintMirror = false;
67  m_PageCount = 1;
68  m_ForceCentered = false;
69  m_Flags = 0;
71  m_PageSetupData = NULL;
72 }
73 
74 
76  EDA_DRAW_FRAME* aParent,
77  const wxString& aTitle ) :
78  wxPrintout( aTitle )
79 {
80  m_PrintParams = aParams; // Make a local copy of the print parameters.
81  m_Parent = aParent;
82 }
83 
84 
86 {
88  int pageCount = lset.count();
89  wxString layer;
90  PCB_LAYER_ID extractLayer;
91 
92  // compute layer mask from page number if we want one page per layer
93  if( m_PrintParams.m_OptionPrintPage == 0 ) // One page per layer
94  {
95  // This sequence is TBD, call a different
96  // sequencer if needed, such as Seq(). Could not find documentation on
97  // page order.
98  LSEQ seq = lset.UIOrder();
99 
100  // aPage starts at 1, not 0
101  if( unsigned( aPage-1 ) < seq.size() )
102  m_PrintParams.m_PrintMaskLayer = LSET( seq[aPage-1] );
103  }
104 
105  if( !m_PrintParams.m_PrintMaskLayer.any() )
106  return false;
107 
109  if( extractLayer == UNDEFINED_LAYER )
110  layer = _( "Multiple Layers" );
111  else
112  layer = LSET::Name( extractLayer );
113 
114  // In Pcbnew we can want the layer EDGE always printed
115  if( m_PrintParams.m_Flags == 1 )
117 
118  DrawPage( layer, aPage, pageCount );
119 
121 
122  return true;
123 }
124 
125 
126 void BOARD_PRINTOUT_CONTROLLER::GetPageInfo( int* minPage, int* maxPage,
127  int* selPageFrom, int* selPageTo )
128 {
129  *minPage = 1;
130  *selPageFrom = 1;
131 
132  int icnt = 1;
133 
135  icnt = m_PrintParams.m_PageCount;
136 
137  *maxPage = icnt;
138  *selPageTo = icnt;
139 }
140 
141 
142 void BOARD_PRINTOUT_CONTROLLER::DrawPage( const wxString& aLayerName, int aPageNum, int aPageCount )
143 {
144  wxPoint offset;
145  double userscale;
146  EDA_RECT boardBoundingBox;
147  EDA_RECT drawRect;
148  wxDC* dc = GetDC();
149  BASE_SCREEN* screen = m_Parent->GetScreen();
150  bool printMirror = m_PrintParams.m_PrintMirror;
151  wxSize pageSizeIU = m_Parent->GetPageSizeIU();
152  int tempScreenNumber;
153  int tempNumberOfScreens;
154 
155  wxBusyCursor dummy;
156 
157  BOARD* brd = ((PCB_BASE_FRAME*) m_Parent)->GetBoard();
158  boardBoundingBox = brd->ComputeBoundingBox();
159  const wxString& titleblockFilename = brd->GetFileName();
160 
161  // Use the page size as the drawing area when the board is shown or the user scale
162  // is less than 1.
164  boardBoundingBox = EDA_RECT( wxPoint( 0, 0 ), pageSizeIU );
165 
166  wxLogTrace( tracePrinting, wxT( "Drawing bounding box: x=%d, y=%d, w=%d, h=%d" ),
167  boardBoundingBox.GetX(), boardBoundingBox.GetY(),
168  boardBoundingBox.GetWidth(), boardBoundingBox.GetHeight() );
169 
170  // Compute the PCB size in internal units
171  userscale = m_PrintParams.m_PrintScale;
172 
173  if( m_PrintParams.m_PrintScale == 0 ) // fit in page option
174  {
175  if( boardBoundingBox.GetWidth() && boardBoundingBox.GetHeight() )
176  {
177  int margin = Millimeter2iu( 10.0 ); // add a margin around the drawings
178  double scaleX = (double)(pageSizeIU.x - (2 * margin)) /
179  boardBoundingBox.GetWidth();
180  double scaleY = (double)(pageSizeIU.y - (2 * margin)) /
181  boardBoundingBox.GetHeight();
182  userscale = (scaleX < scaleY) ? scaleX : scaleY;
183  }
184  else
185  userscale = 1.0;
186  }
187 
188  wxSize scaledPageSize = pageSizeIU;
189  drawRect.SetSize( scaledPageSize );
190  scaledPageSize.x = wxRound( scaledPageSize.x / userscale );
191  scaledPageSize.y = wxRound( scaledPageSize.y / userscale );
192 
193 
195  {
196  wxLogTrace( tracePrinting, wxT( "Fit size to page margins: x=%d, y=%d" ),
197  scaledPageSize.x, scaledPageSize.y );
198 
199  // Always scale to the size of the paper.
200  FitThisSizeToPageMargins( scaledPageSize, *m_PrintParams.m_PageSetupData );
201  }
202 
203  // Compute Accurate scale 1
204  if( m_PrintParams.m_PrintScale == 1.0 )
205  {
206  // We want a 1:1 scale, regardless the page setup
207  // like page size, margin ...
208  MapScreenSizeToPaper(); // set best scale and offset (scale is not used)
209  int w, h;
210  GetPPIPrinter( &w, &h );
211  double accurate_Xscale = (double) w / (IU_PER_MILS*1000);
212  double accurate_Yscale = (double) h / (IU_PER_MILS*1000);
213 
214  if( IsPreview() ) // Scale must take in account the DC size in Preview
215  {
216  // Get the size of the DC in pixels
217  wxSize PlotAreaSize;
218  dc->GetSize( &PlotAreaSize.x, &PlotAreaSize.y );
219  GetPageSizePixels( &w, &h );
220  accurate_Xscale *= (double)PlotAreaSize.x / w;
221  accurate_Yscale *= (double)PlotAreaSize.y / h;
222  }
223  // Fine scale adjust
224  accurate_Xscale *= m_PrintParams.m_XScaleAdjust;
225  accurate_Yscale *= m_PrintParams.m_YScaleAdjust;
226 
227  // Set print scale for 1:1 exact scale
228  dc->SetUserScale( accurate_Xscale, accurate_Yscale );
229  }
230 
231  // Get the final size of the DC in pixels
232  wxSize PlotAreaSizeInPixels;
233  dc->GetSize( &PlotAreaSizeInPixels.x, &PlotAreaSizeInPixels.y );
234  wxLogTrace( tracePrinting, wxT( "Plot area in pixels: x=%d, y=%d" ),
235  PlotAreaSizeInPixels.x, PlotAreaSizeInPixels.y );
236  double scalex, scaley;
237  dc->GetUserScale( &scalex, &scaley );
238  wxLogTrace( tracePrinting, wxT( "DC user scale: x=%g, y=%g" ),
239  scalex, scaley );
240 
241  wxSize PlotAreaSizeInUserUnits;
242  PlotAreaSizeInUserUnits.x = KiROUND( PlotAreaSizeInPixels.x / scalex );
243  PlotAreaSizeInUserUnits.y = KiROUND( PlotAreaSizeInPixels.y / scaley );
244  wxLogTrace( tracePrinting, wxT( "Scaled plot area in user units: x=%d, y=%d" ),
245  PlotAreaSizeInUserUnits.x, PlotAreaSizeInUserUnits.y );
246 
247  // In module editor, the module is located at 0,0 but for printing
248  // it is moved to pageSizeIU.x/2, pageSizeIU.y/2.
249  // So the equivalent board must be moved to the center of the page:
251  {
252  boardBoundingBox.Move( wxPoint( pageSizeIU.x/2, pageSizeIU.y/2 ) );
253  }
254 
255  // In some cases the plot origin is the centre of the board outline rather than the center
256  // of the selected paper size.
258  {
259  // Here we are only drawing the board and it's contents.
260  drawRect = boardBoundingBox;
261  offset.x += wxRound( (double) -scaledPageSize.x / 2.0 );
262  offset.y += wxRound( (double) -scaledPageSize.y / 2.0 );
263 
264  wxPoint center = boardBoundingBox.Centre();
265 
266  if( printMirror )
267  {
268  // Calculate the mirrored center of the board.
269  center.x = m_Parent->GetPageSizeIU().x - boardBoundingBox.Centre().x;
270  }
271 
272  offset += center;
273  }
274 
275  GRResetPenAndBrush( dc );
276 
277  EDA_DRAW_PANEL* panel = m_Parent->GetCanvas();
278  EDA_RECT tmp = *panel->GetClipBox();
279 
280  // Set clip box to the max size
281  #define MAX_VALUE (INT_MAX/2) // MAX_VALUE is the max we can use in an integer
282  // and that allows calculations without overflow
283  panel->SetClipBox( EDA_RECT( wxPoint( 0, 0 ), wxSize( MAX_VALUE, MAX_VALUE ) ) );
284 
285  screen->m_IsPrinting = true;
286  COLOR4D bg_color = m_Parent->GetDrawBgColor();
287 
288  // Print frame reference, if requested, before
290  GRForceBlackPen( true );
291 
293  {
294  tempScreenNumber = screen->m_ScreenNumber;
295  tempNumberOfScreens = screen->m_NumberOfScreens;
296  screen->m_ScreenNumber = aPageNum;
297  screen->m_NumberOfScreens = aPageCount;
299  IU_PER_MILS, titleblockFilename, aLayerName );
300  screen->m_ScreenNumber = tempScreenNumber;
301  screen->m_NumberOfScreens = tempNumberOfScreens;
302  }
303 
304  if( printMirror )
305  {
306  // To plot mirror, we reverse the x axis, and modify the plot x origin
307  dc->SetAxisOrientation( false, false);
308 
309  /* Plot offset x is moved by the x plot area size in order to have
310  * the old draw area in the new draw area, because the draw origin has not moved
311  * (this is the upper left corner) but the X axis is reversed, therefore the plotting area
312  * is the x coordinate values from - PlotAreaSize.x to 0 */
313  int x_dc_offset = PlotAreaSizeInPixels.x;
314  x_dc_offset = KiROUND( x_dc_offset * userscale );
315  dc->SetDeviceOrigin( x_dc_offset, 0 );
316 
317  wxLogTrace( tracePrinting, wxT( "Device origin: x=%d, y=%d" ),
318  x_dc_offset, 0 );
319 
320  panel->SetClipBox( EDA_RECT( wxPoint( -MAX_VALUE/2, -MAX_VALUE/2 ),
321  panel->GetClipBox()->GetSize() ) );
322  }
323 
324  // screen->m_DrawOrg = offset;
325  dc->SetLogicalOrigin( offset.x, offset.y );
326 
327  wxLogTrace( tracePrinting, wxT( "Logical origin: x=%d, y=%d" ),
328  offset.x, offset.y );
329 
330 #if defined(wxUSE_LOG_TRACE) && defined( DEBUG )
331  wxRect paperRect = GetPaperRectPixels();
332  wxLogTrace( tracePrinting, wxT( "Paper rectangle: left=%d, top=%d, "
333  "right=%d, bottom=%d" ),
334  paperRect.GetLeft(), paperRect.GetTop(), paperRect.GetRight(),
335  paperRect.GetBottom() );
336 
337  int devLeft = dc->LogicalToDeviceX( drawRect.GetX() );
338  int devTop = dc->LogicalToDeviceY( drawRect.GetY() );
339  int devRight = dc->LogicalToDeviceX( drawRect.GetRight() );
340  int devBottom = dc->LogicalToDeviceY( drawRect.GetBottom() );
341  wxLogTrace( tracePrinting, wxT( "Final device rectangle: left=%d, top=%d, "
342  "right=%d, bottom=%d\n" ),
343  devLeft, devTop, devRight, devBottom );
344 #endif
345 
347 
348  /* when printing in color mode, we use the graphic OR mode that gives the same look as
349  * the screen but because the background is white when printing, we must use a trick:
350  * In order to plot on a white background in OR mode we must:
351  * 1 - Plot all items in black, this creates a local black background
352  * 2 - Plot in OR mode on black "local" background
353  */
355  {
356  // Creates a "local" black background
357  GRForceBlackPen( true );
359  printMirror, &m_PrintParams );
360  GRForceBlackPen( false );
361  }
362  else
363  GRForceBlackPen( true );
364 
365 
367  &m_PrintParams );
368 
369  m_Parent->SetDrawBgColor( bg_color );
370  screen->m_IsPrinting = false;
371  panel->SetClipBox( tmp );
372  GRForceBlackPen( false );
373 }
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)
KiROUND rounds a floating point number to an int using "round halfway cases away from zero"...
Definition: common.h:107
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:342
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.
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:334
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:54
static const wxString tracePrinting
Flag to enable PCB print controller debug output.
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:352
Class LSET is a set of PCB_LAYER_IDs.
virtual COLOR4D GetDrawBgColor() const
Definition: draw_frame.h:329
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:408
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:234
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
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