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:
220 case SHAPE_T::ELLIPSE:
223 pos = aShape.GetPosition();
224 break;
225 }
226
227 return pos;
228}
229} // namespace ODB
230
231
232void ODB_TREE_WRITER::CreateEntityDirectory( const wxString& aPareDir,
233 const wxString& aSubDir /*= wxEmptyString*/ )
234{
235 wxFileName path = wxFileName::DirName( aPareDir );
236
237 wxArrayString subDirs = wxFileName::DirName( aSubDir.Lower() ).GetDirs();
238
239 for( size_t i = 0; i < subDirs.GetCount(); i++ )
240 path.AppendDir( subDirs[i] );
241
242 if( !path.DirExists() )
243 {
244 if( !path.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
245 {
246 throw( std::runtime_error( "Could not create directory" + path.GetPath() ) );
247 }
248 }
249
250 m_currentPath = path.GetPath();
251}
252
253
254ODB_FILE_WRITER::ODB_FILE_WRITER( ODB_TREE_WRITER& aTreeWriter, const wxString& aFileName ) :
255 m_treeWriter( aTreeWriter )
256{
257 CreateFile( aFileName );
258}
259
260
261void ODB_FILE_WRITER::CreateFile( const wxString& aFileName )
262{
263 if( aFileName.IsEmpty() || m_treeWriter.GetCurrentPath().IsEmpty() )
264 return;
265
266 wxFileName fn;
267 fn.SetPath( m_treeWriter.GetCurrentPath() );
268 fn.SetFullName( aFileName );
269
270 wxString dirPath = fn.GetPath();
271
272 if( !wxDir::Exists( dirPath ) )
273 {
274 if( !wxDir::Make( dirPath ) )
275 throw( std::runtime_error( "Could not create directory" + dirPath ) );
276 }
277
278 if( !fn.IsDirWritable() || ( fn.Exists() && !fn.IsFileWritable() ) )
279 return;
280
281 if( m_ostream.is_open() )
282 m_ostream.close();
283
284 m_ostream.open( TO_UTF8( fn.GetFullPath() ),
285 std::ios_base::out | std::ios_base::trunc | std::ios_base::binary );
286
287 m_ostream.imbue( std::locale::classic() );
288
289 if( !m_ostream.is_open() || !m_ostream.good() )
290 throw std::runtime_error( "Failed to open file: " + fn.GetFullPath() );
291}
292
293
295{
296 if( m_ostream.is_open() )
297 {
298 m_ostream.close();
299
300 if( !m_ostream.good() )
301 throw std::runtime_error( "close file failed" );
302 }
303
304 return true;
305}
306
307
308void ODB_TEXT_WRITER::WriteEquationLine( const std::string& var, int value )
309{
310 WriteIndent();
311 m_ostream << var << "=" << value << std::endl;
312}
313
314
315void ODB_TEXT_WRITER::WriteEquationLine( const wxString& var, const wxString& value )
316{
317 WriteIndent();
318 m_ostream << var << "=" << value << std::endl;
319}
320
321
323{
324 if( in_array )
325 m_ostream << " ";
326}
327
328
329void ODB_TEXT_WRITER::BeginArray( const std::string& a )
330{
331 if( in_array )
332 throw std::runtime_error( "already in array" );
333 in_array = true;
334 m_ostream << a << " {" << std::endl;
335}
336
337
339{
340 if( !in_array )
341 throw std::runtime_error( "not in array" );
342 in_array = false;
343 m_ostream << "}" << std::endl << std::endl;
344}
345
346
347ODB_TEXT_WRITER::ARRAY_PROXY::ARRAY_PROXY( ODB_TEXT_WRITER& aWriter, const std::string& aStr ) :
348 m_writer( aWriter )
349{
350 m_writer.BeginArray( aStr );
351}
352
353
358
359
360ODB_DRILL_TOOLS::ODB_DRILL_TOOLS( const wxString& aUnits, const wxString& aThickness,
361 const wxString& aUserParams ) :
362 m_units( aUnits ), m_thickness( aThickness ), m_userParams( aUserParams )
363{
364}
365
366
367void ODB_DRILL_TOOLS::GenerateFile( std::ostream& aStream )
368{
369 ODB_TEXT_WRITER twriter( aStream );
370
371 twriter.WriteEquationLine( "UNITS", m_units );
372 twriter.WriteEquationLine( "THICKNESS", m_thickness );
373 twriter.WriteEquationLine( "USER_PARAMS", m_userParams );
374
375 for( const auto& tool : m_tools )
376 {
377 const auto array_proxy = twriter.MakeArrayProxy( "TOOLS" );
378 twriter.WriteEquationLine( "NUM", tool.m_num );
379 twriter.WriteEquationLine( "TYPE", tool.m_type );
380 twriter.WriteEquationLine( "TYPE2", tool.m_type2 );
381 twriter.WriteEquationLine( "MIN_TOL", tool.m_minTol );
382 twriter.WriteEquationLine( "MAX_TOL", tool.m_maxTol );
383 twriter.WriteEquationLine( "BIT", tool.m_bit );
384 twriter.WriteEquationLine( "FINISH_SIZE", tool.m_finishSize );
385 twriter.WriteEquationLine( "DRILL_SIZE", tool.m_drillSize );
386 }
387}
int GetRectangleWidth() const
SHAPE_T GetShape() const
Definition eda_shape.h:189
int GetRectangleHeight() const
wxString m_units
Definition odb_util.h:366
void GenerateFile(std::ostream &aStream)
Definition odb_util.cpp:367
ODB_DRILL_TOOLS(const wxString &aUnits, const wxString &aThickness="0", const wxString &aUserParams=wxEmptyString)
Definition odb_util.cpp:360
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:261
ODB_TREE_WRITER & m_treeWriter
Definition odb_util.h:239
ODB_FILE_WRITER(ODB_TREE_WRITER &aTreeWriter, const wxString &aFileName)
Definition odb_util.cpp:254
std::ofstream m_ostream
Definition odb_util.h:240
ARRAY_PROXY(ODB_TEXT_WRITER &aWriter, const std::string &aStr)
Definition odb_util.cpp:347
ODB_TEXT_WRITER & m_writer
Definition odb_util.h:303
void WriteEquationLine(const std::string &var, int value)
Definition odb_util.cpp:308
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:329
void CreateEntityDirectory(const wxString &aPareDir, const wxString &aSubDir=wxEmptyString)
Definition odb_util.cpp:232
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:49
@ ELLIPSE
Definition eda_shape.h:56
@ SEGMENT
Definition eda_shape.h:50
@ RECTANGLE
Use RECTANGLE instead of RECT to avoid collision in a Windows header.
Definition eda_shape.h:51
@ ELLIPSE_ARC
Definition eda_shape.h:57
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:687
VECTOR2< double > VECTOR2D
Definition vector2d.h:686