KiCad PCB EDA Suite
class_gbr_layout.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) 2012-2014 Jean-Pierre Charras jp.charras at wanadoo.fr
5  * Copyright (C) 1992-2014 KiCad Developers, see change_log.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 
30 #include <fctsys.h>
31 #include <gr_basic.h>
32 #include <drawtxt.h>
33 #include <gerbview_frame.h>
34 #include <class_drawpanel.h>
35 #include <class_gbr_layout.h>
38 
41 {
42 }
43 
44 
46 {
47 }
48 
49 // Accessor to the list of gerber files (and drill files) images
51 {
53 }
54 
55 
56 bool GBR_LAYOUT::IsLayerPrintable( int aLayer ) const
57 {
58  for( unsigned ii = 0; ii < m_printLayersList.size(); ++ii )
59  {
60  if( m_printLayersList[ii] == aLayer )
61  return true;
62  }
63 
64  return false;
65 }
66 
67 
69 {
70  EDA_RECT bbox;
71  bool first_item = true;
72 
73  for( unsigned layer = 0; layer < GetImagesList()->ImagesMaxCount(); ++layer )
74  {
75  GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
76 
77  if( gerber == NULL ) // Graphic layer not yet used
78  continue;
79 
80  for( GERBER_DRAW_ITEM* item = gerber->GetItemsList(); item; item = item->Next() )
81  {
82  if( first_item )
83  {
84  bbox = item->GetBoundingBox();
85  first_item = false;
86  }
87  else
88  bbox.Merge( item->GetBoundingBox() );
89  }
90  }
91 
92  bbox.Inflate( ( bbox.GetWidth() / 10 ) + 100 );
93  bbox.Normalize();
94 
95  m_BoundingBox = bbox;
96  return bbox;
97 }
98 
99 
100 // Redraw All GerbView layers, using a buffered mode or not
101 void GBR_LAYOUT::Draw( EDA_DRAW_PANEL* aPanel, wxDC* aDC, GR_DRAWMODE aDrawMode,
102  const wxPoint& aOffset, GBR_DISPLAY_OPTIONS* aDisplayOptions )
103 {
104  GERBVIEW_FRAME* gerbFrame = (GERBVIEW_FRAME*) aPanel->GetParent();
105 
106  // Collect the highlight selections
107  wxString cmpHighlight;
108 
109  if( gerbFrame->m_SelComponentBox->GetSelection() > 0 )
110  cmpHighlight = gerbFrame->m_SelComponentBox->GetStringSelection();
111 
112  wxString netHighlight;
113 
114  if( gerbFrame->m_SelNetnameBox->GetSelection() > 0 )
115  netHighlight = gerbFrame->m_SelNetnameBox->GetStringSelection();
116 
117  wxString aperAttrHighlight = gerbFrame->m_SelAperAttributesBox->GetStringSelection();
118 
119  if( gerbFrame->m_SelAperAttributesBox->GetSelection() > 0 )
120  aperAttrHighlight = gerbFrame->m_SelAperAttributesBox->GetStringSelection();
121 
122 
123  // Because Images can be negative (i.e with background filled in color) items are drawn
124  // graphic layer per graphic layer, after the background is filled
125  // to a temporary bitmap
126  // at least when aDrawMode = GR_COPY or aDrawMode = GR_OR
127  // If aDrawMode = UNSPECIFIED_DRAWMODE, items are drawn to the main screen, and therefore
128  // artifacts can happen with negative items or negative images
129 
130  int bitmapWidth, bitmapHeight;
131  wxDC* plotDC = aDC;
132 
133  aPanel->GetClientSize( &bitmapWidth, &bitmapHeight );
134 
135  wxBitmap* layerBitmap = NULL;
136  wxBitmap* screenBitmap = NULL;
137  wxMemoryDC layerDC; // used sequentially for each gerber layer
138  wxMemoryDC screenDC;
139 
140  // When each image must be drawn using GR_OR (transparency mode)
141  // or GR_COPY (stacked mode) we must use a temporary bitmap
142  // to draw gerber images.
143  // this is due to negative objects (drawn using background color) that create artifacts
144  // on other images when drawn on screen
145  bool useBufferBitmap = false;
146 
147 #ifndef __WXMAC__
148  // Can't work with MAC
149  // Don't try this with retina display
150  if( (aDrawMode == GR_COPY) || ( aDrawMode == GR_OR ) )
151  useBufferBitmap = true;
152 #endif
153 
154  // these parameters are saved here, because they are modified
155  // and restored later
156  EDA_RECT drawBox = *aPanel->GetClipBox();
157  double scale;
158  aDC->GetUserScale(&scale, &scale);
159  wxPoint dev_org = aDC->GetDeviceOrigin();
160  wxPoint logical_org = aDC->GetLogicalOrigin( );
161 
162  COLOR4D bgColor = aDisplayOptions->m_BgDrawColor;
163  wxBrush bgBrush( bgColor.ToColour(), wxBRUSHSTYLE_SOLID );
164 
165  if( useBufferBitmap )
166  {
167  layerBitmap = new wxBitmap( bitmapWidth, bitmapHeight );
168  screenBitmap = new wxBitmap( bitmapWidth, bitmapHeight );
169  layerDC.SelectObject( *layerBitmap );
170  aPanel->DoPrepareDC( layerDC );
171  aPanel->SetClipBox( drawBox );
172  layerDC.SetBackground( bgBrush );
173  layerDC.SetBackgroundMode( wxSOLID );
174  layerDC.Clear();
175 
176  screenDC.SelectObject( *screenBitmap );
177  screenDC.SetBackground( bgBrush );
178  screenDC.SetBackgroundMode( wxSOLID );
179  screenDC.Clear();
180 
181  plotDC = &layerDC;
182  }
183 
184  bool doBlit = false; // this flag requests an image transfer to actual screen when true.
185 
186  bool end = false;
187 
188  // Draw graphic layers from bottom to top, and the active layer is on the top of others.
189  // In non transparent modes, the last layer drawn masks others layers
190  for( int layer = GERBER_DRAWLAYERS_COUNT-1; !end; --layer )
191  {
192  int active_layer = gerbFrame->GetActiveLayer();
193 
194  if( layer == active_layer ) // active layer will be drawn after other layers
195  continue;
196 
197  if( layer < 0 ) // last loop: draw active layer
198  {
199  end = true;
200  layer = active_layer;
201  }
202 
203  GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
204 
205  if( gerber == NULL ) // Graphic layer not yet used
206  continue;
207 
208  if( aDisplayOptions->m_IsPrinting )
209  gerber->m_IsVisible = IsLayerPrintable( layer );
210  else
211  gerber->m_IsVisible = gerbFrame->IsLayerVisible( GERBER_DRAW_LAYER( layer ) );
212 
213  if( !gerber->m_IsVisible )
214  continue;
215 
216  gerber->m_PositiveDrawColor = gerbFrame->GetLayerColor( GERBER_DRAW_LAYER( layer ) );
217 
218  // Force black and white draw mode on request:
219  if( aDisplayOptions->m_ForceBlackAndWhite )
220  gerber->m_PositiveDrawColor = ( aDisplayOptions->m_BgDrawColor == BLACK ) ? WHITE : BLACK;
221 
222  if( useBufferBitmap )
223  {
224  // Draw each layer into a bitmap first. Negative Gerber
225  // layers are drawn in background color.
226  if( gerber->HasNegativeItems() && doBlit )
227  {
228  // Set Device origin, logical origin and scale to default values
229  // This is needed by Blit function when using a mask.
230  // Beside, for Blit call, both layerDC and screenDc must have the same settings
231  layerDC.SetDeviceOrigin(0,0);
232  layerDC.SetLogicalOrigin( 0, 0 );
233  layerDC.SetUserScale( 1, 1 );
234 
235  if( aDrawMode == GR_COPY )
236  {
237  // Use the layer bitmap itself as a mask when blitting. The bitmap
238  // cannot be referenced by a device context when setting the mask.
239  layerDC.SelectObject( wxNullBitmap );
240  layerBitmap->SetMask( new wxMask( *layerBitmap, bgColor.ToColour() ) );
241  layerDC.SelectObject( *layerBitmap );
242  screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxCOPY, true );
243  }
244  else if( aDrawMode == GR_OR )
245  {
246  // On Linux with a large screen, this version is much faster and without
247  // flicker, but gives a Pcbnew look where layer colors blend together.
248  // Plus it works only because the background color is black. But it may
249  // be more usable for some. The difference is due in part because of
250  // the cpu cycles needed to create the monochromatic bitmap above, and
251  // the extra time needed to do bit indexing into the monochromatic bitmap
252  // on the blit above.
253  screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxOR );
254  }
255  // Restore actual values and clear bitmap for next drawing
256  layerDC.SetDeviceOrigin( dev_org.x, dev_org.y );
257  layerDC.SetLogicalOrigin( logical_org.x, logical_org.y );
258  layerDC.SetUserScale( scale, scale );
259  layerDC.SetBackground( bgBrush );
260  layerDC.SetBackgroundMode( wxSOLID );
261  layerDC.Clear();
262 
263  doBlit = false;
264  }
265 
266  }
267 
268  if( gerber->m_ImageNegative )
269  {
270  // Draw background negative (i.e. in graphic layer color) for negative images.
271  COLOR4D neg_color = gerber->GetPositiveDrawColor();
272 
273  GRSetDrawMode( &layerDC, GR_COPY );
274  GRFilledRect( &drawBox, plotDC, drawBox.GetX(), drawBox.GetY(),
275  drawBox.GetRight(), drawBox.GetBottom(),
276  0, neg_color, neg_color );
277 
278  GRSetDrawMode( plotDC, GR_COPY );
279  doBlit = true;
280  }
281 
282  int dcode_highlight = 0;
283 
284  if( layer == gerbFrame->GetActiveLayer() )
285  dcode_highlight = gerber->m_Selected_Tool;
286 
287  GR_DRAWMODE layerdrawMode = GR_COPY;
288 
289  if( aDrawMode == GR_OR && !gerber->HasNegativeItems() )
290  layerdrawMode = GR_OR;
291 
292  // Now we can draw the current layer to the bitmap buffer
293  // When needed, the previous bitmap is already copied to the screen buffer.
294  for( GERBER_DRAW_ITEM* item = gerber->GetItemsList(); item; item = item->Next() )
295  {
296  if( item->GetLayer() != layer )
297  continue;
298 
299  GR_DRAWMODE drawMode = layerdrawMode;
300 
301  if( dcode_highlight && dcode_highlight == item->m_DCode )
302  DrawModeAddHighlight( &drawMode);
303 
304  if( !aperAttrHighlight.IsEmpty() && item->GetDcodeDescr() &&
305  item->GetDcodeDescr()->m_AperFunction == aperAttrHighlight )
306  DrawModeAddHighlight( &drawMode);
307 
308  if( !cmpHighlight.IsEmpty() &&
309  cmpHighlight == item->GetNetAttributes().m_Cmpref )
310  DrawModeAddHighlight( &drawMode);
311 
312  if( !netHighlight.IsEmpty() &&
313  netHighlight == item->GetNetAttributes().m_Netname )
314  DrawModeAddHighlight( &drawMode);
315 
316  item->Draw( aPanel, plotDC, drawMode, wxPoint(0,0), aDisplayOptions );
317  doBlit = true;
318  }
319  }
320 
321  if( doBlit && useBufferBitmap ) // Blit is used only if aDrawMode >= 0
322  {
323  // For this Blit call, layerDC and screenDC must have the same settings
324  // So we set device origin, logical origin and scale to default values
325  // in layerDC
326  layerDC.SetDeviceOrigin(0,0);
327  layerDC.SetLogicalOrigin( 0, 0 );
328  layerDC.SetUserScale( 1, 1 );
329 
330  // this is the last transfer to screenDC. If there are no negative items, this is
331  // the only one
332  if( aDrawMode == GR_COPY )
333  {
334  layerDC.SelectObject( wxNullBitmap );
335  layerBitmap->SetMask( new wxMask( *layerBitmap, bgColor.ToColour() ) );
336  layerDC.SelectObject( *layerBitmap );
337  screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxCOPY, true );
338 
339  }
340  else if( aDrawMode == GR_OR )
341  {
342  screenDC.Blit( 0, 0, bitmapWidth, bitmapHeight, &layerDC, 0, 0, wxOR );
343  }
344  }
345 
346  if( useBufferBitmap )
347  {
348  // For this Blit call, aDC and screenDC must have the same settings
349  // So we set device origin, logical origin and scale to default values
350  // in aDC
351  aDC->SetDeviceOrigin( 0, 0);
352  aDC->SetLogicalOrigin( 0, 0 );
353  aDC->SetUserScale( 1, 1 );
354 
355  aDC->Blit( 0, 0, bitmapWidth, bitmapHeight, &screenDC, 0, 0, wxCOPY );
356 
357  // Restore aDC values
358  aDC->SetDeviceOrigin(dev_org.x, dev_org.y);
359  aDC->SetLogicalOrigin( logical_org.x, logical_org.y );
360  aDC->SetUserScale( scale, scale );
361 
362  layerDC.SelectObject( wxNullBitmap );
363  screenDC.SelectObject( wxNullBitmap );
364  delete layerBitmap;
365  delete screenBitmap;
366  }
367 }
368 
369 
371  GR_DRAWMODE aDrawMode, COLOR4D aDrawColor )
372 {
373  wxString Line;
374 
375  GRSetDrawMode( aDC, aDrawMode );
376 
377  for( unsigned layer = 0; layer < GetImagesList()->ImagesMaxCount(); ++layer )
378  {
379  GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
380 
381  if( gerber == NULL ) // Graphic layer not yet used
382  continue;
383 
384  if( ! gerber->m_IsVisible )
385  continue;
386 
387  for( GERBER_DRAW_ITEM* item = gerber->GetItemsList(); item != NULL; item = item->Next() )
388  {
389  wxPoint pos;
390  int size;
391  double orient;
392 
393  if( ! item->GetTextD_CodePrms( size, pos, orient ) )
394  continue;
395 
396  Line.Printf( wxT( "D%d" ), item->m_DCode );
397 
398  // Avoid to draw text, if it is too small (size in pixel < 5 pixels)
399  // to be readable:
400  int size_pixel = aDC->LogicalToDeviceXRel( size );
401  const int threshold = 5;
402 
403  if( size_pixel >= threshold )
404  {
405  DrawGraphicText( aPanel->GetClipBox(), aDC, pos, aDrawColor, Line,
406  orient, wxSize( size, size ),
408  0, false, false );
409  }
410  }
411  }
412 }
413 
414 
415 SEARCH_RESULT GBR_LAYOUT::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
416 {
417  KICAD_T stype;
419  const KICAD_T* p = scanTypes;
420  bool done = false;
421 
422 #if 0 && defined(DEBUG)
423  std::cout << GetClass().mb_str() << ' ';
424 #endif
425 
426  while( !done )
427  {
428  stype = *p;
429 
430  switch( stype )
431  {
432  case GERBER_IMAGE_LIST_T:
433  for( unsigned layer = 0; layer < GetImagesList()->ImagesMaxCount(); ++layer )
434  {
435  GERBER_FILE_IMAGE* gerber = GetImagesList()->GetGbrImage( layer );
436 
437  if( gerber == NULL ) // Graphic layer not yet used
438  continue;
439 
440  result = gerber->Visit( inspector, testData, p );
441 
442  if( result == SEARCH_QUIT )
443  break;
444  }
445 
446  ++p;
447  break;
448 
449  default: // catch EOT or ANY OTHER type here and return.
450  done = true;
451  break;
452  }
453 
454  if( result == SEARCH_QUIT )
455  break;
456  }
457 
458  return result;
459 }
COLOR4D GetPositiveDrawColor() const
wxString GetClass() const override
Function GetClass returns the class name.
EDA_RECT m_BoundingBox
void DrawGraphicText(EDA_RECT *aClipBox, wxDC *aDC, const wxPoint &aPos, COLOR4D aColor, const wxString &aText, double aOrient, const wxSize &aSize, enum EDA_TEXT_HJUSTIFY_T aH_justify, enum EDA_TEXT_VJUSTIFY_T aV_justify, int aWidth, bool aItalic, bool aBold, void(*aCallback)(int x0, int y0, int xf, int yf), PLOTTER *aPlotter)
Function DrawGraphicText Draw a graphic text (like module texts)
Definition: drawtxt.cpp:122
bool HasNegativeItems()
Function HasNegativeItems.
void Merge(const EDA_RECT &aRect)
Function Merge modifies the position and size of the rectangle in order to contain aRect...
void GRSetDrawMode(wxDC *DC, GR_DRAWMODE draw_mode)
Definition: gr_basic.cpp:296
bool IsLayerPrintable(int aLayer) const
Function IsLayerPrintable tests whether a given layer is visible.
COLOR4D m_BgDrawColor
The background color.
void GRFilledRect(EDA_RECT *ClipBox, wxDC *DC, int x1, int y1, int x2, int y2, COLOR4D Color, COLOR4D BgColor)
Definition: gr_basic.cpp:1116
Class GERBER_FILE_IMAGE holds the Image data and parameters for one gerber file and layer parameters ...
GERBER_FILE_IMAGE_LIST is a helper class to handle a list of GERBER_FILE_IMAGE files which are loaded...
int GetActiveLayer()
Function SetActiveLayer returns the active layer.
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
>
void DrawItemsDCodeID(EDA_DRAW_PANEL *aPanel, wxDC *aDC, GR_DRAWMODE aDrawMode, COLOR4D aDrawColor)
Function DrawItemsDCodeID Draw the DCode value (if exists) corresponding to gerber item (polygons do ...
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_StructType.
Definition: typeinfo.h:78
EDA_RECT ComputeBoundingBox() const
Function ComputeBoundingBox calculates the bounding box containing all Gerber items.
wxChoice * m_SelNetnameBox
void SetClipBox(const EDA_RECT &aRect)
const INSPECTOR_FUNC & INSPECTOR
Definition: base_struct.h:118
#define GERBER_DRAWLAYERS_COUNT
bool m_ForceBlackAndWhite
Option print in blackand white (ont used id draw mode.
GERBER_FILE_IMAGE * GetGbrImage(int aIdx)
GR_DRAWMODE
Drawmode. Compositing mode plus a flag or two.
Definition: gr_basic.h:41
std::vector< int > m_printLayersList
GERBER_DRAW_ITEM * Next() const
static GERBER_FILE_IMAGE_LIST & GetImagesList()
EDA_RECT * GetClipBox()
EDA_DRAW_FRAME * GetParent() const
Definition: draw_panel.cpp:174
int GetBottom() const
int GetRight() const
bool IsLayerVisible(int aLayer) const
Function IsLayerVisible tests whether a given layer is visible.
Definition: gr_basic.h:42
void Normalize()
Function Normalize ensures that the height ant width are positive.
COLOR4D GetLayerColor(int aLayer) const
Function GetLayerColor gets a layer color for any valid layer.
wxChoice * m_SelAperAttributesBox
const int scale
GERBER_DRAW_ITEM * GetItemsList()
Function GetItemsList.
GERBER_FILE_IMAGE_LIST * GetImagesList() const
Class EDA_RECT handles the component boundary box.
int GetX() const
Class EDA_ITEM is a base class for most all the KiCad significant classes, used in schematics and boa...
Definition: base_struct.h:178
int GetWidth() const
Definition: colors.h:49
int GetY() const
void DrawModeAddHighlight(GR_DRAWMODE *mode)
Definition: gr_basic.h:53
wxChoice * m_SelComponentBox
This file is part of the common libary.
#define GERBER_DRAW_LAYER(x)
Definition: colors.h:45
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
>
SEARCH_RESULT
Definition: base_struct.h:82
Class CLASS_GBR_LAYOUT to handle info to draw/print loaded Gerber images and page frame reference...
bool m_IsPrinting
true when printing a page, false when drawing on screen
virtual void DoPrepareDC(wxDC &aDC) override
Function DoPrepareDC sets up the device context aDC for drawing.
Definition: draw_panel.cpp:572
EDA_RECT & Inflate(wxCoord dx, wxCoord dy)
Function Inflate inflates the rectangle horizontally by dx and vertically by dy.
Class COLOR4D is the color representation with 4 components: red, green, blue, alpha.
Definition: color4d.h:39
void Draw(EDA_DRAW_PANEL *aPanel, wxDC *aDC, GR_DRAWMODE aDrawMode, const wxPoint &aOffset, GBR_DISPLAY_OPTIONS *aDisplayOptions)
Function Draw.