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