KiCad PCB EDA Suite
Loading...
Searching...
No Matches
odb_util.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 The KiCad Developers, see AUTHORS.txt for contributors.
5 * Author: SYSUEric <[email protected]>.
6 *
7 * This program is free software: you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License along
18 * with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21#include <string>
22#include <algorithm>
23#include <locale>
24#include "odb_util.h"
25#include <wx/chartype.h>
26#include <wx/dir.h>
27#include <wx/regex.h>
28#include "idf_helpers.h"
29#include "odb_defines.h"
30#include "pcb_io_odbpp.h"
31
32namespace ODB
33{
34
35wxString GenODBString( const wxString& aStr )
36{
37 wxString str;
38
39 for( size_t ii = 0; ii < aStr.Len(); ++ii )
40 {
41 // Rule: we can only use the standard ASCII, control excluded
42 wxUniChar ch = aStr[ii];
43
44 if( ch > 126 || !std::isgraph( static_cast<unsigned char>( ch ) ) )
45 ch = '?';
46
47 str += ch;
48 }
49
50 // Rule: only uppercase
51 str.MakeUpper();
52
53 return str;
54}
55
56
57wxString GenLegalNetName( const wxString& aStr )
58{
59 std::string str = aStr.ToStdString();
60 wxString out;
61 out.reserve( str.size() );
62
63 for( auto c : str )
64 {
65 if( ( c >= 33 && c <= 126 ) && c != ';' )
66 {
67 out.append( 1, c );
68 }
69 else
70 {
71 out.append( 1, '_' ); // Replace invalid characters with underscore
72 }
73 }
74
75 return out;
76}
77
78
79wxString GenLegalComponentName( const wxString& aStr )
80{
81 wxString out;
82 out.reserve( aStr.length() );
83
84 for( size_t ii = 0; ii < aStr.Len(); ++ii )
85 {
86 wxUniChar ch = aStr[ii];
87
88 // ODB++ component names must be printable ASCII (33-126), no spaces or semicolons
89 if( ch >= 33 && ch <= 126 && ch != ';' )
90 {
91 out.append( 1, static_cast<char>( ch.IsAscii() ? ch.GetValue() : '_' ) );
92 }
93 else
94 {
95 out.append( 1, '_' ); // Replace invalid characters with underscore
96 }
97 }
98
99 return out;
100}
101
102
103// The names of these ODB++ entities must comply with
104// the rules for legal entity names:
105// product, model, step, layer, symbol, and attribute.
106wxString GenLegalEntityName( const wxString& aStr )
107{
108 std::string str = aStr.ToStdString();
109 wxString out;
110 out.reserve( str.size() );
111
112 for( auto c : str )
113 {
114 if( isalpha( c ) )
115 c = tolower( c );
116 else if( isdigit( c ) || c == '-' || c == '_' || c == '+' || c == '.' )
117 ;
118 else
119 c = '_';
120
121 out.append( 1, c );
122 }
123
124 if( out.length() > 64 )
125 {
126 out.Truncate( 64 );
127 }
128
129 while( !out.IsEmpty() && ( out[0] == '.' || out[0] == '-' || out[0] == '+' ) )
130 {
131 out.erase( 0, 1 );
132 }
133
134 while( !out.IsEmpty() && out.Last() == '.' )
135 {
136 out.RemoveLast();
137 }
138
139 return out;
140}
141
142
143void RemoveWhitespace( wxString& aStr )
144{
145 aStr.Trim().Trim( false );
146 wxRegEx spaces( "\\s" );
147 spaces.Replace( &aStr, "_" );
148}
149
150
151wxString Double2String( double aVal )
152{
153 // We don't want to output -0.0 as this value is just 0 for fabs
154 if( aVal == -0.0 )
155 aVal = 0.0;
156
157 wxString str = wxString::FromCDouble( aVal, PCB_IO_ODBPP::m_sigfig );
158
159 // Remove all but the last trailing zeros from str
160 while( str.EndsWith( wxT( "00" ) ) )
161 str.RemoveLast();
162
163 return str;
164}
165
166
167std::string Double2String( double aVal, int32_t aDigits )
168{
169 // We don't want to output -0.0 as this value is just 0 for fabs
170 if( aVal == -0.0 )
171 aVal = 0.0;
172
173 wxString str = wxString::FromCDouble( aVal, aDigits );
174
175 return str.ToStdString();
176}
177
178
179wxString SymDouble2String( double aVal )
180{
182}
183
184
185wxString Data2String( double aVal )
186{
187 return Double2String( PCB_IO_ODBPP::m_scale * aVal );
188}
189
190
191std::pair<wxString, wxString> AddXY( const VECTOR2I& aVec )
192{
193 // TODO: to deal with user preference x y increment setting
194 std::pair<wxString, wxString> xy =
195 std::pair<wxString, wxString>( Double2String( PCB_IO_ODBPP::m_scale * aVec.x ),
197
198 return xy;
199}
200
201
203{
204 VECTOR2D pos{};
205
206 switch( aShape.GetShape() )
207 {
208 // Rectangles in KiCad are mapped by their corner while ODBPP uses the center
210 pos = aShape.GetPosition()
211 + VECTOR2I( aShape.GetRectangleWidth() / 2.0, aShape.GetRectangleHeight() / 2.0 );
212 break;
213 // Both KiCad and ODBPP use the center of the circle
214 case SHAPE_T::CIRCLE:
215 // KiCad uses the exact points on the board
216 case SHAPE_T::POLY:
217 case SHAPE_T::BEZIER:
218 case SHAPE_T::SEGMENT:
219 case SHAPE_T::ARC:
221 pos = aShape.GetPosition();
222 break;
223 }
224
225 return pos;
226}
227} // namespace ODB
228
229
230void ODB_TREE_WRITER::CreateEntityDirectory( const wxString& aPareDir,
231 const wxString& aSubDir /*= wxEmptyString*/ )
232{
233 wxFileName path = wxFileName::DirName( aPareDir );
234
235 wxArrayString subDirs = wxFileName::DirName( aSubDir.Lower() ).GetDirs();
236
237 for( size_t i = 0; i < subDirs.GetCount(); i++ )
238 path.AppendDir( subDirs[i] );
239
240 if( !path.DirExists() )
241 {
242 if( !path.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
243 {
244 throw( std::runtime_error( "Could not create directory" + path.GetPath() ) );
245 }
246 }
247
248 m_currentPath = path.GetPath();
249}
250
251
252ODB_FILE_WRITER::ODB_FILE_WRITER( ODB_TREE_WRITER& aTreeWriter, const wxString& aFileName ) :
253 m_treeWriter( aTreeWriter )
254{
255 CreateFile( aFileName );
256}
257
258
259void ODB_FILE_WRITER::CreateFile( const wxString& aFileName )
260{
261 if( aFileName.IsEmpty() || m_treeWriter.GetCurrentPath().IsEmpty() )
262 return;
263
264 wxFileName fn;
265 fn.SetPath( m_treeWriter.GetCurrentPath() );
266 fn.SetFullName( aFileName );
267
268 wxString dirPath = fn.GetPath();
269
270 if( !wxDir::Exists( dirPath ) )
271 {
272 if( !wxDir::Make( dirPath ) )
273 throw( std::runtime_error( "Could not create directory" + dirPath ) );
274 }
275
276 if( !fn.IsDirWritable() || ( fn.Exists() && !fn.IsFileWritable() ) )
277 return;
278
279 if( m_ostream.is_open() )
280 m_ostream.close();
281
282 m_ostream.open( TO_UTF8( fn.GetFullPath() ),
283 std::ios_base::out | std::ios_base::trunc | std::ios_base::binary );
284
285 m_ostream.imbue( std::locale::classic() );
286
287 if( !m_ostream.is_open() || !m_ostream.good() )
288 throw std::runtime_error( "Failed to open file: " + fn.GetFullPath() );
289}
290
291
293{
294 if( m_ostream.is_open() )
295 {
296 m_ostream.close();
297
298 if( !m_ostream.good() )
299 {
300 throw std::runtime_error( "close file failed" );
301 return false;
302 }
303 }
304
305 return true;
306}
307
308
309void ODB_TEXT_WRITER::WriteEquationLine( const std::string& var, int value )
310{
311 WriteIndent();
312 m_ostream << var << "=" << value << std::endl;
313}
314
315
316void ODB_TEXT_WRITER::WriteEquationLine( const wxString& var, const wxString& value )
317{
318 WriteIndent();
319 m_ostream << var << "=" << value << std::endl;
320}
321
322
324{
325 if( in_array )
326 m_ostream << " ";
327}
328
329
330void ODB_TEXT_WRITER::BeginArray( const std::string& a )
331{
332 if( in_array )
333 throw std::runtime_error( "already in array" );
334 in_array = true;
335 m_ostream << a << " {" << std::endl;
336}
337
338
340{
341 if( !in_array )
342 throw std::runtime_error( "not in array" );
343 in_array = false;
344 m_ostream << "}" << std::endl << std::endl;
345}
346
347
348ODB_TEXT_WRITER::ARRAY_PROXY::ARRAY_PROXY( ODB_TEXT_WRITER& aWriter, const std::string& aStr ) :
349 m_writer( aWriter )
350{
351 m_writer.BeginArray( aStr );
352}
353
354
359
360
361ODB_DRILL_TOOLS::ODB_DRILL_TOOLS( const wxString& aUnits, const wxString& aThickness,
362 const wxString& aUserParams ) :
363 m_units( aUnits ), m_thickness( aThickness ), m_userParams( aUserParams )
364{
365}
366
367
368void ODB_DRILL_TOOLS::GenerateFile( std::ostream& aStream )
369{
370 ODB_TEXT_WRITER twriter( aStream );
371
372 twriter.WriteEquationLine( "UNITS", m_units );
373 twriter.WriteEquationLine( "THICKNESS", m_thickness );
374 twriter.WriteEquationLine( "USER_PARAMS", m_userParams );
375
376 for( const auto& tool : m_tools )
377 {
378 const auto array_proxy = twriter.MakeArrayProxy( "TOOLS" );
379 twriter.WriteEquationLine( "NUM", tool.m_num );
380 twriter.WriteEquationLine( "TYPE", tool.m_type );
381 twriter.WriteEquationLine( "TYPE2", tool.m_type2 );
382 twriter.WriteEquationLine( "MIN_TOL", tool.m_minTol );
383 twriter.WriteEquationLine( "MAX_TOL", tool.m_maxTol );
384 twriter.WriteEquationLine( "BIT", tool.m_bit );
385 twriter.WriteEquationLine( "FINISH_SIZE", tool.m_finishSize );
386 twriter.WriteEquationLine( "DRILL_SIZE", tool.m_drillSize );
387 }
388}
int GetRectangleWidth() const
SHAPE_T GetShape() const
Definition eda_shape.h:169
int GetRectangleHeight() const
wxString m_units
Definition odb_util.h:366
void GenerateFile(std::ostream &aStream)
Definition odb_util.cpp:368
ODB_DRILL_TOOLS(const wxString &aUnits, const wxString &aThickness="0", const wxString &aUserParams=wxEmptyString)
Definition odb_util.cpp:361
wxString m_thickness
Definition odb_util.h:367
wxString m_userParams
Definition odb_util.h:368
std::vector< ODB_DRILL_TOOLS::TOOLS > m_tools
Definition odb_util.h:369
void CreateFile(const wxString &aFileName)
Definition odb_util.cpp:259
ODB_TREE_WRITER & m_treeWriter
Definition odb_util.h:239
ODB_FILE_WRITER(ODB_TREE_WRITER &aTreeWriter, const wxString &aFileName)
Definition odb_util.cpp:252
std::ofstream m_ostream
Definition odb_util.h:240
ARRAY_PROXY(ODB_TEXT_WRITER &aWriter, const std::string &aStr)
Definition odb_util.cpp:348
ODB_TEXT_WRITER & m_writer
Definition odb_util.h:303
void WriteEquationLine(const std::string &var, int value)
Definition odb_util.cpp:309
ARRAY_PROXY MakeArrayProxy(const std::string &aStr)
Definition odb_util.h:314
std::ostream & m_ostream
Definition odb_util.h:326
void BeginArray(const std::string &a)
Definition odb_util.cpp:330
void CreateEntityDirectory(const wxString &aPareDir, const wxString &aSubDir=wxEmptyString)
Definition odb_util.cpp:230
wxString m_currentPath
Definition odb_util.h:273
static int m_sigfig
static double m_symbolScale
static double m_scale
VECTOR2I GetPosition() const override
Definition pcb_shape.h:79
@ UNDEFINED
Definition eda_shape.h:44
@ SEGMENT
Definition eda_shape.h:45
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:46
wxString GenLegalComponentName(const wxString &aStr)
Definition odb_util.cpp:79
wxString Data2String(double aVal)
Definition odb_util.cpp:185
void RemoveWhitespace(wxString &aStr)
Definition odb_util.cpp:143
wxString GenODBString(const wxString &aStr)
Definition odb_util.cpp:35
std::pair< wxString, wxString > AddXY(const VECTOR2I &aVec)
Definition odb_util.cpp:191
wxString GenLegalEntityName(const wxString &aStr)
Definition odb_util.cpp:106
wxString GenLegalNetName(const wxString &aStr)
Definition odb_util.cpp:57
wxString Double2String(double aVal)
Definition odb_util.cpp:151
wxString SymDouble2String(double aVal)
Definition odb_util.cpp:179
VECTOR2I GetShapePosition(const PCB_SHAPE &aShape)
Definition odb_util.cpp:202
#define TO_UTF8(wxstring)
Convert a wxString to a UTF8 encoded C string for all wxWidgets build modes.
std::string path
VECTOR2< int32_t > VECTOR2I
Definition vector2d.h:695
VECTOR2< double > VECTOR2D
Definition vector2d.h:694