KiCad PCB EDA Suite
gerber_file_image.cpp
Go to the documentation of this file.
1 
6 /*
7  * This program source code file is part of KiCad, a free EDA CAD application.
8  *
9  * Copyright (C) 1992-2019 Jean-Pierre Charras jp.charras at wanadoo.fr
10  * Copyright (C) 1992-2019 KiCad Developers, see AUTHORS.txt for contributors.
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * as published by the Free Software Foundation; either version 2
15  * of the License, or (at your option) any later version.
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with this program; if not, you may find one here:
24  * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
25  * or you may search the http://www.gnu.org website for the version 2 license,
26  * or you may write to the Free Software Foundation, Inc.,
27  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
28  */
29 
30 #include <convert_to_biu.h>
31 #include <gerbview.h>
32 #include <gerbview_frame.h>
33 #include <gerber_file_image.h>
34 #include <macros.h>
35 #include <X2_gerber_attributes.h>
36 #include <algorithm>
37 #include <map>
38 #include <core/arraydim.h>
39 
40 
45 extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordiantes.cpp
46 
47 /* Format Gerber: NOTES:
48  * Tools and D_CODES
49  * tool number (identification of shapes)
50  * 1 to 999
51  *
52  * D_CODES:
53  * D01 ... D9 = action codes:
54  * D01 = activating light (lower pen) when di placement
55  * D02 = light extinction (lift pen) when di placement
56  * D03 Flash
57  * D09 = VAPE Flash
58  * D10 ... = Indentification Tool (Opening)
59  *
60  * For tools:
61  * DCode min = D10
62  * DCode max = 999
63  */
64 
65 
67 {
69 }
70 
71 
73 {
74 }
75 
76 
78 {
79  m_LayerName = wxT( "no name" ); // Layer name from the LN command
80  m_LayerNegative = false; // true = Negative Layer
81  m_StepForRepeat.x = m_StepForRepeat.y = 0; // X and Y offsets for Step and Repeat command
82  m_XRepeatCount = 1; // The repeat count on X axis
83  m_YRepeatCount = 1; // The repeat count on Y axis
84  m_StepForRepeatMetric = false; // false = Inches, true = metric
85 }
86 
87 
90 {
91  m_GraphicLayer = aLayer; // Graphic layer Number
92  m_IsVisible = true; // must be drawn
93  m_PositiveDrawColor = WHITE; // The color used to draw positive items for this image
94 
95  m_Selected_Tool = 0;
96  m_FileFunction = NULL; // file function parameters
97 
99 
100  for( unsigned ii = 0; ii < arrayDim( m_Aperture_List ); ii++ )
101  m_Aperture_List[ii] = 0;
102 }
103 
104 
106 {
107 
108  for( auto item : GetItems() )
109  delete item;
110 
111  m_drawings.clear();
112 
113  for( unsigned ii = 0; ii < arrayDim( m_Aperture_List ); ii++ )
114  {
115  delete m_Aperture_List[ii];
116  }
117 
118  delete m_FileFunction;
119 }
120 
121 
122 D_CODE* GERBER_FILE_IMAGE::GetDCODEOrCreate( int aDCODE, bool aCreateIfNoExist )
123 {
124  unsigned ndx = aDCODE - FIRST_DCODE;
125 
126  if( ndx < (unsigned) arrayDim( m_Aperture_List ) )
127  {
128  // lazily create the D_CODE if it does not exist.
129  if( aCreateIfNoExist )
130  {
131  if( m_Aperture_List[ndx] == NULL )
132  m_Aperture_List[ndx] = new D_CODE( ndx + FIRST_DCODE );
133  }
134 
135  return m_Aperture_List[ndx];
136  }
137 
138  return NULL;
139 }
140 
141 
143 {
144  unsigned ndx = aDCODE - FIRST_DCODE;
145 
146  if( ndx < (unsigned) arrayDim( m_Aperture_List ) )
147  {
148  return m_Aperture_List[ndx];
149  }
150 
151  return NULL;
152 }
153 
154 
156 {
157  APERTURE_MACRO_SET::iterator iter = m_aperture_macros.find( aLookup );
158 
159  if( iter != m_aperture_macros.end() )
160  {
161  APERTURE_MACRO* pam = (APERTURE_MACRO*) &(*iter);
162  return pam;
163  }
164 
165  return NULL; // not found
166 }
167 
168 
170 {
171  m_InUse = false;
173  m_FileName.Empty();
174  m_ImageName = wxT( "no name" ); // Image name from the IN command
175  m_ImageNegative = false; // true = Negative image
176  m_IsX2_file = false; // true only if a %TF, %TA or %TD command
177  delete m_FileFunction; // file function parameters
179  m_MD5_value.Empty(); // MD5 value found in a %TF.MD5 command
180  m_PartString.Empty(); // string found in a %TF.Part command
181  m_hasNegativeItems = -1; // set to uninitialized
182  m_ImageJustifyOffset = wxPoint(0,0); // Image justify Offset
183  m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
184  m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
185  m_GerbMetric = false; // false = Inches (default), true = metric
186  m_Relative = false; // false = absolute Coord,
187  // true = relative Coord
188  m_NoTrailingZeros = false; // true: trailing zeros deleted
189  m_ImageOffset.x = m_ImageOffset.y = 0; // Coord Offset, from IO command
190  m_ImageRotation = 0; // Allowed 0, 90, 180, 270 (in degree)
191  m_LocalRotation = 0.0; // Layer totation from RO command (in 0.1 degree)
192  m_Offset.x = 0;
193  m_Offset.y = 0; // Coord Offset, from OF command
194  m_Scale.x = m_Scale.y = 1.0; // scale (A and B) this layer
195  m_MirrorA = false; // true: miror / axe A (default = X)
196  m_MirrorB = false; // true: miror / axe B (default = Y)
197  m_SwapAxis = false; // false if A = X, B = Y; true if A =Y, B = Y
198  m_Has_DCode = false; // true = DCodes in file
199  // false = no DCode-> perhaps deprecated RS274D file
200  m_Has_MissingDCode = false; // true = some D_Codes are used, but not defined
201  // perhaps deprecated RS274D file
202  m_FmtScale.x = m_FmtScale.y = 4; // Initialize default format to 3.4 => 4
203  m_FmtLen.x = m_FmtLen.y = 3 + 4; // Initialize default format len = 3+4
204 
205  m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Linear, 90 arc, Circ.
206  m_360Arc_enbl = false; // 360 deg circular
207  // interpolation disable
208  m_AsArcG74G75Cmd = false; // false untile a G74 or G75 comand is found
209  m_Current_Tool = 0; // Current Dcode selected
210  m_CommandState = 0; // State of the current command
211  m_CurrentPos.x = m_CurrentPos.y = 0; // current specified coord
212  m_PreviousPos.x = m_PreviousPos.y = 0; // last specified coord
213  m_IJPos.x = m_IJPos.y = 0; // current centre coord for
214  // plot arcs & circles
215  m_LastCoordIsIJPos = false; // True only after a IJ coordinate is read
216  m_ArcRadius = 0; // radius of arcs in circular interpol (given by A## command).
217  // in command like X##Y##A##
218  m_LastArcDataType = ARC_INFO_TYPE_NONE; // Extra coordinate info type for arcs
219  // (radius or IJ center coord)
220  m_LineNum = 0; // line number in file being read
221  m_Current_File = NULL; // Gerber file to read
222  m_PolygonFillMode = false;
224  m_Selected_Tool = 0;
225  m_Last_Pen_Command = 0;
226  m_Exposure = false;
227 }
228 
229 
230 /* Function HasNegativeItems
231  * return true if at least one item must be drawn in background color
232  * used to optimize screen refresh
233  */
235 {
236  if( m_hasNegativeItems < 0 ) // negative items are not yet searched: find them if any
237  {
238  if( m_ImageNegative ) // A negative layer is expected having always negative objects.
239  m_hasNegativeItems = 1;
240  else
241  {
242  m_hasNegativeItems = 0;
243  for( GERBER_DRAW_ITEM* item : GetItems() )
244  {
245  if( item->GetLayer() != m_GraphicLayer )
246  continue;
247  if( item->HasNegativeItems() )
248  {
249  m_hasNegativeItems = 1;
250  break;
251  }
252  }
253  }
254  }
255  return m_hasNegativeItems == 1;
256 }
257 
259 {
260  int count = 0;
261 
262  for( unsigned ii = 0; ii < arrayDim( m_Aperture_List ); ii++ )
263  {
264  if( m_Aperture_List[ii] )
265  if( m_Aperture_List[ii]->m_InUse || m_Aperture_List[ii]->m_Defined )
266  ++count;
267  }
268 
269  return count;
270 }
271 
272 
274 {
275  for( int count = 0; count < TOOLS_MAX_COUNT; count++ )
276  {
277  if( m_Aperture_List[count] == NULL )
278  continue;
279 
280  m_Aperture_List[count]->m_Num_Dcode = count + FIRST_DCODE;
282  }
283 
284  m_aperture_macros.clear();
285 }
286 
287 
297 {
298  if( GetLayerParams().m_XRepeatCount < 2 &&
299  GetLayerParams().m_YRepeatCount < 2 )
300  return; // Nothing to repeat
301 
302  // Duplicate item:
303  for( int ii = 0; ii < GetLayerParams().m_XRepeatCount; ii++ )
304  {
305  for( int jj = 0; jj < GetLayerParams().m_YRepeatCount; jj++ )
306  {
307  // the first gerber item already exists (this is the template)
308  // create duplicate only if ii or jj > 0
309  if( jj == 0 && ii == 0 )
310  continue;
311 
312  GERBER_DRAW_ITEM* dupItem = new GERBER_DRAW_ITEM( aItem );
313  wxPoint move_vector;
314  move_vector.x = scaletoIU( ii * GetLayerParams().m_StepForRepeat.x,
315  GetLayerParams().m_StepForRepeatMetric );
316  move_vector.y = scaletoIU( jj * GetLayerParams().m_StepForRepeat.y,
317  GetLayerParams().m_StepForRepeatMetric );
318  dupItem->MoveXY( move_vector );
319  AddItemToList( dupItem );
320  }
321  }
322 }
323 
324 
334 {
335  wxString msg;
336 
337  aMainFrame->ClearMsgPanel();
338 
339  // Display Image name (Image specific)
340  aMainFrame->AppendMsgPanel( _( "Image name" ), m_ImageName, CYAN );
341 
342  // Display graphic layer number used to draw this Image
343  // (not a Gerber parameter but is also image specific)
344  msg.Printf( wxT( "%d" ), m_GraphicLayer + 1 );
345  aMainFrame->AppendMsgPanel( _( "Graphic layer" ), msg, BROWN );
346 
347  // Display Image rotation (Image specific)
348  msg.Printf( wxT( "%d" ), m_ImageRotation );
349  aMainFrame->AppendMsgPanel( _( "Img Rot." ), msg, CYAN );
350 
351  // Display Image polarity (Image specific)
352  msg = m_ImageNegative ? _("Negative") : _("Normal");
353  aMainFrame->AppendMsgPanel( _( "Polarity" ), msg, BROWN );
354 
355  // Display Image justification and offset for justification (Image specific)
356  msg = m_ImageJustifyXCenter ? _("Center") : _("Normal");
357  aMainFrame->AppendMsgPanel( _( "X Justify" ), msg, DARKRED );
358 
359  msg = m_ImageJustifyYCenter ? _("Center") : _("Normal");
360  aMainFrame->AppendMsgPanel( _( "Y Justify" ), msg, DARKRED );
361 
362  switch( aMainFrame->GetUserUnits() )
363  {
364  case EDA_UNITS::MILS:
365  msg.Printf( wxT( "X=%f Y=%f" ), Iu2Mils( m_ImageJustifyOffset.x ),
366  Iu2Mils( m_ImageJustifyOffset.y ) );
367  break;
368 
369  case EDA_UNITS::INCHES:
370  msg.Printf( wxT( "X=%f Y=%f" ), Iu2Mils( m_ImageJustifyOffset.x ) / 1000.0,
371  Iu2Mils( m_ImageJustifyOffset.y ) / 1000.0 );
372  break;
373 
375  msg.Printf( wxT( "X=%f Y=%f" ), Iu2Millimeter( m_ImageJustifyOffset.x ),
376  Iu2Millimeter( m_ImageJustifyOffset.y ) );
377  break;
378 
379  default:
380  wxASSERT_MSG( false, "Invalid unit" );
381  }
382 
383 
384  aMainFrame->AppendMsgPanel( _( "Image Justify Offset" ), msg, DARKRED );
385 }
386 
387 
389 {
390  /* Called when a %TD command is found
391  * Remove the attribute specified by the %TD command.
392  * is no attribute, all current attributes specified by the %TO and the %TA
393  * commands are cleared.
394  * if a attribute name is specified (for instance %TD.CN*%) is specified,
395  * only this attribute is cleared
396  */
397  wxString cmd = aAttribute.GetPrm( 0 );
399 
400  if( cmd.IsEmpty() || cmd == ".AperFunction" )
401  m_AperFunction.Clear();
402 }
403 
404 
405 SEARCH_RESULT GERBER_FILE_IMAGE::Visit( INSPECTOR inspector, void* testData, const KICAD_T scanTypes[] )
406 {
407  KICAD_T stype;
409  const KICAD_T* p = scanTypes;
410  bool done = false;
411 
412  while( !done )
413  {
414  stype = *p;
415 
416  switch( stype )
417  {
418  case GERBER_IMAGE_T:
419  case GERBER_LAYOUT_T:
420  ++p;
421  break;
422 
423  case GERBER_DRAW_ITEM_T:
424  result = IterateForward( GetItems(), inspector, testData, p );
425  ++p;
426  break;
427 
428  case EOT:
429  default: // catch EOT or ANY OTHER type here and return.
430  done = true;
431  break;
432  }
433 
434  if( result == SEARCH_RESULT::QUIT )
435  break;
436  }
437 
438  return result;
439 }
APERTURE_MACRO_SET m_aperture_macros
a collection of APERTURE_MACROS, sorted by name
wxString m_LayerName
X2_ATTRIBUTE_FILEFUNCTION * m_FileFunction
bool HasNegativeItems()
Function HasNegativeItems.
X2_ATTRIBUTE The attribute value consists of a number of substrings separated by a comma.
GERBER_DRAW_ITEMS & GetItems()
wxRealPoint m_StepForRepeat
GERBER_FILE_IMAGE(int layer)
D_CODE * GetDCODE(int aDCODE) const
Function GetDCODE returns a pointer to the D_CODE within this GERBER for the given aDCODE.
Definition: color4d.h:62
int scaletoIU(double aCoord, bool isMetric)
Function scaletoIU converts a distance given in floating point to our internal units.
const wxString & GetPrm(int aIdx)
SEARCH_RESULT Visit(INSPECTOR inspector, void *testData, const KICAD_T scanTypes[]) override
const INSPECTOR_FUNC & INSPECTOR
Definition: eda_item.h:94
search types array terminator (End Of Types)
Definition: typeinfo.h:82
KICAD_T
Enum KICAD_T is the set of class identification values, stored in EDA_ITEM::m_structType.
Definition: typeinfo.h:78
This file contains miscellaneous commonly used macros and functions.
D_CODE * m_Aperture_List[TOOLS_MAX_COUNT]
Dcode (Aperture) List for this layer (max TOOLS_MAX_COUNT: see dcode.h)
GERBER_DRAW_ITEMS m_drawings
void DisplayImageInfo(GERBVIEW_FRAME *aMainFrame)
Function DisplayImageInfo has knowledge about the frame and how and where to put status information a...
void AddItemToList(GERBER_DRAW_ITEM *aItem)
Add a new GERBER_DRAW_ITEM item to the drawings list.
GERBER_LAYER m_GBRLayerParams
#define NULL
#define FIRST_DCODE
Definition: dcode.h:71
int m_Num_Dcode
D code value ( >= 10 )
Definition: dcode.h:96
Definition: color4d.h:59
APERTURE_MACRO * FindApertureMacro(const APERTURE_MACRO &aLookup)
Function FindApertureMacro looks up a previously read in aperture macro.
constexpr std::size_t arrayDim(T const (&)[N]) noexcept
Returns # of elements in an array.
Definition: arraydim.h:31
virtual void ClearMsgPanel()
Clear all messages from the message panel.
bool m_StepForRepeatMetric
void RemoveAttribute(X2_ATTRIBUTE &aAttribute)
Function RemoveAttribute.
Definition: color4d.h:49
bool m_Exposure
whether an aperture macro tool is flashed on or off
LAST_EXTRA_ARC_DATA_TYPE m_LastArcDataType
D_CODE holds a gerber DCODE (also called Aperture) definition.
Definition: dcode.h:82
#define _(s)
Definition: 3d_actions.cpp:33
GBR_NETLIST_METADATA m_NetAttributeDict
#define TOOLS_MAX_COUNT
Definition: dcode.h:73
EDA_ITEM is a base class for most all the KiCad significant classes used in schematics and boards.
Definition: eda_item.h:148
void ClearAttribute(const wxString *aName)
remove the net attribute specified by aName If aName == NULL or empty, remove all attributes
static SEARCH_RESULT IterateForward(std::deque< T > &aList, INSPECTOR inspector, void *testData, const KICAD_T scanTypes[])
IterateForward( EDA_ITEM*, INSPECTOR, void*, const KICAD_T )
Definition: eda_item.h:372
Struct APERTURE_MACRO helps support the "aperture macro" defined within standard RS274X.
Definition: am_primitive.h:162
void InitToolTable()
Function InitToolTable.
void MoveXY(const wxPoint &aMoveVector)
Function MoveXY move this object.
SEARCH_RESULT
Definition: eda_item.h:40
void StepAndRepeatItem(const GERBER_DRAW_ITEM &aItem)
Function StepAndRepeatItem Gerber format has a command Step an Repeat This function must be called wh...
void Clear_D_CODE_Data()
Definition: dcode.cpp:76
D_CODE * GetDCODEOrCreate(int aDCODE, bool aCreateIfNoExist=true)
Function GetDCODEOrCreate returns a pointer to the D_CODE within this GERBER for the given aDCODE.
EDA_UNITS GetUserUnits() const
Return the user units currently in use.
GERBER_LAYER & GetLayerParams()
Function GetLayerParams.
virtual void ResetDefaultValues()
void AppendMsgPanel(const wxString &aTextUpper, const wxString &aTextLower, int aPadding=6)
Append a message to the message panel.