KiCad PCB EDA Suite
Loading...
Searching...
No Matches
readgerb.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) 2007-2016 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 "ki_exception.h"
22#include <string_utils.h>
23#include <gerbview.h>
24#include <gerbview_frame.h>
25#include <gerber_file_image.h>
27#include <richio.h>
28#include <view/view.h>
29
31#include <macros.h>
32
33#include <wx/msgdlg.h>
34
35/* Read a gerber file, RS274D, RS274X or RS274X2 format.
36 */
37bool GERBVIEW_FRAME::Read_GERBER_File( const wxString& GERBER_FullFileName )
38{
39 wxString msg;
40
41 int layer = GetActiveLayer();
43 GERBER_FILE_IMAGE* gerber = GetGbrImage( layer );
44
45 if( gerber != nullptr )
46 {
48 }
49
50 // use an unique ptr while we load to free on exception properly
51 std::unique_ptr<GERBER_FILE_IMAGE> gerber_uptr = std::make_unique<GERBER_FILE_IMAGE>( layer );
52
53 // Read the gerber file. The image will be added only if it can be read
54 // to avoid broken data.
55 bool success = gerber_uptr->LoadGerberFile( GERBER_FullFileName );
56
57 if( !success )
58 {
59 gerber_uptr.reset();
60 msg.Printf( _( "File '%s' not found" ), GERBER_FullFileName );
61 ShowInfoBarError( msg );
62 return false;
63 }
64
65 gerber = gerber_uptr.release();
66 wxASSERT( gerber != nullptr );
67 images->AddGbrImage( gerber, layer );
68
69 // Display errors list
70 if( gerber->GetMessages().size() > 0 )
71 {
72 HTML_MESSAGE_BOX dlg( this, _( "Errors" ) );
73 dlg.ListSet( gerber->GetMessages() );
74 dlg.ShowModal();
75 }
76
77 /* if the gerber file has items using D codes but missing D codes definitions,
78 * it can be a deprecated RS274D file (i.e. without any aperture information),
79 * or has missing definitions,
80 * warn the user:
81 */
82 if( gerber->GetItemsCount() && gerber->m_Has_MissingDCode )
83 {
84 if( !gerber->m_Has_DCode )
85 msg = _("Warning: this file has no D-Code definition\n"
86 "Therefore the size of some items is undefined");
87 else
88 msg = _("Warning: this file has some missing D-Code definitions\n"
89 "Therefore the size of some items is undefined");
90
91 wxMessageBox( msg );
92 }
93
94 if( GetCanvas() )
95 {
96 if( gerber->m_ImageNegative )
97 {
98 // TODO: find a way to handle negative images
99 // (maybe convert geometry into positives?)
100 }
101
102 for( GERBER_DRAW_ITEM* item : gerber->GetItems() )
103 GetCanvas()->GetView()->Add( (KIGFX::VIEW_ITEM*) item );
104 }
105
106 return true;
107}
108
109
110/*
111 * Original function derived from gerber_is_rs274x_p() of gerbv 2.7.0.
112 * Copyright of the source file readgerb.cpp included below:
113 */
114/* gEDA - GNU Electronic Design Automation
115 * This is a part of gerbv
116 *
117 * Copyright (C) 2000-2003 Stefan Petersen ([email protected])
118 *
119 * $Id$
120 *
121 * This program is free software; you can redistribute it and/or modify
122 * it under the terms of the GNU General Public License as published by
123 * the Free Software Foundation; either version 2 of the License, or
124 * (at your option) any later version.
125 *
126 * This program is distributed in the hope that it will be useful,
127 * but WITHOUT ANY WARRANTY; without even the implied warranty of
128 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
129 * GNU General Public License for more details.
130 *
131 * You should have received a copy of the GNU General Public License
132 * along with this program. If not, see <https://www.gnu.org/licenses/>.
133 */
134bool GERBER_FILE_IMAGE::TestFileIsRS274( const wxString& aFullFileName )
135{
136 char* letter = nullptr;
137 bool foundADD = false;
138 bool foundD0 = false;
139 bool foundD2 = false;
140 bool foundM0 = false;
141 bool foundM2 = false;
142 bool foundStar = false;
143 bool foundX = false;
144 bool foundY = false;
145
146 try
147 {
148 FILE_LINE_READER gerberReader( aFullFileName );
149
150 while( gerberReader.ReadLine() )
151 {
152 // Remove all whitespace from the beginning and end
153 char* line = StrPurge( gerberReader.Line() );
154
155 // Skip empty lines
156 if( *line == 0 )
157 continue;
158
159 // Check that file is not binary (non-printing chars)
160 size_t len = strlen( line );
161
162 for( size_t i = 0; i < len; i++ )
163 {
164 if( !isascii( line[i] ) )
165 return false;
166 }
167
168 if( strstr( line, "%ADD" ) )
169 foundADD = true;
170
171 if( strstr( line, "D00" ) || strstr( line, "D0" ) )
172 foundD0 = true;
173
174 if( strstr( line, "D02" ) || strstr( line, "D2" ) )
175 foundD2 = true;
176
177 if( strstr( line, "M00" ) || strstr( line, "M0" ) )
178 foundM0 = true;
179
180 if( strstr( line, "M02" ) || strstr( line, "M2" ) )
181 foundM2 = true;
182
183 if( strstr( line, "*" ) )
184 foundStar = true;
185
186 /* look for X<number> or Y<number> */
187 if( ( letter = strstr( line, "X" ) ) != nullptr )
188 {
189 if( isdigit( letter[1] ) )
190 foundX = true;
191 }
192
193 if( ( letter = strstr( line, "Y" ) ) != nullptr )
194 {
195 if( isdigit( letter[1] ) )
196 foundY = true;
197 }
198 }
199 }
200 catch( IO_ERROR& )
201 {
202 return false;
203 }
204
205 // RS-274X
206 if( ( foundD0 || foundD2 || foundM0 || foundM2 ) && foundADD && foundStar
207 && ( foundX || foundY ) )
208 {
209 return true;
210 }
211 // RS-274D. Could be folded into the expression above, but someday
212 // we might want to test for them separately.
213 else if( ( foundD0 || foundD2 || foundM0 || foundM2 ) && !foundADD && foundStar
214 && ( foundX || foundY ) )
215 {
216 return true;
217 }
218
219
220 return false;
221}
222
223
224// A large buffer to store one line
226
227bool GERBER_FILE_IMAGE::LoadGerberFile( const wxString& aFullFileName )
228{
229 int G_command = 0; // command number for G commands like G04
230 int D_commande = 0; // command number for D commands like D02
231 char* text;
232
235
236 // Read the gerber file */
237 m_Current_File = wxFopen( aFullFileName, wxT( "rt" ) );
238
239 if( m_Current_File == nullptr )
240 return false;
241
242 m_FileName = aFullFileName;
243
244 wxString msg;
245
246 while( true )
247 {
248 if( fgets( m_LineBuffer, GERBER_BUFZ, m_Current_File ) == nullptr )
249 break;
250
251 m_LineNum++;
253
254 while( text && *text )
255 {
256 switch( *text )
257 {
258 case ' ':
259 case '\r':
260 case '\n':
261 text++;
262 break;
263
264 case '*': // End command
266 text++;
267 break;
268
269 case 'M': // End file
271 while( *text )
272 text++;
273 break;
274
275 case 'G': /* Line type Gxx : command */
276 G_command = CodeNumber( text );
277 Execute_G_Command( text, G_command );
278 break;
279
280 case 'D': /* Line type Dxx : Tool selection (xx > 0) or
281 * command if xx = 0..9 */
282 D_commande = CodeNumber( text );
283 Execute_DCODE_Command( text, D_commande );
284 break;
285
286 case 'X':
287 case 'Y': /* Move or draw command */
289 if( *text == '*' ) // command like X12550Y19250*
290 {
292 }
293 break;
294
295 case 'I':
296 case 'J': /* Auxiliary Move command */
298
299 if( *text == '*' ) // command like X35142Y15945J504*
300 {
302 }
303 break;
304
305 case '%':
307 {
310 }
311 else //Error
312 {
313 AddMessageToList( wxT( "Expected RS274X Command" ) );
315 text++;
316 }
317 break;
318
319 default:
320 char charBuf[2] = { *text, 0 };
321 wchar_t wcharBuf[2] = { 0 };
322
323 wxWhateverWorksConv().ToWChar( wcharBuf, 1, charBuf, 1 );
324
325 if( wcharBuf[0] < 32 ) // Don't render control characters
326 wcharBuf[0] = '?';
327
328 msg.Printf( wxT( "Unexpected char 0x%2.2X (%c)" ), (unsigned char) *text,
329 wcharBuf[0] );
330
332 text++;
333 break;
334 }
335 }
336 }
337
338 fclose( m_Current_File );
339
340 m_InUse = true;
341
342 return true;
343}
int ShowModal() override
void ShowInfoBarError(const wxString &aErrorMsg, bool aShowCloseButton=false, INFOBAR_MESSAGE_TYPE aType=INFOBAR_MESSAGE_TYPE::GENERIC)
Show the WX_INFOBAR displayed on the top of the canvas with a message and an error icon on the left o...
virtual EDA_DRAW_PANEL_GAL * GetCanvas() const
Return a pointer to GAL-based canvas of given EDA draw frame.
virtual KIGFX::VIEW * GetView() const
Return a pointer to the #VIEW instance used in the panel.
A LINE_READER that reads from an open file.
Definition richio.h:154
char * ReadLine() override
Read a line of text into the buffer and increments the line number counter.
Definition richio.cpp:208
GERBER_FILE_IMAGE_LIST is a helper class to handle a list of GERBER_FILE_IMAGE files which are loaded...
int AddGbrImage(GERBER_FILE_IMAGE *aGbrImage, int aIdx)
Add a GERBER_FILE_IMAGE* at index aIdx or at the first free location if aIdx < 0.
Hold the image data and parameters for one gerber file and layer parameters.
bool Execute_G_Command(char *&text, int G_command)
Definition rs274d.cpp:421
bool LoadGerberFile(const wxString &aFullFileName)
Read and load a gerber file.
Definition readgerb.cpp:227
int m_Last_Pen_Command
Current or last pen state (0..9, set by Dn option with n < 10.
VECTOR2I ReadIJCoord(char *&Text)
Return the current coordinate type pointed to by InnJnn Text (InnnnJmmmm)
static char m_LineBuffer[GERBER_BUFZ+1]
virtual void ResetDefaultValues()
Set all parameters to a default value, before reading a file.
const wxArrayString & GetMessages() const
void ClearMessageList()
Clear the message list.
wxString m_FileName
Full File Name for this layer.
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.
int m_LineNum
Line number of the gerber file while reading.
VECTOR2I m_IJPos
IJ coord (for arcs & circles )
bool Execute_DCODE_Command(char *&text, int D_command)
Definition rs274d.cpp:553
static bool TestFileIsRS274(const wxString &aFullFileName)
Performs a heuristics-based check of whether the file is an RS274 gerber file.
Definition readgerb.cpp:134
bool ReadRS274XCommand(char *aBuff, unsigned int aBuffSize, char *&aText)
Read a single RS274X command terminated with a %.
Definition rs274x.cpp:138
bool m_Has_DCode
< True if has DCodes in file or false if no DCodes found. Perhaps deprecated RS274D file.
VECTOR2I ReadXYCoord(char *&aText, bool aExcellonMode=false)
Return the current coordinate type pointed to by XnnYnn Text (XnnnnYmmmm).
int m_CommandState
state of gerber analysis command
VECTOR2I m_CurrentPos
current specified coord for plot
GERBER_DRAW_ITEMS & GetItems()
int CodeNumber(char *&aText)
Reads the next number and returns the value.
Definition rs274d.cpp:401
GERBER_FILE_IMAGE_LIST * GetImagesList() const
Accessors to GERBER_FILE_IMAGE_LIST and GERBER_FILE_IMAGE data.
int GetActiveLayer() const
Return the active layer.
bool Read_GERBER_File(const wxString &GERBER_FullFileName)
Definition readgerb.cpp:37
GERBER_FILE_IMAGE * GetGbrImage(int aIdx) const
void Erase_Current_DrawLayer(bool query)
void ListSet(const wxString &aList)
Add a list of items.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
An abstract base class for deriving all objects that can be added to a VIEW.
Definition view_item.h:82
virtual void Add(VIEW_ITEM *aItem, int aDrawPriority=-1)
Add a VIEW_ITEM to the view.
Definition view.cpp:300
char * Line() const
Return a pointer to the last line that was read in.
Definition richio.h:98
#define _(s)
#define GERBER_BUFZ
@ END_BLOCK
Definition gerbview.h:61
@ ENTER_RS274X_CMD
Definition gerbview.h:62
@ CMD_IDLE
Definition gerbview.h:60
This file contains miscellaneous commonly used macros and functions.
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
char * StrPurge(char *text)
Remove leading and training spaces, tabs and end of line chars in text.