KiCad PCB EDA Suite
Loading...
Searching...
No Matches
gerber_file_image.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) 1992-2019 Jean-Pierre Charras jp.charras at wanadoo.fr
5 * Copyright The 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, see <https://www.gnu.org/licenses/>.
19 */
20
21#include <gerbview.h>
22#include <gerbview_frame.h>
23#include <gerber_file_image.h>
24#include <gerber_to_polyset.h>
25#include <macros.h>
27#include <algorithm>
28#include <map>
29//#include <numeric>
30#include <core/arraydim.h>
31#include <core/profile.h>
32
33
37extern int scaletoIU( double aCoord, bool isMetric ); // defined it rs274d_read_XY_and_IJ_coordinates.cpp
38
39/* Format Gerber: NOTES:
40 * Tools and D_CODES
41 * tool number (identification of shapes)
42 * 1 to 999
43 *
44 * D_CODES:
45 * D01 ... D9 = action codes:
46 * D01 = activating light (lower pen) when di placement
47 * D02 = light extinction (lift pen) when di placement
48 * D03 Flash
49 * D09 = VAPE Flash
50 * D10 ... = Identification Tool (Opening)
51 *
52 * For tools:
53 * DCode min = D10
54 * DCode max = 999
55 */
56
57
62
63
67
68
70{
71 m_LayerName = wxT( "no name" ); // Layer name from the LN command
72 m_LayerNegative = false; // true = Negative Layer
73 m_StepForRepeat.x = m_StepForRepeat.y = 0; // X and Y offsets for Step and Repeat command
74 m_XRepeatCount = 1; // The repeat count on X axis
75 m_YRepeatCount = 1; // The repeat count on Y axis
76 m_StepForRepeatMetric = false; // false = Inches, true = metric
77}
78
79
81 EDA_ITEM( nullptr, GERBER_IMAGE_T )
82{
83 m_GraphicLayer = aLayer; // Graphic layer Number
84 m_PositiveDrawColor = WHITE; // The color used to draw positive items for this image
85
87 m_FileFunction = nullptr; // file function parameters
88
90
91 m_ApertureList.clear();
92}
93
94
96{
97 // Reverse iteration to avoid O(N^2) memcpy in a vector erase downstream.
98 // It results in a O(N^2) std::find, which is somewhat faster.
99 for( auto it = GetItems().rbegin(); it < GetItems().rend(); it++ )
100 delete *it;
101
102 m_drawings.clear();
103
104 for( const auto& ap_item : m_ApertureList )
105 delete ap_item.second;
106
107 delete m_FileFunction;
108}
109
110
111void GERBER_FILE_IMAGE::AddMessageToList( const wxString& aMessage )
112{
113 /* Add a message to the message list, but only if there are less than max_messages
114 * to avoid very long list (can happens if trying to read a non gerber file)
115 */
116 const int max_messages = 50; // Arbitrary but reasonable value.
117
118 if( m_messagesList.size() < max_messages )
119 m_messagesList.Add( aMessage );
120 else if( m_messagesList.size() == max_messages )
121 m_messagesList.Add( _( "Too many messages, some are skipped" ) );
122}
123
124
126{
127 m_DisplayOffset.x = KiROUND( aOffsetMM.x * gerbIUScale.IU_PER_MM );
128 m_DisplayOffset.y = KiROUND( aOffsetMM.y * gerbIUScale.IU_PER_MM );
129 m_DisplayRotation = aRotation;
130
131 // Clear m_AbsolutePolygon member of Gerber items, because draw coordinates
132 // are now outdated
133 for( GERBER_DRAW_ITEM* item : GetItems() )
134 item->m_AbsolutePolygon.RemoveAllContours();
135}
136
137
138D_CODE* GERBER_FILE_IMAGE::GetDCODEOrCreate( int aDCODE, bool aCreateIfNoExist )
139{
140 auto it = m_ApertureList.find( aDCODE );
141
142 if( it != m_ApertureList.end() )
143 return it->second;
144
145 // lazily create the D_CODE if it does not exist.
146 if( aCreateIfNoExist )
147 {
148 D_CODE* dcode = new D_CODE( aDCODE );
149 m_ApertureList.insert( { aDCODE, dcode } );
150 return dcode;
151 }
152
153 return nullptr;
154}
155
156
158{
159 auto it = m_ApertureList.find( aDCODE );
160
161 if( it != m_ApertureList.end() )
162 return it->second;
163
164 return nullptr;
165}
166
167
169{
170 APERTURE_MACRO_SET::iterator iter = m_aperture_macros.find( aLookup );
171
172 if( iter != m_aperture_macros.end() )
173 {
174 APERTURE_MACRO* pam = (APERTURE_MACRO*) &( *iter );
175 return pam;
176 }
177
178 return nullptr; // not found
179}
180
181
183{
184 m_InUse = false;
185 m_GBRLayerParams.ResetDefaultValues();
186 m_FileName.Empty();
187 m_ArchiveFileName.Empty();
188 m_ImageName = wxEmptyString; // Image name from the IN command (deprecated)
189 m_ImageNegative = false; // true = Negative image
190 m_IsX2_file = false; // true only if a %TF, %TA or %TD command
191 delete m_FileFunction; // file function parameters
192 m_FileFunction = nullptr;
193 m_MD5_value.Empty(); // MD5 value found in a %TF.MD5 command
194 m_PartString.Empty(); // string found in a %TF.Part command
195 m_hasNegativeItems = -1; // set to uninitialized
196 m_ImageJustifyOffset = VECTOR2I( 0, 0 ); // Image justify Offset
197 m_ImageJustifyXCenter = false; // Image Justify Center on X axis (default = false)
198 m_ImageJustifyYCenter = false; // Image Justify Center on Y axis (default = false)
199 m_GerbMetric = false; // false = Inches (default), true = metric
200 m_Relative = false; // false = absolute Coord,
201 // true = relative Coord
202 m_NoTrailingZeros = false; // true: trailing zeros deleted
203 m_ImageOffset.x = m_ImageOffset.y = 0; // Coord Offset, from IO command
204 m_ImageRotation = 0; // Allowed 0, 90, 180, 270 (in degree)
205 m_LocalRotation = 0.0; // Layer rotation from RO command (in 0.1 degree)
206 m_Offset.x = 0;
207 m_Offset.y = 0; // Coord Offset, from OF command
208 m_Scale.x = m_Scale.y = 1.0; // scale (A and B) this layer
209 m_MirrorA = false; // true: mirror / axe A (default = X)
210 m_MirrorB = false; // true: mirror / axe B (default = Y)
211 m_SwapAxis = false; // false if A = X, B = Y; true if A =Y, B = Y
212 m_Has_DCode = false; // true = DCodes in file
213 // false = no DCode-> perhaps deprecated RS274D file
214 m_Has_MissingDCode = false; // true = some D_Codes are used, but not defined
215 // perhaps deprecated RS274D file
216 m_FmtScale.x = m_FmtScale.y = 4; // Initialize default format to 3.4 => 4
217 m_FmtLen.x = m_FmtLen.y = 3 + 4; // Initialize default format len = 3+4
218
219 m_Iterpolation = GERB_INTERPOL_LINEAR_1X; // Linear, 90 arc, Circ.
220 m_360Arc_enbl = true; // 360 deg circular mode (G75) selected as default
221 // interpolation disable
222 m_AsArcG74G75Cmd = false; // false until a G74 or G75 command is found
223 m_Current_Tool = 0; // Current Dcode selected
224 m_CommandState = 0; // State of the current command
225 m_CurrentPos.x = m_CurrentPos.y = 0; // current specified coord
226 m_PreviousPos.x = m_PreviousPos.y = 0; // last specified coord
227 m_IJPos.x = m_IJPos.y = 0; // current centre coord for
228 // plot arcs & circles
229 m_LastCoordIsIJPos = false; // True only after a IJ coordinate is read
230 m_ArcRadius = 0; // radius of arcs in circular interpol (given by A## command).
231 // in command like X##Y##A##
232 m_LastArcDataType = ARC_INFO_TYPE_NONE; // Extra coordinate info type for arcs
233 // (radius or IJ center coord)
234 m_LineNum = 0; // line number in file being read
235 m_Current_File = nullptr; // Gerber file to read
236 m_PolygonFillMode = false;
238 m_Selected_Tool = 0;
240 m_Exposure = false;
241
244
245 m_SRBlockCollecting = false;
247}
248
249
255{
256 if( m_hasNegativeItems < 0 ) // negative items are not yet searched: find them if any
257 {
258 if( m_ImageNegative ) // A negative layer is expected having always negative objects.
259 {
261 }
262 else
263 {
265
266 for( GERBER_DRAW_ITEM* item : GetItems() )
267 {
268 if( item->GetLayer() != m_GraphicLayer )
269 continue;
270
271 if( item->HasNegativeItems() )
272 {
274 break;
275 }
276 }
277 }
278 }
279
280 return m_hasNegativeItems == 1;
281}
282
283
285{
286 int count = 0;
287
288 for( const auto& n : m_ApertureList )
289 {
290 D_CODE* dcode = n.second;
291
292 wxCHECK2( dcode, continue );
293
294 if( dcode->m_InUse || dcode->m_Defined )
295 count++;
296 }
297
298 return count;
299}
300
301
303{
304 // When collecting items for a block-level SR replication, individual item
305 // replication is deferred until the SR block is closed.
307 return;
308
309 if( GetLayerParams().m_XRepeatCount < 2 && GetLayerParams().m_YRepeatCount < 2 )
310 return; // Nothing to repeat
311
312 // Duplicate item:
313 for( int ii = 0; ii < GetLayerParams().m_XRepeatCount; ii++ )
314 {
315 for( int jj = 0; jj < GetLayerParams().m_YRepeatCount; jj++ )
316 {
317 // the first gerber item already exists (this is the template)
318 // create duplicate only if ii or jj > 0
319 if( jj == 0 && ii == 0 )
320 continue;
321
322 GERBER_DRAW_ITEM* dupItem = new GERBER_DRAW_ITEM( aItem );
323 VECTOR2I move_vector;
324 move_vector.x =
325 scaletoIU( ii * GetLayerParams().m_StepForRepeat.x, GetLayerParams().m_StepForRepeatMetric );
326 move_vector.y =
327 scaletoIU( jj * GetLayerParams().m_StepForRepeat.y, GetLayerParams().m_StepForRepeatMetric );
328 dupItem->MoveXY( move_vector );
329 AddItemToList( dupItem );
330 }
331 }
332}
333
334
336{
338 return;
339
340 m_SRBlockCollecting = false;
341
342 const GERBER_LAYER& params = GetLayerParams();
343
344 if( params.m_XRepeatCount < 2 && params.m_YRepeatCount < 2 )
345 return;
346
347 int blockSize = static_cast<int>( m_drawings.size() ) - m_SRBlockStartIdx;
348
349 if( blockSize <= 0 )
350 return;
351
352 // Replicate the entire collected block for each SR copy (skipping the 0,0 original)
353 for( int ii = 0; ii < params.m_XRepeatCount; ii++ )
354 {
355 for( int jj = 0; jj < params.m_YRepeatCount; jj++ )
356 {
357 if( jj == 0 && ii == 0 )
358 continue;
359
360 VECTOR2I move_vector;
361 move_vector.x = scaletoIU( ii * params.m_StepForRepeat.x, params.m_StepForRepeatMetric );
362 move_vector.y = scaletoIU( jj * params.m_StepForRepeat.y, params.m_StepForRepeatMetric );
363
364 for( int kk = 0; kk < blockSize; kk++ )
365 {
366 GERBER_DRAW_ITEM* dupItem =
368 dupItem->MoveXY( move_vector );
369 AddItemToList( dupItem );
370 }
371 }
372 }
373}
374
375
386{
387 wxString msg;
388
389 aMainFrame->ClearMsgPanel();
390
391 // Display the Gerber variant (X1 / X2
392 aMainFrame->AppendMsgPanel( _( "Format" ), m_IsX2_file ? wxT( "X2" ) : wxT( "X1" ) );
393
394 // Display Image name (Image specific). IM command (Image Name) is deprecated
395 // So non empty image name is very rare, probably never found
396 if( !m_ImageName.IsEmpty() )
397 aMainFrame->AppendMsgPanel( _( "Image name" ), m_ImageName );
398
399 // Display graphic layer number used to draw this Image
400 // (not a Gerber parameter but is also image specific)
401 msg.Printf( wxT( "%d" ), m_GraphicLayer + 1 );
402 aMainFrame->AppendMsgPanel( _( "Graphic layer" ), msg );
403
404 // Display Image rotation (Image specific)
405 msg.Printf( wxT( "%d" ), m_ImageRotation );
406 aMainFrame->AppendMsgPanel( _( "Img Rot." ), msg );
407
408 // Display Image polarity (Image specific)
409 msg = m_ImageNegative ? _( "Negative" ) : _( "Normal" );
410 aMainFrame->AppendMsgPanel( _( "Polarity" ), msg );
411
412 // Display Image justification and offset for justification (Image specific)
413 msg = m_ImageJustifyXCenter ? _( "Center" ) : _( "Normal" );
414 aMainFrame->AppendMsgPanel( _( "X Justify" ), msg );
415
416 msg = m_ImageJustifyYCenter ? _( "Center" ) : _( "Normal" );
417 aMainFrame->AppendMsgPanel( _( "Y Justify" ), msg );
418
419 msg.Printf( wxT( "X=%s Y=%s" ), aMainFrame->MessageTextFromValue( m_ImageJustifyOffset.x ),
421
422 aMainFrame->AppendMsgPanel( _( "Image Justify Offset" ), msg );
423}
424
425
427{
428 SHAPE_POLY_SET merged = ConvertGerberToPolySet( this );
429 constexpr double IU2_TO_MM2 = 1e-10;
430 return merged.Area() * IU2_TO_MM2;
431}
432
433
435{
436 /* Called when a %TD command is found
437 * Remove the attribute specified by the %TD command.
438 * is no attribute, all current attributes specified by the %TO and the %TA
439 * commands are cleared.
440 * if a attribute name is specified (for instance %TD.CN*%) is specified,
441 * only this attribute is cleared
442 */
443 wxString cmd = aAttribute.GetPrm( 0 );
444 m_NetAttributeDict.ClearAttribute( &cmd );
445
446 if( cmd.IsEmpty() || cmd == wxT( ".AperFunction" ) )
447 m_AperFunction.Clear();
448}
449
450
451INSPECT_RESULT GERBER_FILE_IMAGE::Visit( INSPECTOR inspector, void* testData, const std::vector<KICAD_T>& aScanTypes )
452{
453 for( KICAD_T scanType : aScanTypes )
454 {
455 if( scanType == GERBER_DRAW_ITEM_T )
456 {
457 if( IterateForward( GetItems(), inspector, testData, { scanType } ) == INSPECT_RESULT::QUIT )
459 }
460 }
461
463}
int scaletoIU(double aCoord, bool isMetric)
Convert a distance given in floating point to our internal units.
constexpr EDA_IU_SCALE gerbIUScale
Definition base_units.h:127
constexpr BOX2I KiROUND(const BOX2D &aBoxD)
Definition box2.h:982
Support the "aperture macro" defined within standard RS274X.
A gerber DCODE (also called Aperture) definition.
Definition dcode.h:76
bool m_Defined
false if the aperture is not defined in the header
Definition dcode.h:209
bool m_InUse
false if the aperture (previously defined) is not used to draw something
Definition dcode.h:207
virtual void ClearMsgPanel()
Clear all messages from the message panel.
void AppendMsgPanel(const wxString &aTextUpper, const wxString &aTextLower, int aPadding=6)
Append a message to the message panel.
static INSPECT_RESULT IterateForward(std::deque< T > &aList, INSPECTOR inspector, void *testData, const std::vector< KICAD_T > &scanTypes)
This changes first parameter to avoid the DList and use the main queue instead.
Definition eda_item.h:401
EDA_ITEM(EDA_ITEM *parent, KICAD_T idType, bool isSCH_ITEM=false, bool isBOARD_ITEM=false)
Definition eda_item.cpp:84
void MoveXY(const VECTOR2I &aMoveVector)
Move this object.
void SetDrawOffetAndRotation(VECTOR2D aOffsetMM, EDA_ANGLE aRotation)
Set the offset and rotation to draw a file image Does not change any coordinate od draw items.
int m_Last_Pen_Command
Current or last pen state (0..9, set by Dn option with n < 10.
APERTURE_MACRO * FindApertureMacro(const APERTURE_MACRO &aLookup)
Look up a previously read in aperture macro.
X2_ATTRIBUTE_FILEFUNCTION * m_FileFunction
file function parameters, found in a %TF command or a G04
void RemoveAttribute(X2_ATTRIBUTE &aAttribute)
Called when a TD command is found the Gerber file.
int m_hasNegativeItems
True if the image is negative or has some negative items.
virtual void ResetDefaultValues()
Set all parameters to a default value, before reading a file.
bool m_SwapAxis
false if A = X and B = Y (default); true if A = Y, B = X
double m_LocalRotation
Local rotation added to m_ImageRotation.
VECTOR2I m_Offset
Coord Offset, from OF command.
wxSize m_FmtScale
Fmt 2.3: m_FmtScale = 3, fmt 3.4: m_FmtScale = 4.
int m_ArcRadius
A value ( = radius in circular routing in Excellon files ).
wxString m_FileName
Full File Name for this layer.
void StepAndRepeatItem(const GERBER_DRAW_ITEM &aItem)
Gerber format has a command Step an Repeat.
bool m_ImageJustifyXCenter
Image Justify Center on X axis (default = false)
void FinishStepAndRepeatBlock()
Called when an SR block is closed (SR*%).
bool m_ImageJustifyYCenter
Image Justify Center on Y axis (default = false)
VECTOR2I m_DisplayOffset
Parameters used only to draw (display) items on this layer.
VECTOR2I m_PreviousPos
old current specified coord for plot
bool m_InUse
true if this image is currently in use (a file is loaded in it) false if it must be not drawn
bool m_ImageNegative
true = Negative image
void AddMessageToList(const wxString &aMessage)
Add a message to the message list.
LAST_EXTRA_ARC_DATA_TYPE m_LastArcDataType
Identifier for arc data type (IJ (center) or A## (radius)).
bool m_Exposure
Whether an aperture macro tool is flashed on or off.
wxArrayString m_messagesList
int m_LineNum
Line number of the gerber file while reading.
COLOR4D m_PositiveDrawColor
The color used to draw positive items.
std::map< int, D_CODE * > m_ApertureList
Dcode (Aperture) List for this layer (see dcode.h)
VECTOR2I m_IJPos
IJ coord (for arcs & circles )
wxString m_ImageName
Image name, from IN <name>* command.
bool m_Relative
false = absolute Coord, true = relative Coord.
wxString m_MD5_value
MD5 value found in a %TF.MD5 command.
bool m_MirrorB
true: mirror / axis B (Y)
wxString m_PartString
string found in a %TF.Part command
D_CODE * GetDCODE(int aDCODE) const
Return a pointer to the D_CODE within this GERBER for the given aDCODE.
double CalculateCopperArea()
Calculate the total copper area in the image.
bool m_IsX2_file
True if a X2 gerber attribute was found in file.
int m_ImageRotation
Image rotation (0, 90, 180, 270 only) in degrees.
VECTOR2I m_ImageOffset
Coord Offset, from IO command.
bool m_Has_DCode
True if has DCodes in file or false if no DCodes found. Perhaps deprecated RS274D file.
int m_Current_Tool
Current Tool (Dcode) number selected.
D_CODE * GetDCODEOrCreate(int aDCODE, bool aCreateIfNoExist=true)
Return a pointer to the D_CODE within this GERBER for the given aDCODE.
void AddItemToList(GERBER_DRAW_ITEM *aItem)
Add a new GERBER_DRAW_ITEM item to the drawings list.
wxSize m_FmtLen
Nb chars per coord. ex fmt 2.3, m_FmtLen = 5.
VECTOR2D m_Scale
scale (X and Y) of layer.
int m_GraphicLayer
Graphic layer Number.
APERTURE_MACRO_SET m_aperture_macros
a collection of APERTURE_MACROS, sorted by name
GERBER_DRAW_ITEMS m_drawings
bool m_GerbMetric
false = Inches, true = metric
GBR_NETLIST_METADATA m_NetAttributeDict
int m_CommandState
state of gerber analysis command
wxString m_ArchiveFileName
Archive containing this layer, if loaded from a ZIP file.
bool m_NoTrailingZeros
true: remove tailing zeros.
int m_Iterpolation
Linear, 90 arc, Circ.
VECTOR2I m_CurrentPos
current specified coord for plot
bool m_MirrorA
true: mirror / axis A (X)
bool m_LastCoordIsIJPos
True if a IJ coord was read (for arcs & circles ).
GERBER_DRAW_ITEMS & GetItems()
VECTOR2I m_ImageJustifyOffset
Image Justify Offset on XY axis (default = 0,0)
GERBER_LAYER m_GBRLayerParams
GERBER_LAYER & GetLayerParams()
void DisplayImageInfo(GERBVIEW_FRAME *aMainFrame)
Display information about image parameters in the status bar.
INSPECT_RESULT Visit(INSPECTOR aInspector, void *aTestData, const std::vector< KICAD_T > &aScanTypes) override
May be re-implemented for each derived class in order to handle all the types given by its member dat...
bool HasNegativeItems()
Return true if at least one item must be drawn in background color used to optimize screen refresh.
wxRealPoint m_StepForRepeat
Represent a set of closed polygons.
double Area()
Return the area of this poly set.
wxString MessageTextFromValue(double aValue, bool aAddUnitLabel=true, EDA_DATA_TYPE aType=EDA_DATA_TYPE::DISTANCE) const
A lower-precision version of StringFromValue().
The attribute value consists of a number of substrings separated by a comma.
const wxString & GetPrm(int aIdx)
@ WHITE
Definition color4d.h:44
#define _(s)
static constexpr EDA_ANGLE ANGLE_0
Definition eda_angle.h:448
INSPECT_RESULT
Definition eda_item.h:44
const INSPECTOR_FUNC & INSPECTOR
std::function passed to nested users by ref, avoids copying std::function.
Definition eda_item.h:91
int scaletoIU(double aCoord, bool isMetric)
Convert a distance given in floating point to our internal units.
@ ARC_INFO_TYPE_NONE
SHAPE_POLY_SET ConvertGerberToPolySet(GERBER_FILE_IMAGE *aImage, int aTolerance)
Convert a GERBER_FILE_IMAGE to a merged SHAPE_POLY_SET.
@ GERB_INTERPOL_LINEAR_1X
Definition gerbview.h:31
This file contains miscellaneous commonly used macros and functions.
KICAD_T
The set of class identification values stored in EDA_ITEM::m_structType.
Definition typeinfo.h:70
@ GERBER_DRAW_ITEM_T
Definition typeinfo.h:206
@ GERBER_IMAGE_T
Definition typeinfo.h:207
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:708
VECTOR2< double > VECTOR2D
Definition vector2d.h:707