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 <wxBasePcbFrame.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  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:196
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.
static int KiROUND(double v)
KiROUND rounds a floating point number to an int 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:337
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
virtual void SetDrawBgColor(COLOR4D aColor)
Definition: draw_frame.h:329
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:585
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:347
Class LSET is a set of PCB_LAYER_IDs.
Classes used in Pcbnew, CvPcb and GerbView.
virtual COLOR4D GetDrawBgColor() const
Definition: draw_frame.h:324
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:405
void GRForceBlackPen(bool flagforce)
Function GRForceBlackPen.
Definition: gr_basic.cpp:277
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 ...)
bool OnPrintPage(int aPage) override
EDA_RECT * GetClipBox()
DrillShapeOptT m_DrillShapeOpt
int GetBottom() const
wxPoint Centre() const
int GetRight() const
Class LSEQ is a sequence (and therefore also a set) of PCB_LAYER_IDs.
wxPageSetupDialogData * m_PageSetupData
void SetSize(const wxSize &size)
#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.
int GetX() const
int GetWidth() const
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
virtual BOARD * GetBoard() const
Function GetBoard returns the BOARD in which this BOARD_ITEM resides, or NULL if none.
bool IsType(FRAME_T aType) const
Definition: wxstruct.h:229
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:77
const wxSize & GetSize() const
class PCB_BASE_FRAME basic PCB main window class for Pcbnew, Gerbview, and CvPcb footprint viewer...
LSEQ UIOrder() const
Definition: lset.cpp:759
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39