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