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